Skip to content

Commit d7f5abf

Browse files
kaovilaiclaude
andcommitted
feat: Use CloudStorage creationSecret as fallback for BSL credentials
When a DataProtectionApplication references a CloudStorage CR without providing explicit credentials, the BSL controller now uses the CloudStorage's creationSecret as a fallback for authentication. Changes: - Enhanced BSL reconciliation to fallback to CloudStorage's creationSecret when DPA doesn't specify credentials - Moved fallback logic into centralized getSecretNameAndKeyFromCloudStorage function for better code organization - Updated validation to allow nil credentials when CloudStorage is referenced - Fixed related test cases to handle the new fallback behavior This allows users to avoid duplicating credential configuration between CloudStorage and DataProtectionApplication resources. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent d9617c6 commit d7f5abf

File tree

5 files changed

+70
-18
lines changed

5 files changed

+70
-18
lines changed

internal/controller/bsl.go

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,18 @@ func (r *DataProtectionApplicationReconciler) ReconcileBackupStorageLocations(lo
182182
}
183183
bsl.Spec.Config["enableSharedConfig"] = "true"
184184
}
185-
bsl.Spec.Credential = bslSpec.CloudStorage.Credential
185+
// Use DPA's CloudStorage credential if provided, otherwise fallback to CloudStorage's creationSecret
186+
if bslSpec.CloudStorage.Credential != nil {
187+
bsl.Spec.Credential = bslSpec.CloudStorage.Credential
188+
} else {
189+
// Use CloudStorage's creationSecret as the BSL credential
190+
bsl.Spec.Credential = &corev1.SecretKeySelector{
191+
LocalObjectReference: corev1.LocalObjectReference{
192+
Name: bucket.Spec.CreationSecret.Name,
193+
},
194+
Key: bucket.Spec.CreationSecret.Key,
195+
}
196+
}
186197
bsl.Spec.Default = bslSpec.CloudStorage.Default
187198
bsl.Spec.ObjectStorage = &velerov1.ObjectStorageLocation{
188199
Bucket: bucket.Spec.Name,
@@ -537,21 +548,15 @@ func (r *DataProtectionApplicationReconciler) ensureSecretDataExists(bsl *oadpv1
537548

538549
// Get secret details from either CloudStorage or Velero
539550
if bsl.CloudStorage != nil {
540-
// Make sure credentials are specified.
541-
if bsl.CloudStorage.Credential == nil {
542-
return fmt.Errorf("must provide a valid credential secret")
543-
}
544-
if bsl.CloudStorage.Credential.Name == "" {
545-
return fmt.Errorf("must provide a valid credential secret name")
546-
}
547-
// Check if user specified empty credential key
548-
if bsl.CloudStorage.Credential.Key == "" {
549-
return fmt.Errorf("must provide a valid credential secret key")
550-
}
551+
// Get credentials - this will fallback to CloudStorage CR if needed
551552
secretName, secretKey, err = r.getSecretNameAndKeyFromCloudStorage(bsl.CloudStorage)
552553
if err != nil {
553554
return err
554555
}
556+
// If still no secret found, it means CloudStorage CR doesn't exist or has no credentials
557+
if secretName == "" {
558+
return fmt.Errorf("must provide credentials either in DPA or CloudStorage CR")
559+
}
555560

556561
// Get provider type from CloudStorage
557562
if bsl.CloudStorage.CloudStorageRef.Name != "" {

internal/controller/bsl_test.go

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4564,7 +4564,7 @@ AZURE_CLOUD_NAME=AzurePublicCloud`),
45644564
wantErr: false,
45654565
},
45664566
{
4567-
name: "CloudStorage without credentials",
4567+
name: "CloudStorage without credentials - should use CloudStorage's creationSecret",
45684568
dpa: &oadpv1alpha1.DataProtectionApplication{
45694569
ObjectMeta: metav1.ObjectMeta{
45704570
Name: "test-dpa",
@@ -4584,8 +4584,34 @@ AZURE_CLOUD_NAME=AzurePublicCloud`),
45844584
Credential: nil,
45854585
},
45864586
},
4587-
wantErr: true,
4588-
errMsg: "must provide a valid credential secret",
4587+
objects: []client.Object{
4588+
&oadpv1alpha1.CloudStorage{
4589+
ObjectMeta: metav1.ObjectMeta{
4590+
Name: "no-cred-cs",
4591+
Namespace: "test-ns",
4592+
},
4593+
Spec: oadpv1alpha1.CloudStorageSpec{
4594+
Name: "test-bucket",
4595+
Provider: oadpv1alpha1.AWSBucketProvider,
4596+
CreationSecret: corev1.SecretKeySelector{
4597+
LocalObjectReference: corev1.LocalObjectReference{
4598+
Name: "cloud-creds",
4599+
},
4600+
Key: "cloud",
4601+
},
4602+
},
4603+
},
4604+
},
4605+
secret: &corev1.Secret{
4606+
ObjectMeta: metav1.ObjectMeta{
4607+
Name: "cloud-creds",
4608+
Namespace: "test-ns",
4609+
},
4610+
Data: map[string][]byte{
4611+
"cloud": []byte("[default]\naws_access_key_id=test\naws_secret_access_key=test"),
4612+
},
4613+
},
4614+
wantErr: false, // Should succeed using CloudStorage's creationSecret
45894615
},
45904616
{
45914617
name: "CloudStorage with empty credential name",
@@ -4613,7 +4639,7 @@ AZURE_CLOUD_NAME=AzurePublicCloud`),
46134639
},
46144640
},
46154641
wantErr: true,
4616-
errMsg: "must provide a valid credential secret name",
4642+
errMsg: "Secret key specified in CloudStorage cannot be empty",
46174643
},
46184644
{
46194645
name: "CloudStorage with empty credential key",
@@ -4642,7 +4668,7 @@ AZURE_CLOUD_NAME=AzurePublicCloud`),
46424668
},
46434669
},
46444670
wantErr: true,
4645-
errMsg: "must provide a valid credential secret key",
4671+
errMsg: "Secret key specified in CloudStorage cannot be empty",
46464672
},
46474673
{
46484674
name: "CloudStorage not found",

internal/controller/registry.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,15 @@ func (r *DataProtectionApplicationReconciler) getSecretNameAndKeyFromCloudStorag
251251
err := r.verifySecretContent(secretName, secretKey)
252252
return secretName, secretKey, err
253253
}
254+
255+
// If no credential is specified, fallback to CloudStorage's creationSecret
256+
if cloudStorage.CloudStorageRef.Name != "" {
257+
bucket := &oadpv1alpha1.CloudStorage{}
258+
if err := r.Get(r.Context, client.ObjectKey{Namespace: r.dpa.Namespace, Name: cloudStorage.CloudStorageRef.Name}, bucket); err == nil {
259+
return bucket.Spec.CreationSecret.Name, bucket.Spec.CreationSecret.Key, nil
260+
}
261+
}
262+
254263
return "", "", nil
255264
}
256265

internal/controller/registry_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,11 @@ func TestDPAReconciler_getSecretNameAndKeyFromCloudStorage(t *testing.T) {
316316
Log: logr.Discard(),
317317
Context: newContextForTest(),
318318
EventRecorder: record.NewFakeRecorder(10),
319+
dpa: &oadpv1alpha1.DataProtectionApplication{
320+
ObjectMeta: metav1.ObjectMeta{
321+
Namespace: "test-ns",
322+
},
323+
},
319324
}
320325

321326
if tt.wantProfile == "aws-cloud-cred" {

internal/controller/validator_test.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -557,12 +557,19 @@ func TestDPAReconciler_ValidateDataProtectionCR(t *testing.T) {
557557
Namespace: "test-ns",
558558
},
559559
Spec: oadpv1alpha1.CloudStorageSpec{
560+
Name: "test-bucket",
560561
Provider: "aws",
562+
CreationSecret: corev1.SecretKeySelector{
563+
LocalObjectReference: corev1.LocalObjectReference{
564+
Name: "", // Empty secret name
565+
},
566+
Key: "cloud",
567+
},
561568
},
562569
},
563570
},
564571
wantErr: true,
565-
messageErr: "must provide a valid credential secret",
572+
messageErr: "must provide credentials either in DPA or CloudStorage CR",
566573
},
567574
{
568575
name: "given valid DPA CR bucket BSL configured and AWS Default Plugin with secret",

0 commit comments

Comments
 (0)