SBOM, signing, and registry allow-listing
The three questions of supply chain security
- What is in this artifact? → SBOM (software bill of materials)
- Who built it and has it been changed? → signature / attestation
- Is this registry allowed at all? → admission policy
1. SBOM: what is inside
bom is allow-listed in the exam — a strong hint.
bom generate --image registry.example.com/app:1.4.2 -o sbom.spdx
bom document outline sbom.spdx # human-readable package list
bom document query sbom.spdx 'name:openssl' # is a package in there?
Alternatives: syft registry.example.com/app:1.4.2 -o spdx-json, and Trivy can
emit one too (trivy image -f spdx-json).
Why it matters for the exam: when a CVE drops in a library, the SBOM tells you
which images are affected without pulling every image and scanning it.
2. Signing and verifying
# key pair
cosign generate-key-pair
# sign by digest (never by tag)
cosign sign --key cosign.key registry.example.com/app@sha256:<digest>
# verify
cosign verify --key cosign.pub registry.example.com/app:1.4.2
cosign verify-attestation --type spdxjson --key cosign.pub registry.example.com/app:1.4.2
cosign verify fails with no matching signatures for an unsigned or tampered
image. Keyless (Fulcio/Rekor) exists and is what real pipelines use; the exam
gives you a key pair.
3. Enforce: three ways, all valid
Gatekeeper
spec:
match:
kinds: [{apiGroups: [""], kinds: ["Pod"]}]
parameters:
repos: ["registry.example.com/", "registry.k8s.io/"]
Kyverno
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata: {name: allowed-registries}
spec:
validationFailureAction: Enforce
rules:
- name: check-registry
match:
any:
- resources: {kinds: ["Pod"]}
validate:
message: "images must come from registry.example.com"
pattern:
spec:
containers:
- image: "registry.example.com/*"
ImagePolicyWebhook — the one people skip, and the exam likes
The API server calls your HTTP service and asks allow/deny. Three pieces:
a. The admission config (/etc/kubernetes/admission/admission-config.yaml):
apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
- name: ImagePolicyWebhook
configuration:
imagePolicy:
kubeConfigFile: /etc/kubernetes/admission/imagepolicy.kubeconfig
allowTTL: 50
denyTTL: 50
retryBackoff: 500
defaultAllow: false # fail closed — the whole point
b. The kubeconfig that points at the webhook (+ its client cert), mounted
into the API server.
c. The flags on the API server:
- --enable-admission-plugins=NodeRestriction,ImagePolicyWebhook
- --admission-control-config-file=/etc/kubernetes/admission/admission-config.yaml
Then a Pod using a non-allowed image is rejected withimage policy webhook backend denied the request.
defaultAllow: false means "if the webhook cannot be reached, deny". Set it totrue and you have a policy that disappears the moment the backend is down.
4. Registry hygiene that is not admission
- Pull secret instead of a public repo: `kubectl create secret docker-registry regcred --docker-server=… --docker-username=… --docker-password=…
+imagePullSecrets`. imagePullPolicy: Alwaysfor mutable tags,IfNotPresentwith a digest.- An artifact repository in front of the internet (Harbor, Artifactory, ECR) — "understand your supply chain" means knowing this layer exists.
What the marker checks
- the image reference in the running Pod (digest? allowed registry?)
- the policy object exists and is enforced (a violation actually rejected)
- for signing tasks:
cosign verifyoutput, or the admission denial message
Practical order under time pressure: allow-list first (cheapest), scanning second
(finds the obvious), signing last (needs keys and a registry that stores them).