Skip to content

Commit cfda38e

Browse files
authored
DBInstance/DBCluster password updates on secret ref changes (#170)
This patch adds a new feature to the rds-controller allowing users to update their `DBInstance` and `DBCluster` passwords, by modifying the secretReference (namespace, name or key). Prior to this patch the controller wasn't able to update `DBInstance` and `DBCluster` passwords due to it's inability to calculate the difference between a desired and observed states. The fact that the API doesn't return any information about the password combined with the controller unable to detect changes of the secret refs By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
1 parent 149cd19 commit cfda38e

17 files changed

+307
-39
lines changed

apis/v1alpha1/ack-generate-metadata.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
ack_generate_info:
2-
build_date: "2024-02-14T04:08:17Z"
2+
build_date: "2024-02-26T20:53:40Z"
33
build_hash: 947081ffebdeefcf2c61c4ca6d7e68810bdf9d08
44
go_version: go1.22.0
55
version: v0.30.0
6-
api_directory_checksum: ec327bd746176accff503d6ca1306e08a55ac61b
6+
api_directory_checksum: 11c44032679e136f20ebca3e336bdc3bd8f71312
77
api_version: v1alpha1
88
aws_sdk_go_version: v1.44.232
99
generator_config_info:

apis/v1alpha1/annotation.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License"). You may
4+
// not use this file except in compliance with the License. A copy of the
5+
// License is located at
6+
//
7+
// http://aws.amazon.com/apache2.0/
8+
//
9+
// or in the "license" file accompanying this file. This file is distributed
10+
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
11+
// express or implied. See the License for the specific language governing
12+
// permissions and limitations under the License.
13+
14+
package v1alpha1
15+
16+
import "fmt"
17+
18+
var (
19+
// LastAppliedConfigMapAnnotation is the annotation key used to store the namespaced name
20+
// of the last used secret for setting the master user password of a DBInstance or DBCluster.
21+
//
22+
// The secret namespaced name stored in this annotation is used to compute the "reference" delta
23+
// when the user updates the DBInstance or DBCluster resource.
24+
//
25+
// This annotation is only applied by the rds-controller, and should not be modified by the user.
26+
// In case the user modifies this annotation, the rds-controller may not be able to correctly
27+
// compute the "reference" delta, and can result in the rds-controller making unnecessary password
28+
// updates to the DBInstance or DBCluster.
29+
LastAppliedSecretAnnotation = fmt.Sprintf("%s/last-applied-secret-reference", GroupVersion.Group)
30+
)

pkg/resource/db_cluster/custom_update.go

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,16 @@ func (rm *resourceManager) customUpdate(
6464
ackcondition.SetSynced(desired, corev1.ConditionTrue, nil, nil)
6565
return desired, nil
6666
}
67+
if delta.DifferentAt("Spec.Tags") {
68+
if err = rm.syncTags(ctx, desired, latest); err != nil {
69+
return nil, err
70+
}
71+
} else if !delta.DifferentExcept("Spec.Tags") {
72+
// If the only difference between the desired and latest is in the
73+
// Spec.Tags field, we can skip the modify db cluster call.
74+
return desired, nil
75+
}
76+
6777
input, err := rm.newCustomUpdateRequestPayload(ctx, desired, latest, delta)
6878
if err != nil {
6979
return nil, err
@@ -77,11 +87,6 @@ func (rm *resourceManager) customUpdate(
7787
if err != nil {
7888
return nil, err
7989
}
80-
if delta.DifferentAt("Spec.Tags") {
81-
if err = rm.syncTags(ctx, desired, latest); err != nil {
82-
return nil, err
83-
}
84-
}
8590
// Merge in the information we read from the API call above to the copy of
8691
// the original Kubernetes object we passed to the function
8792
ko := desired.ko.DeepCopy()
@@ -503,9 +508,20 @@ func (rm *resourceManager) customUpdate(
503508
} else {
504509
ko.Status.VPCSecurityGroups = nil
505510
}
506-
507511
rm.setStatusDefaults(ko)
508-
return &resource{ko}, nil
512+
// When ModifyDBInstance API is successful, it asynchronously
513+
// updates the DBInstanceStatus. Requeue to find the current
514+
// DBInstance status and set Synced condition accordingly
515+
r := &resource{ko}
516+
if err == nil {
517+
// set the last-applied-secret-reference annotation on the DB instance
518+
// resource.
519+
setLastAppliedSecretReferenceAnnotation(r)
520+
// Setting resource synced condition to false will trigger a requeue of
521+
// the resource. No need to return a requeue error here.
522+
ackcondition.SetSynced(r, corev1.ConditionFalse, nil, nil)
523+
}
524+
return r, nil
509525
}
510526

511527
// newCustomUpdateRequestPayload returns an SDK-specific struct for the HTTP

pkg/resource/db_cluster/delta.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/resource/db_cluster/hooks.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"fmt"
2020

2121
svcapitypes "github.com/aws-controllers-k8s/rds-controller/apis/v1alpha1"
22+
"github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1"
2223
ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare"
2324
ackcondition "github.com/aws-controllers-k8s/runtime/pkg/condition"
2425
ackrequeue "github.com/aws-controllers-k8s/runtime/pkg/requeue"
@@ -308,3 +309,44 @@ func (rm *resourceManager) restoreDbClusterFromSnapshot(
308309
}
309310
return &resource{r.ko}, nil
310311
}
312+
313+
// TODO(a-hilaly): generate this code.
314+
315+
// getLastAppliedSecretReferenceString returns a string representation of the
316+
// last-applied secret reference.
317+
func getLastAppliedSecretReferenceString(r *v1alpha1.SecretKeyReference) string {
318+
if r == nil {
319+
return ""
320+
}
321+
return fmt.Sprintf("%s/%s.%s", r.Namespace, r.Name, r.Key)
322+
}
323+
324+
// setLastAppliedSecretReferenceAnnotation sets the last-applied secret reference
325+
// annotation on the supplied resource.
326+
func setLastAppliedSecretReferenceAnnotation(r *resource) {
327+
if r.ko.Annotations == nil {
328+
r.ko.Annotations = make(map[string]string)
329+
}
330+
r.ko.Annotations[svcapitypes.LastAppliedSecretAnnotation] = getLastAppliedSecretReferenceString(r.ko.Spec.MasterUserPassword)
331+
}
332+
333+
// getLastAppliedSecretReferenceAnnotation returns the last-applied secret reference
334+
// annotation on the supplied resource.
335+
func getLastAppliedSecretReferenceAnnotation(r *resource) string {
336+
if r.ko.Annotations == nil {
337+
return ""
338+
}
339+
return r.ko.Annotations[svcapitypes.LastAppliedSecretAnnotation]
340+
}
341+
342+
func compareSecretReferenceChanges(
343+
delta *ackcompare.Delta,
344+
desired *resource,
345+
latest *resource,
346+
) {
347+
oldRef := getLastAppliedSecretReferenceAnnotation(desired)
348+
newRef := getLastAppliedSecretReferenceString(desired.ko.Spec.MasterUserPassword)
349+
if oldRef != newRef {
350+
delta.Add("Spec.MasterUserPassword", oldRef, newRef)
351+
}
352+
}

pkg/resource/db_cluster/sdk.go

Lines changed: 7 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/resource/db_instance/delta.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/resource/db_instance/hooks.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"strings"
2121

2222
svcapitypes "github.com/aws-controllers-k8s/rds-controller/apis/v1alpha1"
23+
"github.com/aws-controllers-k8s/runtime/apis/core/v1alpha1"
2324
ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare"
2425
ackcondition "github.com/aws-controllers-k8s/runtime/pkg/condition"
2526
ackrequeue "github.com/aws-controllers-k8s/runtime/pkg/requeue"
@@ -523,3 +524,44 @@ func sdkTagsFromResourceTags(
523524
}
524525
return tags
525526
}
527+
528+
// TODO(a-hilaly): generate this code.
529+
530+
// getLastAppliedSecretReferenceString returns a string representation of the
531+
// last-applied secret reference.
532+
func getLastAppliedSecretReferenceString(r *v1alpha1.SecretKeyReference) string {
533+
if r == nil {
534+
return ""
535+
}
536+
return fmt.Sprintf("%s/%s.%s", r.Namespace, r.Name, r.Key)
537+
}
538+
539+
// setLastAppliedSecretReferenceAnnotation sets the last-applied secret reference
540+
// annotation on the supplied resource.
541+
func setLastAppliedSecretReferenceAnnotation(r *resource) {
542+
if r.ko.Annotations == nil {
543+
r.ko.Annotations = make(map[string]string)
544+
}
545+
r.ko.Annotations[svcapitypes.LastAppliedSecretAnnotation] = getLastAppliedSecretReferenceString(r.ko.Spec.MasterUserPassword)
546+
}
547+
548+
// getLastAppliedSecretReferenceAnnotation returns the last-applied secret reference
549+
// annotation on the supplied resource.
550+
func getLastAppliedSecretReferenceAnnotation(r *resource) string {
551+
if r.ko.Annotations == nil {
552+
return ""
553+
}
554+
return r.ko.Annotations[svcapitypes.LastAppliedSecretAnnotation]
555+
}
556+
557+
func compareSecretReferenceChanges(
558+
delta *ackcompare.Delta,
559+
desired *resource,
560+
latest *resource,
561+
) {
562+
oldRef := getLastAppliedSecretReferenceAnnotation(desired)
563+
newRef := getLastAppliedSecretReferenceString(desired.ko.Spec.MasterUserPassword)
564+
if oldRef != newRef {
565+
delta.Add("Spec.MasterUserPassword", oldRef, newRef)
566+
}
567+
}

pkg/resource/db_instance/sdk.go

Lines changed: 14 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
compareTags(delta, a, b)
2+
compareSecretReferenceChanges(delta, a, b)

0 commit comments

Comments
 (0)