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 #### Infrastructure roles secret
The infrastructure roles secret is specified by the `infrastructure_roles_secret_name` Infrastructure roles can be specified by the `infrastructure_roles_secrets`
parameter. The role definition looks like this (values are base64 encoded): 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 ```yaml
user1: ZGJ1c2Vy apiVersion: v1
password1: c2VjcmV0 kind: Secret
inrole1: b3BlcmF0b3I= metadata:
name: postgresql-infrastructure-roles
data:
user1: ZGJ1c2Vy
password1: c2VjcmV0
inrole1: b3BlcmF0b3I=
user2: ...
``` ```
The block above describes the infrastructure role 'dbuser' with password The block above describes the infrastructure role 'dbuser' with password
'secret' that is a member of the 'operator' role. For the following definitions 'secret' that is a member of the 'operator' role. The resulting role will
one must increase the index, i.e. the next role will be defined as 'user2' and automatically be a login role.
so on. 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 there is no way to specify role options (like superuser or nologin) or role
memberships. This is where the ConfigMap comes into play. memberships. This is where the ConfigMap comes into play.

View File

@ -47,7 +47,8 @@ data:
# etcd_host: "" # etcd_host: ""
# gcp_credentials: "" # gcp_credentials: ""
# kubernetes_use_configmaps: "false" # 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 # inherited_labels: application,environment
# kube_iam_role: "" # kube_iam_role: ""
# log_s3_bucket: "" # log_s3_bucket: ""

View File

@ -39,6 +39,16 @@ configuration:
enable_pod_disruption_budget: true enable_pod_disruption_budget: true
enable_sidecars: true enable_sidecars: true
# 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
# - secretname: "other-infrastructure-role"
# userkey: "other-user-key"
# passwordkey: "other-password-key"
# template: false
# inherited_labels: # inherited_labels:
# - application # - application
# - environment # - environment

View File

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

View File

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

View File

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

View File

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