Use one secret per user
This commit is contained in:
parent
abb1173035
commit
7e4d0410c2
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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()))
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue