From 1ae1db1308ea956e907cf5ec997d80427ba4a7aa Mon Sep 17 00:00:00 2001 From: Roman Berezkin Date: Fri, 21 Aug 2026 14:03:23 +0300 Subject: [PATCH] [plugins] Advise the cli-download role on a 403 from registry-packages-proxy Plugins are downloaded over /v1/images/, and kube-rbac-proxy authorizes that whole prefix through the deployments/cli-binary subresource, granted by the ClusterRole d8:registry-packages-proxy:cli-download. The 403 diagnostic named packages-download instead. That role covers /v1/packages/, which the CLI never calls, so a user who followed the advice bound the role and still got 403. The same suggestion told the user to wait about 5 minutes and retry with a fresh token. kube-rbac-proxy caches a denial for about 30 seconds, and the existing token keeps working, so both halves of that hint were wrong. The d8 dist copy of the diagnostic carried the same wrong hint and is fixed too. Signed-off-by: Roman Berezkin --- internal/dist/cmd/errdetect/diagnose.go | 2 +- internal/plugins/cmd/errdetect/diagnose.go | 7 +++++-- internal/plugins/cmd/errdetect/diagnose_test.go | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/internal/dist/cmd/errdetect/diagnose.go b/internal/dist/cmd/errdetect/diagnose.go index 785939654..3a3f53080 100644 --- a/internal/dist/cmd/errdetect/diagnose.go +++ b/internal/dist/cmd/errdetect/diagnose.go @@ -42,7 +42,7 @@ func Diagnose(err error) *diagnostic.HelpfulError { return help(err, "registry-packages-proxy: forbidden (403)", "the identity may not download the CLI", "bind the ClusterRole 'd8:registry-packages-proxy:cli-download' to the user/group", - "authorization is cached ~5 min - after binding, retry with a fresh token") + "a denied check is cached ~30s - after binding the role, wait half a minute and retry with the same token") case errors.Is(err, rpp.ErrNotFound): return help(err, "registry-packages-proxy: version not found (404)", "this deckhouse-cli version is not published", diff --git a/internal/plugins/cmd/errdetect/diagnose.go b/internal/plugins/cmd/errdetect/diagnose.go index a80e14b34..fcba38d43 100644 --- a/internal/plugins/cmd/errdetect/diagnose.go +++ b/internal/plugins/cmd/errdetect/diagnose.go @@ -38,11 +38,14 @@ func Diagnose(err error) *diagnostic.HelpfulError { return help(err, "registry-packages-proxy: unauthorized (401)", "no accepted Bearer token (a client-certificate kubeconfig is not enough)", "use a kubeconfig with an OIDC token (Kubeconfig Generator or 'd8 login')") + // Plugins are downloaded over /v1/images/, which kube-rbac-proxy authorizes + // through the deployments/cli-binary subresource: that is the cli-download + // role, not packages-download (it covers /v1/packages/). case errors.Is(err, rpp.ErrForbidden): return help(err, "registry-packages-proxy: forbidden (403)", "the identity may not download plugins", - "bind the ClusterRole 'd8:registry-packages-proxy:packages-download' to the user/group", - "authorization is cached ~5 min - after binding, retry with a fresh token") + "bind the ClusterRole 'd8:registry-packages-proxy:cli-download' to the user/group", + "a denied check is cached ~30s - after binding the role, wait half a minute and retry with the same token") case errors.Is(err, rpp.ErrNotFound): return help(err, "registry-packages-proxy: plugin or version not found (404)", "this plugin or version is not published", diff --git a/internal/plugins/cmd/errdetect/diagnose_test.go b/internal/plugins/cmd/errdetect/diagnose_test.go index 655e46837..89576c12c 100644 --- a/internal/plugins/cmd/errdetect/diagnose_test.go +++ b/internal/plugins/cmd/errdetect/diagnose_test.go @@ -37,7 +37,7 @@ func TestDiagnose(t *testing.T) { wantSol string }{ {"401", rpp.ErrUnauthorized, "unauthorized (401)", "OIDC"}, - {"403", rpp.ErrForbidden, "forbidden (403)", "packages-download"}, + {"403", rpp.ErrForbidden, "forbidden (403)", "cli-download"}, {"404", rpp.ErrNotFound, "plugin or version not found (404)", "deckhouse-cli/plugins"}, {"5xx", rpp.ErrUpstream, "upstream error (5xx)", "registry-packages-proxy pods"}, {"discovery", rpp.ErrEndpointDiscovery, "endpoint discovery via the Kubernetes API failed", "--rpp-endpoint"},