From 115676e91e5ca3b059151cde6b02079bff698908 Mon Sep 17 00:00:00 2001 From: Bayan Taani Date: Thu, 19 Mar 2026 10:45:59 +0100 Subject: [PATCH 1/5] make oauth discovery optional --- authentication/openshift.go | 62 +++++++++++++++++++-------- authentication/openshift/discovery.go | 3 ++ 2 files changed, 46 insertions(+), 19 deletions(-) diff --git a/authentication/openshift.go b/authentication/openshift.go index 3944f3ac9..aa89b9ecb 100644 --- a/authentication/openshift.go +++ b/authentication/openshift.go @@ -77,6 +77,7 @@ type OpenShiftAuthenticator struct { oauth2Config oauth2.Config cookieName string handler http.Handler + oauthEnabled bool } //nolint:funlen @@ -143,19 +144,29 @@ func newOpenshiftAuthenticator(c map[string]interface{}, tenant string, var tokenURL *url.URL - for b.Reset(); b.Ongoing(); { - authURL, tokenURL, err = openshift.DiscoverOAuth(client) - if err != nil { - level.Error(logger).Log( + authURL, tokenURL, err = openshift.DiscoverOAuth(client) + if err != nil { + if strings.Contains(err.Error(), "got 404") || strings.Contains(err.Error(), "OAuth server not found") { + level.Warn(logger).Log( "tenant", tenant, - "msg", errors.Wrap(err, "unable to auto discover OpenShift OAuth endpoints")) - registrationRetryCount.WithLabelValues(tenant, OpenShiftAuthenticatorType).Inc() - b.Wait() - - continue + "msg", errors.Wrap(err, "OpenShift OAuth endpoint not available")) + } + authURL = nil + tokenURL = nil + } else { + // Other errors + for b.Reset(); b.Ongoing(); { + authURL, tokenURL, err = openshift.DiscoverOAuth(client) + if err != nil { + level.Error(logger).Log( + "tenant", tenant, + "msg", errors.Wrap(err, "unable to auto discover OpenShift OAuth endpoints")) + registrationRetryCount.WithLabelValues(tenant, OpenShiftAuthenticatorType).Inc() + b.Wait() + continue + } + break } - - break } var clientID string @@ -221,7 +232,11 @@ func newOpenshiftAuthenticator(c map[string]interface{}, tenant string, client: client, config: config, cookieName: fmt.Sprintf("observatorium_%s", tenant), - oauth2Config: oauth2.Config{ + oauthEnabled: authURL != nil && tokenURL != nil, + } + + if osAuthenticator.oauthEnabled { + osAuthenticator.oauth2Config = oauth2.Config{ ClientID: clientID, ClientSecret: clientSecret, Endpoint: oauth2.Endpoint{ @@ -235,15 +250,17 @@ func newOpenshiftAuthenticator(c map[string]interface{}, tenant string, defaultOAuthScopeListProjects, }, RedirectURL: config.RedirectURL, - }, + } + r := chi.NewRouter() + r.Use(tracing.WithChiRoutePattern) + r.Handle(loginRoute, osAuthenticator.openshiftLoginHandler()) + r.Handle(callbackRoute, osAuthenticator.openshiftCallbackHandler()) + osAuthenticator.handler = r + + } else { + osAuthenticator.handler = chi.NewRouter() } - r := chi.NewRouter() - r.Use(tracing.WithChiRoutePattern) - r.Handle(loginRoute, osAuthenticator.openshiftLoginHandler()) - r.Handle(callbackRoute, osAuthenticator.openshiftCallbackHandler()) - osAuthenticator.handler = r - return osAuthenticator, nil } @@ -442,6 +459,13 @@ func (a OpenShiftAuthenticator) Middleware() Middleware { // when users went through the OAuth2 flow supported by this // provider. Observatorium stores a self-signed JWT token on a // cookie per tenant to identify the subject of incoming requests. + if !a.oauthEnabled { + msg := "OAuth authentication not available" + level.Debug(a.logger).Log("msg", msg) + httperr.PrometheusAPIError(w, msg, http.StatusUnauthorized) + return + } + cookie, err := r.Cookie(a.cookieName) if err != nil { tenant, ok := GetTenant(r.Context()) diff --git a/authentication/openshift/discovery.go b/authentication/openshift/discovery.go index 22b34848e..041475284 100644 --- a/authentication/openshift/discovery.go +++ b/authentication/openshift/discovery.go @@ -73,6 +73,9 @@ func DiscoverOAuth(client *http.Client) (authURL, tokenURL *url.URL, err error) } if resp.StatusCode < 200 || resp.StatusCode >= 300 { + if resp.StatusCode == 404 { + return nil, nil, fmt.Errorf("OAuth server not found") + } return nil, nil, fmt.Errorf("got %d %s", resp.StatusCode, body) } From f7a4d9cccf4d361a144398f9296df98b8fb43972 Mon Sep 17 00:00:00 2001 From: Bayan Taani Date: Wed, 25 Mar 2026 17:39:25 +0100 Subject: [PATCH 2/5] move oauth handling to separate function and add unit test --- authentication/openshift.go | 61 ++++++----- authentication/openshift/discovery.go | 4 +- authentication/openshift_test.go | 140 ++++++++++++++++++++++++++ 3 files changed, 172 insertions(+), 33 deletions(-) create mode 100644 authentication/openshift_test.go diff --git a/authentication/openshift.go b/authentication/openshift.go index aa89b9ecb..421b8e524 100644 --- a/authentication/openshift.go +++ b/authentication/openshift.go @@ -140,37 +140,9 @@ func newOpenshiftAuthenticator(c map[string]interface{}, tenant string, MaxRetries: 0, // Retry indefinitely. }) - var authURL *url.URL - - var tokenURL *url.URL - - authURL, tokenURL, err = openshift.DiscoverOAuth(client) - if err != nil { - if strings.Contains(err.Error(), "got 404") || strings.Contains(err.Error(), "OAuth server not found") { - level.Warn(logger).Log( - "tenant", tenant, - "msg", errors.Wrap(err, "OpenShift OAuth endpoint not available")) - } - authURL = nil - tokenURL = nil - } else { - // Other errors - for b.Reset(); b.Ongoing(); { - authURL, tokenURL, err = openshift.DiscoverOAuth(client) - if err != nil { - level.Error(logger).Log( - "tenant", tenant, - "msg", errors.Wrap(err, "unable to auto discover OpenShift OAuth endpoints")) - registrationRetryCount.WithLabelValues(tenant, OpenShiftAuthenticatorType).Inc() - b.Wait() - continue - } - break - } - } + authURL, tokenURL, oauthEnabled := discoverOAuthEndpoints(client, logger, tenant, registrationRetryCount, b) var clientID string - var clientSecret string for b.Reset(); b.Ongoing(); { @@ -232,10 +204,10 @@ func newOpenshiftAuthenticator(c map[string]interface{}, tenant string, client: client, config: config, cookieName: fmt.Sprintf("observatorium_%s", tenant), - oauthEnabled: authURL != nil && tokenURL != nil, + oauthEnabled: oauthEnabled, } - if osAuthenticator.oauthEnabled { + if oauthEnabled { osAuthenticator.oauth2Config = oauth2.Config{ ClientID: clientID, ClientSecret: clientSecret, @@ -565,3 +537,30 @@ func (a OpenShiftAuthenticator) GRPCMiddleware() grpc.StreamServerInterceptor { func (a OpenShiftAuthenticator) Handler() (string, http.Handler) { return "/openshift/{tenant}", a.handler } + +func discoverOAuthEndpoints(client *http.Client, logger log.Logger, tenant string, registrationRetryCount *prometheus.CounterVec, b *backoff.Backoff) (*url.URL, *url.URL, bool) { + authURL, tokenURL, err := openshift.DiscoverOAuth(client) + if err != nil { + if strings.Contains(err.Error(), "got 404") || strings.Contains(err.Error(), "OAuth server not found") { + level.Warn(logger).Log( + "tenant", tenant, + "msg", errors.Wrap(err, "OpenShift OAuth endpoint not available, likely using external OIDC authentication. But bearer token authentication will continue to work")) + return nil, nil, false + } else { + // Other errors, retry with backoff + for b.Reset(); b.Ongoing(); { + authURL, tokenURL, err = openshift.DiscoverOAuth(client) + if err != nil { + level.Error(logger).Log( + "tenant", tenant, + "msg", errors.Wrap(err, "unable to auto discover OpenShift OAuth endpoints")) + registrationRetryCount.WithLabelValues(tenant, OpenShiftAuthenticatorType).Inc() + b.Wait() + continue + } + break + } + } + } + return authURL, tokenURL, true +} diff --git a/authentication/openshift/discovery.go b/authentication/openshift/discovery.go index 041475284..e1e52905b 100644 --- a/authentication/openshift/discovery.go +++ b/authentication/openshift/discovery.go @@ -11,7 +11,7 @@ import ( ) const ( - oauthWellKnownPath = "/.well-known/oauth-authorization-server" + OauthWellKnownPath = "/.well-known/oauth-authorization-server" // ServiceAccountNamespacePath is the path to the default serviceaccount namespace. ServiceAccountNamespacePath = "/var/run/secrets/kubernetes.io/serviceaccount/namespace" @@ -54,7 +54,7 @@ func DiscoverCredentials(name string) (string, string, error) { // DiscoverOAuth return the authorization and token endpoints of the OpenShift OAuth server. // Returns an error if requesting the `/.well-known/oauth-authorization-server` fails. func DiscoverOAuth(client *http.Client) (authURL, tokenURL *url.URL, err error) { - oauthURL := toKubeAPIURLWithPath(oauthWellKnownPath) + oauthURL := toKubeAPIURLWithPath(OauthWellKnownPath) req, err := http.NewRequest(http.MethodGet, oauthURL.String(), nil) if err != nil { diff --git a/authentication/openshift_test.go b/authentication/openshift_test.go new file mode 100644 index 000000000..1e4314aec --- /dev/null +++ b/authentication/openshift_test.go @@ -0,0 +1,140 @@ +package authentication + +import ( + "context" + "net" + "net/http" + "net/http/httptest" + "net/url" + "testing" + "time" + + "github.com/efficientgo/core/backoff" + "github.com/go-chi/chi/v5" + "github.com/observatorium/api/authentication/openshift" + "github.com/observatorium/api/logger" + "github.com/prometheus/client_golang/prometheus" + "github.com/stretchr/testify/assert" +) + +// redirectTransport redirects all requests to the target host +type redirectTransport struct { + targetHost string + transport http.RoundTripper +} + +func (rt *redirectTransport) RoundTrip(req *http.Request) (*http.Response, error) { + // Redirect request to mock server while keeping the path + req.URL.Host = rt.targetHost + req.URL.Scheme = "http" + return rt.transport.RoundTrip(req) +} + +func TestDiscoverOAuthEndpoints_OAuthEnabled(t *testing.T) { + tenant := "tenant" + logger := logger.NewLogger("warn", logger.LogFormatLogfmt, "") + r := chi.NewMux() + + r.Get(openshift.OauthWellKnownPath, func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + w.Write([]byte(`{ + "authorization_endpoint": "https://oauth.example.com/authorize", + "token_endpoint": "https://oauth.example.com/token" + }`)) + }) + + mockAPIServer := httptest.NewServer(r) + defer mockAPIServer.Close() + + mockURL, err := url.Parse(mockAPIServer.URL) + if err != nil { + t.Fatalf("failed to parse mock server URL: %v", err) + } + + // Split host and port for KUBERNETES env vars + host, port, err := net.SplitHostPort(mockURL.Host) + if err != nil { + t.Fatalf("failed to parse mock server address: %v", err) + } + + t.Setenv("KUBERNETES_SERVICE_HOST", host) + t.Setenv("KUBERNETES_SERVICE_PORT", port) + + retryCounter := prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "test_retries"}, + []string{"tenant", "type"}, + ) + + client := &http.Client{ + Transport: &redirectTransport{ + targetHost: mockURL.Host, + transport: http.DefaultTransport, + }, + } + + b := backoff.New(context.TODO(), backoff.Config{ + Min: 500 * time.Millisecond, + Max: 5 * time.Second, + MaxRetries: 0, // Retry indefinitely. + }) + + authURL, tokenURL, oauthEnabled := discoverOAuthEndpoints(client, logger, tenant, retryCounter, b) + + assert.NotNil(t, authURL) + assert.NotNil(t, tokenURL) + assert.True(t, oauthEnabled) + assert.Equal(t, authURL.String(), "https://oauth.example.com/authorize") + assert.Equal(t, tokenURL.String(), "https://oauth.example.com/token") +} + +func TestDiscoverOAuthEndpoints_OAuthDisabled(t *testing.T) { + tenant := "tenant" + logger := logger.NewLogger("warn", logger.LogFormatLogfmt, "") + r := chi.NewMux() + + r.Get(openshift.OauthWellKnownPath, func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotFound) + w.Write([]byte("404 page not found")) + }) + + mockAPIServer := httptest.NewServer(r) + defer mockAPIServer.Close() + + mockURL, err := url.Parse(mockAPIServer.URL) + if err != nil { + t.Fatalf("failed to parse mock server URL: %v", err) + } + + // Split host and port for KUBERNETES env vars + host, port, err := net.SplitHostPort(mockURL.Host) + if err != nil { + t.Fatalf("failed to parse mock server address: %v", err) + } + + t.Setenv("KUBERNETES_SERVICE_HOST", host) + t.Setenv("KUBERNETES_SERVICE_PORT", port) + + retryCounter := prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "test_retries"}, + []string{"tenant", "type"}, + ) + + client := &http.Client{ + Transport: &redirectTransport{ + targetHost: mockURL.Host, + transport: http.DefaultTransport, + }, + } + + b := backoff.New(context.TODO(), backoff.Config{ + Min: 500 * time.Millisecond, + Max: 5 * time.Second, + MaxRetries: 0, // Retry indefinitely. + }) + + authURL, tokenURL, oauthEnabled := discoverOAuthEndpoints(client, logger, tenant, retryCounter, b) + + assert.Nil(t, authURL) + assert.Nil(t, tokenURL) + assert.False(t, oauthEnabled) +} From 81700b2c42f41f6fbb5f83812bd34c2d711b0636 Mon Sep 17 00:00:00 2001 From: Bayan Taani Date: Wed, 25 Mar 2026 19:37:32 +0100 Subject: [PATCH 3/5] fix lint errors --- authentication/openshift_test.go | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/authentication/openshift_test.go b/authentication/openshift_test.go index 1e4314aec..31a3e537a 100644 --- a/authentication/openshift_test.go +++ b/authentication/openshift_test.go @@ -11,13 +11,14 @@ import ( "github.com/efficientgo/core/backoff" "github.com/go-chi/chi/v5" - "github.com/observatorium/api/authentication/openshift" - "github.com/observatorium/api/logger" "github.com/prometheus/client_golang/prometheus" "github.com/stretchr/testify/assert" + + "github.com/observatorium/api/authentication/openshift" + "github.com/observatorium/api/logger" ) -// redirectTransport redirects all requests to the target host +// redirectTransport redirects all requests to the target host. type redirectTransport struct { targetHost string transport http.RoundTripper @@ -37,10 +38,12 @@ func TestDiscoverOAuthEndpoints_OAuthEnabled(t *testing.T) { r.Get(openshift.OauthWellKnownPath, func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) - w.Write([]byte(`{ + if _, err := w.Write([]byte(`{ "authorization_endpoint": "https://oauth.example.com/authorize", "token_endpoint": "https://oauth.example.com/token" - }`)) + }`)); err != nil { + t.Fatalf("failed to write response %v", err) + } }) mockAPIServer := httptest.NewServer(r) @@ -61,7 +64,9 @@ func TestDiscoverOAuthEndpoints_OAuthEnabled(t *testing.T) { t.Setenv("KUBERNETES_SERVICE_PORT", port) retryCounter := prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: "test_retries"}, + Name: "test_retries_total", + Help: "Total number of OAuth discovery retries", + }, []string{"tenant", "type"}, ) @@ -94,7 +99,9 @@ func TestDiscoverOAuthEndpoints_OAuthDisabled(t *testing.T) { r.Get(openshift.OauthWellKnownPath, func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotFound) - w.Write([]byte("404 page not found")) + if _, err := w.Write([]byte("404 page not found")); err != nil { + t.Fatalf("failed to write response %v", err) + } }) mockAPIServer := httptest.NewServer(r) @@ -115,7 +122,9 @@ func TestDiscoverOAuthEndpoints_OAuthDisabled(t *testing.T) { t.Setenv("KUBERNETES_SERVICE_PORT", port) retryCounter := prometheus.NewCounterVec(prometheus.CounterOpts{ - Name: "test_retries"}, + Name: "test_retries_total", + Help: "Total number of OAuth discovery retries", + }, []string{"tenant", "type"}, ) From 9e1167dc6864e312be1f93ed2c8435680fec9c12 Mon Sep 17 00:00:00 2001 From: Bayan Taani Date: Thu, 9 Apr 2026 14:00:34 +0200 Subject: [PATCH 4/5] address review comments --- authentication/openshift.go | 68 ++++++++++++--------------- authentication/openshift/discovery.go | 6 ++- authentication/openshift_test.go | 6 +-- 3 files changed, 38 insertions(+), 42 deletions(-) diff --git a/authentication/openshift.go b/authentication/openshift.go index 421b8e524..0aa793fe9 100644 --- a/authentication/openshift.go +++ b/authentication/openshift.go @@ -145,19 +145,20 @@ func newOpenshiftAuthenticator(c map[string]interface{}, tenant string, var clientID string var clientSecret string - for b.Reset(); b.Ongoing(); { - clientID, clientSecret, err = openshift.DiscoverCredentials(config.ServiceAccount) - if err != nil { - level.Error(logger).Log( - "tenant", tenant, - "msg", errors.Wrap(err, "unable to read serviceaccount credentials")) - registrationRetryCount.WithLabelValues(tenant, OpenShiftAuthenticatorType).Inc() - b.Wait() + if oauthEnabled { + for b.Reset(); b.Ongoing(); { + clientID, clientSecret, err = openshift.DiscoverCredentials(config.ServiceAccount) + if err != nil { + level.Error(logger).Log( + "tenant", tenant, + "msg", errors.Wrap(err, "unable to read serviceaccount credentials")) + registrationRetryCount.WithLabelValues(tenant, OpenShiftAuthenticatorType).Inc() + b.Wait() - continue + continue + } + break } - - break } authOpts := openshift.DelegatingAuthenticationOptions{ @@ -207,6 +208,8 @@ func newOpenshiftAuthenticator(c map[string]interface{}, tenant string, oauthEnabled: oauthEnabled, } + r := chi.NewRouter() + r.Use(tracing.WithChiRoutePattern) if oauthEnabled { osAuthenticator.oauth2Config = oauth2.Config{ ClientID: clientID, @@ -223,16 +226,13 @@ func newOpenshiftAuthenticator(c map[string]interface{}, tenant string, }, RedirectURL: config.RedirectURL, } - r := chi.NewRouter() - r.Use(tracing.WithChiRoutePattern) + r.Handle(loginRoute, osAuthenticator.openshiftLoginHandler()) r.Handle(callbackRoute, osAuthenticator.openshiftCallbackHandler()) - osAuthenticator.handler = r - - } else { - osAuthenticator.handler = chi.NewRouter() } + osAuthenticator.handler = r + return osAuthenticator, nil } @@ -539,28 +539,22 @@ func (a OpenShiftAuthenticator) Handler() (string, http.Handler) { } func discoverOAuthEndpoints(client *http.Client, logger log.Logger, tenant string, registrationRetryCount *prometheus.CounterVec, b *backoff.Backoff) (*url.URL, *url.URL, bool) { - authURL, tokenURL, err := openshift.DiscoverOAuth(client) - if err != nil { - if strings.Contains(err.Error(), "got 404") || strings.Contains(err.Error(), "OAuth server not found") { - level.Warn(logger).Log( - "tenant", tenant, - "msg", errors.Wrap(err, "OpenShift OAuth endpoint not available, likely using external OIDC authentication. But bearer token authentication will continue to work")) - return nil, nil, false - } else { - // Other errors, retry with backoff - for b.Reset(); b.Ongoing(); { - authURL, tokenURL, err = openshift.DiscoverOAuth(client) - if err != nil { - level.Error(logger).Log( - "tenant", tenant, - "msg", errors.Wrap(err, "unable to auto discover OpenShift OAuth endpoints")) - registrationRetryCount.WithLabelValues(tenant, OpenShiftAuthenticatorType).Inc() - b.Wait() - continue - } - break + var authURL, tokenURL *url.URL + var err error + for b.Reset(); b.Ongoing(); { + authURL, tokenURL, err = openshift.DiscoverOAuth(client) + if err != nil { + if errors.Is(err, openshift.ErrOAuthServerNotFound) { + return nil, nil, false } + level.Error(logger).Log( + "tenant", tenant, + "msg", errors.Wrap(err, "unable to auto discover OpenShift OAuth endpoints")) + registrationRetryCount.WithLabelValues(tenant, OpenShiftAuthenticatorType).Inc() + b.Wait() + continue } + break } return authURL, tokenURL, true } diff --git a/authentication/openshift/discovery.go b/authentication/openshift/discovery.go index e1e52905b..75b1d6b0a 100644 --- a/authentication/openshift/discovery.go +++ b/authentication/openshift/discovery.go @@ -8,6 +8,8 @@ import ( "net/url" "os" "strings" + + "github.com/pkg/errors" ) const ( @@ -21,6 +23,8 @@ const ( ServiceAccountCAPath = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" ) +var ErrOAuthServerNotFound = errors.Errorf("404 not found") + // GetServiceAccountCACert returns the PEM-encoded CA certificate currently mounted. func GetServiceAccountCACert() ([]byte, error) { rawCA, err := os.ReadFile(ServiceAccountCAPath) @@ -74,7 +78,7 @@ func DiscoverOAuth(client *http.Client) (authURL, tokenURL *url.URL, err error) if resp.StatusCode < 200 || resp.StatusCode >= 300 { if resp.StatusCode == 404 { - return nil, nil, fmt.Errorf("OAuth server not found") + return nil, nil, ErrOAuthServerNotFound } return nil, nil, fmt.Errorf("got %d %s", resp.StatusCode, body) } diff --git a/authentication/openshift_test.go b/authentication/openshift_test.go index 31a3e537a..64691b515 100644 --- a/authentication/openshift_test.go +++ b/authentication/openshift_test.go @@ -55,13 +55,12 @@ func TestDiscoverOAuthEndpoints_OAuthEnabled(t *testing.T) { } // Split host and port for KUBERNETES env vars - host, port, err := net.SplitHostPort(mockURL.Host) + host, _, err := net.SplitHostPort(mockURL.Host) if err != nil { t.Fatalf("failed to parse mock server address: %v", err) } t.Setenv("KUBERNETES_SERVICE_HOST", host) - t.Setenv("KUBERNETES_SERVICE_PORT", port) retryCounter := prometheus.NewCounterVec(prometheus.CounterOpts{ Name: "test_retries_total", @@ -113,13 +112,12 @@ func TestDiscoverOAuthEndpoints_OAuthDisabled(t *testing.T) { } // Split host and port for KUBERNETES env vars - host, port, err := net.SplitHostPort(mockURL.Host) + host, _, err := net.SplitHostPort(mockURL.Host) if err != nil { t.Fatalf("failed to parse mock server address: %v", err) } t.Setenv("KUBERNETES_SERVICE_HOST", host) - t.Setenv("KUBERNETES_SERVICE_PORT", port) retryCounter := prometheus.NewCounterVec(prometheus.CounterOpts{ Name: "test_retries_total", From f99e5fb0c188cff2628493087771a6bc3771d66d Mon Sep 17 00:00:00 2001 From: Bayan Taani Date: Thu, 9 Apr 2026 14:03:02 +0200 Subject: [PATCH 5/5] change error text --- authentication/openshift/discovery.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/authentication/openshift/discovery.go b/authentication/openshift/discovery.go index 75b1d6b0a..f748208b1 100644 --- a/authentication/openshift/discovery.go +++ b/authentication/openshift/discovery.go @@ -23,7 +23,7 @@ const ( ServiceAccountCAPath = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" ) -var ErrOAuthServerNotFound = errors.Errorf("404 not found") +var ErrOAuthServerNotFound = errors.Errorf("OAuth server not found") // GetServiceAccountCACert returns the PEM-encoded CA certificate currently mounted. func GetServiceAccountCACert() ([]byte, error) {