mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-22 18:16:52 +00:00
test:integration: add aggregated API test for RequestHeader UID
This commit is contained in:
parent
2cc0370169
commit
dcc6cf9280
@ -29,16 +29,22 @@ import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
v1 "k8s.io/api/authentication/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/version"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apiserver/pkg/authentication/serviceaccount"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/apiserver/pkg/server/dynamiccertificates"
|
||||
genericapiserveroptions "k8s.io/apiserver/pkg/server/options"
|
||||
utilversion "k8s.io/apiserver/pkg/util/version"
|
||||
@ -46,6 +52,7 @@ import (
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
"k8s.io/client-go/transport"
|
||||
"k8s.io/client-go/util/cert"
|
||||
"k8s.io/component-base/featuregate"
|
||||
apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
|
||||
@ -248,6 +255,124 @@ func TestAggregatedAPIServer(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TestFrontProxyConfig tests that the RequestHeader configuration is consumed
|
||||
// correctly by the aggregated API servers.
|
||||
func TestFrontProxyConfig(t *testing.T) {
|
||||
const testNamespace = "integration-test-front-proxy-config"
|
||||
const wardleBinaryVersion = "1.1"
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
|
||||
t.Cleanup(cancel)
|
||||
|
||||
// each wardle binary is bundled with a specific kube binary.
|
||||
kubeBinaryVersion := sampleserver.WardleVersionToKubeVersion(version.MustParse(wardleBinaryVersion)).String()
|
||||
|
||||
// start up the KAS and prepare the options for the wardle API server
|
||||
testKAS, wardleOptions, wardlePort := prepareAggregatedWardleAPIServer(ctx, t, testNamespace, kubeBinaryVersion, wardleBinaryVersion)
|
||||
kubeConfig := getKubeConfig(testKAS)
|
||||
|
||||
// create the SA that we will use to query the aggregated API
|
||||
kubeClient := client.NewForConfigOrDie(kubeConfig)
|
||||
expectedSA, err := kubeClient.CoreV1().ServiceAccounts(testNamespace).Create(ctx, &corev1.ServiceAccount{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "wardle-client-sa",
|
||||
},
|
||||
}, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expectedSAUserInfo := serviceaccount.UserInfo(expectedSA.Namespace, expectedSA.Name, string(expectedSA.UID))
|
||||
expectedRealSAGroups := append(expectedSAUserInfo.GetGroups(), user.AllAuthenticated)
|
||||
|
||||
saTokenReq, err := kubeClient.CoreV1().ServiceAccounts(testNamespace).CreateToken(ctx, "wardle-client-sa", &v1.TokenRequest{}, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
saToken := saTokenReq.Status.Token
|
||||
if len(saToken) == 0 {
|
||||
t.Fatal("empty SA token in token request response")
|
||||
}
|
||||
|
||||
saClientConfig := rest.AnonymousClientConfig(kubeConfig)
|
||||
saClientConfig.BearerToken = saToken
|
||||
|
||||
saKubeClient := client.NewForConfigOrDie(saClientConfig)
|
||||
saDetails, err := saKubeClient.AuthenticationV1().SelfSubjectReviews().Create(ctx, &v1.SelfSubjectReview{}, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("failed to retrieve details about the SA: %v", err)
|
||||
}
|
||||
expectedExtra := expectedSAUserInfo.GetExtra()
|
||||
if expectedExtra == nil {
|
||||
expectedExtra = map[string][]string{}
|
||||
}
|
||||
expectedExtra[user.CredentialIDKey] = saDetails.Status.UserInfo.Extra[user.CredentialIDKey]
|
||||
|
||||
var checksProcessed atomic.Uint32
|
||||
|
||||
// wrap the authz round tripper to catch the request for our SA SAR to the KAS
|
||||
wardleOptions.RecommendedOptions.Authorization.WithCustomRoundTripper(
|
||||
// adding a round tripper wrapper to test default RequestHeader configuration
|
||||
transport.WrapperFunc(func(rt http.RoundTripper) http.RoundTripper {
|
||||
return roundTripperFunc(func(req *http.Request) (*http.Response, error) {
|
||||
gotUser, ok := genericapirequest.UserFrom(req.Context())
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("got an unauthenticated request")
|
||||
}
|
||||
|
||||
// this is likely the KAS checking the OpenAPI endpoints
|
||||
if gotUser.GetName() == "system:anonymous" || gotUser.GetName() == "system:aggregator" {
|
||||
return rt.RoundTrip(req)
|
||||
}
|
||||
|
||||
if len(gotUser.GetUID()) == 0 {
|
||||
t.Errorf("expected UID to be non-empty for user %q", gotUser.GetName())
|
||||
}
|
||||
if got, expected := gotUser.GetUID(), expectedSAUserInfo.GetUID(); expected != got {
|
||||
t.Errorf("expected UID: %q, got: %q", expected, got)
|
||||
}
|
||||
if got, expected := gotUser.GetName(), expectedSAUserInfo.GetName(); expected != got {
|
||||
t.Errorf("expected name: %q, got: %q", expected, got)
|
||||
}
|
||||
if got := gotUser.GetGroups(); !reflect.DeepEqual(expectedRealSAGroups, got) {
|
||||
t.Errorf("expected groups: %v, got: %v", expectedRealSAGroups, got)
|
||||
}
|
||||
if got := gotUser.GetExtra(); !apiequality.Semantic.DeepEqual(expectedExtra, got) {
|
||||
t.Errorf("expected extra to be %v, but got %v", expectedExtra, got)
|
||||
}
|
||||
|
||||
checksProcessed.Add(1)
|
||||
return rt.RoundTrip(req)
|
||||
})
|
||||
}),
|
||||
)
|
||||
|
||||
wardleCertDir, _ := os.MkdirTemp("", "test-integration-wardle-server")
|
||||
defer os.RemoveAll(wardleCertDir)
|
||||
|
||||
runPreparedWardleServer(ctx, t, wardleOptions, wardleCertDir, wardlePort, false, true, wardleBinaryVersion, kubeConfig)
|
||||
waitForWardleAPIServiceReady(ctx, t, kubeConfig, wardleCertDir, testNamespace)
|
||||
|
||||
// get the wardle API client using our SA token
|
||||
wardleClientConfig := rest.AnonymousClientConfig(kubeConfig)
|
||||
wardleClientConfig.BearerToken = saToken
|
||||
wardleClient := wardlev1alpha1client.NewForConfigOrDie(wardleClientConfig)
|
||||
|
||||
_, err = wardleClient.Flunders(metav1.NamespaceSystem).List(ctx, metav1.ListOptions{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if checksProcessed.Load() != 1 {
|
||||
t.Errorf("the request is in fact not being tested")
|
||||
}
|
||||
}
|
||||
|
||||
type roundTripperFunc func(*http.Request) (*http.Response, error)
|
||||
|
||||
func (f roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
return f(req)
|
||||
}
|
||||
|
||||
func testAggregatedAPIServer(t *testing.T, setWardleFeatureGate, banFlunder bool, wardleBinaryVersion, wardleEmulationVersion string) {
|
||||
const testNamespace = "kube-wardle"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user