rename fields, allow secretname, update docs

This commit is contained in:
Felix Kunde 2020-08-02 18:39:27 +02:00
parent 53e049af9a
commit d6c686a70d
7 changed files with 116 additions and 75 deletions

View File

@ -150,21 +150,44 @@ user. There are two ways to define them:
#### Infrastructure roles secret
The infrastructure roles secret is specified by the `infrastructure_roles_secret_name`
parameter. The role definition looks like this (values are base64 encoded):
Infrastructure roles can be specified by the `infrastructure_roles_secrets`
parameter where you can reference multiple existing secrets. Prior to `v1.6.0`
the operator could only reference one secret with the
`infrastructure_roles_secret_name` option. However, this secret could contain
multiple roles using the same set of keys with incremented indexes.
```yaml
user1: ZGJ1c2Vy
password1: c2VjcmV0
inrole1: b3BlcmF0b3I=
apiVersion: v1
kind: Secret
metadata:
name: postgresql-infrastructure-roles
data:
user1: ZGJ1c2Vy
password1: c2VjcmV0
inrole1: b3BlcmF0b3I=
user2: ...
```
The block above describes the infrastructure role 'dbuser' with password
'secret' that is a member of the 'operator' role. For the following definitions
one must increase the index, i.e. the next role will be defined as 'user2' and
so on. The resulting role will automatically be a login role.
'secret' that is a member of the 'operator' role. The resulting role will
automatically be a login role.
Note that with definitions that solely use the infrastructure roles secret
With the new option the user can configure the names of secret keys that
contain the user name, password etc. If the secret uses a template for
multiple roles as described above, the `template` flag must be set to `true`.
The secret itself is referenced by the `secretname` key. Please, refer to the
example manifests to understand who `infrastructure_roles_secrets` has to be
configured for the [configmap](../manifests/configmap.yaml) (can only
reference one existing secret) or [CRD configuration](../manifests/postgresql-operator-default-configuration.yaml)
(reference multiple secret definitions in an array).
If both `infrastructure_roles_secret_name` and `infrastructure_roles_secrets`
are defined the operator will create roles for both of them. So make sure,
they do not collide. To migrate to the new format use the same names for the
secret keys as in the example above and unset the
`infrastructure_roles_secret_name`.
Note, that with definitions that solely use the infrastructure roles secret
there is no way to specify role options (like superuser or nologin) or role
memberships. This is where the ConfigMap comes into play.

View File

@ -47,7 +47,8 @@ data:
# etcd_host: ""
# gcp_credentials: ""
# kubernetes_use_configmaps: "false"
# infrastructure_roles_secret_name: postgresql-infrastructure-roles
# infrastructure_roles_secret_name: "postgresql-infrastructure-roles"
# infrastructure_roles_secrets: "secretname:monitoring-roles,userkey:user,passwordkey:password,rolekey:inrole,template:true"
# inherited_labels: application,environment
# kube_iam_role: ""
# log_s3_bucket: ""

View File

@ -39,6 +39,16 @@ configuration:
enable_pod_disruption_budget: true
enable_sidecars: true
# infrastructure_roles_secret_name: "postgresql-infrastructure-roles"
# infrastructure_roles_secrets:
# - secretname: "monitoring-roles"
# userkey: "user"
# passwordkey: "password"
# rolekey: "inrole"
# template: true
# - secretname: "other-infrastructure-role"
# userkey: "other-user-key"
# passwordkey: "other-password-key"
# template: false
# inherited_labels:
# - application
# - environment

View File

@ -79,10 +79,10 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur
result.InfrastructureRoles = append(
result.InfrastructureRoles,
&config.InfrastructureRole{
SecretName: secret.SecretName,
Name: secret.Name,
Role: secret.Role,
Password: secret.Password,
SecretName: secret.SecretName,
UserKey: secret.UserKey,
RoleKey: secret.RoleKey,
PasswordKey: secret.PasswordKey,
})
}
}

View File

@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"fmt"
"strconv"
"strings"
v1 "k8s.io/api/core/v1"
@ -132,6 +133,8 @@ func (c *Controller) getInfrastructureRoleDefinitions() []*config.Infrastructure
// form key1: value1, key2: value2), which has to be used together with
// an old secret name.
var secretName spec.NamespacedName
var err error
propertySep := ","
valueSep := ":"
@ -139,11 +142,6 @@ func (c *Controller) getInfrastructureRoleDefinitions() []*config.Infrastructure
// convert it to a proper definition
properties := strings.Split(c.opConfig.InfrastructureRolesDefs, propertySep)
roleDef = config.InfrastructureRole{
SecretName: c.opConfig.InfrastructureRolesSecretName,
Template: false,
}
for _, property := range properties {
values := strings.Split(property, valueSep)
if len(values) < 2 {
@ -153,15 +151,24 @@ func (c *Controller) getInfrastructureRoleDefinitions() []*config.Infrastructure
value := strings.TrimSpace(values[1])
switch name {
case "name":
roleDef.Name = value
case "password":
roleDef.Password = value
case "role":
roleDef.Role = value
case "secretname":
if err = secretName.DecodeWorker(value, "default"); err != nil {
c.logger.Warningf("Could not marshal secret name %s: %v", value, err)
} else {
roleDef.SecretName = secretName
}
case "userkey":
roleDef.UserKey = value
case "passwordkey":
roleDef.PasswordKey = value
case "rolekey":
roleDef.RoleKey = value
case "template":
if roleDef.Template, err = strconv.ParseBool(value); err != nil {
c.logger.Warningf("Could not extract template information %s: %v", value, err)
}
default:
c.logger.Warningf("Role description is not known: %s",
c.opConfig.InfrastructureRolesSecretName)
c.logger.Warningf("Role description is not known: %s", properties)
}
}
} else {
@ -169,17 +176,17 @@ func (c *Controller) getInfrastructureRoleDefinitions() []*config.Infrastructure
// via existing definition structure and remember that it's just a
// template, the real values are in user1,password1,inrole1 etc.
roleDef = config.InfrastructureRole{
SecretName: c.opConfig.InfrastructureRolesSecretName,
Name: "user",
Password: "password",
Role: "inrole",
Template: true,
SecretName: c.opConfig.InfrastructureRolesSecretName,
UserKey: "user",
PasswordKey: "password",
RoleKey: "inrole",
Template: true,
}
}
if roleDef.Name != "" &&
roleDef.Password != "" &&
roleDef.Role != "" {
if roleDef.UserKey != "" &&
roleDef.PasswordKey != "" &&
roleDef.RoleKey != "" {
rolesDefs = append(rolesDefs, &roleDef)
}
@ -280,9 +287,9 @@ func (c *Controller) getInfrastructureRole(
Users:
for i := 1; i <= len(secretData); i++ {
properties := []string{
infraRole.Name,
infraRole.Password,
infraRole.Role,
infraRole.UserKey,
infraRole.PasswordKey,
infraRole.RoleKey,
}
t := spec.PgUser{Origin: spec.RoleOriginInfrastructure}
for _, p := range properties {
@ -327,9 +334,9 @@ func (c *Controller) getInfrastructureRole(
return nil, fmt.Errorf("could not decode yaml role: %v", err)
}
} else {
roleDescr.Name = string(secretData[infraRole.Name])
roleDescr.Password = string(secretData[infraRole.Password])
roleDescr.MemberOf = append(roleDescr.MemberOf, string(secretData[infraRole.Role]))
roleDescr.Name = string(secretData[infraRole.UserKey])
roleDescr.Password = string(secretData[infraRole.PasswordKey])
roleDescr.MemberOf = append(roleDescr.MemberOf, string(secretData[infraRole.RoleKey]))
}
if roleDescr.Valid() {

View File

@ -132,11 +132,11 @@ func TestOldInfrastructureRoleFormat(t *testing.T) {
roles, errors := utilTestController.getInfrastructureRoles(
[]*config.InfrastructureRole{
&config.InfrastructureRole{
SecretName: test.secretName,
Name: "user",
Password: "password",
Role: "inrole",
Template: true,
SecretName: test.secretName,
UserKey: "user",
PasswordKey: "password",
RoleKey: "inrole",
Template: true,
},
})
@ -231,11 +231,11 @@ func TestNewInfrastructureRoleFormat(t *testing.T) {
definitions := []*config.InfrastructureRole{}
for _, secret := range test.secrets {
definitions = append(definitions, &config.InfrastructureRole{
SecretName: secret,
Name: "user",
Password: "password",
Role: "inrole",
Template: false,
SecretName: secret,
UserKey: "user",
PasswordKey: "password",
RoleKey: "inrole",
Template: false,
})
}
@ -287,10 +287,10 @@ func TestInfrastructureRoleDefinitions(t *testing.T) {
Namespace: v1.NamespaceDefault,
Name: testInfrastructureRolesNewSecretName,
},
Name: "user",
Password: "password",
Role: "inrole",
Template: false,
UserKey: "user",
PasswordKey: "password",
RoleKey: "inrole",
Template: false,
},
},
spec.NamespacedName{},
@ -301,10 +301,10 @@ func TestInfrastructureRoleDefinitions(t *testing.T) {
Namespace: v1.NamespaceDefault,
Name: testInfrastructureRolesNewSecretName,
},
Name: "user",
Password: "password",
Role: "inrole",
Template: false,
UserKey: "user",
PasswordKey: "password",
RoleKey: "inrole",
Template: false,
},
},
},
@ -322,10 +322,10 @@ func TestInfrastructureRoleDefinitions(t *testing.T) {
Namespace: v1.NamespaceDefault,
Name: testInfrastructureRolesOldSecretName,
},
Name: "user",
Password: "password",
Role: "inrole",
Template: true,
UserKey: "user",
PasswordKey: "password",
RoleKey: "inrole",
Template: true,
},
},
},
@ -336,17 +336,17 @@ func TestInfrastructureRoleDefinitions(t *testing.T) {
Namespace: v1.NamespaceDefault,
Name: testInfrastructureRolesOldSecretName,
},
"name: test-user, password: test-password, role: test-role",
"secretname: infrastructureroles-old-test, userkey: test-user, passwordkey: test-password, rolekey: test-role, template: false",
[]*config.InfrastructureRole{
&config.InfrastructureRole{
SecretName: spec.NamespacedName{
Namespace: v1.NamespaceDefault,
Name: testInfrastructureRolesOldSecretName,
},
Name: "test-user",
Password: "test-password",
Role: "test-role",
Template: false,
UserKey: "test-user",
PasswordKey: "test-password",
RoleKey: "test-role",
Template: false,
},
},
},
@ -364,7 +364,7 @@ func TestInfrastructureRoleDefinitions(t *testing.T) {
{
[]*config.InfrastructureRole{},
spec.NamespacedName{},
"name: test-user, password: test-password, role: test-role",
"userkey: test-user, passwordkey: test-password, rolekey: test-role, template: false",
[]*config.InfrastructureRole{},
},
}

View File

@ -57,18 +57,18 @@ type InfrastructureRole struct {
// configmap with an extra information
SecretName spec.NamespacedName
Name string
Password string
Role string
UserKey string
PasswordKey string
RoleKey string
// This field point out the detailed yaml definition of the role, if exists
Details string
// Specify if a secret contains multiple fields in the following format:
//
// %(name)idx: ...
// %(password)idx: ...
// %(role)idx: ...
// %(userkey)idx: ...
// %(passwordkey)idx: ...
// %(rolekey)idx: ...
//
// If it does, Name/Password/Role are interpreted not as unique field
// names, but as a template.