mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			141 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			141 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
/*
 | 
						|
Copyright 2018 The Kubernetes Authors.
 | 
						|
 | 
						|
Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
you may not use this file except in compliance with the License.
 | 
						|
You may obtain a copy of the License at
 | 
						|
 | 
						|
    http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 | 
						|
Unless required by applicable law or agreed to in writing, software
 | 
						|
distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
See the License for the specific language governing permissions and
 | 
						|
limitations under the License.
 | 
						|
*/
 | 
						|
 | 
						|
package serviceaccount
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
	"context"
 | 
						|
	"errors"
 | 
						|
	"fmt"
 | 
						|
 | 
						|
	"gopkg.in/square/go-jose.v2/jwt"
 | 
						|
	"k8s.io/klog/v2"
 | 
						|
 | 
						|
	"k8s.io/api/core/v1"
 | 
						|
	apiserverserviceaccount "k8s.io/apiserver/pkg/authentication/serviceaccount"
 | 
						|
)
 | 
						|
 | 
						|
func LegacyClaims(serviceAccount v1.ServiceAccount, secret v1.Secret) (*jwt.Claims, interface{}) {
 | 
						|
	return &jwt.Claims{
 | 
						|
			Subject: apiserverserviceaccount.MakeUsername(serviceAccount.Namespace, serviceAccount.Name),
 | 
						|
		}, &legacyPrivateClaims{
 | 
						|
			Namespace:          serviceAccount.Namespace,
 | 
						|
			ServiceAccountName: serviceAccount.Name,
 | 
						|
			ServiceAccountUID:  string(serviceAccount.UID),
 | 
						|
			SecretName:         secret.Name,
 | 
						|
		}
 | 
						|
}
 | 
						|
 | 
						|
const LegacyIssuer = "kubernetes/serviceaccount"
 | 
						|
 | 
						|
type legacyPrivateClaims struct {
 | 
						|
	ServiceAccountName string `json:"kubernetes.io/serviceaccount/service-account.name"`
 | 
						|
	ServiceAccountUID  string `json:"kubernetes.io/serviceaccount/service-account.uid"`
 | 
						|
	SecretName         string `json:"kubernetes.io/serviceaccount/secret.name"`
 | 
						|
	Namespace          string `json:"kubernetes.io/serviceaccount/namespace"`
 | 
						|
}
 | 
						|
 | 
						|
func NewLegacyValidator(lookup bool, getter ServiceAccountTokenGetter) Validator {
 | 
						|
	return &legacyValidator{
 | 
						|
		lookup: lookup,
 | 
						|
		getter: getter,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
type legacyValidator struct {
 | 
						|
	lookup bool
 | 
						|
	getter ServiceAccountTokenGetter
 | 
						|
}
 | 
						|
 | 
						|
var _ = Validator(&legacyValidator{})
 | 
						|
 | 
						|
func (v *legacyValidator) Validate(ctx context.Context, tokenData string, public *jwt.Claims, privateObj interface{}) (*apiserverserviceaccount.ServiceAccountInfo, error) {
 | 
						|
	private, ok := privateObj.(*legacyPrivateClaims)
 | 
						|
	if !ok {
 | 
						|
		klog.Errorf("jwt validator expected private claim of type *legacyPrivateClaims but got: %T", privateObj)
 | 
						|
		return nil, errors.New("Token could not be validated.")
 | 
						|
	}
 | 
						|
 | 
						|
	// Make sure the claims we need exist
 | 
						|
	if len(public.Subject) == 0 {
 | 
						|
		return nil, errors.New("sub claim is missing")
 | 
						|
	}
 | 
						|
	namespace := private.Namespace
 | 
						|
	if len(namespace) == 0 {
 | 
						|
		return nil, errors.New("namespace claim is missing")
 | 
						|
	}
 | 
						|
	secretName := private.SecretName
 | 
						|
	if len(secretName) == 0 {
 | 
						|
		return nil, errors.New("secretName claim is missing")
 | 
						|
	}
 | 
						|
	serviceAccountName := private.ServiceAccountName
 | 
						|
	if len(serviceAccountName) == 0 {
 | 
						|
		return nil, errors.New("serviceAccountName claim is missing")
 | 
						|
	}
 | 
						|
	serviceAccountUID := private.ServiceAccountUID
 | 
						|
	if len(serviceAccountUID) == 0 {
 | 
						|
		return nil, errors.New("serviceAccountUID claim is missing")
 | 
						|
	}
 | 
						|
 | 
						|
	subjectNamespace, subjectName, err := apiserverserviceaccount.SplitUsername(public.Subject)
 | 
						|
	if err != nil || subjectNamespace != namespace || subjectName != serviceAccountName {
 | 
						|
		return nil, errors.New("sub claim is invalid")
 | 
						|
	}
 | 
						|
 | 
						|
	if v.lookup {
 | 
						|
		// Make sure token hasn't been invalidated by deletion of the secret
 | 
						|
		secret, err := v.getter.GetSecret(namespace, secretName)
 | 
						|
		if err != nil {
 | 
						|
			klog.V(4).Infof("Could not retrieve token %s/%s for service account %s/%s: %v", namespace, secretName, namespace, serviceAccountName, err)
 | 
						|
			return nil, errors.New("Token has been invalidated")
 | 
						|
		}
 | 
						|
		if secret.DeletionTimestamp != nil {
 | 
						|
			klog.V(4).Infof("Token is deleted and awaiting removal: %s/%s for service account %s/%s", namespace, secretName, namespace, serviceAccountName)
 | 
						|
			return nil, errors.New("Token has been invalidated")
 | 
						|
		}
 | 
						|
		if !bytes.Equal(secret.Data[v1.ServiceAccountTokenKey], []byte(tokenData)) {
 | 
						|
			klog.V(4).Infof("Token contents no longer matches %s/%s for service account %s/%s", namespace, secretName, namespace, serviceAccountName)
 | 
						|
			return nil, errors.New("Token does not match server's copy")
 | 
						|
		}
 | 
						|
 | 
						|
		// Make sure service account still exists (name and UID)
 | 
						|
		serviceAccount, err := v.getter.GetServiceAccount(namespace, serviceAccountName)
 | 
						|
		if err != nil {
 | 
						|
			klog.V(4).Infof("Could not retrieve service account %s/%s: %v", namespace, serviceAccountName, err)
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
		if serviceAccount.DeletionTimestamp != nil {
 | 
						|
			klog.V(4).Infof("Service account has been deleted %s/%s", namespace, serviceAccountName)
 | 
						|
			return nil, fmt.Errorf("ServiceAccount %s/%s has been deleted", namespace, serviceAccountName)
 | 
						|
		}
 | 
						|
		if string(serviceAccount.UID) != serviceAccountUID {
 | 
						|
			klog.V(4).Infof("Service account UID no longer matches %s/%s: %q != %q", namespace, serviceAccountName, string(serviceAccount.UID), serviceAccountUID)
 | 
						|
			return nil, fmt.Errorf("ServiceAccount UID (%s) does not match claim (%s)", serviceAccount.UID, serviceAccountUID)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return &apiserverserviceaccount.ServiceAccountInfo{
 | 
						|
		Namespace: private.Namespace,
 | 
						|
		Name:      private.ServiceAccountName,
 | 
						|
		UID:       private.ServiceAccountUID,
 | 
						|
	}, nil
 | 
						|
}
 | 
						|
 | 
						|
func (v *legacyValidator) NewPrivateClaims() interface{} {
 | 
						|
	return &legacyPrivateClaims{}
 | 
						|
}
 |