Installation Manual - 107 Gatekeeper rollout and policy closeout
Consolidated Gatekeeper operator, operand, rollback, image mirror, dry-run policy, and final non-enforcement decision for the v7 greenfield clusters.
This chapter is the closeout entry for the completed Gatekeeper rollout and
policy gates. The detailed Gatekeeper chapters 94 through 106 remain public
installation-manual chapters, and this chapter keeps the final durable state,
rollback, restore, image mirror, and promotion-decision evidence in one place.
The result is deliberately conservative: both hub and spoke Gatekeeper operands were installed and rollback-tested, durable spoke-side Gatekeeper image mirror coverage is in place, and the only policy remains scoped dry-run on the spoke. No deny enforcement is active.
Governance
| Field | Value |
|---|---|
| Issue range | #415 through #430 |
| Consolidation issue | OP-GF-DOCS-25 / #431 |
| Milestone | Workspace Governance |
| Governing ADR | ADR 0016 |
| Gate range | OP-GF-OPERATORS-03 through OP-GF-OPERATORS-17 |
| Public scope | One consolidated installation-manual chapter |
Consolidated Gate Sequence
| Gate | Issue | Durable outcome |
|---|---|---|
OP-GF-OPERATORS-03 | #415 | Validated the Gatekeeper package, install shape, and dry-run design without changing GitOps or live clusters. |
OP-GF-OPERATORS-04 | #416 | Installed the Red Hat Gatekeeper Operator on hub-dc-v7, stopping before any operand or policy. |
OP-GF-OPERATORS-05 | #417 | Installed the Red Hat Gatekeeper Operator on spoke-dc-v7, stopping before any operand or policy. |
OP-GF-OPERATORS-06 | #418 | Designed the hub no-constraints operand rollout and rollback path before creating the live operand. |
OP-GF-OPERATORS-07 | #419 | Created the hub Gatekeeper/gatekeeper operand with no constraints or mutation configs. |
OP-GF-OPERATORS-08 | #420 | Proved hub operand rollback and restore through GitOps. |
OP-GF-OPERATORS-09 | #421 | Designed the spoke no-constraints operand rollout and rollback path. |
OP-GF-OPERATORS-10 | #422 | Attempted the spoke operand canary, found image readiness failure, and rolled back cleanly. |
OP-GF-OPERATORS-11 | #423 | Confirmed spoke Gatekeeper operand image readiness before retrying. |
OP-GF-OPERATORS-12 | #424 | Re-ran the spoke operand canary successfully with no constraints or mutation configs. |
OP-GF-OPERATORS-13 | #425 | Proved spoke operand soak, rollback, prune, restore, and post-restore health. |
OP-GF-OPERATORS-14 | #427 | Designed the first privileged-container policy candidate without persisting policy objects. |
OP-GF-OPERATORS-15 | #428 | Persisted one spoke-scoped dry-run policy canary in a labeled namespace. |
OP-GF-OPERATORS-16 | #429 | Proved dry-run canary rollback and restore, then kept the policy non-enforcing. |
OP-GF-OPERATORS-17 | #430 | Added durable spoke Gatekeeper image mirror coverage and closed the policy-gates batch. |
Final Public Manual State
The installation manual exposes the full Gatekeeper sequence as chapters 94
through 107. This chapter is the final state and promotion-decision record
that future Gatekeeper work must start from.
Preflight
The bootstrap clone started at the OP-GF-OPERATORS-15 documentation head:
bootstrap_head=3a8017c
Both Argo CD application views were healthy:
hub_app=Synced Healthy 3a8017c506ae07ded86d6250b18417f8af2e1321
spoke_app=Synced Healthy 3a8017c506ae07ded86d6250b18417f8af2e1321
Both clusters were healthy:
hub clusterversion=4.20.18 Available=True Progressing=False Failing=False nodes=3/3 nonsteady_co=0 nonrunning_pods=0 pending_csrs=0
spoke clusterversion=4.20.18 Available=True Progressing=False Failing=False nodes=6/6 nonsteady_co=0 nonrunning_pods=0 pending_csrs=0
The spoke canary was present:
namespace=gatekeeper-policy-canary label=true
constrainttemplate=k8sdisallowprivilegedcontainers
crd=k8sdisallowprivilegedcontainers.constraints.gatekeeper.sh established=True
constraint=dryrun-disallow-privileged-containers action=dryrun selector=true totalViolations=0
spoke_constraint_api_resources=k8sdisallowprivilegedcontainers
spoke_mutation_api_resources=
Admission smoke dry-runs passed on both clusters.
Rollback Drill
The rollback was split into two commits so the generated constraint API was removed cleanly.
First, the constraint instance was removed:
f717818 Rollback spoke Gatekeeper dry-run constraint
Validation confirmed the constraint was pruned while the namespace,
ConstraintTemplate, and generated CRD remained:
hub_app=Synced Healthy f717818e50062e395e71b6c96e652136615faed6
spoke_app=Synced Healthy f717818e50062e395e71b6c96e652136615faed6
namespace=gatekeeper-policy-canary label=true
constrainttemplate.templates.gatekeeper.sh/k8sdisallowprivilegedcontainers
customresourcedefinition.apiextensions.k8s.io/k8sdisallowprivilegedcontainers.constraints.gatekeeper.sh
constraint=absent
gatekeeper-audit=1/1
gatekeeper-controller-manager=3/3
nonrunning_gatekeeper_pods=0
Then, the namespace and ConstraintTemplate were removed:
e877451 Rollback spoke Gatekeeper dry-run template canary
Validation confirmed the canary was fully pruned:
hub_app=Synced Healthy e877451462205572721cffa2af85a54d11a1991b
spoke_app=Synced Healthy e877451462205572721cffa2af85a54d11a1991b
namespace=absent
constrainttemplate=absent
crd=absent
constraint=absent
spoke_constraint_api_resources=
spoke_mutation_api_resources=
hub gatekeeper-audit=1/1 gatekeeper-controller-manager=3/3
spoke gatekeeper-audit=1/1 gatekeeper-controller-manager=3/3
Admission smoke dry-runs still passed on both clusters.
Restore Drill
Restore also used two commits.
First, the namespace and ConstraintTemplate were restored:
654e242 Restore spoke Gatekeeper dry-run template canary
Validation confirmed the generated CRD returned before the constraint:
hub_app=Synced Healthy 654e2421ed0a026e072305b36f2cfd07888b8851
spoke_app=Synced Healthy 654e2421ed0a026e072305b36f2cfd07888b8851
namespace=gatekeeper-policy-canary label=true
constrainttemplate.templates.gatekeeper.sh/k8sdisallowprivilegedcontainers
crd=k8sdisallowprivilegedcontainers.constraints.gatekeeper.sh established=True
constraint=absent
gatekeeper-audit=1/1
gatekeeper-controller-manager=3/3
Then, the dry-run constraint was restored:
1a519ff Restore spoke Gatekeeper dry-run constraint canary
Final validation confirmed the same safe posture as chapter 106:
hub_app=Synced Healthy 1a519ffa60c5d03161e796d4a4423ba4600c823b
spoke_app=Synced Healthy 1a519ffa60c5d03161e796d4a4423ba4600c823b
namespace=gatekeeper-policy-canary label=true
constrainttemplate=k8sdisallowprivilegedcontainers
crd=k8sdisallowprivilegedcontainers.constraints.gatekeeper.sh established=True
constraint=dryrun-disallow-privileged-containers action=dryrun selector=true
spoke_constraint_api_resources=k8sdisallowprivilegedcontainers
spoke_mutation_api_resources=
Gatekeeper stayed ready:
hub gatekeeper-audit=1/1 gatekeeper-controller-manager=3/3
hub nonrunning_gatekeeper_pods=0
spoke gatekeeper-audit=1/1 gatekeeper-controller-manager=3/3
spoke nonrunning_gatekeeper_pods=0
The Gatekeeper audit status refreshed after restore:
totalViolations=0
auditTimestamp=2026-05-20T01:43:30Z
Privileged Pod server-side dry-run samples were still admitted in both the
canary namespace and default:
pod/gatekeeper-dryrun-restore-canary
pod/gatekeeper-dryrun-restore-default
That proves the restored policy remains non-enforcing.
Image Mirror Batch
The remaining policy-gate prerequisite was durable Gatekeeper image mirror coverage on the spoke. The hub already had exact coverage for the Gatekeeper source repository:
hub gatekeeper_idms_source=registry.redhat.io/gatekeeper mirrors=["quay.v7.comptech-lab.com/openshift-operators/gatekeeper"]
The spoke only had install-time OpenShift release image mirrors, so it lacked
explicit coverage for registry.redhat.io/gatekeeper.
The batch added one narrow spoke-side mirror set:
c449e3f Add spoke Gatekeeper image mirror coverage
The desired object is:
apiVersion: config.openshift.io/v1
kind: ImageDigestMirrorSet
metadata:
name: idms-gatekeeper
spec:
imageDigestMirrors:
- mirrors:
- quay.v7.comptech-lab.com/openshift-operators/gatekeeper
source: registry.redhat.io/gatekeeper
It is intentionally scoped to the Gatekeeper image repository. It does not add broad spoke mirror coverage, deny enforcement, mutation configs, hub constraints, backup objects, node drains, or storage objects.
The functional GitOps revision converged:
hub_app_spoke_cluster_config=Synced Healthy c449e3f91f3829bc943f65f2d61714aaeb7b4d9d
spoke_app_spoke_cluster_config=Synced Healthy c449e3f91f3829bc943f65f2d61714aaeb7b4d9d
The platform GitOps changelog was then updated:
86d9dae Document Gatekeeper policy batch closeout
bootstrap_clone_head=86d9dae
Final cluster validation stayed clean:
hub clusterversion=4.20.18 Available=True Progressing=False Failing=False nodes=3/3 nonsteady_co=0 nonrunning_pods=0 pending_csrs=0
spoke clusterversion=4.20.18 Available=True Progressing=False Failing=False nodes=6/6 nonsteady_co=0 nonrunning_pods=0 pending_csrs=0
spoke master_mcp=Updated=True Updating=False Degraded=False
spoke worker_mcp=Updated=True Updating=False Degraded=False
The spoke now has exact Gatekeeper mirror coverage:
idms_names=idms-gatekeeper image-digest-mirror
gatekeeper_idms_source=registry.redhat.io/gatekeeper mirrors=["quay.v7.comptech-lab.com/openshift-operators/gatekeeper"]
The policy canary remained dry-run only:
namespace=gatekeeper-policy-canary label=true
constrainttemplate.templates.gatekeeper.sh/k8sdisallowprivilegedcontainers
crd=k8sdisallowprivilegedcontainers.constraints.gatekeeper.sh established=True
constraint_action=dryrun selector=true violations=0 audit=2026-05-20T02:04:30Z
Admission dry-runs still passed:
hub_smoke=configmap/gatekeeper-policy-batch-hub
spoke_smoke=configmap/gatekeeper-policy-batch-spoke
canary_privileged=pod/gatekeeper-policy-batch-canary
default_privileged=pod/gatekeeper-policy-batch-default
OpenShift returned the expected Pod Security warning for the privileged canary sample, but Gatekeeper did not block it because the constraint remains dry-run.
Promotion Decision
Do not promote K8sDisallowPrivilegedContainers to deny in this batch.
The reason is operational, not a policy failure:
- rollback and restore are proven;
- durable spoke-side Gatekeeper image mirror coverage now exists;
- dry-run status reports zero violations;
- the canary namespace has no meaningful workload population yet;
- the hub remains intentionally no-policy.
The current state is the intended closeout point for the policy gates: one scoped dry-run policy is live, rollback is proven, image mirror coverage is in place, and no deny enforcement is active.
Residual Risks
Gatekeeper deny enforcement is still not active.
The dry-run canary has not produced real workload signal.
Future enforcement still needs explicit blast-radius review and a rollback window.
Batch Result
No additional Gatekeeper policy prerequisite gates remain for the current scoped dry-run posture.
Any future move from dry-run to deny is a separate enforcement gate, not a continuation of this batch.