Skip to content

Commit 427897e

Browse files
committed
Clean up dead code and fix issues in PvCSI service account validation
- Remove unused vulnerable regex constant PvCsiServiceAccountregex - Fix test cases to match new secure validation logic - Correct test expectations for security fixes (malicious accounts now properly blocked) - Fix typo in error message (namesapace -> namespace) - Refactor duplicated cluster API client creation into helper function - Update test comments to highlight security improvements Removed dead/duplicate code: - PvCsiServiceAccountregex constant (line 42) - no longer used - Outdated test cases expecting malicious accounts to be allowed - Duplicated cluster API client creation code Security test improvements: - malicious-ns:evil-pvcsi now correctly blocked (was allowing bypass) - Wrong namespace tests now properly expect false - Added tests for empty cluster names and colon injection attacks Code quality improvements: - getClusterAPIClient() helper eliminates code duplication - Fixed spelling error in log message - All string literals appropriately scoped as local constants Author: ab002488
1 parent 208a4c3 commit 427897e

2 files changed

Lines changed: 37 additions & 38 deletions

File tree

pkg/syncer/admissionhandler/validate_cnsfileaccessconfig.go

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ import (
3939

4040
const (
4141
KubernetesServiceAccount = "system:serviceaccount:kube-system"
42-
PvCsiServiceAccountregex = "^system:serviceaccount:[^:]+:(vsphere-csi-controller|vsphere-csi-node|pvcsi|[^:]*-pvcsi)$"
4342
KubernetesAdmin = "kubernetes-admin"
4443
)
4544

@@ -150,7 +149,7 @@ func cnsFileAccessConfigAlreadyExists(ctx context.Context, clientConfig *rest.Co
150149
LabelSelector: labelSelector,
151150
})
152151
if err != nil {
153-
log.Errorf("failed to list CnsFileAccessConfigList CRs from %s namesapace. Error: %+v",
152+
log.Errorf("failed to list CnsFileAccessConfigList CRs from %s namespace. Error: %+v",
154153
namespace, err)
155154
return "", err
156155
}
@@ -321,17 +320,20 @@ func validateProviderServiceAccount(serviceAccountName string) (bool, error) {
321320
return validateAgainstAllClusters(ctx, serviceAccountName)
322321
}
323322

324-
// getExpectedProviderServiceAccountName gets the expected service account name
325-
// for the current cluster context following the reference implementation
326-
func getExpectedProviderServiceAccountName(ctx context.Context) (string, error) {
327-
// Get in-cluster config
323+
// getClusterAPIClient creates a Kubernetes client for cluster API operations
324+
func getClusterAPIClient(ctx context.Context) (client.Client, error) {
328325
config, err := rest.InClusterConfig()
329326
if err != nil {
330-
return "", err
327+
return nil, err
331328
}
332329

333-
// Create client for cluster API
334-
k8sClient, err := k8s.NewClientForGroup(ctx, config, ccV1beta2.GroupVersion.Group)
330+
return k8s.NewClientForGroup(ctx, config, ccV1beta2.GroupVersion.Group)
331+
}
332+
333+
// getExpectedProviderServiceAccountName gets the expected service account name
334+
// for the current cluster context following the reference implementation
335+
func getExpectedProviderServiceAccountName(ctx context.Context) (string, error) {
336+
k8sClient, err := getClusterAPIClient(ctx)
335337
if err != nil {
336338
return "", err
337339
}
@@ -356,17 +358,9 @@ func getExpectedProviderServiceAccountName(ctx context.Context) (string, error)
356358

357359
// validateAgainstAllClusters validates the service account name against all available clusters
358360
func validateAgainstAllClusters(ctx context.Context, serviceAccountName string) (bool, error) {
359-
// Get in-cluster config
360-
config, err := rest.InClusterConfig()
361-
if err != nil {
362-
// Fall back to basic validation if we can't get config
363-
return validateBasicProviderServiceAccountPattern(serviceAccountName), nil
364-
}
365-
366-
// Create client for cluster API
367-
k8sClient, err := k8s.NewClientForGroup(ctx, config, ccV1beta2.GroupVersion.Group)
361+
k8sClient, err := getClusterAPIClient(ctx)
368362
if err != nil {
369-
// Fall back to basic validation if we can't create client
363+
// Fall back to basic validation if we can't get client
370364
return validateBasicProviderServiceAccountPattern(serviceAccountName), nil
371365
}
372366

pkg/syncer/admissionhandler/validate_cnsfileaccessconfig_test.go

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -37,27 +37,27 @@ func TestValidatePvCSIServiceAccount(t *testing.T) {
3737
expected: true,
3838
},
3939
{
40-
name: "Valid pvcsi service account",
41-
username: "system:serviceaccount:vmware-system-csi:some-pvcsi",
40+
name: "Valid legacy pvcsi service account",
41+
username: "system:serviceaccount:kube-system:pvcsi",
4242
expected: true,
4343
},
4444
{
45-
name: "Valid service account ending with -pvcsi",
46-
username: "system:serviceaccount:vmware-system-csi:tenant-pvcsi",
47-
expected: true,
45+
name: "Valid cluster-pvcsi pattern (fallback validation)",
46+
username: "system:serviceaccount:vmware-system-csi:test-cluster-pvcsi",
47+
expected: true, // Falls back to basic validation when cluster API unavailable
4848
},
4949
{
50-
name: "Security vulnerability - malicious service account with colon bypass",
50+
name: "SECURITY FIX: malicious service account in wrong namespace blocked",
5151
username: "system:serviceaccount:malicious-ns:evil-pvcsi",
52-
expected: true, // This should still be allowed as it's a legitimate pattern
52+
expected: false, // Now properly blocked - wrong namespace
5353
},
5454
{
55-
name: "Security vulnerability - attempt to bypass with multiple colons",
55+
name: "SECURITY FIX: attempt to bypass with multiple colons blocked",
5656
username: "system:serviceaccount:namespace:extra:vsphere-csi-controller",
5757
expected: false,
5858
},
5959
{
60-
name: "Invalid - wrong service account name",
60+
name: "Invalid - wrong service account name in valid namespace",
6161
username: "system:serviceaccount:vmware-system-csi:invalid-service-account",
6262
expected: false,
6363
},
@@ -97,29 +97,34 @@ func TestValidatePvCSIServiceAccount(t *testing.T) {
9797
expected: false,
9898
},
9999
{
100-
name: "Edge case - namespace with dashes",
100+
name: "Invalid - valid service account in unauthorized namespace",
101101
username: "system:serviceaccount:my-namespace-with-dashes:vsphere-csi-node",
102-
expected: true,
102+
expected: false, // Wrong namespace - only vmware-system-csi allowed for CSI service accounts
103103
},
104104
{
105-
name: "Edge case - namespace with numbers",
105+
name: "Invalid - valid service account in unauthorized namespace",
106106
username: "system:serviceaccount:namespace123:vsphere-csi-controller",
107-
expected: true,
107+
expected: false, // Wrong namespace - only vmware-system-csi allowed for CSI service accounts
108108
},
109109
{
110-
name: "Test exact pvcsi service account",
110+
name: "Invalid - pvcsi service account in wrong namespace",
111111
username: "system:serviceaccount:some-namespace:pvcsi",
112-
expected: true,
112+
expected: false, // pvcsi only allowed in kube-system namespace
113113
},
114114
{
115-
name: "Original vulnerability - multiple colon bypass attempt",
115+
name: "SECURITY FIX: multiple colon bypass attempt blocked",
116116
username: "system:serviceaccount:malicious:namespace:attacker-pvcsi",
117117
expected: false,
118118
},
119119
{
120-
name: "Service account with colon in name (should be blocked)",
121-
username: "system:serviceaccount:namespace:service:account-pvcsi",
122-
expected: false,
120+
name: "SECURITY FIX: service account with colon in name blocked",
121+
username: "system:serviceaccount:vmware-system-csi:service:account-pvcsi",
122+
expected: false, // Colon in cluster name blocked by fallback validation
123+
},
124+
{
125+
name: "Invalid - empty cluster name with -pvcsi suffix",
126+
username: "system:serviceaccount:vmware-system-csi:-pvcsi",
127+
expected: false, // Empty cluster name blocked by fallback validation
123128
},
124129
}
125130

0 commit comments

Comments
 (0)