Support all key algs with structured authn config

Signed-off-by: Monis Khan <mok@microsoft.com>
This commit is contained in:
Monis Khan 2024-02-13 13:45:53 -05:00
parent b8a59346fe
commit b5e0068325
No known key found for this signature in database
4 changed files with 88 additions and 2 deletions

View File

@ -40,6 +40,7 @@ import (
"k8s.io/apiserver/pkg/server/egressselector"
genericoptions "k8s.io/apiserver/pkg/server/options"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/apiserver/plugin/pkg/authenticator/token/oidc"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
v1listers "k8s.io/client-go/listers/core/v1"
@ -461,6 +462,9 @@ func (o *BuiltInAuthenticationOptions) ToAuthenticationConfig() (kubeauthenticat
if ret.AuthenticationConfig, err = loadAuthenticationConfig(o.AuthenticationConfigFile); err != nil {
return kubeauthenticator.Config{}, err
}
// all known signing algs are allowed when using authentication config
// TODO: what we really want to express is 'any alg is fine as long it matches a public key'
ret.OIDCSigningAlgs = oidc.AllValidSigningAlgorithms()
} else if o.OIDC != nil && len(o.OIDC.IssuerURL) > 0 && len(o.OIDC.ClientID) > 0 {
usernamePrefix := o.OIDC.UsernamePrefix

View File

@ -446,6 +446,8 @@ func TestBuiltInAuthenticationOptionsAddFlags(t *testing.T) {
}
func TestToAuthenticationConfig_OIDC(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.StructuredAuthenticationConfiguration, true)()
testCases := []struct {
name string
args []string
@ -640,6 +642,43 @@ func TestToAuthenticationConfig_OIDC(t *testing.T) {
OIDCSigningAlgs: []string{"RS256"},
},
},
{
name: "basic authentication configuration",
args: []string{
"--authentication-config=" + writeTempFile(t, `
apiVersion: apiserver.config.k8s.io/v1alpha1
kind: AuthenticationConfiguration
jwt:
- issuer:
url: https://test-issuer
audiences: [ "🐼" ]
claimMappings:
username:
claim: sub
prefix: ""
`),
},
expectConfig: kubeauthenticator.Config{
TokenSuccessCacheTTL: 10 * time.Second,
AuthenticationConfig: &apiserver.AuthenticationConfiguration{
JWT: []apiserver.JWTAuthenticator{
{
Issuer: apiserver.Issuer{
URL: "https://test-issuer",
Audiences: []string{"🐼"},
},
ClaimMappings: apiserver.ClaimMappings{
Username: apiserver.PrefixedClaimOrExpression{
Claim: "sub",
Prefix: pointer.String(""),
},
},
},
},
},
OIDCSigningAlgs: []string{"ES256", "ES384", "ES512", "PS256", "PS384", "PS512", "RS256", "RS384", "RS512"},
},
},
}
for _, testcase := range testCases {

View File

@ -49,6 +49,7 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/net"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apiserver/pkg/apis/apiserver"
apiservervalidation "k8s.io/apiserver/pkg/apis/apiserver/validation"
@ -196,8 +197,11 @@ func (a *Authenticator) Close() {
a.cancel()
}
// whitelist of signing algorithms to ensure users don't mistakenly pass something
// goofy.
func AllValidSigningAlgorithms() []string {
return sets.List(sets.KeySet(allowedSigningAlgs))
}
// allowlist of signing algorithms to ensure users don't mistakenly pass something goofy.
var allowedSigningAlgs = map[string]bool{
oidc.RS256: true,
oidc.RS384: true,

View File

@ -18,6 +18,8 @@ package oidc
import (
"context"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/tls"
@ -280,6 +282,34 @@ jwt:
for _, tt := range tests {
t.Run(tt.name, singleTestRunner(useAuthenticationConfig, rsaGenerateKey, tt))
}
for _, tt := range []singleTest[*ecdsa.PrivateKey, *ecdsa.PublicKey]{
{
name: "ID token is ok",
configureInfrastructure: configureTestInfrastructure[*ecdsa.PrivateKey, *ecdsa.PublicKey],
configureOIDCServerBehaviour: func(t *testing.T, oidcServer *utilsoidc.TestServer, signingPrivateKey *ecdsa.PrivateKey) {
idTokenLifetime := time.Second * 1200
oidcServer.TokenHandler().EXPECT().Token().Times(1).DoAndReturn(utilsoidc.TokenHandlerBehaviorReturningPredefinedJWT(
t,
signingPrivateKey,
map[string]interface{}{
"iss": oidcServer.URL(),
"sub": defaultOIDCClaimedUsername,
"aud": defaultOIDCClientID,
"exp": time.Now().Add(idTokenLifetime).Unix(),
},
defaultStubAccessToken,
defaultStubRefreshToken,
))
},
configureClient: configureClientFetchingOIDCCredentials,
assertErrFn: func(t *testing.T, errorToCheck error) {
assert.NoError(t, errorToCheck)
},
},
} {
t.Run(tt.name, singleTestRunner(useAuthenticationConfig, ecdsaGenerateKey, tt))
}
}
type singleTest[K utilsoidc.JosePrivateKey, L utilsoidc.JosePublicKey] struct {
@ -755,6 +785,15 @@ func rsaGenerateKey(t *testing.T) (*rsa.PrivateKey, *rsa.PublicKey) {
return privateKey, &privateKey.PublicKey
}
func ecdsaGenerateKey(t *testing.T) (*ecdsa.PrivateKey, *ecdsa.PublicKey) {
t.Helper()
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
require.NoError(t, err)
return privateKey, &privateKey.PublicKey
}
func configureTestInfrastructure[K utilsoidc.JosePrivateKey, L utilsoidc.JosePublicKey](t *testing.T, fn authenticationConfigFunc, keyFunc func(t *testing.T) (K, L)) (
oidcServer *utilsoidc.TestServer,
apiServer *kubeapiserverapptesting.TestServer,