Verifying zone kernel images
Why verify zone kernel images?
Every Edera zone runs its own Linux kernel, independent of the host. Platform engineers select which kernel a workload runs by setting a pod annotation:
metadata:
annotations:
dev.edera/kernel: ghcr.io/edera-dev/zone-kernel:6.12.69This means different pods on the same node can run entirely different kernels.
The host kernel and the zone kernel are independent—you can see this by
comparing uname -a on the host versus inside a zone:
# Host node
Linux ip-192-168-81-255 6.18.16 #1 SMP PREEMPT_DYNAMIC ...
# Inside an Edera zone on the same node
Linux raider-edera 6.12.69 #1 SMP PREEMPT_DYNAMIC ...The zone kernel is the kernel your workload runs on at ring 0. Your application’s syscalls go directly to it. If an attacker compromises a zone kernel image—through a supply chain attack on the build pipeline, a registry compromise, or a tag substitution—they gain ring 0 execution inside that zone.
Edera’s hypervisor boundary contains the blast radius: a compromised zone kernel cannot escape to the host or other zones. But ring 0 inside the zone means full control over that workload and its data.
Edera recommends verifying zone kernel signatures for all production workloads. This guide covers how to do that manually with Sigstore cosign, and points toward admission-time enforcement with Kyverno.
Prerequisites
# macOS
brew install sigstore/tap/cosign crane
# Linux (cosign)
go install github.com/sigstore/cosign/v2/cmd/cosign@latest
# Linux (crane)
go install github.com/google/go-containerregistry/cmd/crane@latestPublished kernel images
Edera publishes kernel images to ghcr.io/edera-dev/ with the following naming
convention:
| Image | Description |
|---|---|
ghcr.io/edera-dev/zone-kernel | Standard zone kernel |
ghcr.io/edera-dev/host-kernel | Host (hypervisor) kernel |
ghcr.io/edera-dev/zone-amdgpu-kernel | Zone kernel with AMD GPU support |
ghcr.io/edera-dev/zone-nvidiagpu-kernel | Zone kernel with NVIDIA GPU support |
Each image also has a corresponding -sdk variant (for example,
ghcr.io/edera-dev/zone-kernel-sdk).
All images are built and signed by the
edera-dev/linux-kernel-oci
GitHub Actions pipeline.
Verifying a kernel image
Step 1: Resolve the platform digest
Edera kernel images are published as multi-architecture OCI image indexes. Signatures are attached to the per-platform manifest, not the image index itself. This means you need to resolve the platform-specific digest before verifying.
For linux/amd64:
DIGEST=$(crane manifest ghcr.io/edera-dev/zone-kernel:latest | \
jq -r '.manifests[] | select(.platform.architecture == "amd64" and .platform.os == "linux") | .digest')For linux/aarch64:
DIGEST=$(crane manifest ghcr.io/edera-dev/zone-kernel:latest | \
jq -r '.manifests[] | select(.platform.architecture == "aarch64" and .platform.os == "linux") | .digest')Step 2: Verify the signature
cosign verify \
"ghcr.io/edera-dev/zone-kernel@${DIGEST}" \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity "https://github.com/edera-dev/linux-kernel-oci/.github/workflows/matrix.yml@refs/heads/main" \
--certificate-github-workflow-repository edera-dev/linux-kernel-ociA successful verification prints the signature payload and:
The following checks were performed on each of these signatures:
- The cosign claims were validated
- Existence of the claims in the transparency log was verified offline
- The code-signing certificate was verified using trusted certificate authority certificatesVerifying other images
Replace zone-kernel with any image from the table above. The signing identity
and issuer are the same for all images:
# Example: verify the host kernel
DIGEST=$(crane manifest ghcr.io/edera-dev/host-kernel:latest | \
jq -r '.manifests[] | select(.platform.architecture == "amd64" and .platform.os == "linux") | .digest')
cosign verify \
"ghcr.io/edera-dev/host-kernel@${DIGEST}" \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity "https://github.com/edera-dev/linux-kernel-oci/.github/workflows/matrix.yml@refs/heads/main" \
--certificate-github-workflow-repository edera-dev/linux-kernel-ociVerifying a specific version
Replace :latest with the version tag:
DIGEST=$(crane manifest ghcr.io/edera-dev/zone-kernel:6.12.25 | \
jq -r '.manifests[] | select(.platform.architecture == "amd64" and .platform.os == "linux") | .digest')
cosign verify \
"ghcr.io/edera-dev/zone-kernel@${DIGEST}" \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity "https://github.com/edera-dev/linux-kernel-oci/.github/workflows/matrix.yml@refs/heads/main" \
--certificate-github-workflow-repository edera-dev/linux-kernel-ociWhat the verification proves
Cosign keyless verification with GitHub Actions OIDC confirms:
- The image was built by GitHub Actions in the
edera-dev/linux-kernel-ocirepository (not by a third party or local build). - The build ran on the
mainbranch via thematrix.ymlworkflow. - The signature is recorded in the Rekor transparency log, providing a tamper-evident audit trail.
Enforcing verification at admission time
Manual verification is useful for auditing, but production clusters should
enforce kernel image signatures automatically. Kyverno’s
ImageValidatingPolicy
can extract the image reference from the dev.edera/kernel annotation and
verify its cosign signature before the pod is admitted.
apiVersion: kyverno.io/v2
kind: ImageValidatingPolicy
metadata:
name: verify-edera-kernel
spec:
images:
- name: kernel-image
expression: '[object.metadata.annotations["dev.edera/kernel"]]'
validations:
- attestors:
- entries:
- keyless:
subject: "https://github.com/edera-dev/linux-kernel-oci/.github/workflows/matrix.yml@refs/heads/main"
issuer: "https://token.actions.githubusercontent.com"
rekor:
url: https://rekor.sigstore.devTroubleshooting
no signatures found
This usually means you are verifying against the image index (manifest list)
digest rather than the per-platform manifest digest. Make sure you resolve the
platform digest with crane manifest first, as shown above.
certificate identity mismatch
The signing workflow is .github/workflows/matrix.yml on refs/heads/main. If
you see a mismatch, check whether the image was built from a different branch or
workflow. Images built from non-main branches are not signed with the main
branch identity.
no matching signatures with correct identity
The image tag may have been rebuilt since the signature was created. Verify
against a specific version tag or digest rather than :latest.