Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ func main() {

//K8S related variable
var overrideExistingSecret bool
var readExistingSecret bool

flag.StringVar(
&metricsAddr,
Expand All @@ -106,6 +107,12 @@ func main() {
false,
"Override existing secret associated to user in case of the secret already exist",
)
flag.BoolVar(
&readExistingSecret,
"read-existing-secret",
false,
"Read existing secret associated to user in case of the secret already exist",
)

opts := zap.Options{
Development: true,
Expand Down Expand Up @@ -203,6 +210,7 @@ func main() {
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
OverrideExistingSecret: overrideExistingSecret,
ReadExistingSecret: readExistingSecret,
ReconcilePeriod: reconcilePeriod,
S3factory: s3Factory,
ControllerHelper: controllerHelper,
Expand Down
3 changes: 2 additions & 1 deletion deploy/charts/s3-operator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ A Helm chart for deploying an operator to manage S3 resources (eg buckets, polic
| crds.install | bool | `true` | Install and upgrade CRDs |
| crds.keep | bool | `true` | Keep CRDs on chart uninstall |
| kubernetes.clusterDomain | string | `"cluster.local"` | |
| kubernetes.overrideExistingSecret | bool | `false` | |
| kubernetes.overrideExistingSecret | bool | `false` | When creating an S3User, update existing secret with the generated secret key |
| kubernetes.readExistingSecret | bool | `false` | When creating an S3User, read existing secret to retrieve the secret key |
| 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 |

1 change: 1 addition & 0 deletions deploy/charts/s3-operator/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ spec:
- --metrics-bind-address=127.0.0.1:8080
- --leader-elect
- --override-existing-secret={{ .Values.kubernetes.overrideExistingSecret }}
- --read-existing-secret={{ .Values.kubernetes.readExistingSecret }}
{{- if .Values.controllerManager.manager.extraArgs }}
{{- toYaml .Values.controllerManager.manager.extraArgs | nindent 8 }}
{{- end }}
Expand Down
3 changes: 3 additions & 0 deletions deploy/charts/s3-operator/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@ controllerManager:

kubernetes:
clusterDomain: cluster.local
# -- When creating an S3User, update existing secret with the generated secret key
overrideExistingSecret: false
# -- When creating an S3User, read existing secret to retrieve the secret key
readExistingSecret: false

# -- Default S3 Instance
s3:
Expand Down
1 change: 1 addition & 0 deletions internal/controller/user/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ type S3UserReconciler struct {
client.Client
Scheme *runtime.Scheme
OverrideExistingSecret bool
ReadExistingSecret bool
ReconcilePeriod time.Duration
S3factory s3factory.S3Factory
ControllerHelper *helpers.ControllerHelper
Expand Down
2 changes: 1 addition & 1 deletion internal/controller/user/finalizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func (r *S3UserReconciler) handleDeletion(
)
}

userOwnedlinkedSecrets, err := r.getUserLinkedSecrets(ctx, userResource)
userOwnedlinkedSecrets, _, err := r.getUserLinkedSecrets(ctx, userResource)
if err != nil {
logger.Error(
err,
Expand Down
173 changes: 113 additions & 60 deletions internal/controller/user/reconcile.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,26 @@ func (r *S3UserReconciler) handleUpdate(
err,
)
}

userOwnedlinkedSecrets, err := r.getUserLinkedSecrets(ctx, userResource)
ownedSecret := true
userOwnedlinkedSecrets, userUnlinkedSecret, err := r.getUserLinkedSecrets(ctx, userResource)
if err != nil {
logger.Error(
err,
"An error occurred while listing the user's secret",
"userResourceName",
userResource.Name,
"NamespacedName",
req.NamespacedName.String(),
)
return r.SetReconciledCondition(
ctx,
req,
userResource,
s3v1alpha1.Unreachable,
"Impossible to list the user's secret",
err,
)
}
if err != nil {
logger.Error(
err,
Expand All @@ -268,9 +286,11 @@ func (r *S3UserReconciler) handleUpdate(
)
}
currentUserSecret := corev1.Secret{}
if len(userOwnedlinkedSecrets) == 0 {
if len(userOwnedlinkedSecrets) == 0 && userUnlinkedSecret == nil {
logger.Info(
"No Secret associated to user found, user will be deleted from the S3 backend, then recreated with a secret",
"userResourceSpecSecretName",
userResource.Spec.SecretName,
"userResourceName",
userResource.Name,
"NamespacedName",
Expand Down Expand Up @@ -298,6 +318,9 @@ func (r *S3UserReconciler) handleUpdate(
)
}
return r.handleCreate(ctx, req, userResource)
} else if userUnlinkedSecret != nil {
currentUserSecret = *userUnlinkedSecret
ownedSecret = false
} else {
foundSecret := false
for _, linkedsecret := range userOwnedlinkedSecrets {
Expand Down Expand Up @@ -473,31 +496,42 @@ func (r *S3UserReconciler) handleUpdate(
}

if !credentialsValid {
logger.Info(
"The secret containing the credentials will be deleted, and the user will be deleted from the S3 backend, then recreated (through another reconcile)",
"userResource",
userResource.Name,
"NamespacedName",
req.NamespacedName.String(),
)
err = r.deleteSecret(ctx, &currentUserSecret)
if err != nil {
logger.Error(err, "Deletion of secret associated to user have failed", "userResource",
userResource.Name,
"userResourceName",
if ownedSecret {
logger.Info(
"The secret containing the credentials will be deleted, and the user will be deleted from the S3 backend, then recreated (through another reconcile)",
"userResource",
userResource.Name,
"NamespacedName",
req.NamespacedName.String())
return r.SetReconciledCondition(
ctx,
req,
userResource,
s3v1alpha1.Unreachable,
"Deletion of secret associated to user have failed",
err,
req.NamespacedName.String(),
)
err = r.deleteSecret(ctx, &currentUserSecret)
if err != nil {
logger.Error(err, "Deletion of secret associated to user have failed", "userResource",
userResource.Name,
"userResourceName",
userResource.Name,
"NamespacedName",
req.NamespacedName.String())
return r.SetReconciledCondition(
ctx,
req,
userResource,
s3v1alpha1.Unreachable,
"Deletion of secret associated to user have failed",
err,
)

}
} else {
logger.Info(
"The user will be deleted from the S3 backend, then recreated (through another reconcile), the secret will be kept.",
"userResource",
userResource.Name,
"NamespacedName",
req.NamespacedName.String(),
)
}

err = s3Client.DeleteUser(userResource.Spec.AccessKey)
if err != nil {
logger.Error(err, "Could not delete user on S3 server", "userResource",
Expand Down Expand Up @@ -534,7 +568,7 @@ func (r *S3UserReconciler) handleUpdate(
req,
userResource,
s3v1alpha1.Reconciled,
"user reconciled",
"User reconciled",
err,
)
}
Expand Down Expand Up @@ -725,12 +759,14 @@ func (r *S3UserReconciler) handleCreate(
err,
)
} else {
// If a secret already exists, but has a different S3User owner reference, then the creation should
// Case 3.1 : If a secret already exists, but has a different S3User owner reference, then the creation should
// fail with no requeue, and use the status to inform that the spec should be changed
for _, ref := range existingK8sSecret.OwnerReferences {
if ref.Kind == "S3User" {
if ref.UID != userResource.UID {
logger.Error(fmt.Errorf(""), "The secret matching the new S3User's spec is owned by a different S3User.",
err = fmt.Errorf("The secret matching the new S3User's spec is owned by a different S3User.")
logger.Error(err,
"S3User could not be created because of existing secret",
"conflictingUser",
ref.Name,
"secretName",
Expand All @@ -751,15 +787,30 @@ func (r *S3UserReconciler) handleCreate(
}
}

if r.OverrideExistingSecret {
// Case 3.2 : they are not valid, but the operator is configured to overwrite it
logger.Info(fmt.Sprintf("A secret with the name %s already exists ; it will be overwritten because of operator configuration", secret.Name), "secretName",
secret.Name,
"userResource",
userResource.Name,
"NamespacedName",
req.NamespacedName.String())

if r.OverrideExistingSecret || r.ReadExistingSecret {
if r.ReadExistingSecret {
// Case 3.2a : read existing secret instead of updating it
logger.Info(fmt.Sprintf("The secret key will be retrieved from the secret named %s.", secret.Name), "secretName",
secret.Name,
"userResource",
userResource.Name,
"NamespacedName",
req.NamespacedName.String())
var cpData = *&existingK8sSecret.Data
for k, v := range cpData {
if k == userResource.Spec.SecretFieldNameSecretKey {
secretKey = string(v)
}
}
} else {
// Case 3.2b : they are not valid, but the operator is configured to overwrite it
logger.Info(fmt.Sprintf("A secret with the name %s already exists ; it will be overwritten because of operator configuration", secret.Name), "secretName",
secret.Name,
"userResource",
userResource.Name,
"NamespacedName",
req.NamespacedName.String())
}
// Creating the user
err = s3Client.CreateUser(userResource.Spec.AccessKey, secretKey)
if err != nil {
Expand All @@ -780,32 +831,33 @@ func (r *S3UserReconciler) handleCreate(
err,
)
}

// Updating the secret
logger.Info("Updating the pre-existing secret with new credentials",
"secretName",
secret.Name,
"userResource",
userResource.Name,
"NamespacedName",
req.NamespacedName.String(),
)
err = r.Update(ctx, secret)
if err != nil {
logger.Error(err, "Could not update secret", "secretName",
if r.OverrideExistingSecret {
// Updating the secret
logger.Info("Updating the pre-existing secret with new credentials",
"secretName",
secret.Name,
"userResource",
userResource.Name,
"NamespacedName",
req.NamespacedName.String())
return r.SetReconciledCondition(
ctx,
req,
userResource,
s3v1alpha1.Unreachable,
"Update of secret have failed",
err,
req.NamespacedName.String(),
)
err = r.Update(ctx, secret)
if err != nil {
logger.Error(err, "Could not update secret", "secretName",
secret.Name,
"userResource",
userResource.Name,
"NamespacedName",
req.NamespacedName.String())
return r.SetReconciledCondition(
ctx,
req,
userResource,
s3v1alpha1.Unreachable,
"Update of secret have failed",
err,
)
}
}

// Add policies
Expand All @@ -826,16 +878,17 @@ func (r *S3UserReconciler) handleCreate(
req,
userResource,
s3v1alpha1.Reconciled,
"User Reconciled",
"User reconciled",
err,
)
}

// Case 3.3 : they are not valid, and the operator is configured keep the existing secret
// The user will not be created, with no requeue and with two possible ways out : either toggle
// OverrideExistingSecret on, or delete the S3User whose credentials are not working anyway.
logger.Error(fmt.Errorf(""),
"A secret with the same name already exists ; as the operator is configured to NOT override any pre-existing secrets, this user will not be created on S3 backend until spec change (to target new secret), or until the operator configuration is changed to override existing secrets",
err = fmt.Errorf("A secret with the same name already exists ; as the operator is configured to NOT override nor read any pre-existing secrets, this user will not be created on S3 backend until spec change (to target new secret), or until the operator configuration is changed to override existing secrets")
logger.Error(err,
"S3User could not be created because of existing secret",
"secretName",
secret.Name,
"userResource",
Expand All @@ -847,7 +900,7 @@ func (r *S3UserReconciler) handleCreate(
req,
userResource,
s3v1alpha1.CreationFailure,
"Creation of user on S3 instance has failed necause secret contains invalid credentials. The user's spec should be changed to target a different secret",
"Creation of user on S3 instance has failed because secret contains invalid credentials. The user's spec should be changed to target a different secret",
err,
)
}
Expand Down
Loading
Loading