Using Gatekeeper’s External Data Provider for Tag to Digest mutation with Skopeo
While I was attempting to create a custom external data provider to help with image validation , I realized the Provider model could be…
Using Gatekeeper’s External Data Provider for Tag to Digest mutation with Skopeo
While I was attempting to create a custom external data provider to help with image validation , I realized the Provider model could be used to wrap almost any CLI tool to be also used for mutation.So here’s an example of me testing the External data provider model with skopeo for helping mutate image tag to digest.
I see this article as more of a continuation of the image validation article, so if you have a few minutes might be a good idea to read that one first before proceeding.
External data providers in Gatekeeper hold the logic for connecting to an external system to allow for mutation and validation with Gatekeeper. Since providers are also just Go code, we can also shell out to any CLI command to obtain data. Here’s a summarized code example(Github Link Below):
// Code Structure Sample - Full Code Link below - provider.go
func main() {
//start a listening https server
}
func mutatetagdigest(w http.ResponseWriter, req *http.Request) {
// Recieve a http request from Gatkeeper Controller at /mutatedigest path
// Parse image details from Gatkeeper Request
// Shell out to skopeoshellCommand to Inspect Image
// Parse Digest from skopeo response
// Send Gatekeeper Controller Response Information
}
func skopeoShellCommand(image string) (SkopeoResponse, error) {
// Function will recieve an image string and run the skopeo inspect command on the image string
// And return a reponse
var outbuf, errbuf strings.Builder
var parsedResponse SkopeoResponse
cmd := exec.Command("skopeo", "inspect", fmt.Sprintf("docker://%s", image))
cmd.Stdout = &outbuf
cmd.Stderr = &errbuf
err := cmd.Run()
if err != nil {
logger.Error("Error running skopeo command: %s", err)
return parsedResponse, err
}
if err := json.Unmarshal([]byte(outbuf.String()), &parsedResponse); err != nil { // Parse []byte to go struct pointer
logger.Error("Can not unmarshal JSON: %s", err)
return parsedResponse, err
}
return parsedResponse, err
}
Gatekeeper provides an Assign policy to allow for mutation, after receiving our digest from the provider via Skopeo our Assign Policy will attempt to replace the value of “location” with data from our provider:
apiVersion: mutations.gatekeeper.sh/v1beta1
kind: Assign
metadata:
name: mutate-images
spec:
applyTo:
- groups: ["apps"]
kinds: ["Deployment"]
versions: ["v1"]
match:
scope: Namespaced
namespaces:
- default
location: "spec.template.spec.containers[name:*].image"
parameters:
assign:
externalData:
provider: registry-gatekeeper-provider-mutate
dataSource: ValueAtLocation
failurePolicy: Fail
So how does it look to a cluster User
They create a standard deployment with an image tag of latest

Deployment before mutation with tag
Image is transparently replaced with image name and digest

Deployment after mutation with digest
I imagine that even more interesting examples are also possible.
Thanks!
Github Code Link:
메타데이터
- post_id
- 5f23dff4f3cd
- slug
- using-gatekeepers-external-data-provider-for-tag-to-digest-mutation-with-skopeo-5f23dff4f3cd
- url
- https://medium.com/@moyo.oyegunle/using-gatekeepers-external-data-provider-for-tag-to-digest-mutation-with-skopeo-5f23dff4f3cd
- canonical_url
- https://medium.com/@moyo.oyegunle/using-gatekeepers-external-data-provider-for-tag-to-digest-mutation-with-skopeo-5f23dff4f3cd
- author_url
- https://medium.com/@moyo.oyegunle
- status
- ok
- fetched_at
- 2026-07-25 00:19:29