From 7e4d0410c2e4357c69f9ce2640a599f4ad7ef5b6 Mon Sep 17 00:00:00 2001 From: Murat Kabilov Date: Tue, 7 Feb 2017 11:07:49 +0100 Subject: [PATCH] Use one secret per user --- pkg/cluster/cluster.go | 47 ++++++++++++++------ pkg/cluster/objects.go | 98 ++++++++++++++++-------------------------- pkg/util/util.go | 2 +- 3 files changed, 70 insertions(+), 77 deletions(-) diff --git a/pkg/cluster/cluster.go b/pkg/cluster/cluster.go index 2903df700..2bb37c0b0 100644 --- a/pkg/cluster/cluster.go +++ b/pkg/cluster/cluster.go @@ -15,7 +15,7 @@ import ( "github.bus.zalan.do/acid/postgres-operator/pkg/util/constants" ) -var patroniUsers = []string{"superuser", "replication", "admin"} +var patroniUsers = []string{"superuser", "replication"} //TODO: remove struct duplication type Config struct { @@ -34,10 +34,9 @@ type Cluster struct { } type pgUser struct { - username string - secretKey string + username []byte password []byte - flags []string + flags []string } func New(cfg Config, spec *spec.Postgresql) *Cluster { @@ -58,15 +57,26 @@ func New(cfg Config, spec *spec.Postgresql) *Cluster { return cluster } -func secretUserKey(userName string) string { - return fmt.Sprintf("%s-password", userName) +func (c *Cluster) labels() map[string]string { + return map[string]string{ + "application": "spilo", + "spilo-cluster": (*c.cluster).Metadata.Name, + } +} + +func (c *Cluster) credentialSecretName(userName string) string { + return fmt.Sprintf( + "%s.%s.credentials.%s.%s", + userName, + (*c.cluster).Metadata.Name, + constants.TPRName, + constants.TPRVendor) } func (c *Cluster) init() { for _, userName := range patroniUsers { user := pgUser{ - username: userName, - secretKey: secretUserKey(userName), + username: []byte(userName), password: util.RandomPasswordBytes(constants.PasswordLength), } c.pgUsers = append(c.pgUsers, user) @@ -74,12 +84,11 @@ func (c *Cluster) init() { for userName, userFlags := range (*c.cluster.Spec).Users { user := pgUser{ - username: userName, - secretKey: secretUserKey(userName), + username: []byte(userName), password: util.RandomPasswordBytes(constants.PasswordLength), - flags: userFlags, + flags: userFlags, } - c.pgUsers = append(c.pgUsers, user) + c.pgUsers = append(c.pgUsers, user) } } @@ -145,9 +154,19 @@ func (c *Cluster) Delete() error { c.logger.Infof("Service %s.%s has been deleted\n", service.Namespace, service.Name) } - err = kubeClient.Secrets(nameSpace).Delete(clusterName, deleteOptions) + secretsList, err := kubeClient.Secrets(nameSpace).List(listOptions) if err != nil { - c.logger.Errorf("Error while deleting Secret %s: %+v", clusterName, err) + return err + } + for _, secret := range secretsList.Items { + err = kubeClient.Secrets(nameSpace).Delete(secret.Name, deleteOptions) + if err != nil { + c.logger.Errorf("Error while deleting Secret %s: %+v", secret.Name, err) + + return err + } + + c.logger.Infof("Secret %s.%s has been deleted\n", secret.Namespace, secret.Name) } //TODO: delete key from etcd diff --git a/pkg/cluster/objects.go b/pkg/cluster/objects.go index 0e4d2afc5..5760ec75d 100644 --- a/pkg/cluster/objects.go +++ b/pkg/cluster/objects.go @@ -48,20 +48,9 @@ func (c *Cluster) createStatefulSet() { ValueFrom: &v1.EnvVarSource{ SecretKeyRef: &v1.SecretKeySelector{ LocalObjectReference: v1.LocalObjectReference{ - Name: clusterName, + Name: c.credentialSecretName("superuser"), }, - Key: secretUserKey("superuser"), - }, - }, - }, - { - Name: "PGPASSWORD_ADMIN", - ValueFrom: &v1.EnvVarSource{ - SecretKeyRef: &v1.SecretKeySelector{ - LocalObjectReference: v1.LocalObjectReference{ - Name: clusterName, - }, - Key: secretUserKey("admin"), + Key: "password", }, }, }, @@ -70,9 +59,9 @@ func (c *Cluster) createStatefulSet() { ValueFrom: &v1.EnvVarSource{ SecretKeyRef: &v1.SecretKeySelector{ LocalObjectReference: v1.LocalObjectReference{ - Name: clusterName, + Name: c.credentialSecretName("replication"), }, - Key: secretUserKey("replication"), + Key: "password", }, }, }, @@ -129,10 +118,7 @@ func (c *Cluster) createStatefulSet() { template := v1.PodTemplateSpec{ ObjectMeta: v1.ObjectMeta{ - Labels: map[string]string{ - "application": "spilo", - "spilo-cluster": clusterName, - }, + Labels: c.labels(), Annotations: map[string]string{"pod.alpha.kubernetes.io/initialized": "true"}, }, Spec: podSpec, @@ -140,11 +126,8 @@ func (c *Cluster) createStatefulSet() { statefulSet := &v1beta1.StatefulSet{ ObjectMeta: v1.ObjectMeta{ - Name: clusterName, - Labels: map[string]string{ - "application": "spilo", - "spilo-cluster": clusterName, - }, + Name: clusterName, + Labels: c.labels(), }, Spec: v1beta1.StatefulSetSpec{ Replicas: &c.cluster.Spec.NumberOfInstances, @@ -157,37 +140,34 @@ func (c *Cluster) createStatefulSet() { } func (c *Cluster) applySecrets() { - clusterName := (*c.cluster).Metadata.Name - secrets := make(map[string][]byte, len(c.pgUsers)) + var err error for _, user := range c.pgUsers { - secrets[user.secretKey] = user.password - } - - secret := v1.Secret{ - ObjectMeta: v1.ObjectMeta{ - Name: clusterName, - Labels: map[string]string{ - "application": "spilo", - "spilo-cluster": clusterName, + secret := v1.Secret{ + ObjectMeta: v1.ObjectMeta{ + Name: c.credentialSecretName(string(user.username)), + Labels: c.labels(), }, - }, - Type: v1.SecretTypeOpaque, - Data: secrets, - } - - _, err := c.config.KubeClient.Secrets(c.config.Namespace).Get(clusterName) - - //TODO: possible race condition (as well as while creating the other objects) - if !k8sutil.ResourceNotFound(err) { - _, err = c.config.KubeClient.Secrets(c.config.Namespace).Update(&secret) - } else { + Type: v1.SecretTypeOpaque, + Data: map[string][]byte{ + "username": user.username, + "password": user.password, + }, + } _, err = c.config.KubeClient.Secrets(c.config.Namespace).Create(&secret) - } - - if err != nil { - c.logger.Errorf("Error while creating or updating secret: %+v", err) - } else { - c.logger.Infof("Secret created: %+v", secret) + if k8sutil.IsKubernetesResourceAlreadyExistError(err) { + _, err = c.config.KubeClient.Secrets(c.config.Namespace).Update(&secret) + if err != nil { + c.logger.Errorf("Error while updating secret: %+v", err) + } else { + c.logger.Infof("Secret updated: %+v", secret) + } + } else { + if err != nil { + c.logger.Errorf("Error while creating secret: %+v", err) + } else { + c.logger.Infof("Secret created: %+v", secret) + } + } } //TODO: remove secrets of the deleted users @@ -204,11 +184,8 @@ func (c *Cluster) createService() { service := v1.Service{ ObjectMeta: v1.ObjectMeta{ - Name: clusterName, - Labels: map[string]string{ - "application": "spilo", - "spilo-cluster": clusterName, - }, + Name: clusterName, + Labels: c.labels(), }, Spec: v1.ServiceSpec{ Type: v1.ServiceTypeClusterIP, @@ -235,11 +212,8 @@ func (c *Cluster) createEndPoint() { endPoint := v1.Endpoints{ ObjectMeta: v1.ObjectMeta{ - Name: clusterName, - Labels: map[string]string{ - "application": "spilo", - "spilo-cluster": clusterName, - }, + Name: clusterName, + Labels: c.labels(), }, } diff --git a/pkg/util/util.go b/pkg/util/util.go index c2232341d..22dac260a 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -5,7 +5,7 @@ import ( "time" ) -var passwordChars = []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*=") +var passwordChars = []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$^&*=") func init() { rand.Seed(int64(time.Now().Unix()))