mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-09 20:17:41 +00:00
Merge pull request #129993 from aramase/aramase/i/fix_129935
Fix service account node audience restriction for in-tree pv to csi migration
This commit is contained in:
commit
7b38ff48af
@ -39,6 +39,8 @@ import (
|
|||||||
storagelisters "k8s.io/client-go/listers/storage/v1"
|
storagelisters "k8s.io/client-go/listers/storage/v1"
|
||||||
"k8s.io/component-base/featuregate"
|
"k8s.io/component-base/featuregate"
|
||||||
"k8s.io/component-helpers/storage/ephemeral"
|
"k8s.io/component-helpers/storage/ephemeral"
|
||||||
|
csitrans "k8s.io/csi-translation-lib"
|
||||||
|
"k8s.io/klog/v2"
|
||||||
kubeletapis "k8s.io/kubelet/pkg/apis"
|
kubeletapis "k8s.io/kubelet/pkg/apis"
|
||||||
podutil "k8s.io/kubernetes/pkg/api/pod"
|
podutil "k8s.io/kubernetes/pkg/api/pod"
|
||||||
authenticationapi "k8s.io/kubernetes/pkg/apis/authentication"
|
authenticationapi "k8s.io/kubernetes/pkg/apis/authentication"
|
||||||
@ -80,6 +82,7 @@ type Plugin struct {
|
|||||||
csiDriverGetter storagelisters.CSIDriverLister
|
csiDriverGetter storagelisters.CSIDriverLister
|
||||||
pvcGetter corev1lister.PersistentVolumeClaimLister
|
pvcGetter corev1lister.PersistentVolumeClaimLister
|
||||||
pvGetter corev1lister.PersistentVolumeLister
|
pvGetter corev1lister.PersistentVolumeLister
|
||||||
|
csiTranslator csitrans.CSITranslator
|
||||||
|
|
||||||
expansionRecoveryEnabled bool
|
expansionRecoveryEnabled bool
|
||||||
dynamicResourceAllocationEnabled bool
|
dynamicResourceAllocationEnabled bool
|
||||||
@ -109,6 +112,7 @@ func (p *Plugin) SetExternalKubeInformerFactory(f informers.SharedInformerFactor
|
|||||||
p.csiDriverGetter = f.Storage().V1().CSIDrivers().Lister()
|
p.csiDriverGetter = f.Storage().V1().CSIDrivers().Lister()
|
||||||
p.pvcGetter = f.Core().V1().PersistentVolumeClaims().Lister()
|
p.pvcGetter = f.Core().V1().PersistentVolumeClaims().Lister()
|
||||||
p.pvGetter = f.Core().V1().PersistentVolumes().Lister()
|
p.pvGetter = f.Core().V1().PersistentVolumes().Lister()
|
||||||
|
p.csiTranslator = csitrans.New()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,7 +193,7 @@ func (p *Plugin) Admit(ctx context.Context, a admission.Attributes, o admission.
|
|||||||
}
|
}
|
||||||
|
|
||||||
case svcacctResource:
|
case svcacctResource:
|
||||||
return p.admitServiceAccount(nodeName, a)
|
return p.admitServiceAccount(ctx, nodeName, a)
|
||||||
|
|
||||||
case leaseResource:
|
case leaseResource:
|
||||||
return p.admitLease(nodeName, a)
|
return p.admitLease(nodeName, a)
|
||||||
@ -581,7 +585,7 @@ func (p *Plugin) getForbiddenLabels(modifiedLabels sets.String) sets.String {
|
|||||||
return forbiddenLabels
|
return forbiddenLabels
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Plugin) admitServiceAccount(nodeName string, a admission.Attributes) error {
|
func (p *Plugin) admitServiceAccount(ctx context.Context, nodeName string, a admission.Attributes) error {
|
||||||
if a.GetOperation() != admission.Create {
|
if a.GetOperation() != admission.Create {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -620,7 +624,7 @@ func (p *Plugin) admitServiceAccount(nodeName string, a admission.Attributes) er
|
|||||||
}
|
}
|
||||||
|
|
||||||
if p.serviceAccountNodeAudienceRestriction {
|
if p.serviceAccountNodeAudienceRestriction {
|
||||||
if err := p.validateNodeServiceAccountAudience(tr, pod); err != nil {
|
if err := p.validateNodeServiceAccountAudience(ctx, tr, pod); err != nil {
|
||||||
return admission.NewForbidden(a, err)
|
return admission.NewForbidden(a, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -634,7 +638,7 @@ func (p *Plugin) admitServiceAccount(nodeName string, a admission.Attributes) er
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Plugin) validateNodeServiceAccountAudience(tr *authenticationapi.TokenRequest, pod *v1.Pod) error {
|
func (p *Plugin) validateNodeServiceAccountAudience(ctx context.Context, tr *authenticationapi.TokenRequest, pod *v1.Pod) error {
|
||||||
// ensure all items in tr.Spec.Audiences are present in a volume mount in the pod
|
// ensure all items in tr.Spec.Audiences are present in a volume mount in the pod
|
||||||
requestedAudience := ""
|
requestedAudience := ""
|
||||||
switch len(tr.Spec.Audiences) {
|
switch len(tr.Spec.Audiences) {
|
||||||
@ -646,7 +650,7 @@ func (p *Plugin) validateNodeServiceAccountAudience(tr *authenticationapi.TokenR
|
|||||||
return fmt.Errorf("node may only request 0 or 1 audiences")
|
return fmt.Errorf("node may only request 0 or 1 audiences")
|
||||||
}
|
}
|
||||||
|
|
||||||
foundAudiencesInPodSpec, err := p.podReferencesAudience(pod, requestedAudience)
|
foundAudiencesInPodSpec, err := p.podReferencesAudience(ctx, pod, requestedAudience)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error validating audience %q: %w", requestedAudience, err)
|
return fmt.Errorf("error validating audience %q: %w", requestedAudience, err)
|
||||||
}
|
}
|
||||||
@ -656,7 +660,7 @@ func (p *Plugin) validateNodeServiceAccountAudience(tr *authenticationapi.TokenR
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Plugin) podReferencesAudience(pod *v1.Pod, audience string) (bool, error) {
|
func (p *Plugin) podReferencesAudience(ctx context.Context, pod *v1.Pod, audience string) (bool, error) {
|
||||||
var errs []error
|
var errs []error
|
||||||
|
|
||||||
for _, v := range pod.Spec.Volumes {
|
for _, v := range pod.Spec.Volumes {
|
||||||
@ -677,11 +681,20 @@ func (p *Plugin) podReferencesAudience(pod *v1.Pod, audience string) (bool, erro
|
|||||||
switch {
|
switch {
|
||||||
case v.Ephemeral != nil && v.Ephemeral.VolumeClaimTemplate != nil:
|
case v.Ephemeral != nil && v.Ephemeral.VolumeClaimTemplate != nil:
|
||||||
pvcName := ephemeral.VolumeClaimName(pod, &v)
|
pvcName := ephemeral.VolumeClaimName(pod, &v)
|
||||||
driverName, err = p.getCSIFromPVC(pod.Namespace, pvcName)
|
driverName, err = p.getCSIFromPVC(ctx, pod.Namespace, pvcName)
|
||||||
case v.PersistentVolumeClaim != nil:
|
case v.PersistentVolumeClaim != nil:
|
||||||
driverName, err = p.getCSIFromPVC(pod.Namespace, v.PersistentVolumeClaim.ClaimName)
|
driverName, err = p.getCSIFromPVC(ctx, pod.Namespace, v.PersistentVolumeClaim.ClaimName)
|
||||||
case v.CSI != nil:
|
case v.CSI != nil:
|
||||||
driverName = v.CSI.Driver
|
driverName = v.CSI.Driver
|
||||||
|
case p.csiTranslator.IsInlineMigratable(&v):
|
||||||
|
pv, translateErr := p.csiTranslator.TranslateInTreeInlineVolumeToCSI(klog.FromContext(ctx), &v, pod.Namespace)
|
||||||
|
if translateErr != nil {
|
||||||
|
err = translateErr
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if pv != nil && pv.Spec.CSI != nil {
|
||||||
|
driverName = pv.Spec.CSI.Driver
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -705,7 +718,7 @@ func (p *Plugin) podReferencesAudience(pod *v1.Pod, audience string) (bool, erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getCSIFromPVC returns the CSI driver name from the PVC->PV->CSI->Driver chain
|
// getCSIFromPVC returns the CSI driver name from the PVC->PV->CSI->Driver chain
|
||||||
func (p *Plugin) getCSIFromPVC(namespace, claimName string) (string, error) {
|
func (p *Plugin) getCSIFromPVC(ctx context.Context, namespace, claimName string) (string, error) {
|
||||||
pvc, err := p.pvcGetter.PersistentVolumeClaims(namespace).Get(claimName)
|
pvc, err := p.pvcGetter.PersistentVolumeClaims(namespace).Get(claimName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@ -717,6 +730,18 @@ func (p *Plugin) getCSIFromPVC(namespace, claimName string) (string, error) {
|
|||||||
if pv.Spec.CSI != nil {
|
if pv.Spec.CSI != nil {
|
||||||
return pv.Spec.CSI.Driver, nil
|
return pv.Spec.CSI.Driver, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if p.csiTranslator.IsPVMigratable(pv) {
|
||||||
|
// For in-tree PV, we need to convert ("translate") the PV to CSI before checking the driver name.
|
||||||
|
translatedPV, err := p.csiTranslator.TranslateInTreePVToCSI(klog.FromContext(ctx), pv)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if translatedPV != nil && translatedPV.Spec.CSI != nil {
|
||||||
|
return translatedPV.Spec.CSI.Driver, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -408,6 +408,19 @@ func Test_nodePlugin_Admit(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
azureFileCSIDriver = &storagev1.CSIDriver{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "file.csi.azure.com",
|
||||||
|
},
|
||||||
|
Spec: storagev1.CSIDriverSpec{
|
||||||
|
TokenRequests: []storagev1.TokenRequest{
|
||||||
|
{
|
||||||
|
Audience: "foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
csiDriverIndex = cache.NewIndexer(cache.MetaNamespaceKeyFunc, nil)
|
csiDriverIndex = cache.NewIndexer(cache.MetaNamespaceKeyFunc, nil)
|
||||||
csiDriverLister = storagelisters.NewCSIDriverLister(csiDriverIndex)
|
csiDriverLister = storagelisters.NewCSIDriverLister(csiDriverIndex)
|
||||||
|
|
||||||
@ -424,6 +437,16 @@ func Test_nodePlugin_Admit(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pvcWithIntreeAzureFile = &corev1.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "pvclaim-azurefile",
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
Spec: corev1.PersistentVolumeClaimSpec{
|
||||||
|
VolumeName: "pvname-azurefile",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
ephemeralVolumePVCWithCSIDriver = &corev1.PersistentVolumeClaim{
|
ephemeralVolumePVCWithCSIDriver = &corev1.PersistentVolumeClaim{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "myephemeralpod-myvol",
|
Name: "myephemeralpod-myvol",
|
||||||
@ -451,6 +474,20 @@ func Test_nodePlugin_Admit(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pvWithIntreeAzureFile = &corev1.PersistentVolume{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "pvname-azurefile",
|
||||||
|
},
|
||||||
|
Spec: corev1.PersistentVolumeSpec{
|
||||||
|
ClaimRef: &corev1.ObjectReference{
|
||||||
|
Namespace: "ns",
|
||||||
|
},
|
||||||
|
PersistentVolumeSource: corev1.PersistentVolumeSource{
|
||||||
|
AzureFile: &corev1.AzureFilePersistentVolumeSource{ShareName: "default", SecretName: "secret"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
pvIndex = cache.NewIndexer(cache.MetaNamespaceKeyFunc, nil)
|
pvIndex = cache.NewIndexer(cache.MetaNamespaceKeyFunc, nil)
|
||||||
pvLister = corev1lister.NewPersistentVolumeLister(pvIndex)
|
pvLister = corev1lister.NewPersistentVolumeLister(pvIndex)
|
||||||
|
|
||||||
@ -463,6 +500,7 @@ func Test_nodePlugin_Admit(t *testing.T) {
|
|||||||
projectedVolumeSource := &corev1.ProjectedVolumeSource{Sources: []corev1.VolumeProjection{{ServiceAccountToken: &corev1.ServiceAccountTokenProjection{Audience: "foo"}}}}
|
projectedVolumeSource := &corev1.ProjectedVolumeSource{Sources: []corev1.VolumeProjection{{ServiceAccountToken: &corev1.ServiceAccountTokenProjection{Audience: "foo"}}}}
|
||||||
csiDriverVolumeSource := &corev1.CSIVolumeSource{Driver: "com.example.csi.mydriver"}
|
csiDriverVolumeSource := &corev1.CSIVolumeSource{Driver: "com.example.csi.mydriver"}
|
||||||
persistentVolumeClaimVolumeSource := &corev1.PersistentVolumeClaimVolumeSource{ClaimName: "pvclaim"}
|
persistentVolumeClaimVolumeSource := &corev1.PersistentVolumeClaimVolumeSource{ClaimName: "pvclaim"}
|
||||||
|
persistentVolumeClaimVolumeSourceAzureFile := &corev1.PersistentVolumeClaimVolumeSource{ClaimName: "pvclaim-azurefile"}
|
||||||
ephemeralVolumeSource := &corev1.EphemeralVolumeSource{VolumeClaimTemplate: &corev1.PersistentVolumeClaimTemplate{}}
|
ephemeralVolumeSource := &corev1.EphemeralVolumeSource{VolumeClaimTemplate: &corev1.PersistentVolumeClaimTemplate{}}
|
||||||
|
|
||||||
coremypodWithProjectedServiceAccountEmptyAudience, v1mypodWithProjectedServiceAccountEmptyAudience := makeTestPod("ns", "mysapod", "mynode", false)
|
coremypodWithProjectedServiceAccountEmptyAudience, v1mypodWithProjectedServiceAccountEmptyAudience := makeTestPod("ns", "mysapod", "mynode", false)
|
||||||
@ -483,10 +521,19 @@ func Test_nodePlugin_Admit(t *testing.T) {
|
|||||||
coremypodWithPVCAndCSI, v1mypodWithPVCAndCSI := makeTestPod("ns", "mypvcandcsipod", "mynode", false)
|
coremypodWithPVCAndCSI, v1mypodWithPVCAndCSI := makeTestPod("ns", "mypvcandcsipod", "mynode", false)
|
||||||
v1mypodWithPVCAndCSI.Spec.Volumes = []corev1.Volume{{VolumeSource: corev1.VolumeSource{PersistentVolumeClaim: persistentVolumeClaimVolumeSource}}, {VolumeSource: corev1.VolumeSource{CSI: csiDriverVolumeSource}}}
|
v1mypodWithPVCAndCSI.Spec.Volumes = []corev1.Volume{{VolumeSource: corev1.VolumeSource{PersistentVolumeClaim: persistentVolumeClaimVolumeSource}}, {VolumeSource: corev1.VolumeSource{CSI: csiDriverVolumeSource}}}
|
||||||
|
|
||||||
|
coremypodIntreeInlineVolToCSI, v1mypodIntreeInlineVolToCSI := makeTestPod("ns", "myintreeinlinevoltocsipod", "mynode", false)
|
||||||
|
v1mypodIntreeInlineVolToCSI.Spec.Volumes = []corev1.Volume{{VolumeSource: corev1.VolumeSource{AzureFile: &corev1.AzureFileVolumeSource{ShareName: "default", SecretName: "secret"}}}}
|
||||||
|
|
||||||
|
coremypodIntreePVToCSI, v1mypodIntreePVToCSI := makeTestPod("ns", "myintreepvtocsipod", "mynode", false)
|
||||||
|
v1mypodIntreePVToCSI.Spec.Volumes = []corev1.Volume{{VolumeSource: corev1.VolumeSource{PersistentVolumeClaim: persistentVolumeClaimVolumeSourceAzureFile}}}
|
||||||
|
|
||||||
checkNilError(t, csiDriverIndex.Add(csiDriverWithAudience))
|
checkNilError(t, csiDriverIndex.Add(csiDriverWithAudience))
|
||||||
|
checkNilError(t, csiDriverIndex.Add(azureFileCSIDriver))
|
||||||
checkNilError(t, pvcIndex.Add(pvcWithCSIDriver))
|
checkNilError(t, pvcIndex.Add(pvcWithCSIDriver))
|
||||||
|
checkNilError(t, pvcIndex.Add(pvcWithIntreeAzureFile))
|
||||||
checkNilError(t, pvcIndex.Add(ephemeralVolumePVCWithCSIDriver))
|
checkNilError(t, pvcIndex.Add(ephemeralVolumePVCWithCSIDriver))
|
||||||
checkNilError(t, pvIndex.Add(pvWithCSIDriver))
|
checkNilError(t, pvIndex.Add(pvWithCSIDriver))
|
||||||
|
checkNilError(t, pvIndex.Add(pvWithIntreeAzureFile))
|
||||||
|
|
||||||
existingPodsIndex.Add(v1mymirrorpod)
|
existingPodsIndex.Add(v1mymirrorpod)
|
||||||
existingPodsIndex.Add(v1othermirrorpod)
|
existingPodsIndex.Add(v1othermirrorpod)
|
||||||
@ -501,6 +548,8 @@ func Test_nodePlugin_Admit(t *testing.T) {
|
|||||||
checkNilError(t, existingPodsIndex.Add(v1mypodWithPVCRefCSI))
|
checkNilError(t, existingPodsIndex.Add(v1mypodWithPVCRefCSI))
|
||||||
checkNilError(t, existingPodsIndex.Add(v1mypodWithEphemeralVolume))
|
checkNilError(t, existingPodsIndex.Add(v1mypodWithEphemeralVolume))
|
||||||
checkNilError(t, existingPodsIndex.Add(v1mypodWithPVCAndCSI))
|
checkNilError(t, existingPodsIndex.Add(v1mypodWithPVCAndCSI))
|
||||||
|
checkNilError(t, existingPodsIndex.Add(v1mypodIntreePVToCSI))
|
||||||
|
checkNilError(t, existingPodsIndex.Add(v1mypodIntreeInlineVolToCSI))
|
||||||
|
|
||||||
existingNodesIndex.Add(&corev1.Node{ObjectMeta: mynodeObjMeta})
|
existingNodesIndex.Add(&corev1.Node{ObjectMeta: mynodeObjMeta})
|
||||||
|
|
||||||
@ -1430,6 +1479,30 @@ func Test_nodePlugin_Admit(t *testing.T) {
|
|||||||
},
|
},
|
||||||
attributes: admission.NewAttributesRecord(makeTokenRequest(coremypodWithCSI.Name, v1mypodWithCSI.UID, []string{"foo"}), nil, tokenrequestKind, coremypod.Namespace, "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
|
attributes: admission.NewAttributesRecord(makeTokenRequest(coremypodWithCSI.Name, v1mypodWithCSI.UID, []string{"foo"}), nil, tokenrequestKind, coremypod.Namespace, "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "intree pv to csi, allow create of token when audience in pod --> csi --> driver --> tokenrequest with audience, ServiceAccountNodeAudienceRestriction=true",
|
||||||
|
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(coremypodIntreePVToCSI.Name, v1mypodIntreePVToCSI.UID, []string{"foo"}), nil, tokenrequestKind, coremypod.Namespace, "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "intree inline vol to csi, allow create of token when audience in pod --> csi --> driver --> tokenrequest with audience, ServiceAccountNodeAudienceRestriction=true",
|
||||||
|
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(coremypodIntreeInlineVolToCSI.Name, v1mypodIntreeInlineVolToCSI.UID, []string{"foo"}), nil, tokenrequestKind, coremypod.Namespace, "mysa", svcacctResource, "token", admission.Create, &metav1.CreateOptions{}, false, mynode),
|
||||||
|
},
|
||||||
|
|
||||||
// Unrelated objects
|
// Unrelated objects
|
||||||
{
|
{
|
||||||
|
@ -908,6 +908,27 @@ func TestNodeRestrictionServiceAccountAudience(t *testing.T) {
|
|||||||
}, metav1.CreateOptions{})
|
}, metav1.CreateOptions{})
|
||||||
checkNilError(t, err)
|
checkNilError(t, err)
|
||||||
|
|
||||||
|
_, err = superuserClient.CoreV1().PersistentVolumeClaims("ns").Create(context.TODO(), &corev1.PersistentVolumeClaim{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: "mypvc-azurefile"},
|
||||||
|
Spec: corev1.PersistentVolumeClaimSpec{
|
||||||
|
AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadOnlyMany},
|
||||||
|
Resources: corev1.VolumeResourceRequirements{Requests: corev1.ResourceList{corev1.ResourceStorage: resource.MustParse("1")}},
|
||||||
|
VolumeName: "mypv-azurefile",
|
||||||
|
},
|
||||||
|
}, metav1.CreateOptions{})
|
||||||
|
checkNilError(t, err)
|
||||||
|
|
||||||
|
_, err = superuserClient.CoreV1().PersistentVolumes().Create(context.TODO(), &corev1.PersistentVolume{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: "mypv-azurefile"},
|
||||||
|
Spec: corev1.PersistentVolumeSpec{
|
||||||
|
AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadOnlyMany},
|
||||||
|
Capacity: corev1.ResourceList{corev1.ResourceStorage: resource.MustParse("1")},
|
||||||
|
ClaimRef: &corev1.ObjectReference{Namespace: "ns", Name: "mypvc-azurefile"},
|
||||||
|
PersistentVolumeSource: corev1.PersistentVolumeSource{AzureFile: &corev1.AzureFilePersistentVolumeSource{ShareName: "share", SecretName: "secret"}},
|
||||||
|
},
|
||||||
|
}, metav1.CreateOptions{})
|
||||||
|
checkNilError(t, err)
|
||||||
|
|
||||||
node1Client, _ := clientsetForToken(tokenNode1, clientConfig)
|
node1Client, _ := clientsetForToken(tokenNode1, clientConfig)
|
||||||
createNode(t, node1Client, "node1")
|
createNode(t, node1Client, "node1")
|
||||||
createDefaultServiceAccount(t, superuserClient)
|
createDefaultServiceAccount(t, superuserClient)
|
||||||
@ -934,12 +955,12 @@ func TestNodeRestrictionServiceAccountAudience(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("pod --> csi --> driver --> tokenrequest with audience works", func(t *testing.T) {
|
t.Run("pod --> csi --> driver --> tokenrequest with audience works", func(t *testing.T) {
|
||||||
createCSIDriver(t, superuserClient, "csidriver-audience")
|
createCSIDriver(t, superuserClient, "csidriver-audience", "com.example.csi.mydriver")
|
||||||
csiDriverVolumeSource := &corev1.CSIVolumeSource{Driver: "com.example.csi.mydriver"}
|
csiDriverVolumeSource := &corev1.CSIVolumeSource{Driver: "com.example.csi.mydriver"}
|
||||||
pod := createPod(t, superuserClient, []corev1.Volume{{Name: "foo", VolumeSource: corev1.VolumeSource{CSI: csiDriverVolumeSource}}})
|
pod := createPod(t, superuserClient, []corev1.Volume{{Name: "foo", VolumeSource: corev1.VolumeSource{CSI: csiDriverVolumeSource}}})
|
||||||
expectAllowed(t, createTokenRequest(node1Client, pod.UID, "csidriver-audience"))
|
expectAllowed(t, createTokenRequest(node1Client, pod.UID, "csidriver-audience"))
|
||||||
deletePod(t, superuserClient, "pod1")
|
deletePod(t, superuserClient, "pod1")
|
||||||
deleteCSIDriver(t, superuserClient)
|
deleteCSIDriver(t, superuserClient, "com.example.csi.mydriver")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("pod --> pvc --> pv --> csi --> driver --> tokenrequest with audience forbidden - CSI driver not found", func(t *testing.T) {
|
t.Run("pod --> pvc --> pv --> csi --> driver --> tokenrequest with audience forbidden - CSI driver not found", func(t *testing.T) {
|
||||||
@ -950,21 +971,21 @@ func TestNodeRestrictionServiceAccountAudience(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("pod --> pvc --> pv --> csi --> driver --> tokenrequest with audience forbidden - pvc not found", func(t *testing.T) {
|
t.Run("pod --> pvc --> pv --> csi --> driver --> tokenrequest with audience forbidden - pvc not found", func(t *testing.T) {
|
||||||
createCSIDriver(t, superuserClient, "pvcnotfound-audience")
|
createCSIDriver(t, superuserClient, "pvcnotfound-audience", "com.example.csi.mydriver")
|
||||||
persistentVolumeClaimVolumeSource := &corev1.PersistentVolumeClaimVolumeSource{ClaimName: "mypvc1"}
|
persistentVolumeClaimVolumeSource := &corev1.PersistentVolumeClaimVolumeSource{ClaimName: "mypvc1"}
|
||||||
pod := createPod(t, superuserClient, []corev1.Volume{{Name: "foo", VolumeSource: corev1.VolumeSource{PersistentVolumeClaim: persistentVolumeClaimVolumeSource}}})
|
pod := createPod(t, superuserClient, []corev1.Volume{{Name: "foo", VolumeSource: corev1.VolumeSource{PersistentVolumeClaim: persistentVolumeClaimVolumeSource}}})
|
||||||
expectedForbiddenMessage(t, createTokenRequest(node1Client, pod.UID, "pvcnotfound-audience"), `error validating audience "pvcnotfound-audience": persistentvolumeclaim "mypvc1" not found`)
|
expectedForbiddenMessage(t, createTokenRequest(node1Client, pod.UID, "pvcnotfound-audience"), `error validating audience "pvcnotfound-audience": persistentvolumeclaim "mypvc1" not found`)
|
||||||
deletePod(t, superuserClient, "pod1")
|
deletePod(t, superuserClient, "pod1")
|
||||||
deleteCSIDriver(t, superuserClient)
|
deleteCSIDriver(t, superuserClient, "com.example.csi.mydriver")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("pod --> pvc --> pv --> csi --> driver --> tokenrequest with audience works", func(t *testing.T) {
|
t.Run("pod --> pvc --> pv --> csi --> driver --> tokenrequest with audience works", func(t *testing.T) {
|
||||||
createCSIDriver(t, superuserClient, "pvccsidriver-audience")
|
createCSIDriver(t, superuserClient, "pvccsidriver-audience", "com.example.csi.mydriver")
|
||||||
persistentVolumeClaimVolumeSource := &corev1.PersistentVolumeClaimVolumeSource{ClaimName: "mypvc"}
|
persistentVolumeClaimVolumeSource := &corev1.PersistentVolumeClaimVolumeSource{ClaimName: "mypvc"}
|
||||||
pod := createPod(t, superuserClient, []corev1.Volume{{Name: "foo", VolumeSource: corev1.VolumeSource{PersistentVolumeClaim: persistentVolumeClaimVolumeSource}}})
|
pod := createPod(t, superuserClient, []corev1.Volume{{Name: "foo", VolumeSource: corev1.VolumeSource{PersistentVolumeClaim: persistentVolumeClaimVolumeSource}}})
|
||||||
expectAllowed(t, createTokenRequest(node1Client, pod.UID, "pvccsidriver-audience"))
|
expectAllowed(t, createTokenRequest(node1Client, pod.UID, "pvccsidriver-audience"))
|
||||||
deletePod(t, superuserClient, "pod1")
|
deletePod(t, superuserClient, "pod1")
|
||||||
deleteCSIDriver(t, superuserClient)
|
deleteCSIDriver(t, superuserClient, "com.example.csi.mydriver")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("pod --> ephemeral --> pvc --> pv --> csi --> driver --> tokenrequest with audience forbidden - CSI driver not found", func(t *testing.T) {
|
t.Run("pod --> ephemeral --> pvc --> pv --> csi --> driver --> tokenrequest with audience forbidden - CSI driver not found", func(t *testing.T) {
|
||||||
@ -980,7 +1001,7 @@ func TestNodeRestrictionServiceAccountAudience(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("pod --> ephemeral --> pvc --> pv --> csi --> driver --> tokenrequest with audience works", func(t *testing.T) {
|
t.Run("pod --> ephemeral --> pvc --> pv --> csi --> driver --> tokenrequest with audience works", func(t *testing.T) {
|
||||||
createCSIDriver(t, superuserClient, "ephemeralcsidriver-audience")
|
createCSIDriver(t, superuserClient, "ephemeralcsidriver-audience", "com.example.csi.mydriver")
|
||||||
ephemeralVolumeSource := &corev1.EphemeralVolumeSource{VolumeClaimTemplate: &corev1.PersistentVolumeClaimTemplate{
|
ephemeralVolumeSource := &corev1.EphemeralVolumeSource{VolumeClaimTemplate: &corev1.PersistentVolumeClaimTemplate{
|
||||||
Spec: corev1.PersistentVolumeClaimSpec{
|
Spec: corev1.PersistentVolumeClaimSpec{
|
||||||
AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadOnlyMany},
|
AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadOnlyMany},
|
||||||
@ -990,28 +1011,28 @@ func TestNodeRestrictionServiceAccountAudience(t *testing.T) {
|
|||||||
pod := createPod(t, superuserClient, []corev1.Volume{{Name: "foo", VolumeSource: corev1.VolumeSource{Ephemeral: ephemeralVolumeSource}}})
|
pod := createPod(t, superuserClient, []corev1.Volume{{Name: "foo", VolumeSource: corev1.VolumeSource{Ephemeral: ephemeralVolumeSource}}})
|
||||||
expectAllowed(t, createTokenRequest(node1Client, pod.UID, "ephemeralcsidriver-audience"))
|
expectAllowed(t, createTokenRequest(node1Client, pod.UID, "ephemeralcsidriver-audience"))
|
||||||
deletePod(t, superuserClient, "pod1")
|
deletePod(t, superuserClient, "pod1")
|
||||||
deleteCSIDriver(t, superuserClient)
|
deleteCSIDriver(t, superuserClient, "com.example.csi.mydriver")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("csidriver exists but tokenrequest audience not found should be forbidden", func(t *testing.T) {
|
t.Run("csidriver exists but tokenrequest audience not found should be forbidden", func(t *testing.T) {
|
||||||
createCSIDriver(t, superuserClient, "csidriver-audience")
|
createCSIDriver(t, superuserClient, "csidriver-audience", "com.example.csi.mydriver")
|
||||||
pod := createPod(t, superuserClient, nil)
|
pod := createPod(t, superuserClient, nil)
|
||||||
expectedForbiddenMessage(t, createTokenRequest(node1Client, pod.UID, "csidriver-audience-not-found"), `audience "csidriver-audience-not-found" not found in pod spec volume`)
|
expectedForbiddenMessage(t, createTokenRequest(node1Client, pod.UID, "csidriver-audience-not-found"), `audience "csidriver-audience-not-found" not found in pod spec volume`)
|
||||||
deletePod(t, superuserClient, "pod1")
|
deletePod(t, superuserClient, "pod1")
|
||||||
deleteCSIDriver(t, superuserClient)
|
deleteCSIDriver(t, superuserClient, "com.example.csi.mydriver")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("pvc and csidriver exists but tokenrequest audience not found should be forbidden", func(t *testing.T) {
|
t.Run("pvc and csidriver exists but tokenrequest audience not found should be forbidden", func(t *testing.T) {
|
||||||
createCSIDriver(t, superuserClient, "csidriver-audience")
|
createCSIDriver(t, superuserClient, "csidriver-audience", "com.example.csi.mydriver")
|
||||||
persistentVolumeClaimVolumeSource := &corev1.PersistentVolumeClaimVolumeSource{ClaimName: "mypvc"}
|
persistentVolumeClaimVolumeSource := &corev1.PersistentVolumeClaimVolumeSource{ClaimName: "mypvc"}
|
||||||
pod := createPod(t, superuserClient, []corev1.Volume{{Name: "foo", VolumeSource: corev1.VolumeSource{PersistentVolumeClaim: persistentVolumeClaimVolumeSource}}})
|
pod := createPod(t, superuserClient, []corev1.Volume{{Name: "foo", VolumeSource: corev1.VolumeSource{PersistentVolumeClaim: persistentVolumeClaimVolumeSource}}})
|
||||||
expectedForbiddenMessage(t, createTokenRequest(node1Client, pod.UID, "csidriver-audience-not-found"), `audience "csidriver-audience-not-found" not found in pod spec volume`)
|
expectedForbiddenMessage(t, createTokenRequest(node1Client, pod.UID, "csidriver-audience-not-found"), `audience "csidriver-audience-not-found" not found in pod spec volume`)
|
||||||
deletePod(t, superuserClient, "pod1")
|
deletePod(t, superuserClient, "pod1")
|
||||||
deleteCSIDriver(t, superuserClient)
|
deleteCSIDriver(t, superuserClient, "com.example.csi.mydriver")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("ephemeral volume source with audience not found should be forbidden", func(t *testing.T) {
|
t.Run("ephemeral volume source with audience not found should be forbidden", func(t *testing.T) {
|
||||||
createCSIDriver(t, superuserClient, "csidriver-audience")
|
createCSIDriver(t, superuserClient, "csidriver-audience", "com.example.csi.mydriver")
|
||||||
ephemeralVolumeSource := &corev1.EphemeralVolumeSource{VolumeClaimTemplate: &corev1.PersistentVolumeClaimTemplate{
|
ephemeralVolumeSource := &corev1.EphemeralVolumeSource{VolumeClaimTemplate: &corev1.PersistentVolumeClaimTemplate{
|
||||||
Spec: corev1.PersistentVolumeClaimSpec{
|
Spec: corev1.PersistentVolumeClaimSpec{
|
||||||
AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadOnlyMany},
|
AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadOnlyMany},
|
||||||
@ -1021,7 +1042,23 @@ func TestNodeRestrictionServiceAccountAudience(t *testing.T) {
|
|||||||
pod := createPod(t, superuserClient, []corev1.Volume{{Name: "foo", VolumeSource: corev1.VolumeSource{Ephemeral: ephemeralVolumeSource}}})
|
pod := createPod(t, superuserClient, []corev1.Volume{{Name: "foo", VolumeSource: corev1.VolumeSource{Ephemeral: ephemeralVolumeSource}}})
|
||||||
expectedForbiddenMessage(t, createTokenRequest(node1Client, pod.UID, "csidriver-audience-not-found"), `audience "csidriver-audience-not-found" not found in pod spec volume`)
|
expectedForbiddenMessage(t, createTokenRequest(node1Client, pod.UID, "csidriver-audience-not-found"), `audience "csidriver-audience-not-found" not found in pod spec volume`)
|
||||||
deletePod(t, superuserClient, "pod1")
|
deletePod(t, superuserClient, "pod1")
|
||||||
deleteCSIDriver(t, superuserClient)
|
deleteCSIDriver(t, superuserClient, "com.example.csi.mydriver")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("intree pv to csi migration, pod --> csi --> driver --> tokenrequest with audience works", func(t *testing.T) {
|
||||||
|
createCSIDriver(t, superuserClient, "csidriver-audience", "file.csi.azure.com")
|
||||||
|
pod := createPod(t, superuserClient, []corev1.Volume{{Name: "foo", VolumeSource: corev1.VolumeSource{PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{ClaimName: "mypvc-azurefile"}}}})
|
||||||
|
expectAllowed(t, createTokenRequest(node1Client, pod.UID, "csidriver-audience"))
|
||||||
|
deletePod(t, superuserClient, "pod1")
|
||||||
|
deleteCSIDriver(t, superuserClient, "file.csi.azure.com")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("intree inline volume to csi migration, pod --> csi --> driver --> tokenrequest with audience works", func(t *testing.T) {
|
||||||
|
createCSIDriver(t, superuserClient, "csidriver-audience", "file.csi.azure.com")
|
||||||
|
pod := createPod(t, superuserClient, []corev1.Volume{{Name: "foo", VolumeSource: corev1.VolumeSource{AzureFile: &corev1.AzureFileVolumeSource{ShareName: "default", SecretName: "mypvsecret"}}}})
|
||||||
|
expectAllowed(t, createTokenRequest(node1Client, pod.UID, "csidriver-audience"))
|
||||||
|
deletePod(t, superuserClient, "pod1")
|
||||||
|
deleteCSIDriver(t, superuserClient, "file.csi.azure.com")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("token request with multiple audiences should be forbidden", func(t *testing.T) {
|
t.Run("token request with multiple audiences should be forbidden", func(t *testing.T) {
|
||||||
@ -1090,11 +1127,11 @@ func createTokenRequest(client clientset.Interface, uid types.UID, audiences ...
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createCSIDriver(t *testing.T, client clientset.Interface, audience string) {
|
func createCSIDriver(t *testing.T, client clientset.Interface, audience, driverName string) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
_, err := client.StorageV1().CSIDrivers().Create(context.TODO(), &storagev1.CSIDriver{
|
_, err := client.StorageV1().CSIDrivers().Create(context.TODO(), &storagev1.CSIDriver{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "com.example.csi.mydriver"},
|
ObjectMeta: metav1.ObjectMeta{Name: driverName},
|
||||||
Spec: storagev1.CSIDriverSpec{
|
Spec: storagev1.CSIDriverSpec{
|
||||||
TokenRequests: []storagev1.TokenRequest{{Audience: audience}},
|
TokenRequests: []storagev1.TokenRequest{{Audience: audience}},
|
||||||
},
|
},
|
||||||
@ -1102,10 +1139,10 @@ func createCSIDriver(t *testing.T, client clientset.Interface, audience string)
|
|||||||
checkNilError(t, err)
|
checkNilError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteCSIDriver(t *testing.T, client clientset.Interface) {
|
func deleteCSIDriver(t *testing.T, client clientset.Interface, driverName string) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
checkNilError(t, client.StorageV1().CSIDrivers().Delete(context.TODO(), "com.example.csi.mydriver", metav1.DeleteOptions{GracePeriodSeconds: ptr.To[int64](0)}))
|
checkNilError(t, client.StorageV1().CSIDrivers().Delete(context.TODO(), driverName, metav1.DeleteOptions{GracePeriodSeconds: ptr.To[int64](0)}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func createDefaultServiceAccount(t *testing.T, client clientset.Interface) {
|
func createDefaultServiceAccount(t *testing.T, client clientset.Interface) {
|
||||||
|
Loading…
Reference in New Issue
Block a user