...

Source file src/k8s.io/kubernetes/test/integration/auth/bootstraptoken_test.go

Documentation: k8s.io/kubernetes/test/integration/auth

     1  /*
     2  Copyright 2017 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  	"bytes"
    21  	"fmt"
    22  	"io"
    23  	"net/http"
    24  	"testing"
    25  	"time"
    26  
    27  	corev1 "k8s.io/api/core/v1"
    28  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    29  	"k8s.io/apimachinery/pkg/labels"
    30  	"k8s.io/apiserver/pkg/authentication/group"
    31  	"k8s.io/apiserver/pkg/authentication/request/bearertoken"
    32  	"k8s.io/client-go/rest"
    33  	bootstrapapi "k8s.io/cluster-bootstrap/token/api"
    34  	"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
    35  	"k8s.io/kubernetes/pkg/controlplane"
    36  	"k8s.io/kubernetes/plugin/pkg/auth/authenticator/token/bootstrap"
    37  	"k8s.io/kubernetes/test/integration"
    38  	"k8s.io/kubernetes/test/integration/framework"
    39  	"k8s.io/kubernetes/test/utils/ktesting"
    40  )
    41  
    42  type bootstrapSecrets []*corev1.Secret
    43  
    44  func (b bootstrapSecrets) List(selector labels.Selector) (ret []*corev1.Secret, err error) {
    45  	return b, nil
    46  }
    47  
    48  func (b bootstrapSecrets) Get(name string) (*corev1.Secret, error) {
    49  	return b[0], nil
    50  }
    51  
    52  // TestBootstrapTokenAuth tests the bootstrap token auth provider
    53  func TestBootstrapTokenAuth(t *testing.T) {
    54  	validTokenID := "token1"
    55  	validSecret := "validtokensecret"
    56  	var bootstrapSecretValid = &corev1.Secret{
    57  		ObjectMeta: metav1.ObjectMeta{
    58  			Namespace: metav1.NamespaceSystem,
    59  			Name:      bootstrapapi.BootstrapTokenSecretPrefix,
    60  		},
    61  		Type: corev1.SecretTypeBootstrapToken,
    62  		Data: map[string][]byte{
    63  			bootstrapapi.BootstrapTokenIDKey:               []byte(validTokenID),
    64  			bootstrapapi.BootstrapTokenSecretKey:           []byte(validSecret),
    65  			bootstrapapi.BootstrapTokenUsageAuthentication: []byte("true"),
    66  		},
    67  	}
    68  	var bootstrapSecretInvalid = &corev1.Secret{
    69  		ObjectMeta: metav1.ObjectMeta{
    70  			Namespace: metav1.NamespaceSystem,
    71  			Name:      bootstrapapi.BootstrapTokenSecretPrefix,
    72  		},
    73  		Type: corev1.SecretTypeBootstrapToken,
    74  		Data: map[string][]byte{
    75  			bootstrapapi.BootstrapTokenIDKey:               []byte(validTokenID),
    76  			bootstrapapi.BootstrapTokenSecretKey:           []byte("invalid"),
    77  			bootstrapapi.BootstrapTokenUsageAuthentication: []byte("true"),
    78  		},
    79  	}
    80  	tokenExpiredTime := time.Now().UTC().Add(-time.Hour).Format(time.RFC3339)
    81  	var expiredBootstrapToken = &corev1.Secret{
    82  		ObjectMeta: metav1.ObjectMeta{
    83  			Namespace: metav1.NamespaceSystem,
    84  			Name:      bootstrapapi.BootstrapTokenSecretPrefix,
    85  		},
    86  		Type: corev1.SecretTypeBootstrapToken,
    87  		Data: map[string][]byte{
    88  			bootstrapapi.BootstrapTokenIDKey:               []byte(validTokenID),
    89  			bootstrapapi.BootstrapTokenSecretKey:           []byte("invalid"),
    90  			bootstrapapi.BootstrapTokenUsageAuthentication: []byte("true"),
    91  			bootstrapapi.BootstrapTokenExpirationKey:       []byte(tokenExpiredTime),
    92  		},
    93  	}
    94  	type request struct {
    95  		verb        string
    96  		URL         string
    97  		body        string
    98  		statusCodes map[int]bool // Set of expected resp.StatusCode if all goes well.
    99  	}
   100  	tests := []struct {
   101  		name    string
   102  		request request
   103  		secret  *corev1.Secret
   104  	}{
   105  		{
   106  			name:    "valid token",
   107  			request: request{verb: "GET", URL: path("pods", "", ""), body: "", statusCodes: integration.Code200},
   108  			secret:  bootstrapSecretValid,
   109  		},
   110  		{
   111  			name:    "invalid token format",
   112  			request: request{verb: "GET", URL: path("pods", "", ""), body: "", statusCodes: integration.Code401},
   113  			secret:  bootstrapSecretInvalid,
   114  		},
   115  		{
   116  			name:    "invalid token expired",
   117  			request: request{verb: "GET", URL: path("pods", "", ""), body: "", statusCodes: integration.Code401},
   118  			secret:  expiredBootstrapToken,
   119  		},
   120  	}
   121  	for _, test := range tests {
   122  		t.Run(test.name, func(t *testing.T) {
   123  			tCtx := ktesting.Init(t)
   124  			authenticator := group.NewAuthenticatedGroupAdder(bearertoken.New(bootstrap.NewTokenAuthenticator(bootstrapSecrets{test.secret})))
   125  
   126  			kubeClient, kubeConfig, tearDownFn := framework.StartTestServer(tCtx, t, framework.TestServerSetup{
   127  				ModifyServerRunOptions: func(opts *options.ServerRunOptions) {
   128  					opts.Authorization.Modes = []string{"AlwaysAllow"}
   129  				},
   130  				ModifyServerConfig: func(config *controlplane.Config) {
   131  					config.GenericConfig.Authentication.Authenticator = authenticator
   132  				},
   133  			})
   134  			defer tearDownFn()
   135  
   136  			ns := framework.CreateNamespaceOrDie(kubeClient, "auth-bootstrap-token", t)
   137  			defer framework.DeleteNamespaceOrDie(kubeClient, ns, t)
   138  
   139  			previousResourceVersion := make(map[string]float64)
   140  			transport, err := rest.TransportFor(kubeConfig)
   141  			if err != nil {
   142  				t.Fatal(err)
   143  			}
   144  
   145  			token := validTokenID + "." + validSecret
   146  			var bodyStr string
   147  			if test.request.body != "" {
   148  				sub := ""
   149  				if test.request.verb == "PUT" {
   150  					// For update operations, insert previous resource version
   151  					if resVersion := previousResourceVersion[getPreviousResourceVersionKey(test.request.URL, "")]; resVersion != 0 {
   152  						sub += fmt.Sprintf(",\r\n\"resourceVersion\": \"%v\"", resVersion)
   153  					}
   154  					sub += fmt.Sprintf(",\r\n\"namespace\": %q", ns.Name)
   155  				}
   156  				bodyStr = fmt.Sprintf(test.request.body, sub)
   157  			}
   158  			test.request.body = bodyStr
   159  			bodyBytes := bytes.NewReader([]byte(bodyStr))
   160  			req, err := http.NewRequest(test.request.verb, kubeConfig.Host+test.request.URL, bodyBytes)
   161  			if err != nil {
   162  				t.Fatalf("unexpected error: %v", err)
   163  			}
   164  			req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
   165  			if test.request.verb == "PATCH" {
   166  				req.Header.Set("Content-Type", "application/merge-patch+json")
   167  			}
   168  
   169  			func() {
   170  				resp, err := transport.RoundTrip(req)
   171  				if err != nil {
   172  					t.Logf("case %v", test.name)
   173  					t.Fatalf("unexpected error: %v", err)
   174  				}
   175  				defer resp.Body.Close()
   176  				b, _ := io.ReadAll(resp.Body)
   177  				if _, ok := test.request.statusCodes[resp.StatusCode]; !ok {
   178  					t.Logf("case %v", test.name)
   179  					t.Errorf("Expected status one of %v, but got %v", test.request.statusCodes, resp.StatusCode)
   180  					t.Errorf("Body: %v", string(b))
   181  				} else {
   182  					if test.request.verb == "POST" {
   183  						// For successful create operations, extract resourceVersion
   184  						id, currentResourceVersion, err := parseResourceVersion(b)
   185  						if err == nil {
   186  							key := getPreviousResourceVersionKey(test.request.URL, id)
   187  							previousResourceVersion[key] = currentResourceVersion
   188  						}
   189  					}
   190  				}
   191  
   192  			}()
   193  		})
   194  	}
   195  }
   196  

View as plain text