From 72bc5c30147a2a7578f98d7e8d5fd22a6d495a62 Mon Sep 17 00:00:00 2001 From: jackyalbo Date: Thu, 21 Sep 2023 19:10:27 +0700 Subject: [PATCH] Adding operator checks to SSL adding external ssl validator using pq driver for golang fix - adapting secret to the one in noobaa spec Signed-off-by: jackyalbo --- deploy/internal/deployment-endpoint.yaml | 7 -- deploy/internal/statefulset-core.yaml | 7 -- go.mod | 1 + go.sum | 2 + pkg/bundle/deploy.go | 18 +---- pkg/system/phase1_verifying.go | 85 ++++++++++++++++++++++++ pkg/system/phase2_creating.go | 19 ++++++ pkg/system/phase4_configuring.go | 18 +++++ pkg/system/reconciler.go | 20 ++++-- pkg/system/system.go | 2 +- 10 files changed, 143 insertions(+), 36 deletions(-) diff --git a/deploy/internal/deployment-endpoint.yaml b/deploy/internal/deployment-endpoint.yaml index e7c591169..b30181c1c 100644 --- a/deploy/internal/deployment-endpoint.yaml +++ b/deploy/internal/deployment-endpoint.yaml @@ -32,10 +32,6 @@ spec: secret: secretName: noobaa-s3-serving-cert optional: true - - name: external-db-ssl-secret - secret: - secretName: noobaa-external-db-cert - optional: true - name: oidc-token projected: sources: @@ -132,9 +128,6 @@ spec: - name: s3-secret mountPath: /etc/s3-secret readOnly: true - - name: external-db-ssl-secret - mountPath: /etc/external-db-secret - readOnly: true - name: noobaa-auth-token mountPath: /etc/noobaa-auth-token readOnly: true diff --git a/deploy/internal/statefulset-core.yaml b/deploy/internal/statefulset-core.yaml index f8b3d49f5..2ed1cc89e 100644 --- a/deploy/internal/statefulset-core.yaml +++ b/deploy/internal/statefulset-core.yaml @@ -33,10 +33,6 @@ spec: secret: secretName: noobaa-s3-serving-cert optional: true - - name: external-db-ssl-secret - secret: - secretName: noobaa-external-db-cert - optional: true - name: noobaa-server secret: secretName: noobaa-server @@ -63,9 +59,6 @@ spec: - name: s3-secret mountPath: /etc/s3-secret readOnly: true - - name: external-db-ssl-secret - mountPath: /etc/external-db-secret - readOnly: true - name: noobaa-server mountPath: /etc/noobaa-server readOnly: true diff --git a/go.mod b/go.mod index b31e281e1..c0369bccc 100644 --- a/go.mod +++ b/go.mod @@ -127,6 +127,7 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.16.5 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect + github.com/lib/pq v1.10.9 github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect diff --git a/go.sum b/go.sum index fb4c24a71..9ef2df0eb 100644 --- a/go.sum +++ b/go.sum @@ -1809,6 +1809,8 @@ github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libopenstorage/autopilot-api v0.6.1-0.20210128210103-5fbb67948648/go.mod h1:6JLrPbR3ZJQFbUY/+QJMl/aF00YdIrLf8/GWAplgvJs= github.com/libopenstorage/openstorage v8.0.0+incompatible/go.mod h1:Sp1sIObHjat1BeXhfMqLZ14wnOzEhNx2YQedreMcUyc= github.com/libopenstorage/operator v0.0.0-20200725001727-48d03e197117/go.mod h1:Qh+VXOB6hj60VmlgsmY+R1w+dFuHK246UueM4SAqZG0= diff --git a/pkg/bundle/deploy.go b/pkg/bundle/deploy.go index 94f63693c..19f6c3841 100644 --- a/pkg/bundle/deploy.go +++ b/pkg/bundle/deploy.go @@ -3678,7 +3678,7 @@ data: su postgres -c "bash -x /usr/bin/run-postgresql" ` -const Sha256_deploy_internal_deployment_endpoint_yaml = "c6b23dc4cd61b35fcdd53df59074a95df46526823ebd42862289886c8b11ae0f" +const Sha256_deploy_internal_deployment_endpoint_yaml = "bd3efd480e3a73ebdc64acfbde114f938283604a7a8291d94a280b535a5c81cd" const File_deploy_internal_deployment_endpoint_yaml = `apiVersion: apps/v1 kind: Deployment @@ -3714,10 +3714,6 @@ spec: secret: secretName: noobaa-s3-serving-cert optional: true - - name: external-db-ssl-secret - secret: - secretName: noobaa-external-db-cert - optional: true - name: oidc-token projected: sources: @@ -3814,9 +3810,6 @@ spec: - name: s3-secret mountPath: /etc/s3-secret readOnly: true - - name: external-db-ssl-secret - mountPath: /etc/external-db-secret - readOnly: true - name: noobaa-auth-token mountPath: /etc/noobaa-auth-token readOnly: true @@ -4704,7 +4697,7 @@ spec: noobaa-s3-svc: "true" ` -const Sha256_deploy_internal_statefulset_core_yaml = "d794c900f09e09b0e2be94869f5537271cbc2ab6d806d5182fb7fe2ff950b8ae" +const Sha256_deploy_internal_statefulset_core_yaml = "0489de0ea1cd3904274a8f58a5bca789592eab4991e911ce7703d238a223a168" const File_deploy_internal_statefulset_core_yaml = `apiVersion: apps/v1 kind: StatefulSet @@ -4741,10 +4734,6 @@ spec: secret: secretName: noobaa-s3-serving-cert optional: true - - name: external-db-ssl-secret - secret: - secretName: noobaa-external-db-cert - optional: true - name: noobaa-server secret: secretName: noobaa-server @@ -4771,9 +4760,6 @@ spec: - name: s3-secret mountPath: /etc/s3-secret readOnly: true - - name: external-db-ssl-secret - mountPath: /etc/external-db-secret - readOnly: true - name: noobaa-server mountPath: /etc/noobaa-server readOnly: true diff --git a/pkg/system/phase1_verifying.go b/pkg/system/phase1_verifying.go index d9b5b69d2..51a3eed7f 100644 --- a/pkg/system/phase1_verifying.go +++ b/pkg/system/phase1_verifying.go @@ -1,9 +1,13 @@ package system import ( + "database/sql" "fmt" "os" + // this is the driver we are using for psql + _ "github.com/lib/pq" + "github.com/asaskevich/govalidator" semver "github.com/coreos/go-semver/semver" dockerref "github.com/docker/distribution/reference" @@ -31,6 +35,34 @@ func (r *Reconciler) ReconcilePhaseVerifying() error { } } + if r.ExternalPgSecret != nil { + if r.ExternalPgSecret.StringData["db_url"] == "" { + return util.NewPersistentError("InvalidExternalPgSecert", + "ExternalPgSecret is missing db_url") + } + if r.ExternalPgSSLSecret != nil { + if r.ExternalPgSSLSecret.StringData["tls.key"] == "" || + r.ExternalPgSSLSecret.StringData["tls.crt"] == "" { + return util.NewPersistentError("InvalidExternalPgCert", + fmt.Sprintf("%q is missing private key (must be tls.key)"+ + " or missing cert key (must be tls.cert)", r.ExternalPgSSLSecret.Name)) + } + err := os.WriteFile("/tmp/tls.key", []byte(r.ExternalPgSSLSecret.StringData["tls.key"]), 0600) + if err != nil { + return fmt.Errorf("failed to write k8s secret tls.key content to a file %v", err) + } + err = os.WriteFile("/tmp/tls.crt", []byte(r.ExternalPgSSLSecret.StringData["tls.crt"]), 0644) + if err != nil { + return fmt.Errorf("failed to write k8s secret tls.key content to a file %v", err) + } + os.Setenv("PGSSLKEY", "/tmp/tls.key") + os.Setenv("PGSSLCERT", "/tmp/tls.crt") + } + if err := r.checkExternalPg(r.ExternalPgSecret.StringData["db_url"]); err != nil { + return err + } + } + return nil } @@ -171,3 +203,56 @@ func (r *Reconciler) CheckJoinSecret() error { } return nil } + +func (r *Reconciler) checkExternalPg(postgresDbURL string) error { + dbURL := r.ExternalPgSecret.StringData["db_url"] + if r.NooBaa.Spec.ExternalPgSSLRequired { + if !r.NooBaa.Spec.ExternalPgSSLUnauthorized { + dbURL += "?sslmode=verify-full" // won't allow self-signed certs + } // when we want to allow self-signed we will use the default sslmode=require + } else { + dbURL += "?sslmode=disable" // don't use ssl - the default is to use it + } + db, err := sql.Open("postgres", dbURL) + if err != nil { + return util.NewPersistentError("InvalidExternalPgUrl", + fmt.Sprintf("failed openning a connection to external DB url: %q, error: %s", + dbURL, err)) + } + defer db.Close() + err = db.Ping() + if err != nil { + return util.NewPersistentError("InvalidExternalPgUrl", + fmt.Sprintf("failed pinging external DB url: %q, error: %s", + dbURL, err)) + } + // Query the PostgreSQL version + var version string + err = db.QueryRow("SELECT current_setting('server_version_num')::integer / 10000").Scan(&version) + if err != nil { + return util.NewPersistentError("InvalidExternalPgVersion", + fmt.Sprintf("failed getting version of external DB url: %q, error: %s", + dbURL, err)) + } + // Check if the version is 15 + if version != "15" { + return util.NewPersistentError("InvalidExternalPgVersion", + fmt.Sprintf("version of external DB %q, is not supported: %s", + dbURL, version)) + } + // Query the database's collation + var collation string + err = db.QueryRow("SELECT datcollate FROM pg_database WHERE datname = current_database()").Scan(&collation) + if err != nil { + return util.NewPersistentError("InvalidExternalPgCollation", + fmt.Sprintf("failed getting database collation of external DB url: %q, error: %s", + dbURL, err)) + } + // Check if the collation is "C" + if collation != "C" { + return util.NewPersistentError("InvalidExternalPgCollation", + fmt.Sprintf("collation of external DB url: %q, is not supported: %s", + dbURL, err)) + } + return nil +} diff --git a/pkg/system/phase2_creating.go b/pkg/system/phase2_creating.go index bc3e726d0..f32d4cb2f 100644 --- a/pkg/system/phase2_creating.go +++ b/pkg/system/phase2_creating.go @@ -519,6 +519,14 @@ func (r *Reconciler) SetDesiredCoreApp() error { }} util.MergeVolumeMountList(&c.VolumeMounts, &configMapVolumeMounts) } + if r.ExternalPgSSLSecret != nil && util.KubeCheckQuiet(r.ExternalPgSSLSecret) { + secretVolumeMounts := []corev1.VolumeMount{{ + Name: r.ExternalPgSSLSecret.Name, + MountPath: "/etc/external-db-secret", + ReadOnly: true, + }} + util.MergeVolumeMountList(&c.VolumeMounts, &secretVolumeMounts) + } } } if r.NooBaa.Spec.ImagePullSecret == nil { @@ -578,6 +586,17 @@ func (r *Reconciler) SetDesiredCoreApp() error { }} util.MergeVolumeList(&podSpec.Volumes, &configMapVolumes) } + if r.ExternalPgSSLSecret != nil && util.KubeCheckQuiet(r.ExternalPgSSLSecret) { + secretVolumes := []corev1.Volume{{ + Name: r.ExternalPgSSLSecret.Name, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: r.ExternalPgSSLSecret.Name, + }, + }, + }} + util.MergeVolumeList(&podSpec.Volumes, &secretVolumes) + } return nil } diff --git a/pkg/system/phase4_configuring.go b/pkg/system/phase4_configuring.go index c8fa7b110..dbc819b6c 100644 --- a/pkg/system/phase4_configuring.go +++ b/pkg/system/phase4_configuring.go @@ -493,6 +493,24 @@ func (r *Reconciler) setDesiredEndpointMounts(podSpec *corev1.PodSpec, container util.MergeVolumeMountList(&container.VolumeMounts, &configMapVolumeMounts) } + if r.ExternalPgSSLSecret != nil && util.KubeCheckQuiet(r.ExternalPgSSLSecret) { + secretVolumes := []corev1.Volume{{ + Name: r.ExternalPgSSLSecret.Name, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: r.ExternalPgSSLSecret.Name, + }, + }, + }} + util.MergeVolumeList(&podSpec.Volumes, &secretVolumes) + secretVolumeMounts := []corev1.VolumeMount{{ + Name: r.ExternalPgSSLSecret.Name, + MountPath: "/etc/external-db-secret", + ReadOnly: true, + }} + util.MergeVolumeMountList(&container.VolumeMounts, &secretVolumeMounts) + } + r.setDesiredRootMasterKeyMounts(podSpec, container) for _, nsStore := range namespaceStoreList.Items { diff --git a/pkg/system/reconciler.go b/pkg/system/reconciler.go index e368be1b9..533b18a2d 100644 --- a/pkg/system/reconciler.go +++ b/pkg/system/reconciler.go @@ -119,6 +119,8 @@ type Reconciler struct { KedaTriggerAuthentication *kedav1alpha1.TriggerAuthentication KedaScaled *kedav1alpha1.ScaledObject AdapterHPA *autoscalingv2.HorizontalPodAutoscaler + ExternalPgSecret *corev1.Secret + ExternalPgSSLSecret *corev1.Secret } // NewReconciler initializes a reconciler to be used for loading or reconciling a noobaa system @@ -392,19 +394,27 @@ func (r *Reconciler) Reconcile() (reconcile.Result, error) { } if r.NooBaa.Spec.ExternalPgSecret != nil { - secret := &corev1.Secret{ + r.ExternalPgSecret = &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Namespace: r.NooBaa.Spec.ExternalPgSecret.Namespace, Name: r.NooBaa.Spec.ExternalPgSecret.Name, }, } - if !util.KubeCheck(secret) { + if !util.KubeCheck(r.ExternalPgSecret) { log.Errorf("❌ External DB secret %q was not found or deleted", r.NooBaa.Spec.ExternalPgSecret.Name) return res, nil } - err = CheckPostgresURL(secret.StringData["db_url"]) - if err != nil { - log.Errorf(`❌ %s`, err) + } + + if r.NooBaa.Spec.ExternalPgSSLSecret != nil { + r.ExternalPgSSLSecret = &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: r.NooBaa.Spec.ExternalPgSSLSecret.Namespace, + Name: r.NooBaa.Spec.ExternalPgSSLSecret.Name, + }, + } + if !util.KubeCheck(r.ExternalPgSSLSecret) { + log.Errorf("❌ External DB secret %q was not found or deleted", r.NooBaa.Spec.ExternalPgSecret.Name) return res, nil } } diff --git a/pkg/system/system.go b/pkg/system/system.go index 64bb791c1..d38ae3f05 100644 --- a/pkg/system/system.go +++ b/pkg/system/system.go @@ -1219,7 +1219,7 @@ func CheckPostgresURL(postgresDbURL string) error { // This is temporary checks - In next PRs we will change to psql client checks instead u, err := url.Parse(postgresDbURL) if err != nil { - return fmt.Errorf("failed parsing external DB url: %q", postgresDbURL) + return fmt.Errorf("failed parsing external DB url: %q, error: %s", postgresDbURL, err) } _, _, err = net.SplitHostPort(u.Host) if err != nil {