Skip to content

Commit bb42ce3

Browse files
graindcafeDonatien26
authored andcommitted
Add the capability to read existing secret for an S3User
1 parent c77853a commit bb42ce3

File tree

7 files changed

+146
-53
lines changed

7 files changed

+146
-53
lines changed

cmd/main.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ func main() {
8080

8181
//K8S related variable
8282
var overrideExistingSecret bool
83+
var readExistingSecret bool
8384

8485
flag.StringVar(
8586
&metricsAddr,
@@ -106,6 +107,12 @@ func main() {
106107
false,
107108
"Override existing secret associated to user in case of the secret already exist",
108109
)
110+
flag.BoolVar(
111+
&readExistingSecret,
112+
"read-existing-secret",
113+
false,
114+
"Read existing secret associated to user in case of the secret already exist",
115+
)
109116

110117
opts := zap.Options{
111118
Development: true,
@@ -203,6 +210,7 @@ func main() {
203210
Client: mgr.GetClient(),
204211
Scheme: mgr.GetScheme(),
205212
OverrideExistingSecret: overrideExistingSecret,
213+
ReadExistingSecret: readExistingSecret,
206214
ReconcilePeriod: reconcilePeriod,
207215
S3factory: s3Factory,
208216
ControllerHelper: controllerHelper,

deploy/charts/s3-operator/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,6 @@ A Helm chart for deploying an operator to manage S3 resources (eg buckets, polic
2424
| crds.install | bool | `true` | Install and upgrade CRDs |
2525
| crds.keep | bool | `true` | Keep CRDs on chart uninstall |
2626
| kubernetes.clusterDomain | string | `"cluster.local"` | |
27-
| kubernetes.overrideExistingSecret | bool | `false` | |
27+
| kubernetes.overrideExistingSecret | bool | `false` | When creating an S3User, update existing secret with the generated secret key |
28+
| kubernetes.readExistingSecret | bool | `false` | When creating an S3User, read existing secret to retrieve the secret key |
2829
| s3 | object | `{"default":{"accessKey":"accessKey","createNamespace":true,"deletion":{"bucket":true,"path":false,"policy":false,"s3user":false},"enabled":false,"namespace":"s3-operator","region":"us-east-1","s3Provider":"minio","secretKey":"secretKey","url":"https://localhost:9000"}}` | Default S3 Instance |
29-

deploy/charts/s3-operator/templates/deployment.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ spec:
3838
- --metrics-bind-address=127.0.0.1:8080
3939
- --leader-elect
4040
- --override-existing-secret={{ .Values.kubernetes.overrideExistingSecret }}
41+
- --read-existing-secret={{ .Values.kubernetes.readExistingSecret }}
4142
{{- if .Values.controllerManager.manager.extraArgs }}
4243
{{- toYaml .Values.controllerManager.manager.extraArgs | nindent 8 }}
4344
{{- end }}

deploy/charts/s3-operator/values.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ controllerManager:
4848
kubernetes:
4949
clusterDomain: cluster.local
5050
overrideExistingSecret: false
51+
readExistingSecret: false
5152

5253
# -- Default S3 Instance
5354
s3:

internal/controller/user/controller.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ type S3UserReconciler struct {
4444
client.Client
4545
Scheme *runtime.Scheme
4646
OverrideExistingSecret bool
47+
ReadExistingSecret bool
4748
ReconcilePeriod time.Duration
4849
S3factory s3factory.S3Factory
4950
ControllerHelper *helpers.ControllerHelper

internal/controller/user/reconcile.go

Lines changed: 100 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ func (r *S3UserReconciler) handleUpdate(
247247
err,
248248
)
249249
}
250-
250+
ownedSecret := true
251251
userOwnedlinkedSecrets, err := r.getUserLinkedSecrets(ctx, userResource)
252252
if err != nil {
253253
logger.Error(
@@ -267,8 +267,27 @@ func (r *S3UserReconciler) handleUpdate(
267267
err,
268268
)
269269
}
270+
userUnlinkedSecret, err := r.getUserUnlinkedSecret(ctx, userResource.Namespace, userResource.Spec.SecretName, userResource.Name)
271+
if err != nil {
272+
logger.Error(
273+
err,
274+
"An error occurred while listing the user's secret",
275+
"userResourceName",
276+
userResource.Name,
277+
"NamespacedName",
278+
req.NamespacedName.String(),
279+
)
280+
return r.SetReconciledCondition(
281+
ctx,
282+
req,
283+
userResource,
284+
s3v1alpha1.Unreachable,
285+
"Impossible to list the user's secret",
286+
err,
287+
)
288+
}
270289
currentUserSecret := corev1.Secret{}
271-
if len(userOwnedlinkedSecrets) == 0 {
290+
if len(userOwnedlinkedSecrets) == 0 && userUnlinkedSecret == nil {
272291
logger.Info(
273292
"No Secret associated to user found, user will be deleted from the S3 backend, then recreated with a secret",
274293
"userResourceName",
@@ -298,6 +317,9 @@ func (r *S3UserReconciler) handleUpdate(
298317
)
299318
}
300319
return r.handleCreate(ctx, req, userResource)
320+
} else if userUnlinkedSecret != nil {
321+
currentUserSecret = *userUnlinkedSecret
322+
ownedSecret = false
301323
} else {
302324
foundSecret := false
303325
for _, linkedsecret := range userOwnedlinkedSecrets {
@@ -473,31 +495,42 @@ func (r *S3UserReconciler) handleUpdate(
473495
}
474496

475497
if !credentialsValid {
476-
logger.Info(
477-
"The secret containing the credentials will be deleted, and the user will be deleted from the S3 backend, then recreated (through another reconcile)",
478-
"userResource",
479-
userResource.Name,
480-
"NamespacedName",
481-
req.NamespacedName.String(),
482-
)
483-
err = r.deleteSecret(ctx, &currentUserSecret)
484-
if err != nil {
485-
logger.Error(err, "Deletion of secret associated to user have failed", "userResource",
486-
userResource.Name,
487-
"userResourceName",
498+
if ownedSecret {
499+
logger.Info(
500+
"The secret containing the credentials will be deleted, and the user will be deleted from the S3 backend, then recreated (through another reconcile)",
501+
"userResource",
488502
userResource.Name,
489503
"NamespacedName",
490-
req.NamespacedName.String())
491-
return r.SetReconciledCondition(
492-
ctx,
493-
req,
494-
userResource,
495-
s3v1alpha1.Unreachable,
496-
"Deletion of secret associated to user have failed",
497-
err,
504+
req.NamespacedName.String(),
498505
)
506+
err = r.deleteSecret(ctx, &currentUserSecret)
507+
if err != nil {
508+
logger.Error(err, "Deletion of secret associated to user have failed", "userResource",
509+
userResource.Name,
510+
"userResourceName",
511+
userResource.Name,
512+
"NamespacedName",
513+
req.NamespacedName.String())
514+
return r.SetReconciledCondition(
515+
ctx,
516+
req,
517+
userResource,
518+
s3v1alpha1.Unreachable,
519+
"Deletion of secret associated to user have failed",
520+
err,
521+
)
499522

523+
}
524+
} else {
525+
logger.Info(
526+
"The user will be deleted from the S3 backend, then recreated (through another reconcile), the secret will be kept.",
527+
"userResource",
528+
userResource.Name,
529+
"NamespacedName",
530+
req.NamespacedName.String(),
531+
)
500532
}
533+
501534
err = s3Client.DeleteUser(userResource.Spec.AccessKey)
502535
if err != nil {
503536
logger.Error(err, "Could not delete user on S3 server", "userResource",
@@ -751,15 +784,30 @@ func (r *S3UserReconciler) handleCreate(
751784
}
752785
}
753786

754-
if r.OverrideExistingSecret {
755-
// Case 3.2 : they are not valid, but the operator is configured to overwrite it
756-
logger.Info(fmt.Sprintf("A secret with the name %s already exists ; it will be overwritten because of operator configuration", secret.Name), "secretName",
757-
secret.Name,
758-
"userResource",
759-
userResource.Name,
760-
"NamespacedName",
787+
if r.OverrideExistingSecret || r.ReadExistingSecret {
788+
if r.ReadExistingSecret {
789+
// Case 3.2a : read existing secret instead of updating it
790+
logger.Info(fmt.Sprintf("The secret key will be retrieved from the secret named %s.", secret.Name), "secretName",
791+
secret.Name,
792+
"userResource",
793+
userResource.Name,
794+
"NamespacedName",
761795
req.NamespacedName.String())
762-
796+
var cpData = *&existingK8sSecret.Data
797+
for k, v := range cpData {
798+
if k == userResource.Spec.SecretFieldNameSecretKey {
799+
secretKey = string(v)
800+
}
801+
}
802+
} else {
803+
// Case 3.2b : they are not valid, but the operator is configured to overwrite it
804+
logger.Info(fmt.Sprintf("A secret with the name %s already exists ; it will be overwritten because of operator configuration", secret.Name), "secretName",
805+
secret.Name,
806+
"userResource",
807+
userResource.Name,
808+
"NamespacedName",
809+
req.NamespacedName.String())
810+
}
763811
// Creating the user
764812
err = s3Client.CreateUser(userResource.Spec.AccessKey, secretKey)
765813
if err != nil {
@@ -780,32 +828,33 @@ func (r *S3UserReconciler) handleCreate(
780828
err,
781829
)
782830
}
783-
784-
// Updating the secret
785-
logger.Info("Updating the pre-existing secret with new credentials",
786-
"secretName",
787-
secret.Name,
788-
"userResource",
789-
userResource.Name,
790-
"NamespacedName",
791-
req.NamespacedName.String(),
792-
)
793-
err = r.Update(ctx, secret)
794-
if err != nil {
795-
logger.Error(err, "Could not update secret", "secretName",
831+
if r.OverrideExistingSecret {
832+
// Updating the secret
833+
logger.Info("Updating the pre-existing secret with new credentials",
834+
"secretName",
796835
secret.Name,
797836
"userResource",
798837
userResource.Name,
799838
"NamespacedName",
800-
req.NamespacedName.String())
801-
return r.SetReconciledCondition(
802-
ctx,
803-
req,
804-
userResource,
805-
s3v1alpha1.Unreachable,
806-
"Update of secret have failed",
807-
err,
839+
req.NamespacedName.String(),
808840
)
841+
err = r.Update(ctx, secret)
842+
if err != nil {
843+
logger.Error(err, "Could not update secret", "secretName",
844+
secret.Name,
845+
"userResource",
846+
userResource.Name,
847+
"NamespacedName",
848+
req.NamespacedName.String())
849+
return r.SetReconciledCondition(
850+
ctx,
851+
req,
852+
userResource,
853+
s3v1alpha1.Unreachable,
854+
"Update of secret have failed",
855+
err,
856+
)
857+
}
809858
}
810859

811860
// Add policies

internal/controller/user/utils.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,39 @@ func (r *S3UserReconciler) getUserLinkedSecrets(
104104
return userSecretList, nil
105105
}
106106

107+
108+
func (r *S3UserReconciler) getUserUnlinkedSecret(
109+
ctx context.Context,
110+
namespace string,
111+
secretNameA string,
112+
secretNameB string,
113+
) (*corev1.Secret, error) {
114+
logger := log.FromContext(ctx)
115+
// Listing every secrets in the S3User's namespace, as a first step
116+
// to get the actual secret matching the S3User proper.
117+
// TODO : proper label matching ?
118+
secretsList := &corev1.SecretList{}
119+
err := r.List(ctx, secretsList, client.InNamespace(namespace))
120+
if err != nil {
121+
logger.Error(err, "An error occurred while listing the secrets in user's namespace")
122+
return nil, fmt.Errorf("SecretListingFailed")
123+
}
124+
if len(secretsList.Items) == 0 {
125+
logger.Info("The user's namespace doesn't appear to contain any secret")
126+
return nil, nil
127+
}
128+
129+
var secretB *corev1.Secret
130+
for _, secret := range secretsList.Items {
131+
if secret.Name == secretNameA {
132+
return &secret, nil
133+
} else if secret.Name == secretNameB {
134+
secretB = &secret
135+
}
136+
}
137+
return secretB, nil
138+
}
139+
107140
func (r *S3UserReconciler) deleteSecret(ctx context.Context, secret *corev1.Secret) error {
108141
logger := log.FromContext(ctx)
109142
logger.Info("the secret named " + secret.Name + " will be deleted")

0 commit comments

Comments
 (0)