# OCI Patch Manifest Proposal ## Problem The industry does not have a standard mechanism to patch an image. Tags are commonly used to help identify if an image is patchable or not. The issue is that this is left to the user to interpret that a tag has been updated or that there is a new version of a given image. For workflow and consuming this refer - Container Patching Workflow for Azure.docx ## Goal The goal is to propose a manifest to define if an image has a patch that can be applied and how runtimes and builders of the image may consume these patches. The following IANA type should be registered to indicate the details of a patch document and clients may acquire the details of the patch using this mediaType that would be the value in the “artifactType” field in the [OCI Artifact Manifest](https://github.com/opencontainers/image-spec/blob/main/artifact.md). | ArtifactType | "applciation/vnd.oci.image.patch.v1+json" | | -------- | -------- | Example Document defining the patches available for an ubuntu:20.04 image. ```jsonc { "mediaType": "application/vnd.oci.artifact.manifest.v1+json", "artifactType": "applciation/vnd.oci.image.patch.v1+json", "subject": { "mediaType": "application/vnd.oci.image.manifest.v1+json", "size": 1234, "digest": "sha256:cc06a2839488b8bd2a2b99dcdc03d5cfd818eed72ad08ef3cc197aac64c0d0a0", "annotations": { "org.opencontainers.image.ref.name": "docker.io/library/ubuntu:20.04" } }, "annotations": { "org.opencontainers.image.patch.minor.digest": "sha256:aabbccdd", "org.opencontainers.image.patch.major.digest": "sha256:eeffdgghh", "org.opencontainers.image.patch.critical.digest": "sha256:iijjkkll" } } ``` > TBD explain: How does this align with packages patching and why are there only types of patches //TODO – Call out the annotations and what they mean. ### Proposal for Builders - Builders should be able to use a patch without having to update their docker files Builders like buildkit may decide to use an upstream patched image to rebuild even if the tag has not been modified. This may include patching the builder and the image in the final stage as well. ```dockerfile FROM golang:1.16 <= Patchable WORKDIR /go/src/github.com/alexellis/href-counter/ RUN go get -d -v golang.org/x/net/html COPY app.go ./ RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . FROM alpine:3.9 <= Patchable RUN apk --no-cache add ca-certificates WORKDIR /root/ COPY --from=0 /go/src/github.com/alexellis/href-counter/app ./ CMD ["./app"] ``` - Users may specify a patch level so that the rebuilt can be triggered without changing the source Dockerfile or the tag mutating the tag in the target. - Regular development may take in minor version updates automatically and release builds may always take a minimum of critical updates before starting the release. ```bash docker buildx build --patch-level critical --platform linux/amd64,linux/arm64,linux/arm/v7 -t myapp:$buildID . ``` ## Basic Workflow of pulling a patched image The builder or runtime can lookup the patch from the target registry and decide what specific patch it may apply. Note: Patches may be applied as per the container patching workflow guidance. Customers should be able to leverage maintenance windows so that patches do not disrupt the services   Attaching a patch to an existing image The example below shows how a publisher can publish patches to an image. Builders/runtime can use the workflow to decide if they need to pick the patch. - amend will support fetching the latest patch manifest followed by - adding/updating the specified annotation and - delete the previous patch manifest ```bash oras attach --amend \ --artifact-type "applciation/vnd.oci.image.patch.v1+json" \ --annotation "org.opencontainers.image.patch.critical.digest:aabbccdd" myregistry.azurecr.io/ubuntu:20.04 ``` ## Possible experiments #### Patching in Containerd The proposal here is to update containerd to provide an option during pod start on in the container fetcher to lookup for existence of patch manifest and support pulling the patch level specified. For e.g. https://github.com/containerd/containerd/blob/main/docs/getting-started.md#creating-an-oci-spec-and-container We can create an option to PullWithPatch(level) – the example below is from the containerd examples that show how images may be pulled with options and needs to be refined with Patch options. ```go ctx := namespaces.WithNamespace(context.Background(), "example") image, err := client.Pull(ctx, "docker.io/library/redis:alpine", containerd.WithPullUnpack) if err != nil { return err } ``` ### Patching apps in Kubernetes TBD: There are options of how operators might want to control when images are patched. This might involve maybe updating some annotations that forces a patched upgrade and we need to consider inputs from operators here. ### Patch Propagation This section should outline a possible recommendation on how patches may be published and how consumers may use them. Consumers of base images should also ensure that the images that they import for things like “ACR Pull Through Cache” should automatically take in patches as well. // TODO : Detail and Diagram to show how when pulling in images, a target may monitor for patches on some cadence. ### Other considerations #### Layer Patching If a vulnerability is found in a particular layer of a base image there are options to identify all images that have this and trigger a patch operation on them. This can still be composed over the above manifest and possibly automated. This document does not define how this patch can be identified and published. #### Hot Patching The current approach does not handle hot-patching of a running container. The container runtimes should ensure that the pods can be recycled on some cadence that enables it to pull at least the critical patches. #### Do we need more patch levels? The proposal only calls out 3 levels of patching (major,minor, critical). The hypothesis is that more complicated patch options makes the policy more complicated. Majority of the vulnerability scenarios that require immediate remediation fall into the critical bucket and services typically don’t want to even take non-critical patches. The minor patch level enable a workflow to automatically enable the build workflow to push out new images for the application during regular application workflows. Major patches are probably only consumed when there needs to be new features that the service needs to use and hence would have much lower cadence.