Skip to content

Commit f4d0af8

Browse files
committed
fix: deduplicate cert secret volumes for shared names
1 parent e5c62cd commit f4d0af8

2 files changed

Lines changed: 120 additions & 9 deletions

File tree

internal/controller/codercontrolplane_controller.go

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,7 +1012,20 @@ func (r *CoderControlPlaneReconciler) reconcileDeployment(ctx context.Context, c
10121012
})
10131013
}
10141014

1015-
for _, secret := range coderControlPlane.Spec.Certs.Secrets {
1015+
certSecretNameCounts := make(map[string]int, len(coderControlPlane.Spec.Certs.Secrets))
1016+
for i := range coderControlPlane.Spec.Certs.Secrets {
1017+
secretName := strings.TrimSpace(coderControlPlane.Spec.Certs.Secrets[i].Name)
1018+
if secretName == "" {
1019+
continue
1020+
}
1021+
certSecretNameCounts[secretName]++
1022+
}
1023+
1024+
certVolumeNameBySecret := make(map[string]string, len(certSecretNameCounts))
1025+
certMountFileCount := make(map[string]int, len(coderControlPlane.Spec.Certs.Secrets))
1026+
certSelectorSeen := make(map[string]struct{}, len(coderControlPlane.Spec.Certs.Secrets))
1027+
for i := range coderControlPlane.Spec.Certs.Secrets {
1028+
secret := coderControlPlane.Spec.Certs.Secrets[i]
10161029
secret.Name = strings.TrimSpace(secret.Name)
10171030
secret.Key = strings.TrimSpace(secret.Key)
10181031
if secret.Name == "" {
@@ -1022,16 +1035,43 @@ func (r *CoderControlPlaneReconciler) reconcileDeployment(ctx context.Context, c
10221035
return fmt.Errorf("assertion failed: cert secret key must not be empty")
10231036
}
10241037

1025-
volumeName := volumeNameForSecret("ca-cert", secret.Name)
1026-
volumes = append(volumes, corev1.Volume{
1027-
Name: volumeName,
1028-
VolumeSource: corev1.VolumeSource{
1029-
Secret: &corev1.SecretVolumeSource{SecretName: secret.Name},
1030-
},
1031-
})
1038+
selectorKey := fmt.Sprintf("%s\x00%s", secret.Name, secret.Key)
1039+
if _, seen := certSelectorSeen[selectorKey]; seen {
1040+
continue
1041+
}
1042+
certSelectorSeen[selectorKey] = struct{}{}
1043+
1044+
volumeName, volumeExists := certVolumeNameBySecret[secret.Name]
1045+
if !volumeExists {
1046+
volumeName = volumeNameForSecret("ca-cert", secret.Name)
1047+
certVolumeNameBySecret[secret.Name] = volumeName
1048+
volumes = append(volumes, corev1.Volume{
1049+
Name: volumeName,
1050+
VolumeSource: corev1.VolumeSource{
1051+
Secret: &corev1.SecretVolumeSource{SecretName: secret.Name},
1052+
},
1053+
})
1054+
}
1055+
1056+
mountFileBase := secret.Name
1057+
if certSecretNameCounts[secret.Name] > 1 {
1058+
mountFileBase = fmt.Sprintf("%s-%s", secret.Name, secret.Key)
1059+
}
1060+
mountFileCount := certMountFileCount[mountFileBase]
1061+
certMountFileCount[mountFileBase] = mountFileCount + 1
1062+
1063+
mountFileName := mountFileBase
1064+
if !strings.HasSuffix(mountFileName, ".crt") {
1065+
mountFileName += ".crt"
1066+
}
1067+
if mountFileCount > 0 {
1068+
mountFileName = strings.TrimSuffix(mountFileName, ".crt")
1069+
mountFileName = fmt.Sprintf("%s-%d.crt", mountFileName, mountFileCount+1)
1070+
}
1071+
10321072
volumeMounts = append(volumeMounts, corev1.VolumeMount{
10331073
Name: volumeName,
1034-
MountPath: fmt.Sprintf("/etc/ssl/certs/%s.crt", secret.Name),
1074+
MountPath: fmt.Sprintf("/etc/ssl/certs/%s", mountFileName),
10351075
SubPath: secret.Key,
10361076
ReadOnly: true,
10371077
})

internal/controller/codercontrolplane_controller_test.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3644,6 +3644,77 @@ func TestReconcile_TLSAndCertSecretVolumeNameSanitization(t *testing.T) {
36443644
}
36453645
}
36463646

3647+
func TestReconcile_CertSecretsWithSharedSecretNameReuseVolume(t *testing.T) {
3648+
ensureGatewaySchemeRegistered(t)
3649+
ctx := context.Background()
3650+
3651+
cp := &coderv1alpha1.CoderControlPlane{
3652+
ObjectMeta: metav1.ObjectMeta{Name: "test-cert-secret-shared-volume", Namespace: "default"},
3653+
Spec: coderv1alpha1.CoderControlPlaneSpec{
3654+
Image: "test-certs-shared-volume:latest",
3655+
Certs: coderv1alpha1.CertsSpec{
3656+
Secrets: []coderv1alpha1.CertSecretSelector{
3657+
{Name: "shared.ca.secret", Key: "ca.crt"},
3658+
{Name: "shared.ca.secret", Key: "alt.crt"},
3659+
},
3660+
},
3661+
},
3662+
}
3663+
if err := k8sClient.Create(ctx, cp); err != nil {
3664+
t.Fatalf("create control plane: %v", err)
3665+
}
3666+
t.Cleanup(func() {
3667+
_ = k8sClient.Delete(ctx, cp)
3668+
})
3669+
3670+
r := &controller.CoderControlPlaneReconciler{Client: k8sClient, Scheme: scheme}
3671+
if _, err := r.Reconcile(ctx, ctrl.Request{NamespacedName: types.NamespacedName{Name: cp.Name, Namespace: cp.Namespace}}); err != nil {
3672+
t.Fatalf("reconcile control plane: %v", err)
3673+
}
3674+
3675+
deployment := &appsv1.Deployment{}
3676+
if err := k8sClient.Get(ctx, types.NamespacedName{Name: cp.Name, Namespace: cp.Namespace}, deployment); err != nil {
3677+
t.Fatalf("get deployment: %v", err)
3678+
}
3679+
podSpec := deployment.Spec.Template.Spec
3680+
container := podSpec.Containers[0]
3681+
3682+
certVolumeName := ""
3683+
certVolumeCount := 0
3684+
for _, volume := range podSpec.Volumes {
3685+
if volume.Secret == nil || volume.Secret.SecretName != "shared.ca.secret" {
3686+
continue
3687+
}
3688+
certVolumeCount++
3689+
certVolumeName = volume.Name
3690+
}
3691+
if certVolumeCount != 1 {
3692+
t.Fatalf("expected exactly one cert volume for shared secret, got %d volumes: %+v", certVolumeCount, podSpec.Volumes)
3693+
}
3694+
3695+
expectedMountBySubPath := map[string]string{
3696+
"ca.crt": "/etc/ssl/certs/shared.ca.secret-ca.crt",
3697+
"alt.crt": "/etc/ssl/certs/shared.ca.secret-alt.crt",
3698+
}
3699+
mountCount := 0
3700+
for _, mount := range container.VolumeMounts {
3701+
if mount.Name != certVolumeName {
3702+
continue
3703+
}
3704+
expectedPath, ok := expectedMountBySubPath[mount.SubPath]
3705+
if !ok {
3706+
t.Fatalf("unexpected cert subPath %q for mount %#v", mount.SubPath, mount)
3707+
}
3708+
if mount.MountPath != expectedPath {
3709+
t.Fatalf("expected mount path %q for subPath %q, got %q", expectedPath, mount.SubPath, mount.MountPath)
3710+
}
3711+
mountCount++
3712+
}
3713+
if mountCount != len(expectedMountBySubPath) {
3714+
t.Fatalf("expected %d cert volume mounts for shared secret, got %d mounts: %+v", len(expectedMountBySubPath), mountCount, container.VolumeMounts)
3715+
}
3716+
}
3717+
36473718
func TestReconcile_PassThroughConfiguration(t *testing.T) {
36483719
ensureGatewaySchemeRegistered(t)
36493720
ctx := context.Background()

0 commit comments

Comments
 (0)