From ee2d3ed052007967427262a6f45eaf12ea53bc18 Mon Sep 17 00:00:00 2001 From: Alejandro Bailo <59607668+alejandrobailo@users.noreply.github.com> Date: Mon, 10 Nov 2025 09:19:10 +0100 Subject: [PATCH 01/23] feat: implement new design system variables across new components and add skeletons (#9193) --- .../components/risk-severity-chart.tsx | 35 ++- .../new-overview/components/status-chart.tsx | 52 ++++- .../new-overview/components/threat-score.tsx | 209 +++++++++--------- ui/app/(prowler)/new-overview/page.tsx | 33 +-- ui/components/graphs/donut-chart.tsx | 10 +- ui/components/graphs/horizontal-bar-chart.tsx | 37 ++-- ui/components/graphs/radial-chart.tsx | 26 +-- ui/components/graphs/shared/constants.ts | 11 +- .../shadcn/card/base-card/base-card.tsx | 36 --- ui/components/shadcn/card/card.tsx | 51 ++++- .../resource-stats-card-container.tsx | 55 ----- .../resource-stats-card-content.tsx | 20 +- .../resource-stats-card-divider.tsx | 59 ----- .../resource-stats-card-header.tsx | 27 +-- .../resource-stats-card.tsx | 16 +- ui/components/shadcn/index.ts | 4 +- ui/components/shadcn/skeleton/skeleton.tsx | 16 ++ ui/styles/globals.css | 61 ++--- 18 files changed, 348 insertions(+), 410 deletions(-) delete mode 100644 ui/components/shadcn/card/base-card/base-card.tsx delete mode 100644 ui/components/shadcn/card/resource-stats-card/resource-stats-card-container.tsx delete mode 100644 ui/components/shadcn/card/resource-stats-card/resource-stats-card-divider.tsx create mode 100644 ui/components/shadcn/skeleton/skeleton.tsx diff --git a/ui/app/(prowler)/new-overview/components/risk-severity-chart.tsx b/ui/app/(prowler)/new-overview/components/risk-severity-chart.tsx index b070a828ba..22f6fbb3b9 100644 --- a/ui/app/(prowler)/new-overview/components/risk-severity-chart.tsx +++ b/ui/app/(prowler)/new-overview/components/risk-severity-chart.tsx @@ -3,10 +3,11 @@ import { HorizontalBarChart } from "@/components/graphs/horizontal-bar-chart"; import { BarDataPoint } from "@/components/graphs/types"; import { - BaseCard, + Card, CardContent, CardHeader, CardTitle, + Skeleton, } from "@/components/shadcn"; import { calculatePercentage } from "@/lib/utils"; @@ -58,7 +59,10 @@ export const RiskSeverityChart = ({ ]; return ( - + Risk Severity @@ -66,6 +70,31 @@ export const RiskSeverityChart = ({ - + ); }; + +export function RiskSeverityChartSkeleton() { + return ( + + + + + + +
+ {/* 5 horizontal bar skeletons */} + {Array.from({ length: 5 }).map((_, index) => ( +
+ + +
+ ))} +
+
+
+ ); +} diff --git a/ui/app/(prowler)/new-overview/components/status-chart.tsx b/ui/app/(prowler)/new-overview/components/status-chart.tsx index 7e773f90e7..1efb406975 100644 --- a/ui/app/(prowler)/new-overview/components/status-chart.tsx +++ b/ui/app/(prowler)/new-overview/components/status-chart.tsx @@ -5,13 +5,13 @@ import { Bell, BellOff, ShieldCheck, TriangleAlert } from "lucide-react"; import { DonutChart } from "@/components/graphs/donut-chart"; import { DonutDataPoint } from "@/components/graphs/types"; import { - BaseCard, + Card, CardContent, CardHeader, CardTitle, CardVariant, ResourceStatsCard, - ResourceStatsCardContainer, + Skeleton, } from "@/components/shadcn"; import { calculatePercentage } from "@/lib/utils"; @@ -60,27 +60,30 @@ export const StatusChart = ({ { name: "Fail Findings", value: failFindingsData.total, - color: "#f43f5e", // Rose-500 + color: "var(--bg-fail-primary)", percentage: Number(failPercentage), change: Number(failChange), }, { name: "Pass Findings", value: passFindingsData.total, - color: "#4ade80", // Green-400 + color: "var(--bg-pass-primary)", percentage: Number(passPercentage), change: Number(passChange), }, ]; return ( - + Check Findings - -
+ +
- +
-
+
- + - + ); }; + +export function StatusChartSkeleton() { + return ( + + + + + + + {/* Circular skeleton for donut chart */} +
+ +
+ + {/* Bottom info box skeleton */} + +
+
+ ); +} diff --git a/ui/app/(prowler)/new-overview/components/threat-score.tsx b/ui/app/(prowler)/new-overview/components/threat-score.tsx index 511f6b9d42..db07e951b8 100644 --- a/ui/app/(prowler)/new-overview/components/threat-score.tsx +++ b/ui/app/(prowler)/new-overview/components/threat-score.tsx @@ -1,7 +1,6 @@ "use client"; import { MessageCircleWarning, ThumbsUp } from "lucide-react"; -import Link from "next/link"; import type { CriticalRequirement, @@ -9,50 +8,33 @@ import type { } from "@/actions/overview/types"; import { RadialChart } from "@/components/graphs/radial-chart"; import { - SEVERITY_COLORS, - STATUS_COLORS, -} from "@/components/graphs/shared/constants"; -import { - BaseCard, + Card, CardContent, CardHeader, CardTitle, + Skeleton, } from "@/components/shadcn"; const THREAT_LEVEL_CONFIG = { - CRITICAL: { + DANGER: { label: "Critical Risk", - color: "text-red-500", - chartColor: SEVERITY_COLORS.Critical, + color: "var(--bg-fail-primary)", + chartColor: "var(--bg-fail-primary)", minScore: 0, - maxScore: 20, + maxScore: 30, }, - HIGH: { - label: "High Risk", - color: "text-orange-500", - chartColor: SEVERITY_COLORS.High, - minScore: 21, - maxScore: 40, - }, - MODERATE: { - label: "Moderately Secure", - color: "text-yellow-500", - chartColor: SEVERITY_COLORS.Medium, - minScore: 41, + WARNING: { + label: "Moderate Risk", + color: "var(--bg-warning-primary)", + chartColor: "var(--bg-warning-primary)", + minScore: 31, maxScore: 60, }, - LOW: { - label: "Low Risk", - color: "text-blue-500", - chartColor: SEVERITY_COLORS.Low, + SUCCESS: { + label: "Secure", + color: "var(--bg-pass-primary)", + chartColor: "var(--bg-pass-primary)", minScore: 61, - maxScore: 80, - }, - SECURE: { - label: "Highly Secure", - color: "text-green-500", - chartColor: STATUS_COLORS.Success, - minScore: 81, maxScore: 100, }, } as const; @@ -74,7 +56,7 @@ function getThreatLevel(score: number): ThreatLevelKey { return key as ThreatLevelKey; } } - return "MODERATE"; + return "WARNING"; } // Convert section scores to tooltip data for the radial chart @@ -84,16 +66,13 @@ function convertSectionScoresToTooltipData( if (!sectionScores) return []; return Object.entries(sectionScores).map(([name, value]) => { - // Determine color based on score value - let color: string = SEVERITY_COLORS.Critical; - if (value >= 80) color = STATUS_COLORS.Success; - else if (value >= 60) color = SEVERITY_COLORS.Low; - else if (value >= 40) color = SEVERITY_COLORS.Medium; - else if (value >= 20) color = SEVERITY_COLORS.High; - // Round to nearest integer const roundedValue = Math.round(value); + // Determine color based on the same ranges as THREAT_LEVEL_CONFIG + const threatLevel = getThreatLevel(roundedValue); + const color = THREAT_LEVEL_CONFIG[threatLevel].chartColor; + return { name, value: roundedValue, color }; }); } @@ -122,22 +101,10 @@ export function ThreatScore({ sectionScores, criticalRequirements, }: ThreatScoreProps) { - if (score === null || score === undefined) { - return ( - - - Prowler Threat Score - - -

- No ThreatScore data available -

-
-
- ); - } + const hasData = score !== null && score !== undefined; + const displayScore = hasData ? score : 0; - const threatLevel = getThreatLevel(score); + const threatLevel = getThreatLevel(displayScore); const config = THREAT_LEVEL_CONFIG[threatLevel]; // Convert section scores to tooltip data @@ -147,20 +114,23 @@ export function ThreatScore({ const gaps = extractTopGaps(criticalRequirements, 2); return ( - + Prowler Threat Score - + {/* Radial Chart */} -
-
+
+
{/* Overlaid Text (centered) */} -
-

- {config.label} -

-
+ {hasData && ( +
+

+ {config.label} +

+
+ )}
- {/* Info Box */} -
-
- {/* Improvement Message */} - {scoreDelta !== undefined && - scoreDelta !== null && - scoreDelta !== 0 && ( -
- + {/* Info Box or Empty State */} + {hasData ? ( + +
+ {/* Improvement Message */} + {scoreDelta !== undefined && + scoreDelta !== null && + scoreDelta !== 0 && ( +
+ +

+ Threat score has{" "} + {scoreDelta > 0 ? "improved" : "decreased"} by{" "} + {Math.abs(scoreDelta)}% +

+
+ )} + + {/* Gaps Message */} + {gaps.length > 0 && ( +
+

- Threat score has {scoreDelta > 0 ? "improved" : "decreased"}{" "} - by {Math.abs(scoreDelta)}% + Major gaps include {gaps.slice(0, 2).join(", ")} + {gaps.length > 2 && ` & ${gaps.length - 2} more...`}

)} - - {/* Gaps Message */} - {gaps.length > 0 && ( -
- -

- Major gaps include {gaps.slice(0, 2).join(", ")} - {gaps.length > 2 && ` & ${gaps.length - 2} more...`} -

-
- )} - - {/* View Remediation Plan Button */} -
- - - View Remediation Plan - -
-
-
+ + ) : ( + +

+ Threat Score Data Unavailable +

+
+ )} - + + ); +} + +export function ThreatScoreSkeleton() { + return ( + + + + + + + {/* Circular skeleton for radial chart */} +
+ +
+ + {/* Bottom info box skeleton */} + +
+
); } diff --git a/ui/app/(prowler)/new-overview/page.tsx b/ui/app/(prowler)/new-overview/page.tsx index d45665be0e..954c668649 100644 --- a/ui/app/(prowler)/new-overview/page.tsx +++ b/ui/app/(prowler)/new-overview/page.tsx @@ -11,9 +11,12 @@ import { SearchParamsProps } from "@/types"; import { AccountsSelector } from "./components/accounts-selector"; import { ProviderTypeSelector } from "./components/provider-type-selector"; -import { RiskSeverityChart } from "./components/risk-severity-chart"; -import { StatusChart } from "./components/status-chart"; -import { ThreatScore } from "./components/threat-score"; +import { + RiskSeverityChart, + RiskSeverityChartSkeleton, +} from "./components/risk-severity-chart"; +import { StatusChart, StatusChartSkeleton } from "./components/status-chart"; +import { ThreatScore, ThreatScoreSkeleton } from "./components/threat-score"; const FILTER_PREFIX = "filter["; @@ -42,33 +45,15 @@ export default async function NewOverviewPage({
- -

Loading...

-
- } - > + }> - -

Loading...

-
- } - > + }> - -

Loading...

-
- } - > + }>
diff --git a/ui/components/graphs/donut-chart.tsx b/ui/components/graphs/donut-chart.tsx index 21fefd058b..e8c1c6e0da 100644 --- a/ui/components/graphs/donut-chart.tsx +++ b/ui/components/graphs/donut-chart.tsx @@ -30,7 +30,7 @@ const CustomTooltip = ({ active, payload }: any) => { const change = entry.payload?.change; return ( -
+
{/* Title with color chip */}
@@ -38,7 +38,7 @@ const CustomTooltip = ({ active, payload }: any) => { className="size-3 shrink-0 rounded" style={{ backgroundColor: color }} /> -

+

{percentage}% {name}

@@ -46,7 +46,7 @@ const CustomTooltip = ({ active, payload }: any) => { {/* Change percentage row */} {change !== undefined && (
-

+

{change > 0 ? "+" : ""} {change}% Since last scan

@@ -171,7 +171,7 @@ export function DonutChart({ { @@ -38,7 +39,7 @@ export function HorizontalBarChart({ data, title }: HorizontalBarChartProps) {

{title}

@@ -50,15 +51,15 @@ export function HorizontalBarChart({ data, title }: HorizontalBarChartProps) { const isHovered = !isEmpty && hoveredIndex === index; const isFaded = !isEmpty && hoveredIndex !== null && !isHovered; const barColor = isEmpty - ? CHART_COLORS.gridLine + ? "var(--bg-neutral-tertiary)" : item.color || getSeverityColorByName(item.name) || - CHART_COLORS.defaultColor; + "var(--bg-neutral-tertiary)"; return (
!isEmpty && setHoveredIndex(index)} onMouseLeave={() => !isEmpty && setHoveredIndex(null)} > @@ -67,18 +68,18 @@ export function HorizontalBarChart({ data, title }: HorizontalBarChartProps) { - {item.name} + {item.name === "Informational" ? "Info" : item.name}
{/* Bar - flexible */}
-
+
{(item.value > 0 || isEmpty) && (
+
{/* Title with color chip */}
@@ -101,8 +102,10 @@ export function HorizontalBarChart({ data, title }: HorizontalBarChartProps) { className="size-3 shrink-0 rounded" style={{ backgroundColor: barColor }} /> -

- {item.value.toLocaleString()} {item.name} Risk +

+ {item.value.toLocaleString()}{" "} + {item.name === "Informational" ? "Info" : item.name}{" "} + Risk

@@ -111,9 +114,9 @@ export function HorizontalBarChart({ data, title }: HorizontalBarChartProps) {
-

+

{item.newFindings} New Findings

@@ -122,7 +125,7 @@ export function HorizontalBarChart({ data, title }: HorizontalBarChartProps) { {/* Change percentage row */} {item.change !== undefined && (
-

+

{item.change > 0 ? "+" : ""} {item.change}% Since last scan

@@ -137,7 +140,7 @@ export function HorizontalBarChart({ data, title }: HorizontalBarChartProps) {
• diff --git a/ui/components/graphs/radial-chart.tsx b/ui/components/graphs/radial-chart.tsx index 70b1c3a019..a80613bc59 100644 --- a/ui/components/graphs/radial-chart.tsx +++ b/ui/components/graphs/radial-chart.tsx @@ -8,8 +8,6 @@ import { Tooltip, } from "recharts"; -import { CHART_COLORS } from "./shared/constants"; - export interface TooltipItem { name: string; value: number; @@ -42,18 +40,18 @@ const CustomTooltip = ({ active, payload }: any) => { return null; return ( -
+
{tooltipItems.map((item: TooltipItem, index: number) => (
-

+

{item.name}

-
+

{item.value}% @@ -67,8 +65,8 @@ const CustomTooltip = ({ active, payload }: any) => { export function RadialChart({ percentage, - color = "var(--chart-success-color)", - backgroundColor = CHART_COLORS.tooltipBackground, + color = "var(--bg-pass-primary)", + backgroundColor = "var(--bg-neutral-tertiary)", height = 250, innerRadius = 60, outerRadius = 100, @@ -154,24 +152,18 @@ export function RadialChart({ const y = centerY - middleRadius * Math.sin(currentAngleRad); return ( - + ); })} {percentage}% diff --git a/ui/components/graphs/shared/constants.ts b/ui/components/graphs/shared/constants.ts index 4aadd4aac0..22fc946ff3 100644 --- a/ui/components/graphs/shared/constants.ts +++ b/ui/components/graphs/shared/constants.ts @@ -1,10 +1,9 @@ export const SEVERITY_COLORS = { - Informational: "var(--chart-info)", - Info: "var(--chart-info)", - Low: "var(--chart-warning)", - Medium: "var(--chart-warning-emphasis)", - High: "var(--chart-danger)", - Critical: "var(--chart-danger-emphasis)", + Informational: "var(--bg-data-info)", + Low: "var(--bg-data-low)", + Medium: "var(--bg-data-medium)", + High: "var(--bg-data-high)", + Critical: "var(--bg-data-critical)", } as const; export const PROVIDER_COLORS = { diff --git a/ui/components/shadcn/card/base-card/base-card.tsx b/ui/components/shadcn/card/base-card/base-card.tsx deleted file mode 100644 index 946e0cc184..0000000000 --- a/ui/components/shadcn/card/base-card/base-card.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { cva, type VariantProps } from "class-variance-authority"; - -import { cn } from "@/lib/utils"; - -import { Card } from "../card"; - -const baseCardVariants = cva("", { - variants: { - variant: { - default: - "border-slate-200 bg-white dark:border-zinc-900 dark:bg-stone-950", - }, - }, - defaultVariants: { - variant: "default", - }, -}); - -interface BaseCardProps - extends React.ComponentProps, - VariantProps {} - -const BaseCard = ({ className, variant, ...props }: BaseCardProps) => { - return ( - - ); -}; - -export { BaseCard }; diff --git a/ui/components/shadcn/card/card.tsx b/ui/components/shadcn/card/card.tsx index 62f4c66865..d57ddf0eb7 100644 --- a/ui/components/shadcn/card/card.tsx +++ b/ui/components/shadcn/card/card.tsx @@ -1,3 +1,5 @@ +import { cva, type VariantProps } from "class-variance-authority"; + import { cn } from "@/lib/utils"; export const CardVariant = { @@ -10,14 +12,44 @@ export const CardVariant = { export type CardVariant = (typeof CardVariant)[keyof typeof CardVariant]; -function Card({ className, ...props }: React.ComponentProps<"div">) { +const cardVariants = cva("flex flex-col gap-6 rounded-xl border", { + variants: { + variant: { + default: "", + base: "border-border-neutral-secondary bg-bg-neutral-secondary px-[18px] pt-3 pb-4", + inner: + "rounded-[12px] backdrop-blur-[46px] border-border-neutral-tertiary bg-bg-neutral-tertiary", + }, + padding: { + default: "", + sm: "px-3 py-2", + md: "px-4 py-3", + lg: "px-5 py-4", + none: "p-0", + }, + }, + compoundVariants: [ + { + variant: "inner", + padding: "default", + className: "px-4 py-3", // md padding by default for inner + }, + ], + defaultVariants: { + variant: "default", + padding: "default", + }, +}); + +interface CardProps + extends React.ComponentProps<"div">, + VariantProps {} + +function Card({ className, variant, padding, ...props }: CardProps) { return (

); @@ -28,7 +60,7 @@ function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
) { return (
); @@ -96,4 +125,6 @@ export { CardFooter, CardHeader, CardTitle, + cardVariants, }; +export type { CardProps }; diff --git a/ui/components/shadcn/card/resource-stats-card/resource-stats-card-container.tsx b/ui/components/shadcn/card/resource-stats-card/resource-stats-card-container.tsx deleted file mode 100644 index de27d052ed..0000000000 --- a/ui/components/shadcn/card/resource-stats-card/resource-stats-card-container.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { cva, type VariantProps } from "class-variance-authority"; - -import { cn } from "@/lib/utils"; - -const containerVariants = cva( - [ - "flex", - "rounded-[12px]", - "border", - "backdrop-blur-[46px]", - "border-slate-300", - "bg-[#F8FAFC80]", - "dark:border-[rgba(38,38,38,0.70)]", - "dark:bg-[rgba(23,23,23,0.50)]", - ], - { - variants: { - padding: { - sm: "px-3 py-2", - md: "px-[19px] py-[9px]", - lg: "px-6 py-3", - none: "p-0", - }, - }, - defaultVariants: { - padding: "md", - }, - }, -); - -export interface ResourceStatsCardContainerProps - extends React.HTMLAttributes, - VariantProps { - ref?: React.Ref; -} - -export const ResourceStatsCardContainer = ({ - className, - children, - padding, - ref, - ...props -}: ResourceStatsCardContainerProps) => { - return ( -
- {children} -
- ); -}; - -ResourceStatsCardContainer.displayName = "ResourceStatsCardContainer"; diff --git a/ui/components/shadcn/card/resource-stats-card/resource-stats-card-content.tsx b/ui/components/shadcn/card/resource-stats-card/resource-stats-card-content.tsx index e338c5e7b1..be3080143d 100644 --- a/ui/components/shadcn/card/resource-stats-card/resource-stats-card-content.tsx +++ b/ui/components/shadcn/card/resource-stats-card/resource-stats-card-content.tsx @@ -11,11 +11,11 @@ export interface StatItem { } const variantColors = { - default: "#868994", - fail: "#f54280", - pass: "#4ade80", - warning: "#fbbf24", - info: "#60a5fa", + default: "var(--bg-neutral-tertiary)", + fail: "var(--bg-fail-primary)", + pass: "var(--bg-pass-primary)", + warning: "var(--bg-warning-primary)", + info: "var(--bg-data-info)", } as const; type BadgeVariant = keyof typeof variantColors; @@ -26,8 +26,8 @@ const badgeVariants = cva( variants: { variant: { [CardVariant.default]: "bg-slate-100 dark:bg-[#535359]", - [CardVariant.fail]: "bg-red-100 dark:bg-[#432232]", - [CardVariant.pass]: "bg-green-100 dark:bg-[#204237]", + [CardVariant.fail]: "bg-bg-fail-secondary", + [CardVariant.pass]: "bg-bg-pass-secondary", [CardVariant.warning]: "bg-amber-100 dark:bg-[#3d3520]", [CardVariant.info]: "bg-blue-100 dark:bg-[#1e3a5f]", }, @@ -58,7 +58,7 @@ const badgeIconVariants = cva("", { }); const labelTextVariants = cva( - "leading-6 font-semibold text-slate-900 dark:text-zinc-300 whitespace-nowrap", + "leading-6 font-semibold text-text-neutral-secondary whitespace-nowrap", { variants: { size: { @@ -73,7 +73,7 @@ const labelTextVariants = cva( }, ); -const statIconVariants = cva("text-slate-600 dark:text-zinc-300", { +const statIconVariants = cva("text-text-neutral-secondary", { variants: { size: { sm: "h-2.5 w-2.5", @@ -87,7 +87,7 @@ const statIconVariants = cva("text-slate-600 dark:text-zinc-300", { }); const statLabelVariants = cva( - "leading-5 font-medium text-slate-700 dark:text-zinc-300", + "leading-5 font-medium text-text-neutral-secondary", { variants: { size: { diff --git a/ui/components/shadcn/card/resource-stats-card/resource-stats-card-divider.tsx b/ui/components/shadcn/card/resource-stats-card/resource-stats-card-divider.tsx deleted file mode 100644 index 3ec8d57ee4..0000000000 --- a/ui/components/shadcn/card/resource-stats-card/resource-stats-card-divider.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { cva, type VariantProps } from "class-variance-authority"; - -import { cn } from "@/lib/utils"; - -const dividerVariants = cva("flex items-center justify-center", { - variants: { - spacing: { - sm: "px-2", - md: "px-[23px]", - lg: "px-8", - }, - orientation: { - vertical: "h-full", - horizontal: "w-full", - }, - }, - defaultVariants: { - spacing: "md", - orientation: "vertical", - }, -}); - -const lineVariants = cva("bg-[rgba(39,39,42,1)]", { - variants: { - orientation: { - vertical: "h-full w-px", - horizontal: "w-full h-px", - }, - }, - defaultVariants: { - orientation: "vertical", - }, -}); - -export interface ResourceStatsCardDividerProps - extends React.HTMLAttributes, - VariantProps { - ref?: React.Ref; -} - -export const ResourceStatsCardDivider = ({ - className, - spacing, - orientation, - ref, - ...props -}: ResourceStatsCardDividerProps) => { - return ( -
-
-
- ); -}; - -ResourceStatsCardDivider.displayName = "ResourceStatsCardDivider"; diff --git a/ui/components/shadcn/card/resource-stats-card/resource-stats-card-header.tsx b/ui/components/shadcn/card/resource-stats-card/resource-stats-card-header.tsx index 2a4068e998..c324376a04 100644 --- a/ui/components/shadcn/card/resource-stats-card/resource-stats-card-header.tsx +++ b/ui/components/shadcn/card/resource-stats-card/resource-stats-card-header.tsx @@ -16,7 +16,7 @@ const headerVariants = cva("flex w-full items-center gap-1", { }, }); -const iconVariants = cva("text-zinc-300 dark:text-zinc-300", { +const iconVariants = cva("text-text-neutral-secondary", { variants: { size: { sm: "h-3.5 w-3.5", @@ -30,7 +30,7 @@ const iconVariants = cva("text-zinc-300 dark:text-zinc-300", { }); const titleVariants = cva( - "leading-7 font-semibold text-zinc-300 dark:text-zinc-300", + "leading-7 font-semibold text-text-neutral-secondary", { variants: { size: { @@ -45,21 +45,18 @@ const titleVariants = cva( }, ); -const countVariants = cva( - "leading-4 font-normal text-zinc-300 dark:text-zinc-300", - { - variants: { - size: { - sm: "text-[9px]", - md: "text-[10px]", - lg: "text-xs", - }, - }, - defaultVariants: { - size: "md", +const countVariants = cva("leading-4 font-normal text-text-neutral-secondary", { + variants: { + size: { + sm: "text-[9px]", + md: "text-[10px]", + lg: "text-xs", }, }, -); + defaultVariants: { + size: "md", + }, +}); export interface ResourceStatsCardHeaderProps extends React.HTMLAttributes, diff --git a/ui/components/shadcn/card/resource-stats-card/resource-stats-card.tsx b/ui/components/shadcn/card/resource-stats-card/resource-stats-card.tsx index 99d3e7867d..bb42f4bfff 100644 --- a/ui/components/shadcn/card/resource-stats-card/resource-stats-card.tsx +++ b/ui/components/shadcn/card/resource-stats-card/resource-stats-card.tsx @@ -3,17 +3,12 @@ import { LucideIcon } from "lucide-react"; import { cn } from "@/lib/utils"; -import { CardVariant } from "../card"; -import { ResourceStatsCardContainer } from "./resource-stats-card-container"; +import { Card, CardVariant } from "../card"; import type { StatItem } from "./resource-stats-card-content"; import { ResourceStatsCardContent } from "./resource-stats-card-content"; import { ResourceStatsCardHeader } from "./resource-stats-card-header"; export type { StatItem }; - -// Todo: when the design system is ready, we must use the colors from the design system (semantic colors) -// Variant styles using CVA for type safety and consistency -// Colors are exact HEX values from Figma design system const cardVariants = cva("", { variants: { variant: { @@ -109,7 +104,7 @@ export const ResourceStatsCard = ({ {header && } {emptyState ? (
-

+

{emptyState.message}

@@ -131,15 +126,16 @@ export const ResourceStatsCard = ({ // Otherwise, render with container return ( - {header && } {emptyState ? (
-

+

{emptyState.message}

@@ -155,7 +151,7 @@ export const ResourceStatsCard = ({ /> ) )} -
+ ); }; diff --git a/ui/components/shadcn/index.ts b/ui/components/shadcn/index.ts index 4bb244fb95..8991f1e34d 100644 --- a/ui/components/shadcn/index.ts +++ b/ui/components/shadcn/index.ts @@ -1,14 +1,12 @@ export * from "./badge/badge"; export * from "./button/button"; -export * from "./card/base-card/base-card"; export * from "./card/card"; export * from "./card/resource-stats-card/resource-stats-card"; -export * from "./card/resource-stats-card/resource-stats-card-container"; export * from "./card/resource-stats-card/resource-stats-card-content"; -export * from "./card/resource-stats-card/resource-stats-card-divider"; export * from "./card/resource-stats-card/resource-stats-card-header"; export * from "./dropdown/dropdown"; export * from "./select/select"; export * from "./separator/separator"; +export * from "./skeleton/skeleton"; export * from "./tabs/generic-tabs"; export * from "./tabs/tabs"; diff --git a/ui/components/shadcn/skeleton/skeleton.tsx b/ui/components/shadcn/skeleton/skeleton.tsx new file mode 100644 index 0000000000..34971c0554 --- /dev/null +++ b/ui/components/shadcn/skeleton/skeleton.tsx @@ -0,0 +1,16 @@ +import { cn } from "@/lib/utils"; + +function Skeleton({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +export { Skeleton }; diff --git a/ui/styles/globals.css b/ui/styles/globals.css index 50272c81a4..d6dfe3ee05 100644 --- a/ui/styles/globals.css +++ b/ui/styles/globals.css @@ -6,11 +6,11 @@ /* ===== LIGHT THEME (ROOT) ===== */ :root { /* ===== LEGACY VARIABLES (CHART COLORS) ===== */ - --chart-info: #3C8DFF; - --chart-warning: #FDFBD4; - --chart-warning-emphasis: #FEC94D; - --chart-danger: #F77852; - --chart-danger-emphasis: #FF006A; + --chart-info: #3c8dff; + --chart-warning: #fdfbd4; + --chart-warning-emphasis: #fec94d; + --chart-danger: #f77852; + --chart-danger-emphasis: #ff006a; --chart-success-color: #16a34a; --chart-fail: #dc2626; --chart-radar-primary: #9d174d; @@ -69,36 +69,40 @@ /* Text Colors */ --text-neutral-primary: var(--color-slate-950); - --text-neutral-secondary: var(--color-zinc-700); + --text-neutral-secondary: var(--color-zinc-800); --text-neutral-tertiary: var(--color-zinc-500); --text-error-primary: var(--color-red-600); /* Background Colors */ - --bg-neutral-primary: #FDFDFD; + --bg-neutral-primary: #fdfdfd; --bg-neutral-secondary: var(--color-white); - --bg-neutral-tertiary: #FBFDFD; + --bg-neutral-tertiary: #fbfdfd; --bg-tag-primary: var(--color-slate-50); --bg-pass-primary: var(--color-emerald-400); --bg-pass-secondary: var(--color-emerald-50); + --bg-warning-primary: var(--color-orange-500); --bg-fail-primary: var(--color-rose-500); --bg-fail-secondary: var(--color-rose-50); /* Severity Colors */ - --bg-data-critical: #FF006A; - --bg-data-high: #F77852; - --bg-data-medium: #FDD34F; - --bg-data-low: #F5F3CE; - --bg-data-info: #3C8DFF; + --bg-data-critical: #ff006a; + --bg-data-high: #f77852; + --bg-data-medium: #fdd34f; + --bg-data-low: #f5f3ce; + --bg-data-info: #3c8dff; + + /* Chart Dots */ + --chart-dots: var(--color-neutral-200); } /* ===== DARK THEME ===== */ .dark { /* ===== LEGACY VARIABLES (CHART COLORS) ===== */ - --chart-info: #3C8DFF; - --chart-warning: #FDFBD4; - --chart-warning-emphasis: #FEC94D; - --chart-danger: #F77852; - --chart-danger-emphasis: #FF006A; + --chart-info: #3c8dff; + --chart-warning: #fdfbd4; + --chart-warning-emphasis: #fec94d; + --chart-danger: #f77852; + --chart-danger-emphasis: #ff006a; --chart-success-color: #86da26; --chart-fail: #db2b49; --chart-radar-primary: #b51c80; @@ -157,26 +161,30 @@ /* Text Colors */ --text-neutral-primary: var(--color-zinc-100); - --text-neutral-secondary: var(--color-zinc-400); + --text-neutral-secondary: var(--color-zinc-300); --text-neutral-tertiary: var(--color-zinc-500); --text-error-primary: var(--color-rose-300); /* Background Colors */ --bg-neutral-primary: var(--color-zinc-950); - --bg-neutral-secondary: var(--color-slate-950); + --bg-neutral-secondary: var(--color-stone-950); --bg-neutral-tertiary: #121110; --bg-tag-primary: var(--color-slate-950); + --bg-warning-primary: var(--color-orange-400); --bg-pass-primary: var(--color-green-400); --bg-pass-secondary: var(--color-emerald-900); --bg-fail-primary: var(--color-rose-500); --bg-fail-secondary: #432232; /* Severity Colors */ - --bg-data-critical: #FF006A; - --bg-data-high: #F77852; - --bg-data-medium: #FEC94D; - --bg-data-low: #FDFBD4; - --bg-data-info: #3C8DFF; + --bg-data-critical: #ff006a; + --bg-data-high: #f77852; + --bg-data-medium: #fec94d; + --bg-data-low: #fdfbd4; + --bg-data-info: #3c8dff; + + /* Chart Dots */ + --chart-dots: var(--text-neutral-primary); } /* ===== TAILWIND THEME MAPPINGS ===== */ @@ -248,6 +256,7 @@ --color-bg-tag: var(--bg-tag-primary); --color-bg-pass: var(--bg-pass-primary); --color-bg-pass-secondary: var(--bg-pass-secondary); + --color-bg-warning: var(--bg-warning-primary); --color-bg-fail: var(--bg-fail-primary); --color-bg-fail-secondary: var(--bg-fail-secondary); } @@ -357,4 +366,4 @@ body { @apply bg-background text-foreground; } -} \ No newline at end of file +} From ef4e28da03ebae1ba06cda9123aa3e5216bd817c Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Mon, 10 Nov 2025 11:23:56 +0100 Subject: [PATCH 02/23] fix(m365_powershell): teams connection with `--sp-env-auth` and enhanced timeouts error logging (#9191) --- prowler/CHANGELOG.md | 1 + .../m365/lib/powershell/m365_powershell.py | 41 +++--- .../lib/powershell/m365_powershell_test.py | 118 ++++++++---------- 3 files changed, 66 insertions(+), 94 deletions(-) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 7ee85b6607..286322a155 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. ### Fixed - Check `check_name` has no `resource_name` error for GCP provider [(#9169)](https://github.com/prowler-cloud/prowler/pull/9169) - Depth Truncation and parsing error in PowerShell queries [(#9181)](https://github.com/prowler-cloud/prowler/pull/9181) +- Fix M365 Teams `--sp-env-auth` connection error and enhanced timeout logging [(#9191)](https://github.com/prowler-cloud/prowler/pull/9191) --- diff --git a/prowler/providers/m365/lib/powershell/m365_powershell.py b/prowler/providers/m365/lib/powershell/m365_powershell.py index e3d729275f..797fd667ce 100644 --- a/prowler/providers/m365/lib/powershell/m365_powershell.py +++ b/prowler/providers/m365/lib/powershell/m365_powershell.py @@ -1,5 +1,4 @@ import os -from typing import Optional from prowler.lib.logger import logger from prowler.lib.powershell.powershell import PowerShellSession @@ -7,12 +6,11 @@ from prowler.providers.m365.exceptions.exceptions import ( M365CertificateCreationError, M365GraphConnectionError, ) -from prowler.providers.m365.lib.jwt.jwt_decoder import decode_jwt, decode_msal_token +from prowler.providers.m365.lib.jwt.jwt_decoder import decode_msal_token from prowler.providers.m365.models import M365Credentials, M365IdentityInfo class M365PowerShell(PowerShellSession): - CONNECT_TIMEOUT = 15 """ Microsoft 365 specific PowerShell session management implementation. @@ -125,9 +123,7 @@ class M365PowerShell(PowerShellSession): '$graphToken = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$tenantID/oauth2/v2.0/token" -Method POST -Body $graphtokenBody | Select-Object -ExpandProperty Access_Token' ) - def _execute_connect_command( - self, command: str, timeout: Optional[int] = None - ) -> str: + def execute_connect(self, command: str) -> str: """ Execute a PowerShell connect command ensuring empty responses surface as timeouts. @@ -138,9 +134,9 @@ class M365PowerShell(PowerShellSession): Returns: str: Command output or 'Timeout' if the command produced no output. """ - effective_timeout = timeout or self.CONNECT_TIMEOUT - result = self.execute(command, timeout=effective_timeout) - return result or "Timeout" + connect_timeout = 15 + result = self.execute(command, timeout=connect_timeout) + return result or "'execute_connect' command timeout reached" def test_credentials(self, credentials: M365Credentials) -> bool: """ @@ -207,7 +203,7 @@ class M365PowerShell(PowerShellSession): def test_graph_certificate_connection(self) -> bool: """Test Microsoft Graph API connection using certificate and raise exception if it fails.""" - result = self._execute_connect_command( + result = self.execute_connect( "Connect-Graph -Certificate $certificate -AppId $clientID -TenantId $tenantID" ) if "Welcome to Microsoft Graph!" not in result: @@ -221,18 +217,13 @@ class M365PowerShell(PowerShellSession): self.execute( '$teamstokenBody = @{ Grant_Type = "client_credentials"; Scope = "48ac35b8-9aa8-4d74-927d-1f4a14a0b239/.default"; Client_Id = $clientID; Client_Secret = $clientSecret }' ) - self.execute( + result = self.execute( '$teamsToken = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$tenantID/oauth2/v2.0/token" -Method POST -Body $teamstokenBody | Select-Object -ExpandProperty Access_Token' ) - permissions = decode_jwt(self.execute("Write-Output $teamsToken")).get( - "roles", [] - ) - if "application_access" not in permissions: - logger.error( - "Microsoft Teams connection failed: Please check your permissions and try again." - ) + if result != "": + logger.error(f"Microsoft Teams connection failed: {result}") return False - self._execute_connect_command( + self.execute_connect( 'Connect-MicrosoftTeams -AccessTokens @("$graphToken","$teamsToken")' ) return True @@ -244,7 +235,7 @@ class M365PowerShell(PowerShellSession): def test_teams_certificate_connection(self) -> bool: """Test Microsoft Teams API connection using certificate and raise exception if it fails.""" - result = self._execute_connect_command( + result = self.execute_connect( "Connect-MicrosoftTeams -Certificate $certificate -ApplicationId $clientID -TenantId $tenantID" ) if self.tenant_identity.identity_id not in result: @@ -268,9 +259,8 @@ class M365PowerShell(PowerShellSession): "Exchange Online connection failed: Please check your permissions and try again." ) return False - self._execute_connect_command( - 'Connect-ExchangeOnline -AccessToken $exchangeToken.AccessToken -Organization "$tenantID"', - timeout=self.CONNECT_TIMEOUT, + self.execute_connect( + 'Connect-ExchangeOnline -AccessToken $exchangeToken.AccessToken -Organization "$tenantID"' ) return True except Exception as e: @@ -281,9 +271,8 @@ class M365PowerShell(PowerShellSession): def test_exchange_certificate_connection(self) -> bool: """Test Exchange Online API connection using certificate and raise exception if it fails.""" - result = self._execute_connect_command( - "Connect-ExchangeOnline -Certificate $certificate -AppId $clientID -Organization $tenantDomain", - timeout=self.CONNECT_TIMEOUT, + result = self.execute_connect( + "Connect-ExchangeOnline -Certificate $certificate -AppId $clientID -Organization $tenantDomain" ) if "https://aka.ms/exov3-module" not in result: logger.error(f"Exchange Online Certificate connection failed: {result}") diff --git a/tests/providers/m365/lib/powershell/m365_powershell_test.py b/tests/providers/m365/lib/powershell/m365_powershell_test.py index 8d37b6c095..28b09768c3 100644 --- a/tests/providers/m365/lib/powershell/m365_powershell_test.py +++ b/tests/providers/m365/lib/powershell/m365_powershell_test.py @@ -547,8 +547,7 @@ class Testm365PowerShell: session.close() @patch("subprocess.Popen") - @patch("prowler.providers.m365.lib.powershell.m365_powershell.decode_jwt") - def test_test_teams_connection_success(self, mock_decode_jwt, mock_popen): + def test_test_teams_connection_success(self, mock_popen): """Test test_teams_connection when token is valid""" mock_process = MagicMock() mock_popen.return_value = mock_process @@ -567,30 +566,20 @@ class Testm365PowerShell: ) session = M365PowerShell(credentials, identity) - # Mock execute to return valid responses - def mock_execute(command, *args, **kwargs): - if "Write-Output $teamsToken" in command: - return "valid_teams_token" - return None - - session.execute = MagicMock(side_effect=mock_execute) - # Mock JWT decode to return proper permissions - mock_decode_jwt.return_value = {"roles": ["application_access"]} + session.execute = MagicMock(side_effect=[None, ""]) + session.execute_connect = MagicMock(return_value="") result = session.test_teams_connection() assert result is True - # Verify all expected PowerShell commands were called - # 4 calls: teamstokenBody, teamsToken, Write-Output $teamsToken, Connect-MicrosoftTeams - assert session.execute.call_count == 4 - mock_decode_jwt.assert_called_once_with("valid_teams_token") + assert session.execute.call_count == 2 + session.execute_connect.assert_called_once_with( + 'Connect-MicrosoftTeams -AccessTokens @("$graphToken","$teamsToken")' + ) session.close() @patch("subprocess.Popen") - @patch("prowler.providers.m365.lib.powershell.m365_powershell.decode_jwt") - def test_test_teams_connection_missing_permissions( - self, mock_decode_jwt, mock_popen - ): + def test_test_teams_connection_missing_permissions(self, mock_popen): """Test test_teams_connection when token lacks required permissions""" mock_process = MagicMock() mock_popen.return_value = mock_process @@ -609,23 +598,17 @@ class Testm365PowerShell: ) session = M365PowerShell(credentials, identity) - # Mock execute to return valid token but decode returns no permissions - def mock_execute(command, *args, **kwargs): - if "Write-Output $teamsToken" in command: - return "valid_teams_token" - return None - - session.execute = MagicMock(side_effect=mock_execute) - # Mock JWT decode to return missing required permission - mock_decode_jwt.return_value = {"roles": ["other_permission"]} + session.execute = MagicMock(side_effect=[None, "Permission denied"]) + session.execute_connect = MagicMock() with patch("prowler.lib.logger.logger.error") as mock_error: result = session.test_teams_connection() assert result is False mock_error.assert_called_once_with( - "Microsoft Teams connection failed: Please check your permissions and try again." + "Microsoft Teams connection failed: Permission denied" ) + session.execute_connect.assert_not_called() session.close() @patch("subprocess.Popen") @@ -688,15 +671,17 @@ class Testm365PowerShell: return None session.execute = MagicMock(side_effect=mock_execute) + session.execute_connect = MagicMock(return_value=None) # Mock MSAL token decode to return proper permissions mock_decode_msal_token.return_value = {"roles": ["Exchange.ManageAsApp"]} result = session.test_exchange_connection() assert result is True - # Verify all expected PowerShell commands were called - # 4 calls: SecureSecret, exchangeToken, Write-Output $exchangeToken, Connect-ExchangeOnline - assert session.execute.call_count == 4 + assert session.execute.call_count == 3 + session.execute_connect.assert_called_once_with( + 'Connect-ExchangeOnline -AccessToken $exchangeToken.AccessToken -Organization "$tenantID"' + ) mock_decode_msal_token.assert_called_once_with("valid_exchange_token") session.close() @@ -730,6 +715,7 @@ class Testm365PowerShell: return None session.execute = MagicMock(side_effect=mock_execute) + session.execute_connect = MagicMock(return_value=None) # Mock MSAL token decode to return missing required permission mock_decode_msal_token.return_value = {"roles": ["other_permission"]} @@ -737,6 +723,7 @@ class Testm365PowerShell: result = session.test_exchange_connection() assert result is False + session.execute_connect.assert_not_called() mock_error.assert_called_once_with( "Exchange Online connection failed: Please check your permissions and try again." ) @@ -781,7 +768,7 @@ class Testm365PowerShell: mock_popen.return_value = mock_process credentials = M365Credentials() - identity = M365IdentityInfo() + identity = M365IdentityInfo(identity_id="expected-id") session = M365PowerShell(credentials, identity) # Test with clean base64 content @@ -924,20 +911,18 @@ class Testm365PowerShell: mock_popen.return_value = mock_process credentials = M365Credentials() - identity = M365IdentityInfo() + identity = M365IdentityInfo(identity_id="expected-id") session = M365PowerShell(credentials, identity) - # Mock successful Exchange connection - session.execute = MagicMock( + session.execute_connect = MagicMock( return_value="Connected successfully https://aka.ms/exov3-module" ) result = session.test_exchange_certificate_connection() assert result is True - session.execute.assert_called_once_with( - "Connect-ExchangeOnline -Certificate $certificate -AppId $clientID -Organization $tenantDomain", - timeout=M365PowerShell.CONNECT_TIMEOUT, + session.execute_connect.assert_called_once_with( + "Connect-ExchangeOnline -Certificate $certificate -AppId $clientID -Organization $tenantDomain" ) session.close() @@ -949,20 +934,23 @@ class Testm365PowerShell: mock_popen.return_value = mock_process credentials = M365Credentials() - identity = M365IdentityInfo() + identity = M365IdentityInfo(identity_id="expected-id") session = M365PowerShell(credentials, identity) - # Mock failed Exchange connection - session.execute = MagicMock( + session.execute_connect = MagicMock( return_value="Connection failed: Authentication error" ) - result = session.test_exchange_certificate_connection() + with patch("prowler.lib.logger.logger.error") as mock_error: + result = session.test_exchange_certificate_connection() + assert result is False - session.execute.assert_called_once_with( - "Connect-ExchangeOnline -Certificate $certificate -AppId $clientID -Organization $tenantDomain", - timeout=M365PowerShell.CONNECT_TIMEOUT, + session.execute_connect.assert_called_once_with( + "Connect-ExchangeOnline -Certificate $certificate -AppId $clientID -Organization $tenantDomain" + ) + mock_error.assert_called_once_with( + "Exchange Online Certificate connection failed: Connection failed: Authentication error" ) session.close() @@ -981,20 +969,15 @@ class Testm365PowerShell: session = M365PowerShell(credentials, identity) # Mock successful Teams connection - the method returns bool - def mock_execute_side_effect(command, *_, **__): - if "Connect-MicrosoftTeams" in command: - # Return result that contains the identity_id for success - return "Connected successfully test_identity_id" - return "" - - session.execute = MagicMock(side_effect=mock_execute_side_effect) + session.execute_connect = MagicMock( + return_value="Connected successfully test_identity_id" + ) result = session.test_teams_certificate_connection() assert result is True - session.execute.assert_called_once_with( - "Connect-MicrosoftTeams -Certificate $certificate -ApplicationId $clientID -TenantId $tenantID", - timeout=M365PowerShell.CONNECT_TIMEOUT, + session.execute_connect.assert_called_once_with( + "Connect-MicrosoftTeams -Certificate $certificate -ApplicationId $clientID -TenantId $tenantID" ) session.close() @@ -1006,22 +989,21 @@ class Testm365PowerShell: mock_popen.return_value = mock_process credentials = M365Credentials() - identity = M365IdentityInfo() + identity = M365IdentityInfo(identity_id="expected-id") session = M365PowerShell(credentials, identity) - # Mock failed Teams connection - def mock_execute_side_effect(command, **kwargs): - if "Connect-MicrosoftTeams" in command: - raise Exception("Connection failed: Authentication error") - return "" + session.execute_connect = MagicMock(return_value="Connection failed") - session.execute = MagicMock(side_effect=mock_execute_side_effect) + with patch("prowler.lib.logger.logger.error") as mock_error: + result = session.test_teams_certificate_connection() - # Should raise exception on connection failure - with pytest.raises(Exception) as exc_info: - session.test_teams_certificate_connection() - - assert "Connection failed: Authentication error" in str(exc_info.value) + assert result is False + session.execute_connect.assert_called_once_with( + "Connect-MicrosoftTeams -Certificate $certificate -ApplicationId $clientID -TenantId $tenantID" + ) + mock_error.assert_called_once_with( + "Microsoft Teams Certificate connection failed: Connection failed" + ) session.close() From 789221d901fb705bfb3f60a00f65bf9e73098aa5 Mon Sep 17 00:00:00 2001 From: Ethan Troy <63926014+ethanolivertroy@users.noreply.github.com> Date: Mon, 10 Nov 2025 08:41:18 -0500 Subject: [PATCH 03/23] feat(compliance): add FedRAMP 20x KSI Low compliance frameworks (#9198) Co-authored-by: pedrooot --- README.md | 6 +- .../compliance/fedramp_20x_ksi_low_aws.py | 46 +++ .../compliance/fedramp_20x_ksi_low_azure.py | 46 +++ .../compliance/fedramp_20x_ksi_low_gcp.py | 46 +++ prowler/CHANGELOG.md | 1 + .../aws/fedramp_20x_ksi_low_aws.json | 347 +++++++++++++++++ .../azure/fedramp_20x_ksi_low_azure.json | 358 ++++++++++++++++++ .../gcp/fedramp_20x_ksi_low_gcp.json | 293 ++++++++++++++ 8 files changed, 1140 insertions(+), 3 deletions(-) create mode 100644 dashboard/compliance/fedramp_20x_ksi_low_aws.py create mode 100644 dashboard/compliance/fedramp_20x_ksi_low_azure.py create mode 100644 dashboard/compliance/fedramp_20x_ksi_low_gcp.py create mode 100644 prowler/compliance/aws/fedramp_20x_ksi_low_aws.json create mode 100644 prowler/compliance/azure/fedramp_20x_ksi_low_azure.json create mode 100644 prowler/compliance/gcp/fedramp_20x_ksi_low_gcp.json diff --git a/README.md b/README.md index 83af8dcfb7..25cc8f6abe 100644 --- a/README.md +++ b/README.md @@ -82,9 +82,9 @@ 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) | Support | Interface | |---|---|---|---|---|---|---| -| AWS | 576 | 82 | 38 | 10 | Official | UI, API, CLI | -| GCP | 79 | 13 | 12 | 3 | Official | UI, API, CLI | -| Azure | 162 | 19 | 12 | 4 | Official | UI, API, CLI | +| AWS | 576 | 82 | 39 | 10 | Official | UI, API, CLI | +| GCP | 79 | 13 | 13 | 3 | Official | UI, API, CLI | +| Azure | 162 | 19 | 13 | 4 | Official | UI, API, CLI | | Kubernetes | 83 | 7 | 5 | 7 | Official | UI, API, CLI | | GitHub | 17 | 2 | 1 | 0 | Official | Stable | UI, API, CLI | | M365 | 70 | 7 | 3 | 2 | Official | UI, API, CLI | diff --git a/dashboard/compliance/fedramp_20x_ksi_low_aws.py b/dashboard/compliance/fedramp_20x_ksi_low_aws.py new file mode 100644 index 0000000000..5ca220301f --- /dev/null +++ b/dashboard/compliance/fedramp_20x_ksi_low_aws.py @@ -0,0 +1,46 @@ +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() + + # Shorten the long FedRAMP KSI descriptions for better display + ksi_short_names = { + "A secure cloud service offering will protect user data, control access, and apply zero trust principles": "Identity and Access Management", + "A secure cloud service offering will use cloud native architecture and design principles to enforce and enhance the Confidentiality, Integrity and Availability of the system": "Cloud Native Architecture", + "A secure cloud service provider will ensure that all system changes are properly documented and configuration baselines are updated accordingly": "Change Management", + "A secure cloud service provider will continuously educate their employees on cybersecurity measures, testing them regularly": "Cybersecurity Education", + "A secure cloud service offering will document, report, and analyze security incidents to ensure regulatory compliance and continuous security improvement": "Incident Reporting", + "A secure cloud service offering will monitor, log, and audit all important events, activity, and changes": "Monitoring, Logging, and Auditing", + "A secure cloud service offering will have intentional, organized, universal guidance for how every information resource, including personnel, is secured": "Policy and Inventory", + "A secure cloud service offering will define, maintain, and test incident response plan(s) and recovery capabilities to ensure minimal service disruption and data loss": "Recovery Planning", + "A secure cloud service offering will follow FedRAMP encryption policies, continuously verify information resource integrity, and restrict access to third-party information resources": "Service Configuration", + "A secure cloud service offering will understand, monitor, and manage supply chain risks from third-party information resources": "Third-Party Information Resources", + } + + # Replace long descriptions with short names - use contains for partial matching + if not aux.empty: + for long_desc, short_name in ksi_short_names.items(): + mask = aux["REQUIREMENTS_DESCRIPTION"].str.contains( + long_desc, na=False, regex=False + ) + aux.loc[mask, "REQUIREMENTS_DESCRIPTION"] = short_name + + return get_section_containers_cis( + aux, "REQUIREMENTS_ID", "REQUIREMENTS_ATTRIBUTES_SECTION" + ) diff --git a/dashboard/compliance/fedramp_20x_ksi_low_azure.py b/dashboard/compliance/fedramp_20x_ksi_low_azure.py new file mode 100644 index 0000000000..5ca220301f --- /dev/null +++ b/dashboard/compliance/fedramp_20x_ksi_low_azure.py @@ -0,0 +1,46 @@ +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() + + # Shorten the long FedRAMP KSI descriptions for better display + ksi_short_names = { + "A secure cloud service offering will protect user data, control access, and apply zero trust principles": "Identity and Access Management", + "A secure cloud service offering will use cloud native architecture and design principles to enforce and enhance the Confidentiality, Integrity and Availability of the system": "Cloud Native Architecture", + "A secure cloud service provider will ensure that all system changes are properly documented and configuration baselines are updated accordingly": "Change Management", + "A secure cloud service provider will continuously educate their employees on cybersecurity measures, testing them regularly": "Cybersecurity Education", + "A secure cloud service offering will document, report, and analyze security incidents to ensure regulatory compliance and continuous security improvement": "Incident Reporting", + "A secure cloud service offering will monitor, log, and audit all important events, activity, and changes": "Monitoring, Logging, and Auditing", + "A secure cloud service offering will have intentional, organized, universal guidance for how every information resource, including personnel, is secured": "Policy and Inventory", + "A secure cloud service offering will define, maintain, and test incident response plan(s) and recovery capabilities to ensure minimal service disruption and data loss": "Recovery Planning", + "A secure cloud service offering will follow FedRAMP encryption policies, continuously verify information resource integrity, and restrict access to third-party information resources": "Service Configuration", + "A secure cloud service offering will understand, monitor, and manage supply chain risks from third-party information resources": "Third-Party Information Resources", + } + + # Replace long descriptions with short names - use contains for partial matching + if not aux.empty: + for long_desc, short_name in ksi_short_names.items(): + mask = aux["REQUIREMENTS_DESCRIPTION"].str.contains( + long_desc, na=False, regex=False + ) + aux.loc[mask, "REQUIREMENTS_DESCRIPTION"] = short_name + + return get_section_containers_cis( + aux, "REQUIREMENTS_ID", "REQUIREMENTS_ATTRIBUTES_SECTION" + ) diff --git a/dashboard/compliance/fedramp_20x_ksi_low_gcp.py b/dashboard/compliance/fedramp_20x_ksi_low_gcp.py new file mode 100644 index 0000000000..5ca220301f --- /dev/null +++ b/dashboard/compliance/fedramp_20x_ksi_low_gcp.py @@ -0,0 +1,46 @@ +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() + + # Shorten the long FedRAMP KSI descriptions for better display + ksi_short_names = { + "A secure cloud service offering will protect user data, control access, and apply zero trust principles": "Identity and Access Management", + "A secure cloud service offering will use cloud native architecture and design principles to enforce and enhance the Confidentiality, Integrity and Availability of the system": "Cloud Native Architecture", + "A secure cloud service provider will ensure that all system changes are properly documented and configuration baselines are updated accordingly": "Change Management", + "A secure cloud service provider will continuously educate their employees on cybersecurity measures, testing them regularly": "Cybersecurity Education", + "A secure cloud service offering will document, report, and analyze security incidents to ensure regulatory compliance and continuous security improvement": "Incident Reporting", + "A secure cloud service offering will monitor, log, and audit all important events, activity, and changes": "Monitoring, Logging, and Auditing", + "A secure cloud service offering will have intentional, organized, universal guidance for how every information resource, including personnel, is secured": "Policy and Inventory", + "A secure cloud service offering will define, maintain, and test incident response plan(s) and recovery capabilities to ensure minimal service disruption and data loss": "Recovery Planning", + "A secure cloud service offering will follow FedRAMP encryption policies, continuously verify information resource integrity, and restrict access to third-party information resources": "Service Configuration", + "A secure cloud service offering will understand, monitor, and manage supply chain risks from third-party information resources": "Third-Party Information Resources", + } + + # Replace long descriptions with short names - use contains for partial matching + if not aux.empty: + for long_desc, short_name in ksi_short_names.items(): + mask = aux["REQUIREMENTS_DESCRIPTION"].str.contains( + long_desc, na=False, regex=False + ) + aux.loc[mask, "REQUIREMENTS_DESCRIPTION"] = short_name + + return get_section_containers_cis( + aux, "REQUIREMENTS_ID", "REQUIREMENTS_ATTRIBUTES_SECTION" + ) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 286322a155..c6be038f9a 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 multiple compliance improvements [(#9145)](https://github.com/prowler-cloud/prowler/pull/9145) - Added validation for invalid checks, services, and categories in `load_checks_to_execute` function [(#8971)](https://github.com/prowler-cloud/prowler/pull/8971) - NIST CSF 2.0 compliance framework for the AWS provider [(#9185)](https://github.com/prowler-cloud/prowler/pull/9185) +- Add FedRAMP 20x KSI Low for AWS, Azure and GCP [(#9198)](https://github.com/prowler-cloud/prowler/pull/9198) ### Changed - Update AWS Direct Connect service metadata to new format [(#8855)](https://github.com/prowler-cloud/prowler/pull/8855) diff --git a/prowler/compliance/aws/fedramp_20x_ksi_low_aws.json b/prowler/compliance/aws/fedramp_20x_ksi_low_aws.json new file mode 100644 index 0000000000..60afe9d4fd --- /dev/null +++ b/prowler/compliance/aws/fedramp_20x_ksi_low_aws.json @@ -0,0 +1,347 @@ +{ + "Framework": "FedRAMP-20x-KSI-Low", + "Name": "FedRAMP 20x Key Security Indicators (KSIs) - Low Impact Level v25.05C", + "Version": "25.05C", + "Provider": "AWS", + "Description": "FedRAMP 20x Key Security Indicators (KSIs) Low Impact Level represent core security indicators for cloud service providers, focusing on automation, continuous monitoring, and cloud-native security principles per FedRAMP 20x Phase One pilot requirements for Low impact systems.", + "Requirements": [ + { + "Id": "ksi-cmt", + "Name": "KSI-CMT: Change Management", + "Description": "A secure cloud service provider will ensure that all system changes are properly documented and configuration baselines are updated accordingly", + "Attributes": [ + { + "ItemId": "ksi-cmt", + "Section": "Change Management", + "Service": "aws" + } + ], + "Checks": [ + "cloudtrail_multi_region_enabled", + "cloudtrail_log_file_validation_enabled", + "cloudtrail_s3_dataevents_read_enabled", + "cloudtrail_s3_dataevents_write_enabled", + "cloudwatch_changes_to_network_acls_alarm_configured", + "cloudwatch_changes_to_network_gateways_alarm_configured", + "cloudwatch_changes_to_network_route_tables_alarm_configured", + "cloudwatch_changes_to_vpcs_alarm_configured", + "cloudwatch_log_metric_filter_and_alarm_for_aws_config_configuration_changes_enabled", + "cloudwatch_log_metric_filter_and_alarm_for_cloudtrail_configuration_changes_enabled", + "cloudwatch_log_metric_filter_aws_organizations_changes", + "cloudwatch_log_metric_filter_for_s3_bucket_policy_changes", + "cloudwatch_log_metric_filter_policy_changes", + "cloudwatch_log_metric_filter_security_group_changes", + "config_recorder_all_regions_enabled", + "ec2_instance_managed_by_ssm", + "ec2_instance_older_than_specific_days", + "ssm_managed_compliant_patching", + "ssm_managed_instance_compliance_association_compliant", + "ssm_managed_instance_compliance_patch_compliant" + ] + }, + { + "Id": "ksi-cna", + "Name": "KSI-CNA: Cloud Native Architecture", + "Description": "A secure cloud service offering will use cloud native architecture and design principles to enforce and enhance the Confidentiality, Integrity and Availability of the system", + "Attributes": [ + { + "ItemId": "ksi-cna", + "Section": "Cloud Native Architecture", + "Service": "aws" + } + ], + "Checks": [ + "autoscaling_group_multiple_az", + "autoscaling_group_multiple_instance_types", + "autoscaling_group_capacity_rebalance_enabled", + "dynamodb_tables_pitr_enabled", + "dynamodb_tables_deletion_protection_enabled", + "ec2_instance_imdsv2_enabled", + "ec2_networkacl_allow_ingress_any_port", + "ec2_securitygroup_default_restrict_traffic", + "ec2_securitygroup_allow_ingress_from_internet_to_any_port", + "eks_cluster_network_policy_enabled", + "eks_cluster_not_publicly_accessible", + "eks_cluster_private_nodes_enabled", + "eks_cluster_uses_a_supported_version", + "elb_cross_zone_load_balancing_enabled", + "elbv2_alb_multi_az_scheme", + "elbv2_waf_acl_attached", + "rds_instance_multi_az", + "rds_cluster_multi_az", + "vpc_subnet_auto_assign_public_ip_disabled", + "vpc_default_security_group_restricts_traffic", + "vpc_peering_connection_routing_tables_with_least_privilege" + ] + }, + { + "Id": "ksi-iam", + "Name": "KSI-IAM: Identity and Access Management", + "Description": "A secure cloud service offering will protect user data, control access, and apply zero trust principles", + "Attributes": [ + { + "ItemId": "ksi-iam", + "Section": "Identity and Access Management", + "Service": "aws" + } + ], + "Checks": [ + "iam_administrator_access_with_mfa", + "iam_aws_attached_policy_no_administrative_privileges", + "iam_customer_attached_policy_no_administrative_privileges", + "iam_inline_policy_no_administrative_privileges", + "iam_no_custom_policy_permissive_role_assumption", + "iam_no_root_access_key", + "iam_password_policy_expires_passwords_within_90_days_or_less", + "iam_password_policy_lowercase", + "iam_password_policy_minimum_length_14", + "iam_password_policy_number", + "iam_password_policy_reuse_24", + "iam_password_policy_symbol", + "iam_password_policy_uppercase", + "iam_policy_attached_only_to_group_or_roles", + "iam_policy_no_full_access_to_cloudtrail", + "iam_policy_no_full_access_to_kms", + "iam_root_hardware_mfa_enabled", + "iam_root_mfa_enabled", + "iam_rotate_access_key_90_days", + "iam_user_accesskey_unused", + "iam_user_console_access_unused", + "iam_user_hardware_mfa_enabled", + "iam_user_mfa_enabled_console_access", + "iam_user_two_active_access_key", + "organizations_scp_check_deny_regions", + "organizations_opt_out_ai_services_policy" + ] + }, + { + "Id": "ksi-inr", + "Name": "KSI-INR: Incident Response", + "Description": "A secure cloud service offering will respond to incidents according to FedRAMP requirements and cloud service provider policies", + "Attributes": [ + { + "ItemId": "ksi-inr", + "Section": "Incident Response", + "Service": "aws" + } + ], + "Checks": [ + "guardduty_centrally_managed", + "guardduty_ec2_malware_protection_enabled", + "guardduty_eks_audit_log_enabled", + "guardduty_eks_protection_enabled", + "guardduty_eks_runtime_monitoring_enabled", + "guardduty_is_enabled", + "guardduty_lambda_protection_enabled", + "guardduty_malware_protection_enabled", + "guardduty_no_high_severity_findings", + "guardduty_rds_protection_enabled", + "guardduty_s3_protection_enabled", + "inspector2_is_enabled", + "inspector2_active_findings_exist", + "securityhub_enabled", + "sns_topics_kms_encryption_at_rest_enabled" + ] + }, + { + "Id": "ksi-mla", + "Name": "KSI-MLA: Monitoring, Logging, and Auditing", + "Description": "A secure cloud service offering will monitor, log, and audit all important events, activity, and changes", + "Attributes": [ + { + "ItemId": "ksi-mla", + "Section": "Monitoring, Logging, and Auditing", + "Service": "aws" + } + ], + "Checks": [ + "apigateway_restapi_logging_enabled", + "cloudtrail_cloudwatch_logging_enabled", + "cloudtrail_kms_encryption_enabled", + "cloudtrail_log_file_validation_enabled", + "cloudtrail_multi_region_enabled", + "cloudtrail_s3_dataevents_read_enabled", + "cloudtrail_s3_dataevents_write_enabled", + "cloudwatch_log_group_kms_encryption_enabled", + "cloudwatch_log_group_retention_policy_specific_days_enabled", + "ecs_cluster_container_insights_enabled", + "eks_cluster_control_plane_audit_logging_enabled", + "elb_logging_enabled", + "elbv2_logging_enabled", + "inspector2_is_enabled", + "opensearch_service_domains_cloudwatch_logging_enabled", + "rds_instance_enhanced_monitoring_enabled", + "rds_instance_integration_cloudwatch_logs", + "redshift_cluster_audit_logging", + "s3_bucket_server_access_logging_enabled", + "vpc_flow_logs_enabled", + "wafv2_webacl_logging_enabled" + ] + }, + { + "Id": "ksi-piy", + "Name": "KSI-PIY: Policy and Inventory", + "Description": "A secure cloud service offering will have intentional, organized, universal guidance for how every information resource, including personnel, is secured", + "Attributes": [ + { + "ItemId": "ksi-piy", + "Section": "Policy and Inventory", + "Service": "aws" + } + ], + "Checks": [ + "config_recorder_all_regions_enabled", + "config_recorder_using_aws_service_role", + "ec2_instance_managed_by_ssm", + "organizations_account_part_of_organizations", + "organizations_delegated_administrators", + "organizations_scp_check_deny_regions", + "organizations_tags_policies_enabled_and_attached", + "resourceexplorer_indexes_found", + "ssm_managed_instance_compliance_association_compliant", + "trustedadvisor_premium_support_plan_subscribed" + ] + }, + { + "Id": "ksi-rpl", + "Name": "KSI-RPL: Recovery Planning", + "Description": "A secure cloud service offering will define, maintain, and test incident response plan(s) and recovery capabilities to ensure minimal service disruption and data loss", + "Attributes": [ + { + "ItemId": "ksi-rpl", + "Section": "Recovery Planning", + "Service": "aws" + } + ], + "Checks": [ + "backup_plans_exist", + "backup_reportplans_exist", + "backup_vaults_exist", + "backup_vaults_encrypted", + "backup_recovery_point_encrypted", + "backup_recovery_point_manual_deletion_disabled", + "backup_recovery_point_minimum_retention_days", + "dlm_ebs_snapshot_lifecycle_policy_exists", + "dynamodb_tables_pitr_enabled", + "dynamodb_tables_deletion_protection_enabled", + "efs_have_backup_enabled", + "fsx_file_system_copy_tags_to_backups", + "rds_instance_backup_enabled", + "rds_instance_backup_retention_policy", + "rds_instance_deletion_protection", + "rds_cluster_deletion_protection", + "rds_snapshots_encrypted", + "redshift_cluster_automated_snapshot" + ] + }, + { + "Id": "ksi-svc", + "Name": "KSI-SVC: Service Configuration", + "Description": "A secure cloud service offering will follow FedRAMP encryption policies, continuously verify information resource integrity, and restrict access to third-party information resources", + "Attributes": [ + { + "ItemId": "ksi-svc", + "Section": "Service Configuration", + "Service": "aws" + } + ], + "Checks": [ + "acm_certificates_expiration_check", + "apigateway_restapi_cache_encrypted", + "cloudtrail_kms_encryption_enabled", + "dax_cluster_encryption_enabled", + "dynamodb_table_encryption_enabled", + "dynamodb_table_encryption_uses_cmks", + "ebs_volume_encryption_enabled", + "ec2_ebs_default_encryption", + "ec2_instance_ebs_optimized", + "efs_encryption_at_rest_enabled", + "eks_cluster_envelope_encryption_enabled", + "elasticache_redis_cluster_encryption_at_rest_enabled", + "elasticache_redis_cluster_encryption_at_transit_enabled", + "elbv2_ssl_listeners", + "fsx_file_system_encryption_at_rest_enabled", + "kinesis_stream_encrypted_at_rest", + "kms_cmk_rotation_enabled", + "kms_cmk_not_scheduled_for_deletion", + "kms_key_not_publicly_accessible", + "rds_instance_storage_encrypted", + "rds_instance_storage_encrypted_with_cmk", + "rds_cluster_storage_encrypted", + "redshift_cluster_encryption_at_rest", + "redshift_cluster_encryption_in_transit", + "s3_bucket_server_side_encryption_enabled", + "s3_bucket_default_encryption", + "s3_bucket_secure_transport_policy", + "sagemaker_notebook_instance_encryption_enabled", + "sns_topics_kms_encryption_at_rest_enabled", + "sqs_queue_server_side_encryption_enabled" + ] + }, + { + "Id": "ksi-tpr", + "Name": "KSI-TPR: Third-Party Information Resources", + "Description": "A secure cloud service offering will understand, monitor, and manage supply chain risks from third-party information resources", + "Attributes": [ + { + "ItemId": "ksi-tpr", + "Section": "Third-Party Information Resources", + "Service": "aws" + } + ], + "Checks": [ + "ecr_registry_scan_images_on_push_enabled", + "ecr_repositories_lifecycle_policy_enabled", + "ecr_repositories_not_publicly_accessible", + "ecr_repositories_scan_on_push_enabled", + "ecr_repositories_scan_vulnerabilities_in_latest_image", + "ecr_repositories_tag_immutability", + "inspector2_active_findings_exist", + "inspector2_is_enabled", + "awslambda_function_using_supported_runtimes", + "ssm_managed_compliant_patching", + "trustedadvisor_premium_support_plan_subscribed", + "guardduty_no_high_severity_findings" + ] + }, + { + "Id": "ksi-iam-07", + "Name": "KSI-IAM-07: Account Lifecycle Management", + "Description": "Securely manage the lifecycle and privileges of all accounts, roles, and groups", + "Attributes": [ + { + "ItemId": "ksi-iam-07", + "Section": "Identity and Access Management", + "Service": "aws" + } + ], + "Checks": [ + "iam_no_root_access_key", + "iam_policy_attached_only_to_group_or_roles", + "iam_rotate_access_key_90_days", + "iam_user_accesskey_unused", + "iam_user_console_access_unused", + "organizations_delegated_administrators" + ] + }, + { + "Id": "ksi-mla-07", + "Name": "KSI-MLA-07: Monitoring and Logging Inventory", + "Description": "Maintain a list of information resources and event types that will be monitored, logged, and audited", + "Attributes": [ + { + "ItemId": "ksi-mla-07", + "Section": "Monitoring, Logging, and Auditing", + "Service": "aws" + } + ], + "Checks": [ + "cloudtrail_multi_region_enabled", + "cloudwatch_log_group_retention_policy_specific_days_enabled", + "config_recorder_all_regions_enabled", + "inspector2_is_enabled", + "resourceexplorer_indexes_found" + ] + } + ] +} diff --git a/prowler/compliance/azure/fedramp_20x_ksi_low_azure.json b/prowler/compliance/azure/fedramp_20x_ksi_low_azure.json new file mode 100644 index 0000000000..c845f75f60 --- /dev/null +++ b/prowler/compliance/azure/fedramp_20x_ksi_low_azure.json @@ -0,0 +1,358 @@ +{ + "Framework": "FedRAMP-20x-KSI-Low", + "Name": "FedRAMP 20x Key Security Indicators (KSIs) - Low Impact Level v25.05C", + "Version": "25.05C", + "Provider": "Azure", + "Description": "FedRAMP 20x Key Security Indicators (KSIs) Low Impact Level represent core security indicators for cloud service providers, focusing on automation, continuous monitoring, and cloud-native security principles per FedRAMP 20x Phase One pilot requirements for Low impact systems.", + "Requirements": [ + { + "Id": "ksi-cmt", + "Name": "KSI-CMT: Change Management", + "Description": "A secure cloud service provider will ensure that all system changes are properly documented and configuration baselines are updated accordingly", + "Attributes": [ + { + "ItemId": "ksi-cmt", + "Section": "Change Management", + "Service": "azure" + } + ], + "Checks": [ + "monitor_activity_log_alert_cmk_delete", + "monitor_activity_log_alert_create_policy_assignment", + "monitor_activity_log_alert_create_update_delete_network_sg", + "monitor_activity_log_alert_create_update_delete_network_sg_rule", + "monitor_activity_log_alert_create_update_delete_sql_server_fw_rule", + "monitor_activity_log_alert_create_update_nsg", + "monitor_activity_log_alert_create_update_public_ip_address", + "monitor_activity_log_alert_create_update_security_solution", + "monitor_activity_log_alert_delete_nsg", + "monitor_activity_log_alert_delete_policy_assignment", + "monitor_activity_log_alert_delete_public_ip_address", + "monitor_activity_log_alert_delete_security_solution", + "monitor_log_profile_all_categories", + "monitor_log_profile_all_regions", + "vm_agent_installed", + "vm_antimalware_solution_installed", + "vm_endpoint_protection_installed", + "vm_guest_configuration_installed", + "vm_guest_configuration_with_no_managed_identity", + "vm_guest_configuration_with_user_identity" + ] + }, + { + "Id": "ksi-cna", + "Name": "KSI-CNA: Cloud Native Architecture", + "Description": "A secure cloud service offering will use cloud native architecture and design principles to enforce and enhance the Confidentiality, Integrity and Availability of the system", + "Attributes": [ + { + "ItemId": "ksi-cna", + "Section": "Cloud Native Architecture", + "Service": "azure" + } + ], + "Checks": [ + "aks_clusters_created_with_private_nodes", + "aks_clusters_public_access_disabled", + "aks_network_policy_enabled", + "app_function_vnet_integration_enabled", + "app_function_not_publicly_accessible", + "containerregistry_not_publicly_accessible", + "containerregistry_uses_private_link", + "cosmosdb_account_use_private_endpoints", + "cosmosdb_account_firewall_use_selected_networks", + "databricks_workspace_vnet_injection_enabled", + "keyvault_access_only_through_private_endpoints", + "keyvault_private_endpoints", + "network_bastion_host_exists", + "network_flow_logs_enabled", + "network_security_group_not_empty", + "network_sg_ssh_access_restricted", + "network_sg_rdp_access_restricted", + "network_sg_open_all_ports_to_any_source", + "network_watcher_enabled", + "postgresql_flexible_server_public_network_access_disabled", + "sqlserver_public_network_access_disabled", + "storage_default_network_access_rule_set_to_deny", + "vm_availability_zones_enabled", + "vm_availability_set_deployed" + ] + }, + { + "Id": "ksi-iam", + "Name": "KSI-IAM: Identity and Access Management", + "Description": "A secure cloud service offering will protect user data, control access, and apply zero trust principles", + "Attributes": [ + { + "ItemId": "ksi-iam", + "Section": "Identity and Access Management", + "Service": "azure" + } + ], + "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", + "iam_custom_role_has_permissions_to_administer_resource_locks", + "iam_role_user_access_admin_restricted", + "iam_subscription_roles_owner_custom_not_created", + "keyvault_rbac_enabled", + "app_function_identity_is_configured", + "app_function_identity_without_admin_privileges", + "app_ensure_auth_is_set_up", + "app_register_with_identity", + "vm_managed_identity_enabled" + ] + }, + { + "Id": "ksi-inr", + "Name": "KSI-INR: Incident Response", + "Description": "A secure cloud service offering will respond to incidents according to FedRAMP requirements and cloud service provider policies", + "Attributes": [ + { + "ItemId": "ksi-inr", + "Section": "Incident Response", + "Service": "azure" + } + ], + "Checks": [ + "defender_attack_path_notifications_properly_configured", + "defender_ensure_notify_alerts_severity_is_high", + "defender_ensure_notify_emails_to_owners", + "defender_additional_email_configured_with_a_security_contact", + "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_wdatp_is_enabled" + ] + }, + { + "Id": "ksi-mla", + "Name": "KSI-MLA: Monitoring, Logging, and Auditing", + "Description": "A secure cloud service offering will monitor, log, and audit all important events, activity, and changes", + "Attributes": [ + { + "ItemId": "ksi-mla", + "Section": "Monitoring, Logging, and Auditing", + "Service": "azure" + } + ], + "Checks": [ + "app_function_application_insights_enabled", + "app_http_logs_enabled", + "appinsights_ensure_is_configured", + "defender_auto_provisioning_log_analytics_agent_vms_on", + "defender_auto_provisioning_vulnerabilty_assessments_machines_on", + "keyvault_logging_enabled", + "monitor_activity_log_retention_policy_set", + "monitor_diagnostic_logs_categories", + "monitor_diagnostic_setting_deployed_for_all_resources", + "monitor_diagnostic_settings_captures_proper_categories", + "monitor_log_profile_all_categories", + "monitor_log_profile_all_regions", + "monitor_log_profile_captures_all_activities", + "monitor_log_profile_retention_policy_at_least_365", + "network_flow_logs_enabled", + "network_flow_log_retention_policy_at_least_90", + "network_watcher_enabled", + "postgresql_flexible_server_audit_logs_enabled", + "postgresql_flexible_server_log_checkpoints_enabled", + "postgresql_flexible_server_log_connections_enabled", + "postgresql_flexible_server_log_disconnections_enabled", + "sqlserver_auditing_on", + "sqlserver_auditing_retention_90_days", + "storage_storage_account_logging_queue_read_write_delete_enabled" + ] + }, + { + "Id": "ksi-piy", + "Name": "KSI-PIY: Policy and Inventory", + "Description": "A secure cloud service offering will have intentional, organized, universal guidance for how every information resource, including personnel, is secured", + "Attributes": [ + { + "ItemId": "ksi-piy", + "Section": "Policy and Inventory", + "Service": "azure" + } + ], + "Checks": [ + "policy_ensure_asc_for_aks_is_enabled", + "policy_ensure_asc_for_app_services_is_enabled", + "policy_ensure_asc_for_azure_sql_is_enabled", + "policy_ensure_asc_for_key_vault_is_enabled", + "policy_ensure_asc_for_servers_is_enabled", + "policy_ensure_asc_for_sql_servers_is_enabled", + "policy_ensure_asc_for_storage_is_enabled", + "policy_ensure_allowed_extensions_are_installed", + "policy_ensure_allowed_locations_is_enabled", + "policy_ensure_allowed_resource_types_is_enabled", + "policy_ensure_audit_diagnostic_log_enabled_for_all_services", + "policy_ensure_not_allowed_resource_types_is_enabled", + "vm_guest_configuration_installed", + "vm_guest_configuration_with_no_managed_identity", + "vm_guest_configuration_with_user_identity" + ] + }, + { + "Id": "ksi-rpl", + "Name": "KSI-RPL: Recovery Planning", + "Description": "A secure cloud service offering will define, maintain, and test incident response plan(s) and recovery capabilities to ensure minimal service disruption and data loss", + "Attributes": [ + { + "ItemId": "ksi-rpl", + "Section": "Recovery Planning", + "Service": "azure" + } + ], + "Checks": [ + "mysql_flexible_server_geo_redundant_backup_enabled", + "mysql_flexible_server_retain_backup_35_days", + "postgresql_flexible_server_geo_redundant_backup_enabled", + "postgresql_flexible_server_backup_retention_period_35_days", + "recovery_services_vault_uses_private_link", + "recovery_services_vault_uses_private_link_for_backup", + "sqlserver_database_long_term_geo_redundant_backup", + "sqlserver_database_retention_policy_exceeds_90_days", + "storage_default_storage_account_encrypted_with_cmk_not_stored_in_storage_account", + "storage_geo_redundant_enabled", + "storage_infrastructure_encryption_is_enabled", + "storage_soft_delete_containers_enabled", + "storage_soft_delete_enabled", + "vm_backup_enabled", + "vm_sufficient_daily_backup_retention_period" + ] + }, + { + "Id": "ksi-svc", + "Name": "KSI-SVC: Service Configuration", + "Description": "A secure cloud service offering will follow FedRAMP encryption policies, continuously verify information resource integrity, and restrict access to third-party information resources", + "Attributes": [ + { + "ItemId": "ksi-svc", + "Section": "Service Configuration", + "Service": "azure" + } + ], + "Checks": [ + "app_client_certificates_on", + "app_ensure_http_is_redirected_to_https", + "app_minimum_tls_version_12", + "containerregistry_admin_user_disabled", + "cosmosdb_account_use_aad_and_rbac", + "databricks_workspace_cmk_encryption_enabled", + "keyvault_key_expiration_set_in_non_rbac", + "keyvault_key_rotation_enabled", + "keyvault_non_rbac_secret_expiration_set", + "mysql_flexible_server_encrypted_at_rest_using_cmk", + "mysql_flexible_server_encrypted_in_transit", + "mysql_flexible_server_minimum_tls_version_tls12", + "postgresql_flexible_server_encrypted_at_rest_using_cmk", + "postgresql_flexible_server_encrypted_in_transit", + "postgresql_flexible_server_minimum_tls_version_tls12", + "sqlserver_advanced_data_security_enabled", + "sqlserver_database_encryption_with_cmk", + "sqlserver_database_tde_encryption_enabled", + "sqlserver_minimum_tls_version_12", + "storage_secure_transfer_required_enabled", + "storage_default_storage_account_encrypted_with_cmk", + "storage_infrastructure_encryption_is_enabled", + "storage_storage_account_encrypted_with_cmk", + "storage_storage_account_minimum_tls_version_tls12", + "vm_encrypted_at_host", + "vm_data_disks_encrypted_with_cmk", + "vm_managed_disks_encrypted_with_cmk", + "vm_os_disk_are_encrypted_with_cmk", + "vm_temporary_disks_and_cache_encrypted" + ] + }, + { + "Id": "ksi-tpr", + "Name": "KSI-TPR: Third-Party Information Resources", + "Description": "A secure cloud service offering will understand, monitor, and manage supply chain risks from third-party information resources", + "Attributes": [ + { + "ItemId": "ksi-tpr", + "Section": "Third-Party Information Resources", + "Service": "azure" + } + ], + "Checks": [ + "app_ensure_java_version_is_latest", + "app_ensure_php_version_is_latest", + "app_ensure_python_version_is_latest", + "app_function_latest_runtime_version", + "defender_container_images_resolved_vulnerabilities", + "defender_container_images_scan_enabled", + "defender_ensure_system_updates_are_applied", + "vm_agent_installed", + "vm_antimalware_solution_installed", + "vm_endpoint_protection_installed", + "vm_os_update_system_updates", + "vm_security_patch_assessment" + ] + }, + { + "Id": "ksi-iam-07", + "Name": "KSI-IAM-07: Account Lifecycle Management", + "Description": "Securely manage the lifecycle and privileges of all accounts, roles, and groups", + "Attributes": [ + { + "ItemId": "ksi-iam-07", + "Section": "Identity and Access Management", + "Service": "azure" + } + ], + "Checks": [ + "entra_non_privileged_user_has_mfa", + "entra_privileged_user_has_mfa", + "entra_user_with_vm_access_has_mfa", + "iam_custom_role_has_permissions_to_administer_resource_locks", + "iam_role_user_access_admin_restricted", + "app_function_identity_is_configured", + "vm_managed_identity_enabled" + ] + }, + { + "Id": "ksi-mla-07", + "Name": "KSI-MLA-07: Monitoring and Logging Inventory", + "Description": "Maintain a list of information resources and event types that will be monitored, logged, and audited", + "Attributes": [ + { + "ItemId": "ksi-mla-07", + "Section": "Monitoring, Logging, and Auditing", + "Service": "azure" + } + ], + "Checks": [ + "monitor_log_profile_all_categories", + "monitor_log_profile_all_regions", + "monitor_log_profile_captures_all_activities", + "monitor_diagnostic_setting_deployed_for_all_resources", + "network_watcher_enabled" + ] + } + ] +} diff --git a/prowler/compliance/gcp/fedramp_20x_ksi_low_gcp.json b/prowler/compliance/gcp/fedramp_20x_ksi_low_gcp.json new file mode 100644 index 0000000000..420601d810 --- /dev/null +++ b/prowler/compliance/gcp/fedramp_20x_ksi_low_gcp.json @@ -0,0 +1,293 @@ +{ + "Framework": "FedRAMP-20x-KSI-Low", + "Name": "FedRAMP 20x Key Security Indicators (KSIs) - Low Impact Level v25.05C", + "Version": "25.05C", + "Provider": "GCP", + "Description": "FedRAMP 20x Key Security Indicators (KSIs) Low Impact Level represent core security indicators for cloud service providers, focusing on automation, continuous monitoring, and cloud-native security principles per FedRAMP 20x Phase One pilot requirements for Low impact systems.", + "Requirements": [ + { + "Id": "ksi-cmt", + "Name": "KSI-CMT: Change Management", + "Description": "A secure cloud service provider will ensure that all system changes are properly documented and configuration baselines are updated accordingly", + "Attributes": [ + { + "ItemId": "ksi-cmt", + "Section": "Change Management", + "Service": "gcp" + } + ], + "Checks": [ + "iam_audit_logs_enabled", + "iam_cloud_asset_inventory_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", + "compute_instance_serial_ports_in_use", + "compute_project_os_login_enabled" + ] + }, + { + "Id": "ksi-cna", + "Name": "KSI-CNA: Cloud Native Architecture", + "Description": "A secure cloud service offering will use cloud native architecture and design principles to enforce and enhance the Confidentiality, Integrity and Availability of the system", + "Attributes": [ + { + "ItemId": "ksi-cna", + "Section": "Cloud Native Architecture", + "Service": "gcp" + } + ], + "Checks": [ + "cloudsql_instance_private_ip_assignment", + "cloudsql_instance_public_access", + "cloudsql_instance_public_ip", + "cloudstorage_bucket_uniform_bucket_level_access", + "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_confidential_computing_enabled", + "compute_instance_ip_forwarding_is_enabled", + "compute_instance_public_ip", + "compute_instance_shielded_vm_enabled", + "compute_loadbalancer_logging_enabled", + "compute_network_default_in_use", + "compute_network_dns_logging_enabled", + "compute_network_not_legacy", + "compute_subnet_flow_logs_enabled", + "gke_cluster_no_default_service_account" + ] + }, + { + "Id": "ksi-iam", + "Name": "KSI-IAM: Identity and Access Management", + "Description": "A secure cloud service offering will protect user data, control access, and apply zero trust principles", + "Attributes": [ + { + "ItemId": "ksi-iam", + "Section": "Identity and Access Management", + "Service": "gcp" + } + ], + "Checks": [ + "apikeys_api_restrictions_configured", + "apikeys_key_exists", + "apikeys_key_rotated_in_90_days", + "compute_instance_default_service_account_in_use", + "compute_instance_default_service_account_in_use_with_full_api_access", + "iam_no_service_roles_at_project_level", + "iam_role_kms_enforce_separation_of_duties", + "iam_role_sa_enforce_separation_of_duties", + "iam_sa_no_administrative_privileges", + "iam_sa_no_user_managed_keys", + "iam_sa_user_managed_key_rotate_90_days", + "iam_sa_user_managed_key_unused", + "iam_service_account_unused" + ] + }, + { + "Id": "ksi-inr", + "Name": "KSI-INR: Incident Response", + "Description": "A secure cloud service offering will respond to incidents according to FedRAMP requirements and cloud service provider policies", + "Attributes": [ + { + "ItemId": "ksi-inr", + "Section": "Incident Response", + "Service": "gcp" + } + ], + "Checks": [ + "iam_organization_essential_contacts_configured", + "iam_account_access_approval_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" + ] + }, + { + "Id": "ksi-mla", + "Name": "KSI-MLA: Monitoring, Logging, and Auditing", + "Description": "A secure cloud service offering will monitor, log, and audit all important events, activity, and changes", + "Attributes": [ + { + "ItemId": "ksi-mla", + "Section": "Monitoring, Logging, and Auditing", + "Service": "gcp" + } + ], + "Checks": [ + "cloudsql_instance_postgres_enable_pgaudit_flag", + "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", + "cloudsql_instance_sqlserver_trace_flag", + "cloudstorage_bucket_log_retention_policy_lock", + "compute_loadbalancer_logging_enabled", + "compute_network_dns_logging_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": "ksi-piy", + "Name": "KSI-PIY: Policy and Inventory", + "Description": "A secure cloud service offering will have intentional, organized, universal guidance for how every information resource, including personnel, is secured", + "Attributes": [ + { + "ItemId": "ksi-piy", + "Section": "Policy and Inventory", + "Service": "gcp" + } + ], + "Checks": [ + "iam_cloud_asset_inventory_enabled", + "iam_organization_essential_contacts_configured", + "iam_audit_logs_enabled", + "compute_project_os_login_enabled", + "compute_instance_serial_ports_in_use", + "compute_instance_block_project_wide_ssh_keys_disabled", + "logging_sink_created" + ] + }, + { + "Id": "ksi-rpl", + "Name": "KSI-RPL: Recovery Planning", + "Description": "A secure cloud service offering will define, maintain, and test incident response plan(s) and recovery capabilities to ensure minimal service disruption and data loss", + "Attributes": [ + { + "ItemId": "ksi-rpl", + "Section": "Recovery Planning", + "Service": "gcp" + } + ], + "Checks": [ + "cloudsql_instance_automated_backups", + "cloudstorage_bucket_log_retention_policy_lock", + "cloudstorage_bucket_versioning_enabled", + "cloudstorage_bucket_lifecycle_management_enabled" + ] + }, + { + "Id": "ksi-svc", + "Name": "KSI-SVC: Service Configuration", + "Description": "A secure cloud service offering will follow FedRAMP encryption policies, continuously verify information resource integrity, and restrict access to third-party information resources", + "Attributes": [ + { + "ItemId": "ksi-svc", + "Section": "Service Configuration", + "Service": "gcp" + } + ], + "Checks": [ + "bigquery_dataset_cmk_encryption", + "bigquery_table_cmk_encryption", + "cloudsql_instance_mysql_local_infile_flag", + "cloudsql_instance_mysql_skip_show_database_flag", + "cloudsql_instance_postgres_enable_pgaudit_flag", + "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", + "cloudsql_instance_sqlserver_contained_database_authentication_flag", + "cloudsql_instance_sqlserver_cross_db_ownership_chaining_flag", + "cloudsql_instance_sqlserver_external_scripts_enabled_flag", + "cloudsql_instance_sqlserver_remote_access_flag", + "cloudsql_instance_sqlserver_trace_flag", + "cloudsql_instance_sqlserver_user_connections_flag", + "cloudsql_instance_sqlserver_user_options_flag", + "cloudsql_instance_ssl_connections", + "compute_instance_encryption_with_csek_enabled", + "compute_instance_shielded_vm_enabled", + "dataproc_encrypted_with_cmks_disabled", + "dns_dnssec_disabled", + "dns_rsasha1_in_use_to_key_sign_in_dnssec", + "dns_rsasha1_in_use_to_zone_sign_in_dnssec", + "kms_key_not_publicly_accessible", + "kms_key_rotation_enabled" + ] + }, + { + "Id": "ksi-tpr", + "Name": "KSI-TPR: Third-Party Information Resources", + "Description": "A secure cloud service offering will understand, monitor, and manage supply chain risks from third-party information resources", + "Attributes": [ + { + "ItemId": "ksi-tpr", + "Section": "Third-Party Information Resources", + "Service": "gcp" + } + ], + "Checks": [ + "artifacts_container_analysis_enabled", + "gcr_container_scanning_enabled", + "compute_public_address_shodan", + "cloudsql_instance_automated_backups", + "iam_sa_user_managed_key_rotate_90_days", + "iam_service_account_unused" + ] + }, + { + "Id": "ksi-iam-07", + "Name": "KSI-IAM-07: Account Lifecycle Management", + "Description": "Securely manage the lifecycle and privileges of all accounts, roles, and groups", + "Attributes": [ + { + "ItemId": "ksi-iam-07", + "Section": "Identity and Access Management", + "Service": "gcp" + } + ], + "Checks": [ + "apikeys_key_rotated_in_90_days", + "iam_sa_user_managed_key_rotate_90_days", + "iam_sa_user_managed_key_unused", + "iam_service_account_unused", + "compute_instance_default_service_account_in_use" + ] + }, + { + "Id": "ksi-mla-07", + "Name": "KSI-MLA-07: Monitoring and Logging Inventory", + "Description": "Maintain a list of information resources and event types that will be monitored, logged, and audited", + "Attributes": [ + { + "ItemId": "ksi-mla-07", + "Section": "Monitoring, Logging, and Auditing", + "Service": "gcp" + } + ], + "Checks": [ + "iam_audit_logs_enabled", + "iam_cloud_asset_inventory_enabled", + "logging_sink_created", + "compute_subnet_flow_logs_enabled", + "compute_network_dns_logging_enabled" + ] + } + ] +} From 521afab4aa66681d310cef1ff4be2aa964ad6e44 Mon Sep 17 00:00:00 2001 From: Prowler Bot Date: Mon, 10 Nov 2025 15:37:18 +0100 Subject: [PATCH 04/23] feat(aws): Update regions for AWS services (#9194) Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com> --- .../providers/aws/aws_regions_by_service.json | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/prowler/providers/aws/aws_regions_by_service.json b/prowler/providers/aws/aws_regions_by_service.json index 6969414824..c6217b0c60 100644 --- a/prowler/providers/aws/aws_regions_by_service.json +++ b/prowler/providers/aws/aws_regions_by_service.json @@ -1555,6 +1555,7 @@ "aws": [ "af-south-1", "ap-east-1", + "ap-east-2", "ap-northeast-1", "ap-northeast-2", "ap-northeast-3", @@ -1565,6 +1566,8 @@ "ap-southeast-3", "ap-southeast-4", "ap-southeast-5", + "ap-southeast-6", + "ap-southeast-7", "ca-central-1", "ca-west-1", "eu-central-1", @@ -1578,6 +1581,7 @@ "il-central-1", "me-central-1", "me-south-1", + "mx-central-1", "sa-east-1", "us-east-1", "us-east-2", @@ -4584,8 +4588,10 @@ "ap-southeast-2", "ca-central-1", "eu-central-1", + "eu-south-1", "eu-west-1", "eu-west-2", + "eu-west-3", "us-east-1", "us-east-2", "us-west-2" @@ -7261,6 +7267,7 @@ "eu-west-1", "eu-west-2", "eu-west-3", + "me-central-1", "me-south-1", "sa-east-1", "us-east-1", @@ -7953,6 +7960,7 @@ "aws": [ "af-south-1", "ap-east-1", + "ap-east-2", "ap-northeast-1", "ap-northeast-2", "ap-northeast-3", @@ -7963,6 +7971,8 @@ "ap-southeast-3", "ap-southeast-4", "ap-southeast-5", + "ap-southeast-6", + "ap-southeast-7", "ca-central-1", "ca-west-1", "eu-central-1", @@ -7976,6 +7986,7 @@ "il-central-1", "me-central-1", "me-south-1", + "mx-central-1", "sa-east-1", "us-east-1", "us-east-2", @@ -9799,6 +9810,20 @@ ] } }, + "rtbfabric": { + "regions": { + "aws": [ + "ap-northeast-1", + "ap-southeast-1", + "eu-central-1", + "eu-west-1", + "us-east-1", + "us-west-2" + ], + "aws-cn": [], + "aws-us-gov": [] + } + }, "rum": { "regions": { "aws": [ From be0b8bba0de2425980d9dbfe677ee5d3e839d734 Mon Sep 17 00:00:00 2001 From: Sergio Garcia Date: Mon, 10 Nov 2025 10:15:54 -0500 Subject: [PATCH 05/23] fix(html): rename `get_oci_assessment_summary` (#9200) --- prowler/CHANGELOG.md | 1 + prowler/lib/outputs/html/html.py | 16 +++++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index c6be038f9a..e3823d9fa5 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -51,6 +51,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Check `check_name` has no `resource_name` error for GCP provider [(#9169)](https://github.com/prowler-cloud/prowler/pull/9169) - Depth Truncation and parsing error in PowerShell queries [(#9181)](https://github.com/prowler-cloud/prowler/pull/9181) - Fix M365 Teams `--sp-env-auth` connection error and enhanced timeout logging [(#9191)](https://github.com/prowler-cloud/prowler/pull/9191) +- Rename `get_oci_assessment_summary` to `get_oraclecloud_assessment_summary` in HTML output [(#9200)](https://github.com/prowler-cloud/prowler/pull/9200) --- diff --git a/prowler/lib/outputs/html/html.py b/prowler/lib/outputs/html/html.py index d8a390bd1b..9295cc4abb 100644 --- a/prowler/lib/outputs/html/html.py +++ b/prowler/lib/outputs/html/html.py @@ -974,18 +974,20 @@ class HTML(Output): return "" @staticmethod - def get_oci_assessment_summary(provider: Provider) -> str: + def get_oraclecloud_assessment_summary(provider: Provider) -> str: """ - get_oci_assessment_summary gets the HTML assessment summary for the OCI provider + get_oraclecloud_assessment_summary gets the HTML assessment summary for the OracleCloud provider Args: - provider (Provider): the OCI provider object + provider (Provider): the OracleCloud provider object Returns: - str: HTML assessment summary for the OCI provider + str: HTML assessment summary for the OracleCloud provider """ try: profile = getattr(provider.session, "profile", "default") + if profile is None: + profile = "instance-principal" tenancy_name = getattr(provider.identity, "tenancy_name", "unknown") tenancy_id = getattr(provider.identity, "tenancy_id", "unknown") @@ -993,11 +995,11 @@ class HTML(Output):
- OCI Assessment Summary + OracleCloud Assessment Summary
  • - OCI Tenancy: {tenancy_name if tenancy_name != "unknown" else tenancy_id} + OracleCloud Tenancy: {tenancy_name if tenancy_name != "unknown" else tenancy_id}
@@ -1005,7 +1007,7 @@ class HTML(Output):
- OCI Credentials + OracleCloud Credentials