Compare commits
1 commit
main
...
prowler-mu
| Author | SHA1 | Date | |
|---|---|---|---|
| 0b68d48eba |
8 changed files with 240 additions and 0 deletions
|
|
@ -51,3 +51,5 @@ spec:
|
|||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
|
|
|
|||
|
|
@ -15,6 +15,28 @@ spec:
|
|||
securityContext:
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
initContainers:
|
||||
- name: merge-mutelist
|
||||
image: registry.ops.eblu.me/blumeops/prowler:kustomized
|
||||
command: ["python3", "-c"]
|
||||
args:
|
||||
- |
|
||||
import yaml, glob, pathlib
|
||||
merged = {"Mutelist": {"Accounts": {"*": {"Checks": {}}}}}
|
||||
for f in sorted(glob.glob("/mutelist-parts/*.yaml")):
|
||||
with open(f) as fh:
|
||||
data = yaml.safe_load(fh)
|
||||
checks = data.get("Mutelist", {}).get("Accounts", {}).get("*", {}).get("Checks", {})
|
||||
merged["Mutelist"]["Accounts"]["*"]["Checks"].update(checks)
|
||||
pathlib.Path("/tmp/mutelist").mkdir(exist_ok=True)
|
||||
with open("/tmp/mutelist/mutelist.yaml", "w") as fh:
|
||||
yaml.dump(merged, fh, default_flow_style=False)
|
||||
print(f"Merged {len(merged['Mutelist']['Accounts']['*']['Checks'])} checks from {len(glob.glob('/mutelist-parts/*.yaml'))} files")
|
||||
volumeMounts:
|
||||
- name: mutelist-parts
|
||||
mountPath: /mutelist-parts
|
||||
- name: mutelist-merged
|
||||
mountPath: /tmp/mutelist
|
||||
containers:
|
||||
- name: prowler
|
||||
image: registry.ops.eblu.me/blumeops/prowler:kustomized
|
||||
|
|
@ -22,6 +44,8 @@ spec:
|
|||
- kubernetes
|
||||
- --compliance
|
||||
- cis_1.11_kubernetes
|
||||
- --mutelist-file
|
||||
- /tmp/mutelist/mutelist.yaml
|
||||
- -z
|
||||
- --output-formats
|
||||
- html
|
||||
|
|
@ -32,6 +56,9 @@ spec:
|
|||
volumeMounts:
|
||||
- name: reports
|
||||
mountPath: /reports
|
||||
- name: mutelist-merged
|
||||
mountPath: /tmp/mutelist
|
||||
readOnly: true
|
||||
- name: var-lib-kubelet
|
||||
mountPath: /var/lib/kubelet
|
||||
readOnly: true
|
||||
|
|
@ -47,6 +74,11 @@ spec:
|
|||
- name: reports
|
||||
persistentVolumeClaim:
|
||||
claimName: prowler-reports
|
||||
- name: mutelist-parts
|
||||
configMap:
|
||||
name: prowler-mutelist
|
||||
- name: mutelist-merged
|
||||
emptyDir: {}
|
||||
- name: var-lib-kubelet
|
||||
hostPath:
|
||||
path: /var/lib/kubelet
|
||||
|
|
|
|||
|
|
@ -13,6 +13,16 @@ resources:
|
|||
- cronjob-image-scan.yaml
|
||||
- cronjob-iac-scan.yaml
|
||||
|
||||
configMapGenerator:
|
||||
- name: prowler-mutelist
|
||||
options:
|
||||
disableNameSuffixHash: true
|
||||
files:
|
||||
- mutelist/apiserver.yaml
|
||||
- mutelist/control-plane.yaml
|
||||
- mutelist/core-pod-security.yaml
|
||||
- mutelist/rbac.yaml
|
||||
|
||||
images:
|
||||
- name: registry.ops.eblu.me/blumeops/prowler
|
||||
newTag: v5.22.0-6960243
|
||||
|
|
|
|||
54
argocd/manifests/prowler/mutelist/apiserver.yaml
Normal file
54
argocd/manifests/prowler/mutelist/apiserver.yaml
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
# Minikube apiserver — flags managed by static pod manifests.
|
||||
# Compensating control: cluster not internet-exposed; access via Tailscale ACLs.
|
||||
Mutelist:
|
||||
Accounts:
|
||||
"*":
|
||||
Checks:
|
||||
"apiserver_always_pull_images_plugin":
|
||||
Regions: ["*"]
|
||||
Resources: ["^kube-apiserver-minikube$"]
|
||||
Description: "Minikube default; AlwaysPullImages not enabled."
|
||||
"apiserver_audit_log_maxage_set":
|
||||
Regions: ["*"]
|
||||
Resources: ["^kube-apiserver-minikube$"]
|
||||
Description: "Minikube does not configure audit logging."
|
||||
"apiserver_audit_log_maxbackup_set":
|
||||
Regions: ["*"]
|
||||
Resources: ["^kube-apiserver-minikube$"]
|
||||
Description: "Minikube does not configure audit logging."
|
||||
"apiserver_audit_log_maxsize_set":
|
||||
Regions: ["*"]
|
||||
Resources: ["^kube-apiserver-minikube$"]
|
||||
Description: "Minikube does not configure audit logging."
|
||||
"apiserver_audit_log_path_set":
|
||||
Regions: ["*"]
|
||||
Resources: ["^kube-apiserver-minikube$"]
|
||||
Description: "Minikube does not configure audit logging."
|
||||
"apiserver_deny_service_external_ips":
|
||||
Regions: ["*"]
|
||||
Resources: ["^kube-apiserver-minikube$"]
|
||||
Description: "Minikube default; no external IPs in use."
|
||||
"apiserver_disable_profiling":
|
||||
Regions: ["*"]
|
||||
Resources: ["^kube-apiserver-minikube$"]
|
||||
Description: "Minikube default; profiling endpoint not exposed."
|
||||
"apiserver_encryption_provider_config_set":
|
||||
Regions: ["*"]
|
||||
Resources: ["^kube-apiserver-minikube$"]
|
||||
Description: "Minikube does not configure etcd encryption at rest."
|
||||
"apiserver_kubelet_cert_auth":
|
||||
Regions: ["*"]
|
||||
Resources: ["^kube-apiserver-minikube$"]
|
||||
Description: "Minikube manages kubelet certificates automatically."
|
||||
"apiserver_request_timeout_set":
|
||||
Regions: ["*"]
|
||||
Resources: ["^kube-apiserver-minikube$"]
|
||||
Description: "Minikube default; using K8s default timeout."
|
||||
"apiserver_service_account_lookup_true":
|
||||
Regions: ["*"]
|
||||
Resources: ["^kube-apiserver-minikube$"]
|
||||
Description: "Minikube default."
|
||||
"apiserver_strong_ciphers_only":
|
||||
Regions: ["*"]
|
||||
Resources: ["^kube-apiserver-minikube$"]
|
||||
Description: "Minikube default TLS cipher suite."
|
||||
18
argocd/manifests/prowler/mutelist/control-plane.yaml
Normal file
18
argocd/manifests/prowler/mutelist/control-plane.yaml
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# Minikube control-plane components — managed by static pod manifests.
|
||||
# Compensating control: cluster not internet-exposed; access via Tailscale ACLs.
|
||||
Mutelist:
|
||||
Accounts:
|
||||
"*":
|
||||
Checks:
|
||||
"controllermanager_disable_profiling":
|
||||
Regions: ["*"]
|
||||
Resources: ["^kube-controller-manager-minikube$"]
|
||||
Description: "Minikube default; profiling endpoint not exposed outside tailnet."
|
||||
"scheduler_profiling":
|
||||
Regions: ["*"]
|
||||
Resources: ["^kube-scheduler-minikube$"]
|
||||
Description: "Minikube default; profiling endpoint not exposed outside tailnet."
|
||||
"kubelet_tls_cert_and_key":
|
||||
Regions: ["*"]
|
||||
Resources: ["^kubelet-config$"]
|
||||
Description: "Minikube uses auto-generated kubelet certificates."
|
||||
86
argocd/manifests/prowler/mutelist/core-pod-security.yaml
Normal file
86
argocd/manifests/prowler/mutelist/core-pod-security.yaml
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
# Pod security checks — system pods, operator-managed pods, and accepted
|
||||
# operational needs. Each check ID appears once with all matching resources.
|
||||
Mutelist:
|
||||
Accounts:
|
||||
"*":
|
||||
Checks:
|
||||
"core_minimize_hostNetwork_containers":
|
||||
Regions: ["*"]
|
||||
Resources:
|
||||
# Minikube control plane — requires hostNetwork by design
|
||||
- "^etcd-minikube$"
|
||||
- "^kube-apiserver-minikube$"
|
||||
- "^kube-controller-manager-minikube$"
|
||||
- "^kube-scheduler-minikube$"
|
||||
# Minikube system pods
|
||||
- "^kube-proxy-"
|
||||
- "^kindnet-"
|
||||
- "^storage-provisioner$"
|
||||
Description: >-
|
||||
Control-plane and networking pods require hostNetwork.
|
||||
All managed by minikube.
|
||||
"core_minimize_privileged_containers":
|
||||
Regions: ["*"]
|
||||
Resources:
|
||||
# Minikube system
|
||||
- "^kube-proxy-"
|
||||
# Tailscale operator-managed proxies
|
||||
- "^ts-"
|
||||
- "^ingress-"
|
||||
# Forgejo runner — Docker-in-Docker for CI builds
|
||||
- "^forgejo-runner-"
|
||||
Description: >-
|
||||
kube-proxy: iptables (minikube). ts-*/ingress-*: network
|
||||
namespace manipulation (Tailscale operator). forgejo-runner:
|
||||
Docker-in-Docker for CI.
|
||||
"core_seccomp_profile_docker_default":
|
||||
Regions: ["*"]
|
||||
Resources:
|
||||
# Minikube system pods
|
||||
- "^coredns-"
|
||||
- "^kube-proxy-"
|
||||
- "^kindnet-"
|
||||
- "^storage-provisioner$"
|
||||
# Tailscale operator-managed pods
|
||||
- "^ts-"
|
||||
- "^operator-"
|
||||
- "^nameserver-"
|
||||
- "^ingress-"
|
||||
Description: >-
|
||||
System pods (minikube) and Tailscale operator pods — seccomp
|
||||
profiles set by upstream/operator, not user manifests.
|
||||
"core_minimize_hostPID_containers":
|
||||
Regions: ["*"]
|
||||
Resources:
|
||||
- "^prowler-"
|
||||
Description: >-
|
||||
Prowler CIS scanner requires hostPID to check file
|
||||
permissions on kubelet and etcd data directories.
|
||||
"core_minimize_root_containers_admission":
|
||||
Regions: ["*"]
|
||||
Resources:
|
||||
- "^grafana-"
|
||||
Description: >-
|
||||
Grafana init-chown-data runs as root to fix PVC ownership.
|
||||
Main containers run as UID 472. Standard pattern.
|
||||
"core_minimize_containers_added_capabilities":
|
||||
Regions: ["*"]
|
||||
Resources:
|
||||
# Minikube system pods
|
||||
- "^coredns-"
|
||||
- "^kindnet-"
|
||||
# Grafana init-chown-data (CHOWN capability)
|
||||
- "^grafana-"
|
||||
Description: >-
|
||||
System pods: NET_BIND_SERVICE/NET_RAW required by function
|
||||
(minikube). Grafana: CHOWN for PVC init; all other
|
||||
containers drop ALL.
|
||||
"core_minimize_containers_capabilities_assigned":
|
||||
Regions: ["*"]
|
||||
Resources:
|
||||
- "^coredns-"
|
||||
- "^kindnet-"
|
||||
- "^grafana-"
|
||||
Description: >-
|
||||
System pods (minikube) and Grafana init-chown-data.
|
||||
See core_minimize_containers_added_capabilities.
|
||||
37
argocd/manifests/prowler/mutelist/rbac.yaml
Normal file
37
argocd/manifests/prowler/mutelist/rbac.yaml
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
# RBAC checks — built-in Kubernetes roles and operator roles that require
|
||||
# broad permissions by design.
|
||||
Mutelist:
|
||||
Accounts:
|
||||
"*":
|
||||
Checks:
|
||||
"rbac_minimize_wildcard_use_roles":
|
||||
Regions: ["*"]
|
||||
Resources:
|
||||
# Built-in Kubernetes roles
|
||||
- "^cluster-admin$"
|
||||
- "^system:"
|
||||
# ArgoCD — requires broad access for deployment management;
|
||||
# ArgoCD itself is SSO-gated via Authentik
|
||||
- "^argocd-"
|
||||
Description: >-
|
||||
Built-in K8s roles and ArgoCD. ArgoCD access is SSO-gated
|
||||
via Authentik.
|
||||
"rbac_minimize_pod_creation_access":
|
||||
Regions: ["*"]
|
||||
Resources:
|
||||
# Built-in Kubernetes roles
|
||||
- "^admin$"
|
||||
- "^edit$"
|
||||
- "^system:"
|
||||
# CloudNativePG operator
|
||||
- "^cnpg-manager$"
|
||||
Description: >-
|
||||
Built-in K8s roles required for workload controllers.
|
||||
cnpg-manager: CloudNativePG operator manages PostgreSQL pods.
|
||||
"rbac_minimize_service_account_token_creation":
|
||||
Regions: ["*"]
|
||||
Resources:
|
||||
- "^system:"
|
||||
Description: >-
|
||||
kube-controller-manager requires token creation for service
|
||||
account management. Built-in role.
|
||||
1
docs/changelog.d/prowler-mutelist.infra.md
Normal file
1
docs/changelog.d/prowler-mutelist.infra.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
Add Prowler mutelist to suppress expected findings from system components, operator-managed pods, and accepted operational needs. Fix missing seccomp profile on kube-state-metrics.
|
||||
Loading…
Add table
Add a link
Reference in a new issue