add integration tests
Signed-off-by: Anish Ramasekar <anish.ramasekar@gmail.com>
This commit is contained in:
@@ -27,23 +27,28 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
rbacv1 "k8s.io/api/rbac/v1"
|
rbacv1 "k8s.io/api/rbac/v1"
|
||||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apiserver/pkg/features"
|
||||||
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
|
_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
|
||||||
"k8s.io/client-go/rest"
|
"k8s.io/client-go/rest"
|
||||||
"k8s.io/client-go/tools/clientcmd/api"
|
"k8s.io/client-go/tools/clientcmd/api"
|
||||||
certutil "k8s.io/client-go/util/cert"
|
certutil "k8s.io/client-go/util/cert"
|
||||||
|
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||||
kubeapiserverapptesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
|
kubeapiserverapptesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
|
||||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||||
"k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes"
|
|
||||||
"k8s.io/kubernetes/test/integration/framework"
|
"k8s.io/kubernetes/test/integration/framework"
|
||||||
utilsoidc "k8s.io/kubernetes/test/utils/oidc"
|
utilsoidc "k8s.io/kubernetes/test/utils/oidc"
|
||||||
utilsnet "k8s.io/utils/net"
|
utilsnet "k8s.io/utils/net"
|
||||||
@@ -95,9 +100,21 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestOIDC(t *testing.T) {
|
func TestOIDC(t *testing.T) {
|
||||||
|
t.Log("Testing OIDC authenticator with --oidc-* flags")
|
||||||
|
runTests(t, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStructuredAuthenticationConfig(t *testing.T) {
|
||||||
|
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.StructuredAuthenticationConfiguration, true)()
|
||||||
|
|
||||||
|
t.Log("Testing OIDC authenticator with authentication config")
|
||||||
|
runTests(t, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func runTests(t *testing.T, useAuthenticationConfig bool) {
|
||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
name string
|
name string
|
||||||
configureInfrastructure func(t *testing.T) (
|
configureInfrastructure func(t *testing.T, useAuthenticationConfig bool) (
|
||||||
oidcServer *utilsoidc.TestServer,
|
oidcServer *utilsoidc.TestServer,
|
||||||
apiServer *kubeapiserverapptesting.TestServer,
|
apiServer *kubeapiserverapptesting.TestServer,
|
||||||
signingPrivateKey *rsa.PrivateKey,
|
signingPrivateKey *rsa.PrivateKey,
|
||||||
@@ -207,7 +224,7 @@ func TestOIDC(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "ID token signature can not be verified due to wrong JWKs",
|
name: "ID token signature can not be verified due to wrong JWKs",
|
||||||
configureInfrastructure: func(t *testing.T) (
|
configureInfrastructure: func(t *testing.T, useAuthenticationConfig bool) (
|
||||||
oidcServer *utilsoidc.TestServer,
|
oidcServer *utilsoidc.TestServer,
|
||||||
apiServer *kubeapiserverapptesting.TestServer,
|
apiServer *kubeapiserverapptesting.TestServer,
|
||||||
signingPrivateKey *rsa.PrivateKey,
|
signingPrivateKey *rsa.PrivateKey,
|
||||||
@@ -220,7 +237,13 @@ func TestOIDC(t *testing.T) {
|
|||||||
require.NoError(t, wantErr)
|
require.NoError(t, wantErr)
|
||||||
|
|
||||||
oidcServer = utilsoidc.BuildAndRunTestServer(t, caFilePath, caKeyFilePath)
|
oidcServer = utilsoidc.BuildAndRunTestServer(t, caFilePath, caKeyFilePath)
|
||||||
apiServer = startTestAPIServerForOIDC(t, oidcServer.URL(), defaultOIDCClientID, caFilePath)
|
|
||||||
|
if useAuthenticationConfig {
|
||||||
|
authenticationConfig := generateAuthenticationConfig(t, oidcServer.URL(), defaultOIDCClientID, string(caCertContent), defaultOIDCUsernamePrefix)
|
||||||
|
apiServer = startTestAPIServerForOIDC(t, "", "", "", authenticationConfig)
|
||||||
|
} else {
|
||||||
|
apiServer = startTestAPIServerForOIDC(t, oidcServer.URL(), defaultOIDCClientID, caFilePath, "")
|
||||||
|
}
|
||||||
|
|
||||||
adminClient := kubernetes.NewForConfigOrDie(apiServer.ClientConfig)
|
adminClient := kubernetes.NewForConfigOrDie(apiServer.ClientConfig)
|
||||||
configureRBAC(t, adminClient, defaultRole, defaultRoleBinding)
|
configureRBAC(t, adminClient, defaultRole, defaultRoleBinding)
|
||||||
@@ -252,7 +275,7 @@ func TestOIDC(t *testing.T) {
|
|||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
oidcServer, apiServer, signingPrivateKey, caCert, certPath := tt.configureInfrastructure(t)
|
oidcServer, apiServer, signingPrivateKey, caCert, certPath := tt.configureInfrastructure(t, useAuthenticationConfig)
|
||||||
|
|
||||||
tt.configureOIDCServerBehaviour(t, oidcServer, signingPrivateKey)
|
tt.configureOIDCServerBehaviour(t, oidcServer, signingPrivateKey)
|
||||||
|
|
||||||
@@ -304,7 +327,7 @@ func TestUpdatingRefreshTokenInCaseOfExpiredIDToken(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
oidcServer, apiServer, signingPrivateKey, caCert, certPath := configureTestInfrastructure(t)
|
oidcServer, apiServer, signingPrivateKey, caCert, certPath := configureTestInfrastructure(t, false)
|
||||||
|
|
||||||
tokenURL, err := oidcServer.TokenURL()
|
tokenURL, err := oidcServer.TokenURL()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -333,7 +356,7 @@ func TestUpdatingRefreshTokenInCaseOfExpiredIDToken(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func configureTestInfrastructure(t *testing.T) (
|
func configureTestInfrastructure(t *testing.T, useAuthenticationConfig bool) (
|
||||||
oidcServer *utilsoidc.TestServer,
|
oidcServer *utilsoidc.TestServer,
|
||||||
apiServer *kubeapiserverapptesting.TestServer,
|
apiServer *kubeapiserverapptesting.TestServer,
|
||||||
signingPrivateKey *rsa.PrivateKey,
|
signingPrivateKey *rsa.PrivateKey,
|
||||||
@@ -348,7 +371,13 @@ func configureTestInfrastructure(t *testing.T) (
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
oidcServer = utilsoidc.BuildAndRunTestServer(t, caFilePath, caKeyFilePath)
|
oidcServer = utilsoidc.BuildAndRunTestServer(t, caFilePath, caKeyFilePath)
|
||||||
apiServer = startTestAPIServerForOIDC(t, oidcServer.URL(), defaultOIDCClientID, caFilePath)
|
|
||||||
|
if useAuthenticationConfig {
|
||||||
|
authenticationConfig := generateAuthenticationConfig(t, oidcServer.URL(), defaultOIDCClientID, string(caCertContent), defaultOIDCUsernamePrefix)
|
||||||
|
apiServer = startTestAPIServerForOIDC(t, "", "", "", authenticationConfig)
|
||||||
|
} else {
|
||||||
|
apiServer = startTestAPIServerForOIDC(t, oidcServer.URL(), defaultOIDCClientID, caFilePath, "")
|
||||||
|
}
|
||||||
|
|
||||||
oidcServer.JwksHandler().EXPECT().KeySet().AnyTimes().DoAndReturn(utilsoidc.DefaultJwksHandlerBehaviour(t, &signingPrivateKey.PublicKey))
|
oidcServer.JwksHandler().EXPECT().KeySet().AnyTimes().DoAndReturn(utilsoidc.DefaultJwksHandlerBehaviour(t, &signingPrivateKey.PublicKey))
|
||||||
|
|
||||||
@@ -399,19 +428,26 @@ func configureClientConfigForOIDC(t *testing.T, config *rest.Config, clientID, c
|
|||||||
return cfg
|
return cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
func startTestAPIServerForOIDC(t *testing.T, oidcURL, oidcClientID, oidcCAFilePath string) *kubeapiserverapptesting.TestServer {
|
func startTestAPIServerForOIDC(t *testing.T, oidcURL, oidcClientID, oidcCAFilePath, authenticationConfigYAML string) *kubeapiserverapptesting.TestServer {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
server, err := kubeapiserverapptesting.StartTestServer(
|
var customFlags []string
|
||||||
t,
|
if authenticationConfigYAML != "" {
|
||||||
kubeapiserverapptesting.NewDefaultTestServerOptions(),
|
customFlags = []string{fmt.Sprintf("--authentication-config=%s", writeTempFile(t, authenticationConfigYAML))}
|
||||||
[]string{
|
} else {
|
||||||
|
customFlags = []string{
|
||||||
fmt.Sprintf("--oidc-issuer-url=%s", oidcURL),
|
fmt.Sprintf("--oidc-issuer-url=%s", oidcURL),
|
||||||
fmt.Sprintf("--oidc-client-id=%s", oidcClientID),
|
fmt.Sprintf("--oidc-client-id=%s", oidcClientID),
|
||||||
fmt.Sprintf("--oidc-ca-file=%s", oidcCAFilePath),
|
fmt.Sprintf("--oidc-ca-file=%s", oidcCAFilePath),
|
||||||
fmt.Sprintf("--oidc-username-prefix=%s", defaultOIDCUsernamePrefix),
|
fmt.Sprintf("--oidc-username-prefix=%s", defaultOIDCUsernamePrefix),
|
||||||
fmt.Sprintf("--authorization-mode=%s", modes.ModeRBAC),
|
}
|
||||||
},
|
}
|
||||||
|
customFlags = append(customFlags, "--authorization-mode=RBAC")
|
||||||
|
|
||||||
|
server, err := kubeapiserverapptesting.StartTestServer(
|
||||||
|
t,
|
||||||
|
kubeapiserverapptesting.NewDefaultTestServerOptions(),
|
||||||
|
customFlags,
|
||||||
framework.SharedEtcd(),
|
framework.SharedEtcd(),
|
||||||
)
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -494,3 +530,44 @@ func generateCert(t *testing.T) (cert, key []byte, certFilePath, keyFilePath str
|
|||||||
|
|
||||||
return cert, key, certFilePath, keyFilePath
|
return cert, key, certFilePath, keyFilePath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func writeTempFile(t *testing.T, content string) string {
|
||||||
|
t.Helper()
|
||||||
|
file, err := os.CreateTemp("", "oidc-test")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
t.Cleanup(func() {
|
||||||
|
if err := os.Remove(file.Name()); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if err := os.WriteFile(file.Name(), []byte(content), 0600); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return file.Name()
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateAuthenticationConfig(t *testing.T, issuerURL, clientID, caCert, usernamePrefix string) string {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
// Indent the certificate authority to match the format of the generated
|
||||||
|
// authentication config.
|
||||||
|
caCert = strings.ReplaceAll(caCert, "\n", "\n ")
|
||||||
|
|
||||||
|
return fmt.Sprintf(`
|
||||||
|
apiVersion: apiserver.config.k8s.io/v1alpha1
|
||||||
|
kind: AuthenticationConfiguration
|
||||||
|
jwt:
|
||||||
|
- issuer:
|
||||||
|
url: %s
|
||||||
|
audiences:
|
||||||
|
- %s
|
||||||
|
certificateAuthority: |
|
||||||
|
%s
|
||||||
|
claimMappings:
|
||||||
|
username:
|
||||||
|
claim: sub
|
||||||
|
prefix: %s
|
||||||
|
`, issuerURL, clientID, string(caCert), usernamePrefix)
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user