mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	Enforce sa token node audience restriction when ServiceAccountNodeAudienceRestriction=true
Signed-off-by: Anish Ramasekar <anish.ramasekar@gmail.com>
This commit is contained in:
		@@ -24,17 +24,21 @@ import (
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/go-cmp/cmp"
 | 
			
		||||
 | 
			
		||||
	v1 "k8s.io/api/core/v1"
 | 
			
		||||
	apiequality "k8s.io/apimachinery/pkg/api/equality"
 | 
			
		||||
	apierrors "k8s.io/apimachinery/pkg/api/errors"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/api/meta"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/labels"
 | 
			
		||||
	utilerrors "k8s.io/apimachinery/pkg/util/errors"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/sets"
 | 
			
		||||
	"k8s.io/apiserver/pkg/admission"
 | 
			
		||||
	apiserveradmission "k8s.io/apiserver/pkg/admission/initializer"
 | 
			
		||||
	"k8s.io/client-go/informers"
 | 
			
		||||
	corev1lister "k8s.io/client-go/listers/core/v1"
 | 
			
		||||
	storagelisters "k8s.io/client-go/listers/storage/v1"
 | 
			
		||||
	"k8s.io/component-base/featuregate"
 | 
			
		||||
	"k8s.io/component-helpers/storage/ephemeral"
 | 
			
		||||
	kubeletapis "k8s.io/kubelet/pkg/apis"
 | 
			
		||||
	podutil "k8s.io/kubernetes/pkg/api/pod"
 | 
			
		||||
	authenticationapi "k8s.io/kubernetes/pkg/apis/authentication"
 | 
			
		||||
@@ -43,7 +47,7 @@ import (
 | 
			
		||||
	api "k8s.io/kubernetes/pkg/apis/core"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/apis/policy"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/apis/resource"
 | 
			
		||||
	storage "k8s.io/kubernetes/pkg/apis/storage"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/apis/storage"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/auth/nodeidentifier"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/features"
 | 
			
		||||
)
 | 
			
		||||
@@ -70,13 +74,17 @@ func NewPlugin(nodeIdentifier nodeidentifier.NodeIdentifier) *Plugin {
 | 
			
		||||
// Plugin holds state for and implements the admission plugin.
 | 
			
		||||
type Plugin struct {
 | 
			
		||||
	*admission.Handler
 | 
			
		||||
	nodeIdentifier nodeidentifier.NodeIdentifier
 | 
			
		||||
	podsGetter     corev1lister.PodLister
 | 
			
		||||
	nodesGetter    corev1lister.NodeLister
 | 
			
		||||
	nodeIdentifier  nodeidentifier.NodeIdentifier
 | 
			
		||||
	podsGetter      corev1lister.PodLister
 | 
			
		||||
	nodesGetter     corev1lister.NodeLister
 | 
			
		||||
	csiDriverGetter storagelisters.CSIDriverLister
 | 
			
		||||
	pvcGetter       corev1lister.PersistentVolumeClaimLister
 | 
			
		||||
	pvGetter        corev1lister.PersistentVolumeLister
 | 
			
		||||
 | 
			
		||||
	expansionRecoveryEnabled                       bool
 | 
			
		||||
	dynamicResourceAllocationEnabled               bool
 | 
			
		||||
	allowInsecureKubeletCertificateSigningRequests bool
 | 
			
		||||
	serviceAccountNodeAudienceRestriction          bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
@@ -90,12 +98,18 @@ func (p *Plugin) InspectFeatureGates(featureGates featuregate.FeatureGate) {
 | 
			
		||||
	p.expansionRecoveryEnabled = featureGates.Enabled(features.RecoverVolumeExpansionFailure)
 | 
			
		||||
	p.dynamicResourceAllocationEnabled = featureGates.Enabled(features.DynamicResourceAllocation)
 | 
			
		||||
	p.allowInsecureKubeletCertificateSigningRequests = featureGates.Enabled(features.AllowInsecureKubeletCertificateSigningRequests)
 | 
			
		||||
	p.serviceAccountNodeAudienceRestriction = featureGates.Enabled(features.ServiceAccountNodeAudienceRestriction)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetExternalKubeInformerFactory registers an informer factory into Plugin
 | 
			
		||||
func (p *Plugin) SetExternalKubeInformerFactory(f informers.SharedInformerFactory) {
 | 
			
		||||
	p.podsGetter = f.Core().V1().Pods().Lister()
 | 
			
		||||
	p.nodesGetter = f.Core().V1().Nodes().Lister()
 | 
			
		||||
	if p.serviceAccountNodeAudienceRestriction {
 | 
			
		||||
		p.csiDriverGetter = f.Storage().V1().CSIDrivers().Lister()
 | 
			
		||||
		p.pvcGetter = f.Core().V1().PersistentVolumeClaims().Lister()
 | 
			
		||||
		p.pvGetter = f.Core().V1().PersistentVolumes().Lister()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ValidateInitialization validates the Plugin was initialized properly
 | 
			
		||||
@@ -109,6 +123,17 @@ func (p *Plugin) ValidateInitialization() error {
 | 
			
		||||
	if p.nodesGetter == nil {
 | 
			
		||||
		return fmt.Errorf("%s requires a node getter", PluginName)
 | 
			
		||||
	}
 | 
			
		||||
	if p.serviceAccountNodeAudienceRestriction {
 | 
			
		||||
		if p.csiDriverGetter == nil {
 | 
			
		||||
			return fmt.Errorf("%s requires a CSI driver getter", PluginName)
 | 
			
		||||
		}
 | 
			
		||||
		if p.pvcGetter == nil {
 | 
			
		||||
			return fmt.Errorf("%s requires a PVC getter", PluginName)
 | 
			
		||||
		}
 | 
			
		||||
		if p.pvGetter == nil {
 | 
			
		||||
			return fmt.Errorf("%s requires a PV getter", PluginName)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -594,6 +619,12 @@ func (p *Plugin) admitServiceAccount(nodeName string, a admission.Attributes) er
 | 
			
		||||
		return admission.NewForbidden(a, fmt.Errorf("node requested token bound to a pod scheduled on a different node"))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if p.serviceAccountNodeAudienceRestriction {
 | 
			
		||||
		if err := p.validateNodeServiceAccountAudience(tr, pod); err != nil {
 | 
			
		||||
			return admission.NewForbidden(a, err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Note: A token may only be bound to one object at a time. By requiring
 | 
			
		||||
	// the Pod binding, noderestriction eliminates the opportunity to spoof
 | 
			
		||||
	// a Node binding. Instead, kube-apiserver automatically infers and sets
 | 
			
		||||
@@ -603,6 +634,106 @@ func (p *Plugin) admitServiceAccount(nodeName string, a admission.Attributes) er
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Plugin) validateNodeServiceAccountAudience(tr *authenticationapi.TokenRequest, pod *v1.Pod) error {
 | 
			
		||||
	// ensure all items in tr.Spec.Audiences are present in a volume mount in the pod
 | 
			
		||||
	requestedAudience := ""
 | 
			
		||||
	switch len(tr.Spec.Audiences) {
 | 
			
		||||
	case 0:
 | 
			
		||||
		requestedAudience = ""
 | 
			
		||||
	case 1:
 | 
			
		||||
		requestedAudience = tr.Spec.Audiences[0]
 | 
			
		||||
	default:
 | 
			
		||||
		return fmt.Errorf("node may only request 0 or 1 audiences")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	foundAudiencesInPodSpec, err := p.podReferencesAudience(pod, requestedAudience)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("error validating audience %q: %w", requestedAudience, err)
 | 
			
		||||
	}
 | 
			
		||||
	if !foundAudiencesInPodSpec {
 | 
			
		||||
		return fmt.Errorf("audience %q not found in pod spec volume", requestedAudience)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Plugin) podReferencesAudience(pod *v1.Pod, audience string) (bool, error) {
 | 
			
		||||
	var errs []error
 | 
			
		||||
 | 
			
		||||
	for _, v := range pod.Spec.Volumes {
 | 
			
		||||
		if v.Projected != nil {
 | 
			
		||||
			for _, src := range v.Projected.Sources {
 | 
			
		||||
				if src.ServiceAccountToken != nil && src.ServiceAccountToken.Audience == audience {
 | 
			
		||||
					return true, nil
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// also allow audiences for CSI token requests
 | 
			
		||||
		// - pod --> ephemeral --> pvc --> pv --> csi --> driver --> tokenrequest with audience
 | 
			
		||||
		// - pod --> pvc --> pv --> csi --> driver --> tokenrequest with audience
 | 
			
		||||
		// - pod --> csi --> driver --> tokenrequest with audience
 | 
			
		||||
		var driverName string
 | 
			
		||||
		var err error
 | 
			
		||||
		switch {
 | 
			
		||||
		case v.Ephemeral != nil && v.Ephemeral.VolumeClaimTemplate != nil:
 | 
			
		||||
			pvcName := ephemeral.VolumeClaimName(pod, &v)
 | 
			
		||||
			driverName, err = p.getCSIFromPVC(pod.Namespace, pvcName)
 | 
			
		||||
		case v.PersistentVolumeClaim != nil:
 | 
			
		||||
			driverName, err = p.getCSIFromPVC(pod.Namespace, v.PersistentVolumeClaim.ClaimName)
 | 
			
		||||
		case v.CSI != nil:
 | 
			
		||||
			driverName = v.CSI.Driver
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			errs = append(errs, err)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if len(driverName) > 0 {
 | 
			
		||||
			hasAudience, hasAudienceErr := p.csiDriverHasAudience(driverName, audience)
 | 
			
		||||
			if hasAudienceErr != nil {
 | 
			
		||||
				errs = append(errs, hasAudienceErr)
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			if hasAudience {
 | 
			
		||||
				return true, nil
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false, utilerrors.NewAggregate(errs)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getCSIFromPVC returns the CSI driver name from the PVC->PV->CSI->Driver chain
 | 
			
		||||
func (p *Plugin) getCSIFromPVC(namespace, claimName string) (string, error) {
 | 
			
		||||
	pvc, err := p.pvcGetter.PersistentVolumeClaims(namespace).Get(claimName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	pv, err := p.pvGetter.Get(pvc.Spec.VolumeName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	if pv.Spec.CSI != nil {
 | 
			
		||||
		return pv.Spec.CSI.Driver, nil
 | 
			
		||||
	}
 | 
			
		||||
	return "", nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Plugin) csiDriverHasAudience(driverName, audience string) (bool, error) {
 | 
			
		||||
	driver, err := p.csiDriverGetter.Get(driverName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, tokenRequest := range driver.Spec.TokenRequests {
 | 
			
		||||
		if tokenRequest.Audience == audience {
 | 
			
		||||
			return true, nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Plugin) admitLease(nodeName string, a admission.Attributes) error {
 | 
			
		||||
	// the request must be against the system namespace reserved for node leases
 | 
			
		||||
	if a.GetNamespace() != api.NamespaceNodeLease {
 | 
			
		||||
 
 | 
			
		||||
@@ -28,11 +28,8 @@ import (
 | 
			
		||||
	"testing"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"k8s.io/apiserver/pkg/util/feature"
 | 
			
		||||
	featuregatetesting "k8s.io/component-base/featuregate/testing"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/features"
 | 
			
		||||
 | 
			
		||||
	corev1 "k8s.io/api/core/v1"
 | 
			
		||||
	storagev1 "k8s.io/api/storage/v1"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/api/resource"
 | 
			
		||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/runtime"
 | 
			
		||||
@@ -41,9 +38,12 @@ import (
 | 
			
		||||
	"k8s.io/apimachinery/pkg/util/sets"
 | 
			
		||||
	"k8s.io/apiserver/pkg/admission"
 | 
			
		||||
	"k8s.io/apiserver/pkg/authentication/user"
 | 
			
		||||
	"k8s.io/apiserver/pkg/util/feature"
 | 
			
		||||
	corev1lister "k8s.io/client-go/listers/core/v1"
 | 
			
		||||
	storagelisters "k8s.io/client-go/listers/storage/v1"
 | 
			
		||||
	"k8s.io/client-go/tools/cache"
 | 
			
		||||
	"k8s.io/component-base/featuregate"
 | 
			
		||||
	featuregatetesting "k8s.io/component-base/featuregate/testing"
 | 
			
		||||
	kubeletapis "k8s.io/kubelet/pkg/apis"
 | 
			
		||||
	authenticationapi "k8s.io/kubernetes/pkg/apis/authentication"
 | 
			
		||||
	certificatesapi "k8s.io/kubernetes/pkg/apis/certificates"
 | 
			
		||||
@@ -51,8 +51,9 @@ import (
 | 
			
		||||
	api "k8s.io/kubernetes/pkg/apis/core"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/apis/policy"
 | 
			
		||||
	resourceapi "k8s.io/kubernetes/pkg/apis/resource"
 | 
			
		||||
	storage "k8s.io/kubernetes/pkg/apis/storage"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/apis/storage"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/auth/nodeidentifier"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/features"
 | 
			
		||||
	"k8s.io/utils/pointer"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -107,10 +108,10 @@ func makeTestPodEviction(name string) *policy.Eviction {
 | 
			
		||||
	return eviction
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func makeTokenRequest(podname string, poduid types.UID) *authenticationapi.TokenRequest {
 | 
			
		||||
func makeTokenRequest(podname string, poduid types.UID, audiences []string) *authenticationapi.TokenRequest {
 | 
			
		||||
	tr := &authenticationapi.TokenRequest{
 | 
			
		||||
		Spec: authenticationapi.TokenRequestSpec{
 | 
			
		||||
			Audiences: []string{"foo"},
 | 
			
		||||
			Audiences: audiences,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	if podname != "" {
 | 
			
		||||
@@ -214,13 +215,16 @@ func setForbiddenUpdateLabels(node *api.Node, value string) *api.Node {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type admitTestCase struct {
 | 
			
		||||
	name        string
 | 
			
		||||
	podsGetter  corev1lister.PodLister
 | 
			
		||||
	nodesGetter corev1lister.NodeLister
 | 
			
		||||
	attributes  admission.Attributes
 | 
			
		||||
	features    featuregate.FeatureGate
 | 
			
		||||
	setupFunc   func(t *testing.T)
 | 
			
		||||
	err         string
 | 
			
		||||
	name            string
 | 
			
		||||
	podsGetter      corev1lister.PodLister
 | 
			
		||||
	nodesGetter     corev1lister.NodeLister
 | 
			
		||||
	csiDriverGetter storagelisters.CSIDriverLister
 | 
			
		||||
	pvcGetter       corev1lister.PersistentVolumeClaimLister
 | 
			
		||||
	pvGetter        corev1lister.PersistentVolumeLister
 | 
			
		||||
	attributes      admission.Attributes
 | 
			
		||||
	features        featuregate.FeatureGate
 | 
			
		||||
	setupFunc       func(t *testing.T)
 | 
			
		||||
	err             string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (a *admitTestCase) run(t *testing.T) {
 | 
			
		||||
@@ -234,6 +238,9 @@ func (a *admitTestCase) run(t *testing.T) {
 | 
			
		||||
		}
 | 
			
		||||
		c.podsGetter = a.podsGetter
 | 
			
		||||
		c.nodesGetter = a.nodesGetter
 | 
			
		||||
		c.csiDriverGetter = a.csiDriverGetter
 | 
			
		||||
		c.pvcGetter = a.pvcGetter
 | 
			
		||||
		c.pvGetter = a.pvGetter
 | 
			
		||||
		err := c.Admit(context.TODO(), a.attributes, nil)
 | 
			
		||||
		if (err == nil) != (len(a.err) == 0) {
 | 
			
		||||
			t.Errorf("nodePlugin.Admit() error = %v, expected %v", err, a.err)
 | 
			
		||||
@@ -387,8 +394,100 @@ func Test_nodePlugin_Admit(t *testing.T) {
 | 
			
		||||
		abLabeledPod = withLabels(coremypod, labelsAB)
 | 
			
		||||
 | 
			
		||||
		privKey, _ = rsa.GenerateKey(rand.Reader, 2048)
 | 
			
		||||
 | 
			
		||||
		csiDriverWithAudience = &storagev1.CSIDriver{
 | 
			
		||||
			ObjectMeta: metav1.ObjectMeta{
 | 
			
		||||
				Name: "com.example.csi.mydriver",
 | 
			
		||||
			},
 | 
			
		||||
			Spec: storagev1.CSIDriverSpec{
 | 
			
		||||
				TokenRequests: []storagev1.TokenRequest{
 | 
			
		||||
					{
 | 
			
		||||
						Audience: "foo",
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		csiDriverIndex  = cache.NewIndexer(cache.MetaNamespaceKeyFunc, nil)
 | 
			
		||||
		csiDriverLister = storagelisters.NewCSIDriverLister(csiDriverIndex)
 | 
			
		||||
 | 
			
		||||
		noexistingCSIDriverIndex  = cache.NewIndexer(cache.MetaNamespaceKeyFunc, nil)
 | 
			
		||||
		noexistingCSIDriverLister = storagelisters.NewCSIDriverLister(noexistingCSIDriverIndex)
 | 
			
		||||
 | 
			
		||||
		pvcWithCSIDriver = &corev1.PersistentVolumeClaim{
 | 
			
		||||
			ObjectMeta: metav1.ObjectMeta{
 | 
			
		||||
				Name:      "pvclaim",
 | 
			
		||||
				Namespace: "ns",
 | 
			
		||||
			},
 | 
			
		||||
			Spec: corev1.PersistentVolumeClaimSpec{
 | 
			
		||||
				VolumeName: "pvname",
 | 
			
		||||
			},
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ephemeralVolumePVCWithCSIDriver = &corev1.PersistentVolumeClaim{
 | 
			
		||||
			ObjectMeta: metav1.ObjectMeta{
 | 
			
		||||
				Name:      "myephemeralpod-myvol",
 | 
			
		||||
				Namespace: "ns",
 | 
			
		||||
			},
 | 
			
		||||
			Spec: corev1.PersistentVolumeClaimSpec{
 | 
			
		||||
				VolumeName: "pvname",
 | 
			
		||||
			},
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		pvcIndex  = cache.NewIndexer(cache.MetaNamespaceKeyFunc, nil)
 | 
			
		||||
		pvcLister = corev1lister.NewPersistentVolumeClaimLister(pvcIndex)
 | 
			
		||||
 | 
			
		||||
		noexistingPVCIndex  = cache.NewIndexer(cache.MetaNamespaceKeyFunc, nil)
 | 
			
		||||
		noexistingPVCLister = corev1lister.NewPersistentVolumeClaimLister(noexistingPVCIndex)
 | 
			
		||||
 | 
			
		||||
		pvWithCSIDriver = &corev1.PersistentVolume{
 | 
			
		||||
			ObjectMeta: metav1.ObjectMeta{
 | 
			
		||||
				Name: "pvname",
 | 
			
		||||
			},
 | 
			
		||||
			Spec: corev1.PersistentVolumeSpec{
 | 
			
		||||
				PersistentVolumeSource: corev1.PersistentVolumeSource{
 | 
			
		||||
					CSI: &corev1.CSIPersistentVolumeSource{Driver: "com.example.csi.mydriver"},
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		pvIndex  = cache.NewIndexer(cache.MetaNamespaceKeyFunc, nil)
 | 
			
		||||
		pvLister = corev1lister.NewPersistentVolumeLister(pvIndex)
 | 
			
		||||
 | 
			
		||||
		noexistingPVIndex  = cache.NewIndexer(cache.MetaNamespaceKeyFunc, nil)
 | 
			
		||||
		noexistingPVLister = corev1lister.NewPersistentVolumeLister(noexistingPVIndex)
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	// create pods for validating the service account node audience restriction
 | 
			
		||||
	projectedVolumeSourceEmptyAudience := &corev1.ProjectedVolumeSource{Sources: []corev1.VolumeProjection{{ServiceAccountToken: &corev1.ServiceAccountTokenProjection{Audience: ""}}}}
 | 
			
		||||
	projectedVolumeSource := &corev1.ProjectedVolumeSource{Sources: []corev1.VolumeProjection{{ServiceAccountToken: &corev1.ServiceAccountTokenProjection{Audience: "foo"}}}}
 | 
			
		||||
	csiDriverVolumeSource := &corev1.CSIVolumeSource{Driver: "com.example.csi.mydriver"}
 | 
			
		||||
	persistentVolumeClaimVolumeSource := &corev1.PersistentVolumeClaimVolumeSource{ClaimName: "pvclaim"}
 | 
			
		||||
	ephemeralVolumeSource := &corev1.EphemeralVolumeSource{VolumeClaimTemplate: &corev1.PersistentVolumeClaimTemplate{}}
 | 
			
		||||
 | 
			
		||||
	coremypodWithProjectedServiceAccountEmptyAudience, v1mypodWithProjectedServiceAccountEmptyAudience := makeTestPod("ns", "mysapod", "mynode", false)
 | 
			
		||||
	v1mypodWithProjectedServiceAccountEmptyAudience.Spec.Volumes = []corev1.Volume{{VolumeSource: corev1.VolumeSource{Projected: projectedVolumeSourceEmptyAudience}}}
 | 
			
		||||
 | 
			
		||||
	coremypodWithProjectedServiceAccount, v1mypodWithProjectedServiceAccount := makeTestPod("ns", "mysapod", "mynode", false)
 | 
			
		||||
	v1mypodWithProjectedServiceAccount.Spec.Volumes = []corev1.Volume{{VolumeSource: corev1.VolumeSource{Projected: projectedVolumeSource}}}
 | 
			
		||||
 | 
			
		||||
	coremypodWithCSI, v1mypodWithCSI := makeTestPod("ns", "mycsipod", "mynode", false)
 | 
			
		||||
	v1mypodWithCSI.Spec.Volumes = []corev1.Volume{{VolumeSource: corev1.VolumeSource{CSI: csiDriverVolumeSource}}}
 | 
			
		||||
 | 
			
		||||
	coremypodWithPVCRefCSI, v1mypodWithPVCRefCSI := makeTestPod("ns", "mypvcpod", "mynode", false)
 | 
			
		||||
	v1mypodWithPVCRefCSI.Spec.Volumes = []corev1.Volume{{VolumeSource: corev1.VolumeSource{PersistentVolumeClaim: persistentVolumeClaimVolumeSource}}}
 | 
			
		||||
 | 
			
		||||
	coremypodWithEphemeralVolume, v1mypodWithEphemeralVolume := makeTestPod("ns", "myephemeralpod", "mynode", false)
 | 
			
		||||
	v1mypodWithEphemeralVolume.Spec.Volumes = []corev1.Volume{{Name: "myvol", VolumeSource: corev1.VolumeSource{Ephemeral: ephemeralVolumeSource}}}
 | 
			
		||||
 | 
			
		||||
	coremypodWithPVCAndCSI, v1mypodWithPVCAndCSI := makeTestPod("ns", "mypvcandcsipod", "mynode", false)
 | 
			
		||||
	v1mypodWithPVCAndCSI.Spec.Volumes = []corev1.Volume{{VolumeSource: corev1.VolumeSource{PersistentVolumeClaim: persistentVolumeClaimVolumeSource}}, {VolumeSource: corev1.VolumeSource{CSI: csiDriverVolumeSource}}}
 | 
			
		||||
 | 
			
		||||
	checkNilError(t, csiDriverIndex.Add(csiDriverWithAudience))
 | 
			
		||||
	checkNilError(t, pvcIndex.Add(pvcWithCSIDriver))
 | 
			
		||||
	checkNilError(t, pvcIndex.Add(ephemeralVolumePVCWithCSIDriver))
 | 
			
		||||
	checkNilError(t, pvIndex.Add(pvWithCSIDriver))
 | 
			
		||||
 | 
			
		||||
	existingPodsIndex.Add(v1mymirrorpod)
 | 
			
		||||
	existingPodsIndex.Add(v1othermirrorpod)
 | 
			
		||||
	existingPodsIndex.Add(v1unboundmirrorpod)
 | 
			
		||||
@@ -396,6 +495,13 @@ func Test_nodePlugin_Admit(t *testing.T) {
 | 
			
		||||
	existingPodsIndex.Add(v1otherpod)
 | 
			
		||||
	existingPodsIndex.Add(v1unboundpod)
 | 
			
		||||
 | 
			
		||||
	checkNilError(t, existingPodsIndex.Add(v1mypodWithProjectedServiceAccountEmptyAudience))
 | 
			
		||||
	checkNilError(t, existingPodsIndex.Add(v1mypodWithProjectedServiceAccount))
 | 
			
		||||
	checkNilError(t, existingPodsIndex.Add(v1mypodWithCSI))
 | 
			
		||||
	checkNilError(t, existingPodsIndex.Add(v1mypodWithPVCRefCSI))
 | 
			
		||||
	checkNilError(t, existingPodsIndex.Add(v1mypodWithEphemeralVolume))
 | 
			
		||||
	checkNilError(t, existingPodsIndex.Add(v1mypodWithPVCAndCSI))
 | 
			
		||||
 | 
			
		||||
	existingNodesIndex.Add(&corev1.Node{ObjectMeta: mynodeObjMeta})
 | 
			
		||||
 | 
			
		||||
	sapod, _ := makeTestPod("ns", "mysapod", "mynode", true)
 | 
			
		||||
@@ -1089,31 +1195,240 @@ func Test_nodePlugin_Admit(t *testing.T) {
 | 
			
		||||
		{
 | 
			
		||||
			name:       "forbid create of unbound token",
 | 
			
		||||
			podsGetter: noExistingPods,
 | 
			
		||||
			attributes: admission.NewAttributesRecord(makeTokenRequest("", ""), nil, tokenrequestKind, "ns", "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
 | 
			
		||||
			attributes: admission.NewAttributesRecord(makeTokenRequest("", "", []string{"foo"}), nil, tokenrequestKind, "ns", "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
 | 
			
		||||
			err:        "not bound to a pod",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:       "forbid create of token bound to nonexistant pod",
 | 
			
		||||
			podsGetter: noExistingPods,
 | 
			
		||||
			attributes: admission.NewAttributesRecord(makeTokenRequest("nopod", "someuid"), nil, tokenrequestKind, "ns", "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
 | 
			
		||||
			attributes: admission.NewAttributesRecord(makeTokenRequest("nopod", "someuid", []string{"foo"}), nil, tokenrequestKind, "ns", "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
 | 
			
		||||
			err:        "not found",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:       "forbid create of token bound to pod without uid",
 | 
			
		||||
			podsGetter: existingPods,
 | 
			
		||||
			attributes: admission.NewAttributesRecord(makeTokenRequest(coremypod.Name, ""), nil, tokenrequestKind, "ns", "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
 | 
			
		||||
			attributes: admission.NewAttributesRecord(makeTokenRequest(coremypod.Name, "", []string{"foo"}), nil, tokenrequestKind, "ns", "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
 | 
			
		||||
			err:        "pod binding without a uid",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:       "forbid create of token bound to pod scheduled on another node",
 | 
			
		||||
			podsGetter: existingPods,
 | 
			
		||||
			attributes: admission.NewAttributesRecord(makeTokenRequest(coreotherpod.Name, coreotherpod.UID), nil, tokenrequestKind, coreotherpod.Namespace, "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
 | 
			
		||||
			attributes: admission.NewAttributesRecord(makeTokenRequest(coreotherpod.Name, coreotherpod.UID, []string{"foo"}), nil, tokenrequestKind, coreotherpod.Namespace, "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
 | 
			
		||||
			err:        "pod scheduled on a different node",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:       "allow create of token bound to pod scheduled this node",
 | 
			
		||||
			podsGetter: existingPods,
 | 
			
		||||
			attributes: admission.NewAttributesRecord(makeTokenRequest(coremypod.Name, coremypod.UID), nil, tokenrequestKind, coremypod.Namespace, "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
 | 
			
		||||
			attributes: admission.NewAttributesRecord(makeTokenRequest(coremypod.Name, coremypod.UID, []string{"foo"}), nil, tokenrequestKind, coremypod.Namespace, "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
 | 
			
		||||
		},
 | 
			
		||||
		// Service accounts tests with token audience restrictions
 | 
			
		||||
		{
 | 
			
		||||
			name:       "allow create of token when audience in PSAT volume and ServiceAccountNodeAudienceRestriction is enabled, empty audience",
 | 
			
		||||
			podsGetter: existingPods,
 | 
			
		||||
			features:   feature.DefaultFeatureGate,
 | 
			
		||||
			setupFunc: func(t *testing.T) {
 | 
			
		||||
				t.Helper()
 | 
			
		||||
				featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.ServiceAccountNodeAudienceRestriction, true)
 | 
			
		||||
			},
 | 
			
		||||
			attributes: admission.NewAttributesRecord(makeTokenRequest(coremypodWithProjectedServiceAccountEmptyAudience.Name, coremypodWithProjectedServiceAccountEmptyAudience.UID, []string{"foo"}), nil, tokenrequestKind, coremypod.Namespace, "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:       "allow create of token when audience in PSAT volume and ServiceAccountNodeAudienceRestriction is enabled, single audience",
 | 
			
		||||
			podsGetter: existingPods,
 | 
			
		||||
			features:   feature.DefaultFeatureGate,
 | 
			
		||||
			setupFunc: func(t *testing.T) {
 | 
			
		||||
				t.Helper()
 | 
			
		||||
				featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.ServiceAccountNodeAudienceRestriction, true)
 | 
			
		||||
			},
 | 
			
		||||
			attributes: admission.NewAttributesRecord(makeTokenRequest(coremypodWithProjectedServiceAccount.Name, coremypodWithProjectedServiceAccount.UID, []string{"foo"}), nil, tokenrequestKind, coremypod.Namespace, "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:       "forbid create of token with multiple audiences in token request and ServiceAccountNodeAudienceRestriction is enabled",
 | 
			
		||||
			podsGetter: existingPods,
 | 
			
		||||
			features:   feature.DefaultFeatureGate,
 | 
			
		||||
			setupFunc: func(t *testing.T) {
 | 
			
		||||
				t.Helper()
 | 
			
		||||
				featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.ServiceAccountNodeAudienceRestriction, true)
 | 
			
		||||
			},
 | 
			
		||||
			attributes: admission.NewAttributesRecord(makeTokenRequest(coremypodWithProjectedServiceAccount.Name, coremypodWithProjectedServiceAccount.UID, []string{"foo", "bar"}), nil, tokenrequestKind, coremypod.Namespace, "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
 | 
			
		||||
			err:        "node may only request 0 or 1 audiences",
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:       "forbid create of token when audience not in pod spec and ServiceAccountNodeAudienceRestriction is enabled",
 | 
			
		||||
			podsGetter: existingPods,
 | 
			
		||||
			features:   feature.DefaultFeatureGate,
 | 
			
		||||
			setupFunc: func(t *testing.T) {
 | 
			
		||||
				t.Helper()
 | 
			
		||||
				featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.ServiceAccountNodeAudienceRestriction, true)
 | 
			
		||||
			},
 | 
			
		||||
			attributes: admission.NewAttributesRecord(makeTokenRequest(coremypod.Name, coremypod.UID, []string{"foo"}), nil, tokenrequestKind, coremypod.Namespace, "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
 | 
			
		||||
			err:        `serviceaccounts "mysa" is forbidden: audience "foo" not found in pod spec volume`,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:            "allow create of token when audience in pod --> csi --> driver --> tokenrequest with audience and ServiceAccountNodeAudienceRestriction is enabled",
 | 
			
		||||
			podsGetter:      existingPods,
 | 
			
		||||
			csiDriverGetter: csiDriverLister,
 | 
			
		||||
			features:        feature.DefaultFeatureGate,
 | 
			
		||||
			setupFunc: func(t *testing.T) {
 | 
			
		||||
				t.Helper()
 | 
			
		||||
				featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.ServiceAccountNodeAudienceRestriction, true)
 | 
			
		||||
			},
 | 
			
		||||
			attributes: admission.NewAttributesRecord(makeTokenRequest(coremypodWithCSI.Name, v1mypodWithCSI.UID, []string{"foo"}), nil, tokenrequestKind, coremypod.Namespace, "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:            "forbid create of token when audience in pod --> csi --> driver --> tokenrequest does not have audience and ServiceAccountNodeAudienceRestriction is enabled",
 | 
			
		||||
			podsGetter:      existingPods,
 | 
			
		||||
			csiDriverGetter: csiDriverLister,
 | 
			
		||||
			features:        feature.DefaultFeatureGate,
 | 
			
		||||
			setupFunc: func(t *testing.T) {
 | 
			
		||||
				t.Helper()
 | 
			
		||||
				featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.ServiceAccountNodeAudienceRestriction, true)
 | 
			
		||||
			},
 | 
			
		||||
			attributes: admission.NewAttributesRecord(makeTokenRequest(coremypodWithCSI.Name, v1mypodWithCSI.UID, []string{"bar"}), nil, tokenrequestKind, coremypod.Namespace, "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
 | 
			
		||||
			err:        `audience "bar" not found in pod spec volume`,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:            "forbid create of token when audience in pod --> csi --> driver --> tokenrequest with audience and ServiceAccountNodeAudienceRestriction is enabled, csidriver not found",
 | 
			
		||||
			podsGetter:      existingPods,
 | 
			
		||||
			csiDriverGetter: noexistingCSIDriverLister,
 | 
			
		||||
			features:        feature.DefaultFeatureGate,
 | 
			
		||||
			setupFunc: func(t *testing.T) {
 | 
			
		||||
				t.Helper()
 | 
			
		||||
				featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.ServiceAccountNodeAudienceRestriction, true)
 | 
			
		||||
			},
 | 
			
		||||
			attributes: admission.NewAttributesRecord(makeTokenRequest(coremypodWithCSI.Name, v1mypodWithCSI.UID, []string{"foo"}), nil, tokenrequestKind, coremypod.Namespace, "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
 | 
			
		||||
			err:        `error validating audience "foo": csidriver.storage.k8s.io "com.example.csi.mydriver" not found`,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:            "allow create of token when audience in pod --> pvc --> pv --> csi --> driver --> tokenrequest with audience and ServiceAccountNodeAudienceRestriction is enabled",
 | 
			
		||||
			podsGetter:      existingPods,
 | 
			
		||||
			csiDriverGetter: csiDriverLister,
 | 
			
		||||
			pvcGetter:       pvcLister,
 | 
			
		||||
			pvGetter:        pvLister,
 | 
			
		||||
			features:        feature.DefaultFeatureGate,
 | 
			
		||||
			setupFunc: func(t *testing.T) {
 | 
			
		||||
				t.Helper()
 | 
			
		||||
				featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.ServiceAccountNodeAudienceRestriction, true)
 | 
			
		||||
			},
 | 
			
		||||
			attributes: admission.NewAttributesRecord(makeTokenRequest(coremypodWithPVCRefCSI.Name, v1mypodWithPVCRefCSI.UID, []string{"foo"}), nil, tokenrequestKind, coremypod.Namespace, "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:            "forbid create of token when audience in pod --> pvc --> pv --> csi --> driver --> tokenrequest does not have audience and ServiceAccountNodeAudienceRestriction is enabled",
 | 
			
		||||
			podsGetter:      existingPods,
 | 
			
		||||
			csiDriverGetter: csiDriverLister,
 | 
			
		||||
			pvcGetter:       pvcLister,
 | 
			
		||||
			pvGetter:        pvLister,
 | 
			
		||||
			features:        feature.DefaultFeatureGate,
 | 
			
		||||
			setupFunc: func(t *testing.T) {
 | 
			
		||||
				t.Helper()
 | 
			
		||||
				featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.ServiceAccountNodeAudienceRestriction, true)
 | 
			
		||||
			},
 | 
			
		||||
			attributes: admission.NewAttributesRecord(makeTokenRequest(coremypodWithPVCRefCSI.Name, v1mypodWithPVCRefCSI.UID, []string{"bar"}), nil, tokenrequestKind, coremypod.Namespace, "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
 | 
			
		||||
			err:        `audience "bar" not found in pod spec volume`,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:            "forbid create of token when audience in pod --> pvc --> pv --> csi --> driver --> tokenrequest with audience and ServiceAccountNodeAudienceRestriction is enabled, pvc not found",
 | 
			
		||||
			podsGetter:      existingPods,
 | 
			
		||||
			csiDriverGetter: csiDriverLister,
 | 
			
		||||
			pvcGetter:       noexistingPVCLister,
 | 
			
		||||
			pvGetter:        pvLister,
 | 
			
		||||
			features:        feature.DefaultFeatureGate,
 | 
			
		||||
			setupFunc: func(t *testing.T) {
 | 
			
		||||
				t.Helper()
 | 
			
		||||
				featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.ServiceAccountNodeAudienceRestriction, true)
 | 
			
		||||
			},
 | 
			
		||||
			attributes: admission.NewAttributesRecord(makeTokenRequest(coremypodWithPVCRefCSI.Name, v1mypodWithPVCRefCSI.UID, []string{"foo"}), nil, tokenrequestKind, coremypod.Namespace, "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
 | 
			
		||||
			err:        `error validating audience "foo": persistentvolumeclaim "pvclaim" not found`,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:            "forbid create of token when audience in pod --> pvc --> pv --> csi --> driver --> tokenrequest with audience and ServiceAccountNodeAudienceRestriction is enabled, pv not found",
 | 
			
		||||
			podsGetter:      existingPods,
 | 
			
		||||
			csiDriverGetter: csiDriverLister,
 | 
			
		||||
			pvcGetter:       pvcLister,
 | 
			
		||||
			pvGetter:        noexistingPVLister,
 | 
			
		||||
			features:        feature.DefaultFeatureGate,
 | 
			
		||||
			setupFunc: func(t *testing.T) {
 | 
			
		||||
				t.Helper()
 | 
			
		||||
				featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.ServiceAccountNodeAudienceRestriction, true)
 | 
			
		||||
			},
 | 
			
		||||
			attributes: admission.NewAttributesRecord(makeTokenRequest(coremypodWithPVCRefCSI.Name, v1mypodWithPVCRefCSI.UID, []string{"foo"}), nil, tokenrequestKind, coremypod.Namespace, "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
 | 
			
		||||
			err:        `error validating audience "foo": persistentvolume "pvname" not found`,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:            "allow create of token when audience in pod --> ephemeral --> pvc --> pv --> csi --> driver --> tokenrequest with audience and ServiceAccountNodeAudienceRestriction is enabled",
 | 
			
		||||
			podsGetter:      existingPods,
 | 
			
		||||
			csiDriverGetter: csiDriverLister,
 | 
			
		||||
			pvcGetter:       pvcLister,
 | 
			
		||||
			pvGetter:        pvLister,
 | 
			
		||||
			features:        feature.DefaultFeatureGate,
 | 
			
		||||
			setupFunc: func(t *testing.T) {
 | 
			
		||||
				t.Helper()
 | 
			
		||||
				featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.ServiceAccountNodeAudienceRestriction, true)
 | 
			
		||||
			},
 | 
			
		||||
			attributes: admission.NewAttributesRecord(makeTokenRequest(coremypodWithEphemeralVolume.Name, v1mypodWithEphemeralVolume.UID, []string{"foo"}), nil, tokenrequestKind, coremypod.Namespace, "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:            "forbid create of token when audience in pod --> ephemeral --> pvc --> pv --> csi --> driver --> tokenrequest does not have audience and ServiceAccountNodeAudienceRestriction is enabled",
 | 
			
		||||
			podsGetter:      existingPods,
 | 
			
		||||
			csiDriverGetter: csiDriverLister,
 | 
			
		||||
			pvcGetter:       pvcLister,
 | 
			
		||||
			pvGetter:        pvLister,
 | 
			
		||||
			features:        feature.DefaultFeatureGate,
 | 
			
		||||
			setupFunc: func(t *testing.T) {
 | 
			
		||||
				t.Helper()
 | 
			
		||||
				featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.ServiceAccountNodeAudienceRestriction, true)
 | 
			
		||||
			},
 | 
			
		||||
			attributes: admission.NewAttributesRecord(makeTokenRequest(coremypodWithEphemeralVolume.Name, v1mypodWithEphemeralVolume.UID, []string{"bar"}), nil, tokenrequestKind, coremypod.Namespace, "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
 | 
			
		||||
			err:        `audience "bar" not found in pod spec volume`,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:            "allow create of token when ServiceAccountNodeAudienceRestriction is disabled, pvc not found should not be checked",
 | 
			
		||||
			podsGetter:      existingPods,
 | 
			
		||||
			csiDriverGetter: csiDriverLister,
 | 
			
		||||
			pvcGetter:       noexistingPVCLister,
 | 
			
		||||
			features:        feature.DefaultFeatureGate,
 | 
			
		||||
			setupFunc: func(t *testing.T) {
 | 
			
		||||
				t.Helper()
 | 
			
		||||
				featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.ServiceAccountNodeAudienceRestriction, true)
 | 
			
		||||
			},
 | 
			
		||||
			attributes: admission.NewAttributesRecord(makeTokenRequest(coremypodWithPVCAndCSI.Name, v1mypodWithPVCAndCSI.UID, []string{"foo"}), nil, tokenrequestKind, coremypod.Namespace, "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:            "allow create of token when audience in pod --> csi --> driver --> tokenrequest with audience and ServiceAccountNodeAudienceRestriction is enabled, pv not found",
 | 
			
		||||
			podsGetter:      existingPods,
 | 
			
		||||
			csiDriverGetter: csiDriverLister,
 | 
			
		||||
			pvcGetter:       pvcLister,
 | 
			
		||||
			pvGetter:        noexistingPVLister,
 | 
			
		||||
			features:        feature.DefaultFeatureGate,
 | 
			
		||||
			setupFunc: func(t *testing.T) {
 | 
			
		||||
				t.Helper()
 | 
			
		||||
				featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.ServiceAccountNodeAudienceRestriction, true)
 | 
			
		||||
			},
 | 
			
		||||
			attributes: admission.NewAttributesRecord(makeTokenRequest(coremypodWithPVCAndCSI.Name, v1mypodWithPVCAndCSI.UID, []string{"foo"}), nil, tokenrequestKind, coremypod.Namespace, "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:            "allow create of token when ServiceAccountNodeAudienceRestriction is disabled, pv not found should not be checked",
 | 
			
		||||
			podsGetter:      existingPods,
 | 
			
		||||
			csiDriverGetter: csiDriverLister,
 | 
			
		||||
			pvcGetter:       pvcLister,
 | 
			
		||||
			pvGetter:        noexistingPVLister,
 | 
			
		||||
			features:        feature.DefaultFeatureGate,
 | 
			
		||||
			setupFunc: func(t *testing.T) {
 | 
			
		||||
				t.Helper()
 | 
			
		||||
				featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.ServiceAccountNodeAudienceRestriction, false)
 | 
			
		||||
			},
 | 
			
		||||
			attributes: admission.NewAttributesRecord(makeTokenRequest(coremypodWithPVCAndCSI.Name, v1mypodWithPVCAndCSI.UID, []string{"foo"}), nil, tokenrequestKind, coremypod.Namespace, "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			name:            "allow create of token when ServiceAccountNodeAudienceRestriction is disabled, csidriver not found should not be checked",
 | 
			
		||||
			podsGetter:      existingPods,
 | 
			
		||||
			csiDriverGetter: noexistingCSIDriverLister,
 | 
			
		||||
			features:        feature.DefaultFeatureGate,
 | 
			
		||||
			setupFunc: func(t *testing.T) {
 | 
			
		||||
				t.Helper()
 | 
			
		||||
				featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, features.ServiceAccountNodeAudienceRestriction, false)
 | 
			
		||||
			},
 | 
			
		||||
			attributes: admission.NewAttributesRecord(makeTokenRequest(coremypodWithCSI.Name, v1mypodWithCSI.UID, []string{"foo"}), nil, tokenrequestKind, coremypod.Namespace, "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// Unrelated objects
 | 
			
		||||
@@ -1839,3 +2154,10 @@ func TestAdmitResourceSlice(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func checkNilError(t *testing.T, err error) {
 | 
			
		||||
	t.Helper()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("unexpected error: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user