Use one secret per user

This commit is contained in:
Murat Kabilov 2017-02-07 11:07:49 +01:00
parent abb1173035
commit 7e4d0410c2
3 changed files with 70 additions and 77 deletions

View File

@ -15,7 +15,7 @@ import (
"github.bus.zalan.do/acid/postgres-operator/pkg/util/constants" "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 //TODO: remove struct duplication
type Config struct { type Config struct {
@ -34,10 +34,9 @@ type Cluster struct {
} }
type pgUser struct { type pgUser struct {
username string username []byte
secretKey string
password []byte password []byte
flags []string flags []string
} }
func New(cfg Config, spec *spec.Postgresql) *Cluster { func New(cfg Config, spec *spec.Postgresql) *Cluster {
@ -58,15 +57,26 @@ func New(cfg Config, spec *spec.Postgresql) *Cluster {
return cluster return cluster
} }
func secretUserKey(userName string) string { func (c *Cluster) labels() map[string]string {
return fmt.Sprintf("%s-password", userName) 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() { func (c *Cluster) init() {
for _, userName := range patroniUsers { for _, userName := range patroniUsers {
user := pgUser{ user := pgUser{
username: userName, username: []byte(userName),
secretKey: secretUserKey(userName),
password: util.RandomPasswordBytes(constants.PasswordLength), password: util.RandomPasswordBytes(constants.PasswordLength),
} }
c.pgUsers = append(c.pgUsers, user) c.pgUsers = append(c.pgUsers, user)
@ -74,12 +84,11 @@ func (c *Cluster) init() {
for userName, userFlags := range (*c.cluster.Spec).Users { for userName, userFlags := range (*c.cluster.Spec).Users {
user := pgUser{ user := pgUser{
username: userName, username: []byte(userName),
secretKey: secretUserKey(userName),
password: util.RandomPasswordBytes(constants.PasswordLength), 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) 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 { 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 //TODO: delete key from etcd

View File

@ -48,20 +48,9 @@ func (c *Cluster) createStatefulSet() {
ValueFrom: &v1.EnvVarSource{ ValueFrom: &v1.EnvVarSource{
SecretKeyRef: &v1.SecretKeySelector{ SecretKeyRef: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{ LocalObjectReference: v1.LocalObjectReference{
Name: clusterName, Name: c.credentialSecretName("superuser"),
}, },
Key: secretUserKey("superuser"), Key: "password",
},
},
},
{
Name: "PGPASSWORD_ADMIN",
ValueFrom: &v1.EnvVarSource{
SecretKeyRef: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{
Name: clusterName,
},
Key: secretUserKey("admin"),
}, },
}, },
}, },
@ -70,9 +59,9 @@ func (c *Cluster) createStatefulSet() {
ValueFrom: &v1.EnvVarSource{ ValueFrom: &v1.EnvVarSource{
SecretKeyRef: &v1.SecretKeySelector{ SecretKeyRef: &v1.SecretKeySelector{
LocalObjectReference: v1.LocalObjectReference{ 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{ template := v1.PodTemplateSpec{
ObjectMeta: v1.ObjectMeta{ ObjectMeta: v1.ObjectMeta{
Labels: map[string]string{ Labels: c.labels(),
"application": "spilo",
"spilo-cluster": clusterName,
},
Annotations: map[string]string{"pod.alpha.kubernetes.io/initialized": "true"}, Annotations: map[string]string{"pod.alpha.kubernetes.io/initialized": "true"},
}, },
Spec: podSpec, Spec: podSpec,
@ -140,11 +126,8 @@ func (c *Cluster) createStatefulSet() {
statefulSet := &v1beta1.StatefulSet{ statefulSet := &v1beta1.StatefulSet{
ObjectMeta: v1.ObjectMeta{ ObjectMeta: v1.ObjectMeta{
Name: clusterName, Name: clusterName,
Labels: map[string]string{ Labels: c.labels(),
"application": "spilo",
"spilo-cluster": clusterName,
},
}, },
Spec: v1beta1.StatefulSetSpec{ Spec: v1beta1.StatefulSetSpec{
Replicas: &c.cluster.Spec.NumberOfInstances, Replicas: &c.cluster.Spec.NumberOfInstances,
@ -157,37 +140,34 @@ func (c *Cluster) createStatefulSet() {
} }
func (c *Cluster) applySecrets() { func (c *Cluster) applySecrets() {
clusterName := (*c.cluster).Metadata.Name var err error
secrets := make(map[string][]byte, len(c.pgUsers))
for _, user := range c.pgUsers { for _, user := range c.pgUsers {
secrets[user.secretKey] = user.password secret := v1.Secret{
} ObjectMeta: v1.ObjectMeta{
Name: c.credentialSecretName(string(user.username)),
secret := v1.Secret{ Labels: c.labels(),
ObjectMeta: v1.ObjectMeta{
Name: clusterName,
Labels: map[string]string{
"application": "spilo",
"spilo-cluster": clusterName,
}, },
}, Type: v1.SecretTypeOpaque,
Type: v1.SecretTypeOpaque, Data: map[string][]byte{
Data: secrets, "username": user.username,
} "password": user.password,
},
_, 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 {
_, err = c.config.KubeClient.Secrets(c.config.Namespace).Create(&secret) _, err = c.config.KubeClient.Secrets(c.config.Namespace).Create(&secret)
} if k8sutil.IsKubernetesResourceAlreadyExistError(err) {
_, err = c.config.KubeClient.Secrets(c.config.Namespace).Update(&secret)
if err != nil { if err != nil {
c.logger.Errorf("Error while creating or updating secret: %+v", err) c.logger.Errorf("Error while updating secret: %+v", err)
} else { } else {
c.logger.Infof("Secret created: %+v", secret) 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 //TODO: remove secrets of the deleted users
@ -204,11 +184,8 @@ func (c *Cluster) createService() {
service := v1.Service{ service := v1.Service{
ObjectMeta: v1.ObjectMeta{ ObjectMeta: v1.ObjectMeta{
Name: clusterName, Name: clusterName,
Labels: map[string]string{ Labels: c.labels(),
"application": "spilo",
"spilo-cluster": clusterName,
},
}, },
Spec: v1.ServiceSpec{ Spec: v1.ServiceSpec{
Type: v1.ServiceTypeClusterIP, Type: v1.ServiceTypeClusterIP,
@ -235,11 +212,8 @@ func (c *Cluster) createEndPoint() {
endPoint := v1.Endpoints{ endPoint := v1.Endpoints{
ObjectMeta: v1.ObjectMeta{ ObjectMeta: v1.ObjectMeta{
Name: clusterName, Name: clusterName,
Labels: map[string]string{ Labels: c.labels(),
"application": "spilo",
"spilo-cluster": clusterName,
},
}, },
} }

View File

@ -5,7 +5,7 @@ import (
"time" "time"
) )
var passwordChars = []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*=") var passwordChars = []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$^&*=")
func init() { func init() {
rand.Seed(int64(time.Now().Unix())) rand.Seed(int64(time.Now().Unix()))