Lead Platform-Wide Security Governance (STRIDE PolicySet)

Duration: ~25 minutes

Overview

201-11 named the controls. This lab ships them as an RHACM PolicySet so every cluster in the Placement gets the same namespace, PSA, Quota, default-deny NetworkPolicy, and a ServiceAccount that does not automount a token.

That is the platform operating model: the security team owns the PolicySet; application teams consume stride-workloads. Inform first (report drift), then enforce (create the missing objects)—the same loop as 201-10, expanded to the STRIDE rows.

Why it matters

A threat model in a slide deck does not configure the next cluster. RHACM Policy objects do. DoD CC SRG, DISA STIG, and NIST SP 800-53 expect an approved baseline, not tribal knowledge. The Governance UI columns (standards, categories, controls) are how an ISSO traces a green cluster back to AC-6, CM-6, SC-7, and SC-5.

What does it solve

  • EoP — workloads landing in namespaces without restricted PSA

  • DoS — unbounded CPU/memory in a shared tenant namespace

  • Spoofing — app ServiceAccounts that still automount API tokens

  • Disclosure / lateral movement — namespaces with no default-deny NetworkPolicy

  • Drift — each cluster’s “baseline” living in a different wiki

Your Mission

Apply PolicySet stride-ocp-baseline, watch it NonCompliant while inform is on, enforce it so the cluster configures itself, then prove restricted PSA still denies a privileged pod.

Policy in the set STRIDE row Objects

policy-stride-ns-psa

Elevation of privilege

Namespace stride-workloads + restricted PSA labels

policy-stride-quota-limits

Denial of service

LimitRange + ResourceQuota

policy-stride-netpol-sa

Spoofing + Information disclosure

default-deny NetworkPolicy + SA app with automountServiceAccountToken: false

Prerequisites

  • Red Hat Advanced Cluster Management (or MCE with the governance policy add-on). CRD: policies.policy.open-cluster-management.io

  • A ManagedCluster (hub is usually local-cluster)

  • Cluster-admin on the hub

  • 201-10 recommended (same policies namespace and ClusterSet binding)

Click each step only if you need a hint.

Part A: Hub inventory

Confirm RHACM Policy CRDs and local-cluster

If this fails, install Advanced Cluster Management for Kubernetes from OperatorHub (or ask the platform owner).

oc get crd policies.policy.open-cluster-management.io
oc get managedcluster
oc get managedcluster local-cluster --show-labels 2>/dev/null || oc get managedcluster --show-labels
CRD exists. local-cluster=true is the usual hub label.
Bind a ClusterSet into namespace policies

Skip if you already ran this in 201-10. Placement selects zero clusters until a ManagedClusterSetBinding exists.

cd ~/openshift-security-roadshow/setup/acm-lab
chmod +x bind-clusterset.sh
./bind-clusterset.sh
managedclustersetbinding created (or already configured) in policies.

Part B: Inform (report drift)

Apply the STRIDE PolicySet (inform)

Three Policies + a PolicySet + Placement. Remediation starts as inform—RHACM reports NonCompliant until the objects exist.

oc apply -f ~/openshift-security-roadshow/setup/acm-lab/policy-stride-ocp-baseline.yaml
Policies, PolicySet stride-ocp-baseline, Placement, and PlacementBinding created in policies.
Read PolicySet status (expect NonCompliant)
oc get policyset,policy,placement,placementbinding -n policies
oc get ns stride-workloads 2>/dev/null || echo "stride-workloads not created yet (inform does not remediate)"
COMPLIANT is NonCompliant (or empty for a few seconds). Namespace stride-workloads should not exist yet. Console: Fleet Management → Governance → PolicySets.

Part C: Enforce (configure the cluster from policy)

Switch the three Policies to enforce

The PolicySet groups them; each Policy still has its own remediationAction. Patch all three.

for p in policy-stride-ns-psa policy-stride-quota-limits policy-stride-netpol-sa; do
  oc patch policy "$p" -n policies --type merge -p '{"spec":{"remediationAction":"enforce"}}'
done
Three patched messages. Wait 15–30 seconds.
Confirm the STRIDE objects exist
oc get policy -n policies -l app.kubernetes.io/component=301-01-acm
oc get ns stride-workloads --show-labels
oc get networkpolicy,limitrange,resourcequota,sa -n stride-workloads
oc get sa app -n stride-workloads -o jsonpath='{.automountServiceAccountToken}{"\n"}'
Policies Compliant. Namespace labels include pod-security.kubernetes.io/enforce=restricted. default-deny-ingress, bounded-defaults, bounded-quota, and SA app with automount false.

Part D: Admission still matches the baseline

Apply a privileged pod in stride-workloads (expect deny)

privileged: true violates restricted PSA (AC-6 / EoP).

oc apply -n stride-workloads -f - <<'EOF'
apiVersion: v1
kind: Pod
metadata:
  name: privileged-denied
spec:
  containers:
  - name: app
    image: registry.access.redhat.com/ubi9/ubi
    securityContext:
      privileged: true
    command: ["sleep","5"]
EOF
Admission rejects the pod (Forbidden / violates PodSecurity). The PolicySet stayed Compliant—the deny is the baseline working.

Debrief

Platform governance is the STRIDE map as Policy: who may change SCC and ANP is a platform decision; app teams do not freestyle namespaces. Inform then enforce is how drift is corrected. 301-02 puts these YAML files in Git.

What breaks without this:

  • Threat model with no delivery mechanism → next cluster is a snowflake

  • Hand-crafted namespaces → STIG drift

  • Automount left on by default → stolen tokens (Spoofing) still work

PolicySet + Placement + inform then enforce. Do not rewrite cluster restricted SCC in this lab.
GitOps of these same CRs is 301-02. Tenant NetworkPolicy still cannot beat platform ANP (301-03).
giphy

Cleanup

Removes the STRIDE PolicySet and stride-workloads. Leaves RHACM and the 201-10 DoD Policy (if present).

cd ~/ocp5-rhacs-showroom
bash setup/lab-cleanup.sh --module 301-01