k8s.io/kubernetes@v1.29.3/test/e2e/auth/selfsubjectreviews.go (about)

     1  /*
     2  Copyright 2022 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package auth
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  
    23  	"github.com/onsi/ginkgo/v2"
    24  	"github.com/onsi/gomega"
    25  	authenticationv1 "k8s.io/api/authentication/v1"
    26  	authenticationv1alpha1 "k8s.io/api/authentication/v1alpha1"
    27  	authenticationv1beta1 "k8s.io/api/authentication/v1beta1"
    28  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    29  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    30  	"k8s.io/client-go/kubernetes"
    31  	"k8s.io/client-go/rest"
    32  	"k8s.io/kubernetes/test/e2e/framework"
    33  	admissionapi "k8s.io/pod-security-admission/api"
    34  )
    35  
    36  var _ = SIGDescribe("SelfSubjectReview", func() {
    37  	f := framework.NewDefaultFramework("selfsubjectreviews")
    38  	f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
    39  
    40  	/*
    41  			Release: v1.28
    42  			Testname: SelfSubjectReview API
    43  			Description:
    44  			The authentication.k8s.io API group MUST exist in the /apis discovery document.
    45  			The authentication.k8s.io/v1alpha1 API group/version MUST exist in the /apis/mode.k8s.io discovery document.
    46  		    The authentication.k8s.io/v1beta1 API group/version MUST exist in the /apis/mode.k8s.io discovery document.
    47  			The authentication.k8s.io/v1 API group/version MUST exist in the /apis/mode.k8s.io discovery document.
    48  			The selfsubjectreviews resource MUST exist in the /apis/authentication.k8s.io/v1alpha1 discovery document.
    49  			The selfsubjectreviews resource MUST exist in the /apis/authentication.k8s.io/v1beta1 discovery document.
    50  			The selfsubjectreviews resource MUST exist in the /apis/authentication.k8s.io/v1 discovery document.
    51  			The selfsubjectreviews resource MUST support create.
    52  	*/
    53  	ginkgo.DescribeTable(
    54  		"testing SSR in different API groups",
    55  		func(ctx context.Context, apiVersion, gv string) {
    56  			// Discovery
    57  			ginkgo.By("getting /apis")
    58  			{
    59  				discoveryGroups, err := f.ClientSet.Discovery().ServerGroups()
    60  				framework.ExpectNoError(err)
    61  				found := false
    62  				for _, group := range discoveryGroups.Groups {
    63  					if group.Name == authenticationv1alpha1.GroupName {
    64  						for _, version := range group.Versions {
    65  							if version.Version == apiVersion {
    66  								found = true
    67  								break
    68  							}
    69  						}
    70  					}
    71  				}
    72  				if !found {
    73  					ginkgo.Skip(fmt.Sprintf("expected SelfSubjectReview API group/version, got %#v", discoveryGroups.Groups))
    74  				}
    75  			}
    76  
    77  			ginkgo.By("getting /apis/authentication.k8s.io")
    78  			{
    79  				group := &metav1.APIGroup{}
    80  				err := f.ClientSet.Discovery().RESTClient().Get().AbsPath("/apis/authentication.k8s.io").Do(ctx).Into(group)
    81  				framework.ExpectNoError(err)
    82  				found := false
    83  				for _, version := range group.Versions {
    84  					if version.Version == apiVersion {
    85  						found = true
    86  						break
    87  					}
    88  				}
    89  				if !found {
    90  					ginkgo.Skip(fmt.Sprintf("expected SelfSubjectReview API version, got %#v", group.Versions))
    91  				}
    92  			}
    93  
    94  			ginkgo.By("getting /apis/authentication.k8s.io/" + apiVersion)
    95  			{
    96  				resources, err := f.ClientSet.Discovery().ServerResourcesForGroupVersion(gv)
    97  				framework.ExpectNoError(err)
    98  				found := false
    99  				for _, resource := range resources.APIResources {
   100  					switch resource.Name {
   101  					case "selfsubjectreviews":
   102  						found = true
   103  					}
   104  				}
   105  				if !found {
   106  					ginkgo.Skip(fmt.Sprintf("expected selfsubjectreviews, got %#v", resources.APIResources))
   107  				}
   108  			}
   109  		},
   110  		ginkgo.Entry("authentication/v1alpha1", "v1alpha1", authenticationv1alpha1.SchemeGroupVersion.String()),
   111  		ginkgo.Entry("authentication/v1beta1", "v1beta1", authenticationv1beta1.SchemeGroupVersion.String()),
   112  		ginkgo.Entry("authentication/v1", "v1", authenticationv1.SchemeGroupVersion.String()),
   113  	)
   114  
   115  	ginkgo.It("should support SelfSubjectReview API operations", func(ctx context.Context) {
   116  		// Check creating
   117  		ginkgo.By("creating SSR authentication/v1alpha1")
   118  		{
   119  			// Use impersonate to make user attributes predictable
   120  			config := restConfig(f)
   121  
   122  			ssrClient := kubernetes.NewForConfigOrDie(config).AuthenticationV1alpha1().SelfSubjectReviews()
   123  			res, err := ssrClient.Create(ctx, &authenticationv1alpha1.SelfSubjectReview{}, metav1.CreateOptions{})
   124  			if apierrors.IsNotFound(err) {
   125  				return // Alpha API is disabled
   126  			}
   127  
   128  			framework.ExpectNoError(err)
   129  			gomega.Expect(config.Impersonate.UserName).To(gomega.Equal(res.Status.UserInfo.Username))
   130  			gomega.Expect(config.Impersonate.UID).To(gomega.Equal(res.Status.UserInfo.UID))
   131  			gomega.Expect(config.Impersonate.Groups).To(gomega.Equal(res.Status.UserInfo.Groups))
   132  
   133  			extra := make(map[string][]string, len(res.Status.UserInfo.Extra))
   134  			for k, v := range res.Status.UserInfo.Extra {
   135  				extra[k] = v
   136  			}
   137  
   138  			gomega.Expect(config.Impersonate.Extra).To(gomega.Equal(extra))
   139  		}
   140  
   141  		ginkgo.By("creating SSR authentication/v1beta1")
   142  		{
   143  			config := restConfig(f)
   144  
   145  			ssrClient := kubernetes.NewForConfigOrDie(config).AuthenticationV1beta1().SelfSubjectReviews()
   146  			res, err := ssrClient.Create(ctx, &authenticationv1beta1.SelfSubjectReview{}, metav1.CreateOptions{})
   147  			if apierrors.IsNotFound(err) {
   148  				return // Beta API is disabled
   149  			}
   150  
   151  			framework.ExpectNoError(err)
   152  			gomega.Expect(config.Impersonate.UserName).To(gomega.Equal(res.Status.UserInfo.Username))
   153  			gomega.Expect(config.Impersonate.UID).To(gomega.Equal(res.Status.UserInfo.UID))
   154  			gomega.Expect(config.Impersonate.Groups).To(gomega.Equal(res.Status.UserInfo.Groups))
   155  
   156  			extra := make(map[string][]string, len(res.Status.UserInfo.Extra))
   157  			for k, v := range res.Status.UserInfo.Extra {
   158  				extra[k] = v
   159  			}
   160  
   161  			gomega.Expect(config.Impersonate.Extra).To(gomega.Equal(extra))
   162  		}
   163  
   164  		ginkgo.By("creating SSR authentication/v1")
   165  		{
   166  			config := restConfig(f)
   167  
   168  			ssrClient := kubernetes.NewForConfigOrDie(config).AuthenticationV1().SelfSubjectReviews()
   169  			res, err := ssrClient.Create(ctx, &authenticationv1.SelfSubjectReview{}, metav1.CreateOptions{})
   170  			framework.ExpectNoError(err)
   171  
   172  			gomega.Expect(config.Impersonate.UserName).To(gomega.Equal(res.Status.UserInfo.Username))
   173  			gomega.Expect(config.Impersonate.UID).To(gomega.Equal(res.Status.UserInfo.UID))
   174  			gomega.Expect(config.Impersonate.Groups).To(gomega.Equal(res.Status.UserInfo.Groups))
   175  
   176  			extra := make(map[string][]string, len(res.Status.UserInfo.Extra))
   177  			for k, v := range res.Status.UserInfo.Extra {
   178  				extra[k] = v
   179  			}
   180  
   181  			gomega.Expect(config.Impersonate.Extra).To(gomega.Equal(extra))
   182  		}
   183  	})
   184  })
   185  
   186  func restConfig(f *framework.Framework) *rest.Config {
   187  	// Use impersonate to make user attributes predictable
   188  	config := f.ClientConfig()
   189  	config.Impersonate.UserName = "jane-doe"
   190  	config.Impersonate.UID = "uniq-id"
   191  	config.Impersonate.Groups = []string{"system:authenticated", "developers"}
   192  	config.Impersonate.Extra = map[string][]string{
   193  		"known-languages": {"python", "javascript"},
   194  	}
   195  
   196  	return config
   197  }