diff --git a/api/v1beta2/cryostat_types.go b/api/v1beta2/cryostat_types.go index e87fa0798..61606f4a5 100644 --- a/api/v1beta2/cryostat_types.go +++ b/api/v1beta2/cryostat_types.go @@ -603,7 +603,7 @@ type TargetDiscoveryOptions struct { type DatabaseOptions struct { // Name of the secret containing database keys. This secret must contain a CONNECTION_KEY secret which is the // database connection password, and an ENCRYPTION_KEY secret which is the key used to encrypt sensitive data - // stored within the database, such as the target credentials keyring. + // stored within the database, such as the target credentials keyring. Cannot be updated. // +optional // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors={"urn:alm:descriptor:io.kubernetes:Secret"} SecretName *string `json:"secretName,omitempty"` diff --git a/bundle/manifests/cryostat-operator.clusterserviceversion.yaml b/bundle/manifests/cryostat-operator.clusterserviceversion.yaml index 12aee9bfb..de07daa7c 100644 --- a/bundle/manifests/cryostat-operator.clusterserviceversion.yaml +++ b/bundle/manifests/cryostat-operator.clusterserviceversion.yaml @@ -53,7 +53,7 @@ metadata: capabilities: Seamless Upgrades categories: Monitoring, Developer Tools containerImage: quay.io/cryostat/cryostat-operator:3.0.0-dev - createdAt: "2024-05-28T20:14:14Z" + createdAt: "2024-05-31T05:18:57Z" description: JVM monitoring and profiling tool operatorframework.io/initialization-resource: |- { @@ -580,6 +580,7 @@ spec: contain a CONNECTION_KEY secret which is the database connection password, and an ENCRYPTION_KEY secret which is the key used to encrypt sensitive data stored within the database, such as the target credentials keyring. + Cannot be updated. displayName: Secret Name path: databaseOptions.secretName x-descriptors: diff --git a/bundle/manifests/operator.cryostat.io_cryostats.yaml b/bundle/manifests/operator.cryostat.io_cryostats.yaml index abe2529f6..80ede6f08 100644 --- a/bundle/manifests/operator.cryostat.io_cryostats.yaml +++ b/bundle/manifests/operator.cryostat.io_cryostats.yaml @@ -5212,7 +5212,7 @@ spec: secret must contain a CONNECTION_KEY secret which is the database connection password, and an ENCRYPTION_KEY secret which is the key used to encrypt sensitive data stored within the database, - such as the target credentials keyring. + such as the target credentials keyring. Cannot be updated. type: string type: object enableCertManager: diff --git a/config/crd/bases/operator.cryostat.io_cryostats.yaml b/config/crd/bases/operator.cryostat.io_cryostats.yaml index c8bb0ddd1..1b16a937a 100644 --- a/config/crd/bases/operator.cryostat.io_cryostats.yaml +++ b/config/crd/bases/operator.cryostat.io_cryostats.yaml @@ -5202,7 +5202,7 @@ spec: secret must contain a CONNECTION_KEY secret which is the database connection password, and an ENCRYPTION_KEY secret which is the key used to encrypt sensitive data stored within the database, - such as the target credentials keyring. + such as the target credentials keyring. Cannot be updated. type: string type: object enableCertManager: diff --git a/config/manifests/bases/cryostat-operator.clusterserviceversion.yaml b/config/manifests/bases/cryostat-operator.clusterserviceversion.yaml index 2ac7fd2c3..6d3eca3f6 100644 --- a/config/manifests/bases/cryostat-operator.clusterserviceversion.yaml +++ b/config/manifests/bases/cryostat-operator.clusterserviceversion.yaml @@ -125,6 +125,7 @@ spec: contain a CONNECTION_KEY secret which is the database connection password, and an ENCRYPTION_KEY secret which is the key used to encrypt sensitive data stored within the database, such as the target credentials keyring. + Cannot be updated. displayName: Secret Name path: databaseOptions.secretName x-descriptors: diff --git a/internal/controllers/secrets.go b/internal/controllers/secrets.go index b2519c0b0..d12f9660b 100644 --- a/internal/controllers/secrets.go +++ b/internal/controllers/secrets.go @@ -16,12 +16,13 @@ package controllers import ( "context" + "errors" "fmt" "github.com/cryostatio/cryostat-operator/internal/controllers/constants" "github.com/cryostatio/cryostat-operator/internal/controllers/model" corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" + kerrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" ) @@ -57,23 +58,35 @@ func (r *Reconciler) reconcileAuthProxyCookieSecret(ctx context.Context, cr *mod }) } -// databaseSecretNameSuffix is the suffix to be appended to the name of a -// Cryostat CR to name its database secret -const databaseSecretNameSuffix = "-db" +const ( + // The suffix to be appended to the name of a Cryostat CR to name its database secret + databaseSecretNameSuffix = "-db" + eventDatabaseSecretMismatchedType = "DatabaseSecretMismatched" + eventDatabaseMismatchMsg = "\"databaseOptions.secretName\" field cannot be updated, please revert its value or re-create this Cryostat custom resource" +) + +var errDatabaseSecretUpdated = errors.New("database secret cannot be updated, but another secret is specified") func (r *Reconciler) reconcileDatabaseConnectionSecret(ctx context.Context, cr *model.CryostatInstance) error { - var secretName string + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: cr.Name + databaseSecretNameSuffix, + Namespace: cr.InstallNamespace, + }, + } + secretName := secret.Name secretProvided := cr.Spec.DatabaseOptions != nil && cr.Spec.DatabaseOptions.SecretName != nil if secretProvided { - // Do not delete default secret to allow reverting to use default if needed secretName = *cr.Spec.DatabaseOptions.SecretName - } else { - secret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: cr.Name + databaseSecretNameSuffix, - Namespace: cr.InstallNamespace, - }, - } + } + + // If the CR status contains the secret name, emit an Event in case the configured secret's name does not match. + if len(cr.Status.DatabaseSecret) > 0 && cr.Status.DatabaseSecret != secretName { + r.EventRecorder.Event(cr.Object, corev1.EventTypeWarning, eventDatabaseSecretMismatchedType, eventDatabaseMismatchMsg) + return errDatabaseSecretUpdated + } + + if !secretProvided { err := r.createOrUpdateSecret(ctx, secret, cr.Object, func() error { if secret.StringData == nil { secret.StringData = map[string]string{} @@ -90,8 +103,8 @@ func (r *Reconciler) reconcileDatabaseConnectionSecret(ctx context.Context, cr * if err != nil { return err } - secretName = secret.Name } + cr.Status.DatabaseSecret = secretName return r.Client.Status().Update(ctx, cr.Object) } @@ -150,7 +163,7 @@ func (r *Reconciler) createOrUpdateSecret(ctx context.Context, secret *corev1.Se func (r *Reconciler) deleteSecret(ctx context.Context, secret *corev1.Secret) error { err := r.Client.Delete(ctx, secret) - if err != nil && !errors.IsNotFound(err) { + if err != nil && !kerrors.IsNotFound(err) { r.Log.Error(err, "Could not delete secret", "name", secret.Name, "namespace", secret.Namespace) return err }