From a90f614be89eedbb439d9173225fdd936f0e98d0 Mon Sep 17 00:00:00 2001 From: Marcin Owsiany Date: Tue, 9 Jun 2026 12:20:51 +0200 Subject: [PATCH 1/4] feat: add OCP mode for kubelet image credential provider integration Add support for OpenShift Container Platform credential provider paths, using /etc/kubernetes/credential-providers/ for config and /usr/libexec/kubelet-image-credential-provider-plugins for binaries, matching the paths used by the OpenShift machine-config-operator. Co-Authored-By: Claude Opus 4.6 (1M context) --- README.md | 5 +++-- deploy/deployment.yaml.gotpl | 16 +++++++++++++++- deploy/main.go | 2 +- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 207f324..565499b 100644 --- a/README.md +++ b/README.md @@ -51,10 +51,11 @@ It also optionally collects each pull attempt's duration and result. - `--collect-metrics`: if the image pull metrics should be collected. - `--use-kubelet-image-credential-integration=MODE`: enables kubelet [credential provider](https://kubernetes.io/blog/2022/12/22/kubelet-credential-providers/) plugin integration. Plugin credentials fetched dynamically and tried for the images configured in the `CredentialProviderConfig` before pull secrets. - Currently only supports mode `GKE`, which uses `/etc/srv/kubernetes/cri_auth_config.yaml` and `/home/kubernetes/bin` mounted from the host. - Note that in this case, the tool uses distro-based prefetcher images, to provide the dynamic linker and shared libraries that a credential plugin binary might need. + Currently supported modes are: + - `GKE`, which uses `/etc/srv/kubernetes/cri_auth_config.yaml` and `/home/kubernetes/bin` mounted from the host. + - `OCP`, which uses `/etc/kubernetes/credential-providers/` and `/usr/libexec/kubelet-image-credential-provider-plugins` mounted from the host. Example: diff --git a/deploy/deployment.yaml.gotpl b/deploy/deployment.yaml.gotpl index e466b4d..fe1377e 100644 --- a/deploy/deployment.yaml.gotpl +++ b/deploy/deployment.yaml.gotpl @@ -167,6 +167,10 @@ spec: - "--image-credential-provider-config=/tmp/credential-provider/cri_auth_config.yaml" - "--image-credential-provider-bin-dir=/tmp/credential-provider-bin" {{ end }} + {{ if eq .UseKubeletImageCredentialIntegration "OCP" }} + - "--image-credential-provider-config=/tmp/credential-provider/generic-credential-provider.yaml" + - "--image-credential-provider-bin-dir=/tmp/credential-provider-bin" + {{ end }} env: - name: NODE_NAME valueFrom: @@ -193,7 +197,7 @@ spec: name: pull-secret readOnly: true {{ end }} - {{ if eq .UseKubeletImageCredentialIntegration "GKE" }} + {{ if or (eq .UseKubeletImageCredentialIntegration "GKE") (eq .UseKubeletImageCredentialIntegration "OCP")}} - mountPath: /tmp/credential-provider name: credential-provider-config readOnly: true @@ -247,3 +251,13 @@ spec: path: /home/kubernetes/bin type: Directory {{ end }} + {{ if eq .UseKubeletImageCredentialIntegration "OCP" }} + - name: credential-provider-config + hostPath: + path: /etc/kubernetes/credential-providers + type: Directory + - name: credential-provider-bin + hostPath: + path: /usr/libexec/kubelet-image-credential-provider-plugins + type: Directory + {{ end }} diff --git a/deploy/main.go b/deploy/main.go index bee6d7a..6686cbc 100644 --- a/deploy/main.go +++ b/deploy/main.go @@ -50,7 +50,7 @@ func init() { flag.TextVar(&k8sFlavor, "k8s-flavor", flavor(vanillaFlavor), fmt.Sprintf("Kubernetes flavor. Accepted values: %s", strings.Join(allFlavors, ","))) flag.StringVar(&secret, "secret", "", "Kubernetes image pull Secret to use when pulling.") flag.BoolVar(&collectMetrics, "collect-metrics", false, "Whether to collect and expose image pull metrics.") - flag.StringVar(&useKubeletImageCredentialIntegration, "use-kubelet-image-credential-integration", "", "Enable kubelet image credential provider plugin integration. Accepted values: GKE") + flag.StringVar(&useKubeletImageCredentialIntegration, "use-kubelet-image-credential-integration", "", "Enable kubelet image credential provider plugin integration. Accepted values: GKE, OCP.") } // processVersion processes the version string and returns the appropriate format. From c4a8c7aea9a2890cda5fac71bddfe16e5138d2eb Mon Sep 17 00:00:00 2001 From: Marcin Owsiany Date: Tue, 9 Jun 2026 13:02:12 +0200 Subject: [PATCH 2/4] feat: add OCP modes for kubelet credential provider integration Add support for OpenShift Container Platform credential provider paths with cloud-specific modes: OCP-GCR, OCP-ECR, OCP-ACR. Each mode uses the corresponding credential provider config from /etc/kubernetes/credential-providers/ and binaries from /usr/libexec/kubelet-image-credential-provider-plugins, matching the paths used by the OpenShift machine-config-operator. Co-Authored-By: Claude Opus 4.6 (1M context) --- README.md | 3 ++- deploy/deployment.yaml.gotpl | 16 ++++++++++++---- deploy/main.go | 2 +- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 565499b..43c427c 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,8 @@ It also optionally collects each pull attempt's duration and result. linker and shared libraries that a credential plugin binary might need. Currently supported modes are: - `GKE`, which uses `/etc/srv/kubernetes/cri_auth_config.yaml` and `/home/kubernetes/bin` mounted from the host. - - `OCP`, which uses `/etc/kubernetes/credential-providers/` and `/usr/libexec/kubelet-image-credential-provider-plugins` mounted from the host. + - `OCP-GCR`, `OCP-ECR`, `OCP-ACR`, for OCP on GCP, AWS, and Azure respectively. + These use the corresponding credential provider config from `/etc/kubernetes/credential-providers/` and binaries from `/usr/libexec/kubelet-image-credential-provider-plugins` mounted from the host. Example: diff --git a/deploy/deployment.yaml.gotpl b/deploy/deployment.yaml.gotpl index fe1377e..d2a64d4 100644 --- a/deploy/deployment.yaml.gotpl +++ b/deploy/deployment.yaml.gotpl @@ -167,8 +167,16 @@ spec: - "--image-credential-provider-config=/tmp/credential-provider/cri_auth_config.yaml" - "--image-credential-provider-bin-dir=/tmp/credential-provider-bin" {{ end }} - {{ if eq .UseKubeletImageCredentialIntegration "OCP" }} - - "--image-credential-provider-config=/tmp/credential-provider/generic-credential-provider.yaml" + {{ if eq .UseKubeletImageCredentialIntegration "OCP-GCR" }} + - "--image-credential-provider-config=/tmp/credential-provider/gcr-credential-provider.yaml" + - "--image-credential-provider-bin-dir=/tmp/credential-provider-bin" + {{ end }} + {{ if eq .UseKubeletImageCredentialIntegration "OCP-ECR" }} + - "--image-credential-provider-config=/tmp/credential-provider/ecr-credential-provider.yaml" + - "--image-credential-provider-bin-dir=/tmp/credential-provider-bin" + {{ end }} + {{ if eq .UseKubeletImageCredentialIntegration "OCP-ACR" }} + - "--image-credential-provider-config=/tmp/credential-provider/acr-credential-provider.yaml" - "--image-credential-provider-bin-dir=/tmp/credential-provider-bin" {{ end }} env: @@ -197,7 +205,7 @@ spec: name: pull-secret readOnly: true {{ end }} - {{ if or (eq .UseKubeletImageCredentialIntegration "GKE") (eq .UseKubeletImageCredentialIntegration "OCP")}} + {{ if or (eq .UseKubeletImageCredentialIntegration "GKE") (eq .UseKubeletImageCredentialIntegration "OCP-GCR") (eq .UseKubeletImageCredentialIntegration "OCP-ECR") (eq .UseKubeletImageCredentialIntegration "OCP-ACR")}} - mountPath: /tmp/credential-provider name: credential-provider-config readOnly: true @@ -251,7 +259,7 @@ spec: path: /home/kubernetes/bin type: Directory {{ end }} - {{ if eq .UseKubeletImageCredentialIntegration "OCP" }} + {{ if or (eq .UseKubeletImageCredentialIntegration "OCP-GCR") (eq .UseKubeletImageCredentialIntegration "OCP-ECR") (eq .UseKubeletImageCredentialIntegration "OCP-ACR") }} - name: credential-provider-config hostPath: path: /etc/kubernetes/credential-providers diff --git a/deploy/main.go b/deploy/main.go index 6686cbc..918b4d1 100644 --- a/deploy/main.go +++ b/deploy/main.go @@ -50,7 +50,7 @@ func init() { flag.TextVar(&k8sFlavor, "k8s-flavor", flavor(vanillaFlavor), fmt.Sprintf("Kubernetes flavor. Accepted values: %s", strings.Join(allFlavors, ","))) flag.StringVar(&secret, "secret", "", "Kubernetes image pull Secret to use when pulling.") flag.BoolVar(&collectMetrics, "collect-metrics", false, "Whether to collect and expose image pull metrics.") - flag.StringVar(&useKubeletImageCredentialIntegration, "use-kubelet-image-credential-integration", "", "Enable kubelet image credential provider plugin integration. Accepted values: GKE, OCP.") + flag.StringVar(&useKubeletImageCredentialIntegration, "use-kubelet-image-credential-integration", "", "Enable kubelet image credential provider plugin integration. Accepted values: GKE, OCP-GCR, OCP-ECR, OCP-ACR.") } // processVersion processes the version string and returns the appropriate format. From c00a31c9c6a377d0133f06d09c9e7e10a4b3ba51 Mon Sep 17 00:00:00 2001 From: Marcin Owsiany Date: Wed, 10 Jun 2026 12:07:44 +0200 Subject: [PATCH 3/4] use host network for the plugin --- deploy/deployment.yaml.gotpl | 1 + 1 file changed, 1 insertion(+) diff --git a/deploy/deployment.yaml.gotpl b/deploy/deployment.yaml.gotpl index d2a64d4..8f16671 100644 --- a/deploy/deployment.yaml.gotpl +++ b/deploy/deployment.yaml.gotpl @@ -142,6 +142,7 @@ spec: openshift.io/required-scc: privileged {{ end }} spec: + hostNetwork: true serviceAccountName: {{ .Name }} tolerations: # Broad toleration to match stackrox collector. From 8e8f33eee28214be15c1458e31096f16993bf026 Mon Sep 17 00:00:00 2001 From: Marcin Owsiany Date: Wed, 10 Jun 2026 13:02:48 +0200 Subject: [PATCH 4/4] lint --- deploy/deployment.yaml.gotpl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/deploy/deployment.yaml.gotpl b/deploy/deployment.yaml.gotpl index 8f16671..e6d9c45 100644 --- a/deploy/deployment.yaml.gotpl +++ b/deploy/deployment.yaml.gotpl @@ -129,6 +129,7 @@ metadata: ignore-check.kube-linter.io/privilege-escalation-container: "Needs access to CRI socket." ignore-check.kube-linter.io/privileged-container: "Needs access to CRI socket." ignore-check.kube-linter.io/run-as-non-root: "Needs access to CRI socket." + ignore-check.kube-linter.io/host-network: "Credential provider plugins may need host network access." spec: selector: matchLabels: @@ -142,7 +143,9 @@ spec: openshift.io/required-scc: privileged {{ end }} spec: + {{ if .UseKubeletImageCredentialIntegration }} hostNetwork: true + {{ end }} serviceAccountName: {{ .Name }} tolerations: # Broad toleration to match stackrox collector.