mirror of
https://github.com/zalando/postgres-operator.git
synced 2026-09-30 18:28:06 +02:00
[WIP] Extend infrastructure roles handling (#1064)
Extend infrastructure roles handling
Postgres Operator uses infrastructure roles to provide access to a database for
external users e.g. for monitoring purposes. Such infrastructure roles are
expected to be present in the form of k8s secrets with the following content:
inrole1: some_encrypted_role
password1: some_encrypted_password
user1: some_entrypted_name
inrole2: some_encrypted_role
password2: some_encrypted_password
user2: some_entrypted_name
The format of this content is implied implicitly and not flexible enough. In
case if we do not have possibility to change the format of a secret we want to
use in the Operator, we need to recreate it in this format.
To address this lets make the format of secret content explicitly. The idea is
to introduce a new configuration option for the Operator.
infrastructure_roles_secrets:
- secretname: k8s_secret_name
userkey: some_encrypted_name
passwordkey: some_encrypted_password
rolekey: some_encrypted_role
- secretname: k8s_secret_name
userkey: some_encrypted_name
passwordkey: some_encrypted_password
rolekey: some_encrypted_role
This would allow Operator to use any avalable secrets to prepare infrastructure
roles. To make it backward compatible simulate the old behaviour if the new
option is not present.
The new configuration option is intended be used mainly from CRD, but it's also
available via Operator ConfigMap in a limited fashion. For ConfigMap one can
put there only a string with one secret definition in the following format (as
a string):
infrastructure_roles_secrets: |
secretname: k8s_secret_name,
userkey: some_encrypted_name,
passwordkey: some_encrypted_password,
rolekey: some_encrypted_role
Note than only one secret could be specified this way, no multiple secrets are
allowed.
Eventually the resulting list of infrastructure roles would be a total sum of
all supported ways to describe it, namely legacy via
infrastructure_roles_secret_name and infrastructure_roles_secrets from both
ConfigMap and CRD.
This commit is contained in:
@@ -52,16 +52,42 @@ type Resources struct {
|
||||
ShmVolume *bool `name:"enable_shm_volume" default:"true"`
|
||||
}
|
||||
|
||||
type InfrastructureRole struct {
|
||||
// Name of a secret which describes the role, and optionally name of a
|
||||
// configmap with an extra information
|
||||
SecretName spec.NamespacedName
|
||||
|
||||
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:
|
||||
//
|
||||
// %(userkey)idx: ...
|
||||
// %(passwordkey)idx: ...
|
||||
// %(rolekey)idx: ...
|
||||
//
|
||||
// If it does, Name/Password/Role are interpreted not as unique field
|
||||
// names, but as a template.
|
||||
|
||||
Template bool
|
||||
}
|
||||
|
||||
// Auth describes authentication specific configuration parameters
|
||||
type Auth struct {
|
||||
SecretNameTemplate StringTemplate `name:"secret_name_template" default:"{username}.{cluster}.credentials.{tprkind}.{tprgroup}"`
|
||||
PamRoleName string `name:"pam_role_name" default:"zalandos"`
|
||||
PamConfiguration string `name:"pam_configuration" default:"https://info.example.com/oauth2/tokeninfo?access_token= uid realm=/employees"`
|
||||
TeamsAPIUrl string `name:"teams_api_url" default:"https://teams.example.com/api/"`
|
||||
OAuthTokenSecretName spec.NamespacedName `name:"oauth_token_secret_name" default:"postgresql-operator"`
|
||||
InfrastructureRolesSecretName spec.NamespacedName `name:"infrastructure_roles_secret_name"`
|
||||
SuperUsername string `name:"super_username" default:"postgres"`
|
||||
ReplicationUsername string `name:"replication_username" default:"standby"`
|
||||
SecretNameTemplate StringTemplate `name:"secret_name_template" default:"{username}.{cluster}.credentials.{tprkind}.{tprgroup}"`
|
||||
PamRoleName string `name:"pam_role_name" default:"zalandos"`
|
||||
PamConfiguration string `name:"pam_configuration" default:"https://info.example.com/oauth2/tokeninfo?access_token= uid realm=/employees"`
|
||||
TeamsAPIUrl string `name:"teams_api_url" default:"https://teams.example.com/api/"`
|
||||
OAuthTokenSecretName spec.NamespacedName `name:"oauth_token_secret_name" default:"postgresql-operator"`
|
||||
InfrastructureRolesSecretName spec.NamespacedName `name:"infrastructure_roles_secret_name"`
|
||||
InfrastructureRoles []*InfrastructureRole `name:"-"`
|
||||
InfrastructureRolesDefs string `name:"infrastructure_roles_secrets"`
|
||||
SuperUsername string `name:"super_username" default:"postgres"`
|
||||
ReplicationUsername string `name:"replication_username" default:"standby"`
|
||||
}
|
||||
|
||||
// Scalyr holds the configuration for the Scalyr Agent sidecar for log shipping:
|
||||
|
||||
+56
-14
@@ -271,31 +271,73 @@ func SameLogicalBackupJob(cur, new *batchv1beta1.CronJob) (match bool, reason st
|
||||
}
|
||||
|
||||
func (c *mockSecret) Get(ctx context.Context, name string, options metav1.GetOptions) (*v1.Secret, error) {
|
||||
if name != "infrastructureroles-test" {
|
||||
return nil, fmt.Errorf("NotFound")
|
||||
}
|
||||
secret := &v1.Secret{}
|
||||
secret.Name = "testcluster"
|
||||
secret.Data = map[string][]byte{
|
||||
oldFormatSecret := &v1.Secret{}
|
||||
oldFormatSecret.Name = "testcluster"
|
||||
oldFormatSecret.Data = map[string][]byte{
|
||||
"user1": []byte("testrole"),
|
||||
"password1": []byte("testpassword"),
|
||||
"inrole1": []byte("testinrole"),
|
||||
"foobar": []byte(b64.StdEncoding.EncodeToString([]byte("password"))),
|
||||
}
|
||||
return secret, nil
|
||||
|
||||
newFormatSecret := &v1.Secret{}
|
||||
newFormatSecret.Name = "test-secret-new-format"
|
||||
newFormatSecret.Data = map[string][]byte{
|
||||
"user": []byte("new-test-role"),
|
||||
"password": []byte("new-test-password"),
|
||||
"inrole": []byte("new-test-inrole"),
|
||||
"new-foobar": []byte(b64.StdEncoding.EncodeToString([]byte("password"))),
|
||||
}
|
||||
|
||||
secrets := map[string]*v1.Secret{
|
||||
"infrastructureroles-old-test": oldFormatSecret,
|
||||
"infrastructureroles-new-test": newFormatSecret,
|
||||
}
|
||||
|
||||
for idx := 1; idx <= 2; idx++ {
|
||||
newFormatStandaloneSecret := &v1.Secret{}
|
||||
newFormatStandaloneSecret.Name = fmt.Sprintf("test-secret-new-format%d", idx)
|
||||
newFormatStandaloneSecret.Data = map[string][]byte{
|
||||
"user": []byte(fmt.Sprintf("new-test-role%d", idx)),
|
||||
"password": []byte(fmt.Sprintf("new-test-password%d", idx)),
|
||||
"inrole": []byte(fmt.Sprintf("new-test-inrole%d", idx)),
|
||||
}
|
||||
|
||||
secrets[fmt.Sprintf("infrastructureroles-new-test%d", idx)] =
|
||||
newFormatStandaloneSecret
|
||||
}
|
||||
|
||||
if secret, exists := secrets[name]; exists {
|
||||
return secret, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("NotFound")
|
||||
|
||||
}
|
||||
|
||||
func (c *mockConfigMap) Get(ctx context.Context, name string, options metav1.GetOptions) (*v1.ConfigMap, error) {
|
||||
if name != "infrastructureroles-test" {
|
||||
return nil, fmt.Errorf("NotFound")
|
||||
}
|
||||
configmap := &v1.ConfigMap{}
|
||||
configmap.Name = "testcluster"
|
||||
configmap.Data = map[string]string{
|
||||
oldFormatConfigmap := &v1.ConfigMap{}
|
||||
oldFormatConfigmap.Name = "testcluster"
|
||||
oldFormatConfigmap.Data = map[string]string{
|
||||
"foobar": "{}",
|
||||
}
|
||||
return configmap, nil
|
||||
|
||||
newFormatConfigmap := &v1.ConfigMap{}
|
||||
newFormatConfigmap.Name = "testcluster"
|
||||
newFormatConfigmap.Data = map[string]string{
|
||||
"new-foobar": "{\"user_flags\": [\"createdb\"]}",
|
||||
}
|
||||
|
||||
configmaps := map[string]*v1.ConfigMap{
|
||||
"infrastructureroles-old-test": oldFormatConfigmap,
|
||||
"infrastructureroles-new-test": newFormatConfigmap,
|
||||
}
|
||||
|
||||
if configmap, exists := configmaps[name]; exists {
|
||||
return configmap, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("NotFound")
|
||||
}
|
||||
|
||||
// Secrets to be mocked
|
||||
|
||||
Reference in New Issue
Block a user