blumeops/compensating-controls.yaml

153 lines
6.5 KiB
YAML
Raw Normal View History

Add compensating controls framework and date-based report dirs (#320) ## Summary - Add `compensating-controls.yaml` tracking 9 named controls that justify suppressed security findings - Update all Prowler mutelist descriptions with `CC: <id>` references to named controls - Add `mise run review-compensating-controls` task — surfaces stalest control with all codebase references - Add [[review-compensating-controls]] how-to doc - Organize Prowler and Kingfisher reports into `YYYY-MM-DD` subdirectories ### Compensating controls | ID | Mitigates | |----|-----------| | `single-user-cluster` | Image cache abuse, RBAC breadth, system pod privileges | | `tailscale-network-isolation` | Profiling endpoints, weak TLS, debug ports | | `local-registry` | AlwaysPullImages gap | | `sso-gated-admin-tools` | ArgoCD wildcard RBAC | | `operator-managed-pods` | Tailscale proxy pod security settings | | `ephemeral-privileged-jobs` | Prowler hostPID exposure | | `trusted-ci-only` | Forgejo runner DinD | | `init-container-isolation` | Grafana root init container | | `observability-stack-audit` | Missing apiserver audit logging | ## Test plan - [ ] `mise run review-compensating-controls` shows table and references - [ ] `kubectl kustomize argocd/manifests/prowler/` renders correctly - [ ] Sync prowler and kingfisher, verify next scan writes to dated subdirectory - [ ] Grep for `CC:` in mutelist files — every muted finding should have at least one 🤖 Generated with [Claude Code](https://claude.com/claude-code) Reviewed-on: https://forge.eblu.me/eblume/blumeops/pulls/320
2026-03-30 17:44:11 -07:00
# Compensating Controls
#
# Documents controls that mitigate risks from suppressed or accepted security
# findings. Referenced by security tools (Prowler mutelist, Kingfisher config,
# etc.) via "CC: <id>" in finding descriptions or suppression notes.
#
# Used by `mise run review-compensating-controls` to surface stale controls.
#
# Fields:
# id - kebab-case unique identifier, referenced from tool configs
# description - what the control actually does to mitigate risk
# created - date (YYYY-MM-DD) the control was documented
# last-reviewed - date (YYYY-MM-DD) or null
# notes - optional context
controls:
- id: single-user-cluster
description: >-
Only the cluster operator (eblume) has kubectl access. No untrusted
users can create pods, access cached images, or bind RBAC roles.
created: 2026-03-30
last-reviewed: 2026-04-01
Add compensating controls framework and date-based report dirs (#320) ## Summary - Add `compensating-controls.yaml` tracking 9 named controls that justify suppressed security findings - Update all Prowler mutelist descriptions with `CC: <id>` references to named controls - Add `mise run review-compensating-controls` task — surfaces stalest control with all codebase references - Add [[review-compensating-controls]] how-to doc - Organize Prowler and Kingfisher reports into `YYYY-MM-DD` subdirectories ### Compensating controls | ID | Mitigates | |----|-----------| | `single-user-cluster` | Image cache abuse, RBAC breadth, system pod privileges | | `tailscale-network-isolation` | Profiling endpoints, weak TLS, debug ports | | `local-registry` | AlwaysPullImages gap | | `sso-gated-admin-tools` | ArgoCD wildcard RBAC | | `operator-managed-pods` | Tailscale proxy pod security settings | | `ephemeral-privileged-jobs` | Prowler hostPID exposure | | `trusted-ci-only` | Forgejo runner DinD | | `init-container-isolation` | Grafana root init container | | `observability-stack-audit` | Missing apiserver audit logging | ## Test plan - [ ] `mise run review-compensating-controls` shows table and references - [ ] `kubectl kustomize argocd/manifests/prowler/` renders correctly - [ ] Sync prowler and kingfisher, verify next scan writes to dated subdirectory - [ ] Grep for `CC:` in mutelist files — every muted finding should have at least one 🤖 Generated with [Claude Code](https://claude.com/claude-code) Reviewed-on: https://forge.eblu.me/eblume/blumeops/pulls/320
2026-03-30 17:44:11 -07:00
notes: >-
Verify by checking kubeconfig distribution and Tailscale ACLs.
If additional users gain cluster access, re-evaluate all findings
muted under this control.
- id: tailscale-network-isolation
description: >-
Cluster is not internet-exposed. All access requires Tailscale
identity with ACL enforcement. Profiling endpoints, debug ports,
and control-plane APIs are unreachable from the public internet.
created: 2026-03-30
last-reviewed: 2026-04-06
Add compensating controls framework and date-based report dirs (#320) ## Summary - Add `compensating-controls.yaml` tracking 9 named controls that justify suppressed security findings - Update all Prowler mutelist descriptions with `CC: <id>` references to named controls - Add `mise run review-compensating-controls` task — surfaces stalest control with all codebase references - Add [[review-compensating-controls]] how-to doc - Organize Prowler and Kingfisher reports into `YYYY-MM-DD` subdirectories ### Compensating controls | ID | Mitigates | |----|-----------| | `single-user-cluster` | Image cache abuse, RBAC breadth, system pod privileges | | `tailscale-network-isolation` | Profiling endpoints, weak TLS, debug ports | | `local-registry` | AlwaysPullImages gap | | `sso-gated-admin-tools` | ArgoCD wildcard RBAC | | `operator-managed-pods` | Tailscale proxy pod security settings | | `ephemeral-privileged-jobs` | Prowler hostPID exposure | | `trusted-ci-only` | Forgejo runner DinD | | `init-container-isolation` | Grafana root init container | | `observability-stack-audit` | Missing apiserver audit logging | ## Test plan - [ ] `mise run review-compensating-controls` shows table and references - [ ] `kubectl kustomize argocd/manifests/prowler/` renders correctly - [ ] Sync prowler and kingfisher, verify next scan writes to dated subdirectory - [ ] Grep for `CC:` in mutelist files — every muted finding should have at least one 🤖 Generated with [Claude Code](https://claude.com/claude-code) Reviewed-on: https://forge.eblu.me/eblume/blumeops/pulls/320
2026-03-30 17:44:11 -07:00
notes: >-
Verify with 'tailscale serve status --json' on indri and review
Tailscale ACLs in pulumi/tailscale/. Only tag:flyio-target services
are publicly routable.
- id: local-registry
description: >-
Operator-built services use a private zot registry
(registry.ops.eblu.me) for supply-chain control. Remaining
images are pulled from public registries without stored
credentials. No shared registry secrets are cached on cluster
nodes.
Add compensating controls framework and date-based report dirs (#320) ## Summary - Add `compensating-controls.yaml` tracking 9 named controls that justify suppressed security findings - Update all Prowler mutelist descriptions with `CC: <id>` references to named controls - Add `mise run review-compensating-controls` task — surfaces stalest control with all codebase references - Add [[review-compensating-controls]] how-to doc - Organize Prowler and Kingfisher reports into `YYYY-MM-DD` subdirectories ### Compensating controls | ID | Mitigates | |----|-----------| | `single-user-cluster` | Image cache abuse, RBAC breadth, system pod privileges | | `tailscale-network-isolation` | Profiling endpoints, weak TLS, debug ports | | `local-registry` | AlwaysPullImages gap | | `sso-gated-admin-tools` | ArgoCD wildcard RBAC | | `operator-managed-pods` | Tailscale proxy pod security settings | | `ephemeral-privileged-jobs` | Prowler hostPID exposure | | `trusted-ci-only` | Forgejo runner DinD | | `init-container-isolation` | Grafana root init container | | `observability-stack-audit` | Missing apiserver audit logging | ## Test plan - [ ] `mise run review-compensating-controls` shows table and references - [ ] `kubectl kustomize argocd/manifests/prowler/` renders correctly - [ ] Sync prowler and kingfisher, verify next scan writes to dated subdirectory - [ ] Grep for `CC:` in mutelist files — every muted finding should have at least one 🤖 Generated with [Claude Code](https://claude.com/claude-code) Reviewed-on: https://forge.eblu.me/eblume/blumeops/pulls/320
2026-03-30 17:44:11 -07:00
created: 2026-03-30
last-reviewed: 2026-04-12
Add compensating controls framework and date-based report dirs (#320) ## Summary - Add `compensating-controls.yaml` tracking 9 named controls that justify suppressed security findings - Update all Prowler mutelist descriptions with `CC: <id>` references to named controls - Add `mise run review-compensating-controls` task — surfaces stalest control with all codebase references - Add [[review-compensating-controls]] how-to doc - Organize Prowler and Kingfisher reports into `YYYY-MM-DD` subdirectories ### Compensating controls | ID | Mitigates | |----|-----------| | `single-user-cluster` | Image cache abuse, RBAC breadth, system pod privileges | | `tailscale-network-isolation` | Profiling endpoints, weak TLS, debug ports | | `local-registry` | AlwaysPullImages gap | | `sso-gated-admin-tools` | ArgoCD wildcard RBAC | | `operator-managed-pods` | Tailscale proxy pod security settings | | `ephemeral-privileged-jobs` | Prowler hostPID exposure | | `trusted-ci-only` | Forgejo runner DinD | | `init-container-isolation` | Grafana root init container | | `observability-stack-audit` | Missing apiserver audit logging | ## Test plan - [ ] `mise run review-compensating-controls` shows table and references - [ ] `kubectl kustomize argocd/manifests/prowler/` renders correctly - [ ] Sync prowler and kingfisher, verify next scan writes to dated subdirectory - [ ] Grep for `CC:` in mutelist files — every muted finding should have at least one 🤖 Generated with [Claude Code](https://claude.com/claude-code) Reviewed-on: https://forge.eblu.me/eblume/blumeops/pulls/320
2026-03-30 17:44:11 -07:00
notes: >-
Verify by checking image prefixes in kustomization.yaml files.
Known external-image categories: (1) upstream apps not yet
mirrored — immich, ollama, frigate, frigate-notify, valkey;
(2) infrastructure components — tailscale operator/proxy,
external-secrets, 1password-connect, forgejo-runner, docker
DinD, nvidia-device-plugin; (3) utility base images — busybox,
alpine (grafana init containers). Track upstream versions in
service-versions.yaml. Goal is to progressively mirror these
into zot.
Add compensating controls framework and date-based report dirs (#320) ## Summary - Add `compensating-controls.yaml` tracking 9 named controls that justify suppressed security findings - Update all Prowler mutelist descriptions with `CC: <id>` references to named controls - Add `mise run review-compensating-controls` task — surfaces stalest control with all codebase references - Add [[review-compensating-controls]] how-to doc - Organize Prowler and Kingfisher reports into `YYYY-MM-DD` subdirectories ### Compensating controls | ID | Mitigates | |----|-----------| | `single-user-cluster` | Image cache abuse, RBAC breadth, system pod privileges | | `tailscale-network-isolation` | Profiling endpoints, weak TLS, debug ports | | `local-registry` | AlwaysPullImages gap | | `sso-gated-admin-tools` | ArgoCD wildcard RBAC | | `operator-managed-pods` | Tailscale proxy pod security settings | | `ephemeral-privileged-jobs` | Prowler hostPID exposure | | `trusted-ci-only` | Forgejo runner DinD | | `init-container-isolation` | Grafana root init container | | `observability-stack-audit` | Missing apiserver audit logging | ## Test plan - [ ] `mise run review-compensating-controls` shows table and references - [ ] `kubectl kustomize argocd/manifests/prowler/` renders correctly - [ ] Sync prowler and kingfisher, verify next scan writes to dated subdirectory - [ ] Grep for `CC:` in mutelist files — every muted finding should have at least one 🤖 Generated with [Claude Code](https://claude.com/claude-code) Reviewed-on: https://forge.eblu.me/eblume/blumeops/pulls/320
2026-03-30 17:44:11 -07:00
- id: sso-gated-admin-tools
description: >-
ArgoCD requires SSO authentication via Authentik OIDC. Wildcard
RBAC roles are mitigated by requiring authenticated identity
before any API access.
Add compensating controls framework and date-based report dirs (#320) ## Summary - Add `compensating-controls.yaml` tracking 9 named controls that justify suppressed security findings - Update all Prowler mutelist descriptions with `CC: <id>` references to named controls - Add `mise run review-compensating-controls` task — surfaces stalest control with all codebase references - Add [[review-compensating-controls]] how-to doc - Organize Prowler and Kingfisher reports into `YYYY-MM-DD` subdirectories ### Compensating controls | ID | Mitigates | |----|-----------| | `single-user-cluster` | Image cache abuse, RBAC breadth, system pod privileges | | `tailscale-network-isolation` | Profiling endpoints, weak TLS, debug ports | | `local-registry` | AlwaysPullImages gap | | `sso-gated-admin-tools` | ArgoCD wildcard RBAC | | `operator-managed-pods` | Tailscale proxy pod security settings | | `ephemeral-privileged-jobs` | Prowler hostPID exposure | | `trusted-ci-only` | Forgejo runner DinD | | `init-container-isolation` | Grafana root init container | | `observability-stack-audit` | Missing apiserver audit logging | ## Test plan - [ ] `mise run review-compensating-controls` shows table and references - [ ] `kubectl kustomize argocd/manifests/prowler/` renders correctly - [ ] Sync prowler and kingfisher, verify next scan writes to dated subdirectory - [ ] Grep for `CC:` in mutelist files — every muted finding should have at least one 🤖 Generated with [Claude Code](https://claude.com/claude-code) Reviewed-on: https://forge.eblu.me/eblume/blumeops/pulls/320
2026-03-30 17:44:11 -07:00
created: 2026-03-30
last-reviewed: 2026-04-14
Add compensating controls framework and date-based report dirs (#320) ## Summary - Add `compensating-controls.yaml` tracking 9 named controls that justify suppressed security findings - Update all Prowler mutelist descriptions with `CC: <id>` references to named controls - Add `mise run review-compensating-controls` task — surfaces stalest control with all codebase references - Add [[review-compensating-controls]] how-to doc - Organize Prowler and Kingfisher reports into `YYYY-MM-DD` subdirectories ### Compensating controls | ID | Mitigates | |----|-----------| | `single-user-cluster` | Image cache abuse, RBAC breadth, system pod privileges | | `tailscale-network-isolation` | Profiling endpoints, weak TLS, debug ports | | `local-registry` | AlwaysPullImages gap | | `sso-gated-admin-tools` | ArgoCD wildcard RBAC | | `operator-managed-pods` | Tailscale proxy pod security settings | | `ephemeral-privileged-jobs` | Prowler hostPID exposure | | `trusted-ci-only` | Forgejo runner DinD | | `init-container-isolation` | Grafana root init container | | `observability-stack-audit` | Missing apiserver audit logging | ## Test plan - [ ] `mise run review-compensating-controls` shows table and references - [ ] `kubectl kustomize argocd/manifests/prowler/` renders correctly - [ ] Sync prowler and kingfisher, verify next scan writes to dated subdirectory - [ ] Grep for `CC:` in mutelist files — every muted finding should have at least one 🤖 Generated with [Claude Code](https://claude.com/claude-code) Reviewed-on: https://forge.eblu.me/eblume/blumeops/pulls/320
2026-03-30 17:44:11 -07:00
notes: >-
Verify Authentik OIDC provider config for ArgoCD and that
anonymous access is disabled. Check ArgoCD --auth-token isn't
leaked. The workflow-bot API key account is scoped to sync/get
only.
Add compensating controls framework and date-based report dirs (#320) ## Summary - Add `compensating-controls.yaml` tracking 9 named controls that justify suppressed security findings - Update all Prowler mutelist descriptions with `CC: <id>` references to named controls - Add `mise run review-compensating-controls` task — surfaces stalest control with all codebase references - Add [[review-compensating-controls]] how-to doc - Organize Prowler and Kingfisher reports into `YYYY-MM-DD` subdirectories ### Compensating controls | ID | Mitigates | |----|-----------| | `single-user-cluster` | Image cache abuse, RBAC breadth, system pod privileges | | `tailscale-network-isolation` | Profiling endpoints, weak TLS, debug ports | | `local-registry` | AlwaysPullImages gap | | `sso-gated-admin-tools` | ArgoCD wildcard RBAC | | `operator-managed-pods` | Tailscale proxy pod security settings | | `ephemeral-privileged-jobs` | Prowler hostPID exposure | | `trusted-ci-only` | Forgejo runner DinD | | `init-container-isolation` | Grafana root init container | | `observability-stack-audit` | Missing apiserver audit logging | ## Test plan - [ ] `mise run review-compensating-controls` shows table and references - [ ] `kubectl kustomize argocd/manifests/prowler/` renders correctly - [ ] Sync prowler and kingfisher, verify next scan writes to dated subdirectory - [ ] Grep for `CC:` in mutelist files — every muted finding should have at least one 🤖 Generated with [Claude Code](https://claude.com/claude-code) Reviewed-on: https://forge.eblu.me/eblume/blumeops/pulls/320
2026-03-30 17:44:11 -07:00
- id: operator-managed-pods
description: >-
Tailscale operator manages proxy pod specs (ts-*, ingress-*,
operator-*, nameserver-*). Pod security settings are set by the
operator, not user manifests. Operator is tracked in
service-versions.yaml and regularly updated.
created: 2026-03-30
last-reviewed: 2026-04-21
Add compensating controls framework and date-based report dirs (#320) ## Summary - Add `compensating-controls.yaml` tracking 9 named controls that justify suppressed security findings - Update all Prowler mutelist descriptions with `CC: <id>` references to named controls - Add `mise run review-compensating-controls` task — surfaces stalest control with all codebase references - Add [[review-compensating-controls]] how-to doc - Organize Prowler and Kingfisher reports into `YYYY-MM-DD` subdirectories ### Compensating controls | ID | Mitigates | |----|-----------| | `single-user-cluster` | Image cache abuse, RBAC breadth, system pod privileges | | `tailscale-network-isolation` | Profiling endpoints, weak TLS, debug ports | | `local-registry` | AlwaysPullImages gap | | `sso-gated-admin-tools` | ArgoCD wildcard RBAC | | `operator-managed-pods` | Tailscale proxy pod security settings | | `ephemeral-privileged-jobs` | Prowler hostPID exposure | | `trusted-ci-only` | Forgejo runner DinD | | `init-container-isolation` | Grafana root init container | | `observability-stack-audit` | Missing apiserver audit logging | ## Test plan - [ ] `mise run review-compensating-controls` shows table and references - [ ] `kubectl kustomize argocd/manifests/prowler/` renders correctly - [ ] Sync prowler and kingfisher, verify next scan writes to dated subdirectory - [ ] Grep for `CC:` in mutelist files — every muted finding should have at least one 🤖 Generated with [Claude Code](https://claude.com/claude-code) Reviewed-on: https://forge.eblu.me/eblume/blumeops/pulls/320
2026-03-30 17:44:11 -07:00
notes: >-
Verify operator version is current via 'mise run service-review'.
Check Tailscale changelog for security fixes. If operator adds
seccomp support, remove these mutes. As of 2026-04-21: still no
default seccomp on operator-generated pods (upstream issue #7359
open). A ProxyClass + generic device plugin can downgrade proxies
from privileged to NET_ADMIN+NET_RAW and set seccompProfile —
potential future remediation to remove the seccomp mute without
waiting for upstream defaults.
Add compensating controls framework and date-based report dirs (#320) ## Summary - Add `compensating-controls.yaml` tracking 9 named controls that justify suppressed security findings - Update all Prowler mutelist descriptions with `CC: <id>` references to named controls - Add `mise run review-compensating-controls` task — surfaces stalest control with all codebase references - Add [[review-compensating-controls]] how-to doc - Organize Prowler and Kingfisher reports into `YYYY-MM-DD` subdirectories ### Compensating controls | ID | Mitigates | |----|-----------| | `single-user-cluster` | Image cache abuse, RBAC breadth, system pod privileges | | `tailscale-network-isolation` | Profiling endpoints, weak TLS, debug ports | | `local-registry` | AlwaysPullImages gap | | `sso-gated-admin-tools` | ArgoCD wildcard RBAC | | `operator-managed-pods` | Tailscale proxy pod security settings | | `ephemeral-privileged-jobs` | Prowler hostPID exposure | | `trusted-ci-only` | Forgejo runner DinD | | `init-container-isolation` | Grafana root init container | | `observability-stack-audit` | Missing apiserver audit logging | ## Test plan - [ ] `mise run review-compensating-controls` shows table and references - [ ] `kubectl kustomize argocd/manifests/prowler/` renders correctly - [ ] Sync prowler and kingfisher, verify next scan writes to dated subdirectory - [ ] Grep for `CC:` in mutelist files — every muted finding should have at least one 🤖 Generated with [Claude Code](https://claude.com/claude-code) Reviewed-on: https://forge.eblu.me/eblume/blumeops/pulls/320
2026-03-30 17:44:11 -07:00
- id: ephemeral-privileged-jobs
description: >-
Prowler CIS scanner runs as a CronJob with 7-day TTL
auto-deletion, not as a persistent privileged workload. hostPID
exposure is time-bounded to scan duration (~20s).
created: 2026-03-30
last-reviewed: 2026-03-30
notes: >-
Verify TTL is set in cronjob.yaml. Check that no persistent
pods run with hostPID.
- id: trusted-ci-only
description: >-
Forgejo runner only executes workflows from repos on the private
forge (forge.ops.eblu.me). No external or untrusted repos can
trigger privileged CI jobs.
created: 2026-03-30
last-reviewed: 2026-03-30
notes: >-
Verify runner registration is limited to the forge instance.
Check Forgejo runner config for repo allow-lists.
- id: init-container-isolation
description: >-
Root privileges and added capabilities (CHOWN) are limited to
init containers that run once at pod startup. All runtime
containers run as non-root (UID 472) with all capabilities
dropped.
created: 2026-03-30
last-reviewed: 2026-03-30
notes: >-
Verify by inspecting grafana deployment.yaml securityContext
for both init and runtime containers. If fsGroup alone can
handle PVC ownership, remove init-chown-data and this control.
- id: node-config-automated-verification
description: >-
Prowler reports certain node-level checks as MANUAL because it runs
inside a pod and cannot evaluate kubelet file permissions, kubelet
config arguments, etcd CA separation, or cluster-admin RBAC bindings.
The review-compliance-reports script SSHes into the minikube node
weekly and programmatically verifies each condition, failing loudly
if any check deviates from expected values.
created: 2026-04-14
last-reviewed: 2026-04-14
notes: >-
Verification runs as part of 'mise run review-compliance-reports'.
If minikube node is unreachable, all checks report as FAIL. If new
MANUAL findings appear in Prowler, add corresponding verification
logic to the script and update the mutelist.
Add compensating controls framework and date-based report dirs (#320) ## Summary - Add `compensating-controls.yaml` tracking 9 named controls that justify suppressed security findings - Update all Prowler mutelist descriptions with `CC: <id>` references to named controls - Add `mise run review-compensating-controls` task — surfaces stalest control with all codebase references - Add [[review-compensating-controls]] how-to doc - Organize Prowler and Kingfisher reports into `YYYY-MM-DD` subdirectories ### Compensating controls | ID | Mitigates | |----|-----------| | `single-user-cluster` | Image cache abuse, RBAC breadth, system pod privileges | | `tailscale-network-isolation` | Profiling endpoints, weak TLS, debug ports | | `local-registry` | AlwaysPullImages gap | | `sso-gated-admin-tools` | ArgoCD wildcard RBAC | | `operator-managed-pods` | Tailscale proxy pod security settings | | `ephemeral-privileged-jobs` | Prowler hostPID exposure | | `trusted-ci-only` | Forgejo runner DinD | | `init-container-isolation` | Grafana root init container | | `observability-stack-audit` | Missing apiserver audit logging | ## Test plan - [ ] `mise run review-compensating-controls` shows table and references - [ ] `kubectl kustomize argocd/manifests/prowler/` renders correctly - [ ] Sync prowler and kingfisher, verify next scan writes to dated subdirectory - [ ] Grep for `CC:` in mutelist files — every muted finding should have at least one 🤖 Generated with [Claude Code](https://claude.com/claude-code) Reviewed-on: https://forge.eblu.me/eblume/blumeops/pulls/320
2026-03-30 17:44:11 -07:00
- id: observability-stack-audit
description: >-
Alloy collects pod logs and ships them to Loki, providing an
audit trail for cluster activity. Compensates for missing
apiserver audit logging which minikube does not configure.
created: 2026-03-30
last-reviewed: 2026-03-30
notes: >-
Verify Alloy DaemonSet is running and Loki is receiving logs.
Note this is weaker than native apiserver audit logs — it
captures pod stdout/stderr, not API request-level auditing.
Consider enabling minikube audit logging if supported.