K8s: remove standalone authenticator in favor of providing one through the factory (#85901)

This commit is contained in:
Charandas
2024-04-11 12:30:23 -07:00
committed by GitHub
parent 1031c2f1d2
commit a39fe593c2
9 changed files with 12 additions and 186 deletions

View File

@@ -1,71 +0,0 @@
package auth
import (
"net/http"
"strings"
"github.com/grafana/authlib/authn"
"k8s.io/apiserver/pkg/authentication/authenticator"
"k8s.io/apiserver/pkg/authentication/user"
)
const (
headerKeyAccessToken = "X-Access-Token"
headerKeyGrafanaID = "X-Grafana-Id"
extraKeyAccessToken = "access-token"
extraKeyGrafanaID = "id-token"
extraKeyGLSA = "glsa"
)
func NewAccessTokenAuthenticator(config *authn.IDVerifierConfig) authenticator.RequestFunc {
verifier := authn.NewVerifier[CustomClaims](authn.IDVerifierConfig{
SigningKeysURL: config.SigningKeysURL,
AllowedAudiences: config.AllowedAudiences,
})
return getAccessTokenAuthenticatorFunc(&TokenValidator{verifier})
}
func getAccessTokenAuthenticatorFunc(validator *TokenValidator) authenticator.RequestFunc {
return func(req *http.Request) (*authenticator.Response, bool, error) {
accessToken := req.Header.Get(headerKeyAccessToken)
if accessToken == "" {
return nil, false, nil
}
// While the authn token system is in development, we can temporarily use
// service account tokens. Note this does not grant any real permissions/verification,
// it simply allows forwarding the token to the next request
if strings.HasPrefix(accessToken, "glsa_") {
return &authenticator.Response{
Audiences: authenticator.Audiences([]string{}),
User: &user.DefaultInfo{
Name: "glsa-forwarding-request",
UID: "",
Groups: []string{},
Extra: map[string][]string{
extraKeyGLSA: {accessToken},
},
},
}, true, nil
}
result, err := validator.Validate(req.Context(), accessToken)
if err != nil {
return nil, false, err
}
return &authenticator.Response{
Audiences: authenticator.Audiences(result.Claims.Audience),
User: &user.DefaultInfo{
Name: result.Subject,
UID: "",
Groups: []string{},
Extra: map[string][]string{
extraKeyAccessToken: {accessToken},
extraKeyGrafanaID: {req.Header.Get("X-Grafana-Id")}, // this may exist if starting with a user
},
},
}, true, nil
}
}

View File

@@ -1,57 +0,0 @@
package auth
import (
"context"
"fmt"
"k8s.io/apiserver/pkg/authentication/authenticator"
"k8s.io/apiserver/pkg/authentication/request/union"
"k8s.io/apiserver/pkg/endpoints/request"
)
func AppendToAuthenticators(newAuthenticator authenticator.RequestFunc, authRequestHandlers ...authenticator.Request) authenticator.Request {
handlers := append([]authenticator.Request{newAuthenticator}, authRequestHandlers...)
return union.New(handlers...)
}
// Get tokens that can be forwarded to the next service
// In the future this will need to create new tokens with a new audience
func GetIDForwardingAuthHeaders(ctx context.Context) (map[string]string, error) {
user, ok := request.UserFrom(ctx)
if !ok {
return nil, fmt.Errorf("missing user")
}
getter := func(key string) string {
vals, ok := user.GetExtra()[key]
if ok && len(vals) == 1 {
return vals[0]
}
return ""
}
token := getter(extraKeyGLSA)
if token != "" {
// Service account tokens get forwarded as auth tokens
// this lets us keep testing the workflows while the ID token system is in dev
return map[string]string{
"Authorization": "Bearer " + token,
}, nil
}
accessToken := getter(extraKeyAccessToken)
if accessToken == "" {
return nil, fmt.Errorf("missing access token in user info")
}
idToken := getter(extraKeyGrafanaID)
if idToken != "" {
return map[string]string{
headerKeyAccessToken: accessToken,
headerKeyGrafanaID: idToken,
}, nil
}
return map[string]string{
headerKeyAccessToken: accessToken,
}, nil
}

View File

@@ -1,24 +0,0 @@
package auth
import (
"context"
"github.com/grafana/authlib/authn"
)
type CustomClaims struct {
// Nothing yet
}
type TokenValidator struct {
verifier authn.Verifier[CustomClaims]
}
func (v *TokenValidator) Validate(ctx context.Context, token string) (*authn.Claims[CustomClaims], error) {
customClaims, err := v.verifier.Verify(ctx, token)
if err != nil {
return nil, err
}
return customClaims, nil
}

View File

@@ -14,7 +14,6 @@ import (
netutils "k8s.io/utils/net"
"github.com/grafana/grafana/pkg/apiserver/builder"
"github.com/grafana/grafana/pkg/cmd/grafana/apiserver/auth"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/tracing"
grafanaAPIServer "github.com/grafana/grafana/pkg/services/apiserver"
@@ -101,12 +100,11 @@ func (o *APIServerOptions) Config() (*genericapiserver.RecommendedConfig, error)
return nil, fmt.Errorf("failed to apply options to server config: %w", err)
}
// When the ID signing key exists, configure access-token support
if len(o.Options.AuthnOptions.IDVerifierConfig.SigningKeysURL) > 0 {
serverConfig.Authentication.Authenticator = auth.AppendToAuthenticators(
auth.NewAccessTokenAuthenticator(o.Options.AuthnOptions.IDVerifierConfig),
serverConfig.Authentication.Authenticator,
)
if factoryOptions := o.factory.GetOptions(); factoryOptions != nil {
err := factoryOptions.ApplyTo(serverConfig)
if err != nil {
return nil, fmt.Errorf("factory's applyTo func failed: %s", err.Error())
}
}
serverConfig.DisabledPostStartHooks = serverConfig.DisabledPostStartHooks.Insert("generic-apiserver-start-informers")