Skip to content

Commit 282b6d2

Browse files
authored
allow secrets of default users in a different namespace (zalando#1581)
* allow secrets of default users in a different namespace * add warning in case secretNamespace is ignored
1 parent 47dc0a9 commit 282b6d2

File tree

8 files changed

+84
-20
lines changed

8 files changed

+84
-20
lines changed

charts/postgres-operator/crds/postgresqls.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,8 @@ spec:
394394
type: boolean
395395
defaultRoles:
396396
type: boolean
397+
secretNamespace:
398+
type: string
397399
replicaLoadBalancer: # deprecated
398400
type: boolean
399401
resources:

docs/reference/cluster_manifest.md

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,11 @@ These parameters are grouped directly under the `spec` key in the manifest.
109109
`SUPERUSER`, `REPLICATION`, `INHERIT`, `LOGIN`, `NOLOGIN`, `CREATEROLE`,
110110
`CREATEDB`, `BYPASSURL`. A login user is created by default unless NOLOGIN is
111111
specified, in which case the operator creates a role. One can specify empty
112-
flags by providing a JSON empty array '*[]*'. Optional.
112+
flags by providing a JSON empty array '*[]*'. If the config option
113+
`enable_cross_namespace_secrets` is enabled you can specify the namespace in
114+
the user name in the form `{namespace}.{username}` and the operator will
115+
create the K8s secret in that namespace. The part after the first `.` is
116+
considered to be the user name. Optional.
113117

114118
* **databases**
115119
a map of database names to database owners for the databases that should be
@@ -185,6 +189,35 @@ These parameters are grouped directly under the `spec` key in the manifest.
185189
If you set the `all` special item, it will be mounted in all containers (postgres + sidecars).
186190
Else you can set the list of target containers in which the additional volumes will be mounted (eg : postgres, telegraf)
187191

192+
## Prepared Databases
193+
194+
The operator can create databases with default owner, reader and writer roles
195+
without the need to specifiy them under `users` or `databases` sections. Those
196+
parameters are grouped under the `preparedDatabases` top-level key. For more
197+
information, see [user docs](../user.md#prepared-databases-with-roles-and-default-privileges).
198+
199+
* **defaultUsers**
200+
The operator will always create default `NOLOGIN` roles for defined prepared
201+
databases, but if `defaultUsers` is set to `true` three additional `LOGIN`
202+
roles with `_user` suffix will get created. Default is `false`.
203+
204+
* **extensions**
205+
map of extensions with target database schema that the operator will install
206+
in the database. Optional.
207+
208+
* **schemas**
209+
map of schemas that the operator will create. Optional - if no schema is
210+
listed, the operator will create a schema called `data`. Under each schema
211+
key, it can be defined if `defaultRoles` (NOLOGIN) and `defaultUsers` (LOGIN)
212+
roles shall be created that have schema-exclusive privileges. Both flags are
213+
set to `false` by default.
214+
215+
* **secretNamespace**
216+
for each default LOGIN role the operator will create a secret. You can
217+
specify the namespace in which these secrets will get created, if
218+
`enable_cross_namespace_secrets` is set to `true` in the config. Otherwise,
219+
the cluster namespace is used.
220+
188221
## Postgres parameters
189222

190223
Those parameters are grouped under the `postgresql` top-level key, which is
@@ -258,31 +291,33 @@ explanation of `ttl` and `loop_wait` parameters.
258291

259292
Those parameters define [CPU and memory requests and limits](https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/)
260293
for the Postgres container. They are grouped under the `resources` top-level
261-
key with subgroups `requests` and `limits`.
294+
key with subgroups `requests` and `limits`. The whole section is optional,
295+
however if you specify a request or limit you have to define everything
296+
(unless you are not modifying the default CRD schema validation).
262297

263298
### Requests
264299

265300
CPU and memory requests for the Postgres container.
266301

267302
* **cpu**
268303
CPU requests for the Postgres container. Optional, overrides the
269-
`default_cpu_requests` operator configuration parameter. Optional.
304+
`default_cpu_requests` operator configuration parameter.
270305

271306
* **memory**
272307
memory requests for the Postgres container. Optional, overrides the
273-
`default_memory_request` operator configuration parameter. Optional.
308+
`default_memory_request` operator configuration parameter.
274309

275310
### Limits
276311

277312
CPU and memory limits for the Postgres container.
278313

279314
* **cpu**
280315
CPU limits for the Postgres container. Optional, overrides the
281-
`default_cpu_limits` operator configuration parameter. Optional.
316+
`default_cpu_limits` operator configuration parameter.
282317

283318
* **memory**
284319
memory limits for the Postgres container. Optional, overrides the
285-
`default_memory_limits` operator configuration parameter. Optional.
320+
`default_memory_limits` operator configuration parameter.
286321

287322
## Parameters defining how to clone the cluster from another one
288323

docs/reference/operator_parameters.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -267,9 +267,7 @@ configuration they are grouped under the `kubernetes` key.
267267
* **enable_cross_namespace_secrets**
268268
To allow secrets in a different namespace other than the Postgres cluster
269269
namespace. Once enabled, specify the namespace in the user name under the
270-
`users` section in the form `{namespace}.{username}`. The operator will then
271-
create the user secret in that namespace. The part after the first `.` is
272-
considered to be the user name. The default is `false`.
270+
`users` section in the form `{namespace}.{username}`. The default is `false`.
273271

274272
* **enable_init_containers**
275273
global option to allow for creating init containers in the cluster manifest to

docs/user.md

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,9 @@ secret, without ever sharing it outside of the cluster.
139139
At the moment it is not possible to define membership of the manifest role in
140140
other roles.
141141

142-
To define the secrets for the users in a different namespace than that of the cluster,
143-
one can set `enable_cross_namespace_secret` and declare the namespace for the
144-
secrets in the manifest in the following manner,
142+
To define the secrets for the users in a different namespace than that of the
143+
cluster, one can set `enable_cross_namespace_secret` and declare the namespace
144+
for the secrets in the manifest in the following manner,
145145

146146
```yaml
147147
spec:
@@ -150,7 +150,8 @@ spec:
150150
appspace.db_user:
151151
- createdb
152152
```
153-
Here, anything before the first dot is taken as the namespace and the text after
153+
154+
Here, anything before the first dot is considered the namespace and the text after
154155
the first dot is the username. Also, the postgres roles of these usernames would
155156
be in the form of `namespace.username`.
156157

@@ -520,7 +521,7 @@ Then, the schemas are owned by the database owner, too.
520521

521522
The roles described in the previous paragraph can be granted to LOGIN roles from
522523
the `users` section in the manifest. Optionally, the Postgres Operator can also
523-
create default LOGIN roles for the database an each schema individually. These
524+
create default LOGIN roles for the database and each schema individually. These
524525
roles will get the `_user` suffix and they inherit all rights from their NOLOGIN
525526
counterparts. Therefore, you cannot have `defaultRoles` set to `false` and enable
526527
`defaultUsers` at the same time.
@@ -550,6 +551,19 @@ Default access privileges are also defined for LOGIN roles on database and
550551
schema creation. This means they are currently not set when `defaultUsers`
551552
(or `defaultRoles` for schemas) are enabled at a later point in time.
552553

554+
For all LOGIN roles the operator will create K8s secrets in the namespace
555+
specified in `secretNamespace`, if `enable_cross_namespace_secret` is set to
556+
`true` in the config. Otherwise, they are created in the same namespace like
557+
the Postgres cluster.
558+
559+
```yaml
560+
spec:
561+
preparedDatabases:
562+
foo:
563+
defaultUsers: true
564+
secretNamespace: appspace
565+
```
566+
553567
### Schema `search_path` for default roles
554568

555569
The schema [`search_path`](https://www.postgresql.org/docs/13/ddl-schemas.html#DDL-SCHEMAS-PATH)

manifests/postgresql.crd.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,8 @@ spec:
390390
type: boolean
391391
defaultRoles:
392392
type: boolean
393+
secretNamespace:
394+
type: string
393395
replicaLoadBalancer: # deprecated
394396
type: boolean
395397
resources:

pkg/apis/acid.zalan.do/v1/crds.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,9 @@ var PostgresCRDResourceValidation = apiextv1.CustomResourceValidation{
573573
},
574574
},
575575
},
576+
"secretNamespace": {
577+
Type: "string",
578+
},
576579
},
577580
},
578581
},

pkg/apis/acid.zalan.do/v1/postgresql_type.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ type PreparedDatabase struct {
9595
PreparedSchemas map[string]PreparedSchema `json:"schemas,omitempty"`
9696
DefaultUsers bool `json:"defaultUsers,omitempty" defaults:"false"`
9797
Extensions map[string]string `json:"extensions,omitempty"`
98+
SecretNamespace string `json:"secretNamespace,omitempty"`
9899
}
99100

100101
// PreparedSchema describes elements to be bootstrapped per schema

pkg/cluster/cluster.go

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,11 +1077,11 @@ func (c *Cluster) initPreparedDatabaseRoles() error {
10771077
}
10781078

10791079
// default roles per database
1080-
if err := c.initDefaultRoles(defaultRoles, "admin", preparedDbName, searchPath.String()); err != nil {
1080+
if err := c.initDefaultRoles(defaultRoles, "admin", preparedDbName, searchPath.String(), preparedDB.SecretNamespace); err != nil {
10811081
return fmt.Errorf("could not initialize default roles for database %s: %v", preparedDbName, err)
10821082
}
10831083
if preparedDB.DefaultUsers {
1084-
if err := c.initDefaultRoles(defaultUsers, "admin", preparedDbName, searchPath.String()); err != nil {
1084+
if err := c.initDefaultRoles(defaultUsers, "admin", preparedDbName, searchPath.String(), preparedDB.SecretNamespace); err != nil {
10851085
return fmt.Errorf("could not initialize default roles for database %s: %v", preparedDbName, err)
10861086
}
10871087
}
@@ -1092,14 +1092,14 @@ func (c *Cluster) initPreparedDatabaseRoles() error {
10921092
if err := c.initDefaultRoles(defaultRoles,
10931093
preparedDbName+constants.OwnerRoleNameSuffix,
10941094
preparedDbName+"_"+preparedSchemaName,
1095-
constants.DefaultSearchPath+", "+preparedSchemaName); err != nil {
1095+
constants.DefaultSearchPath+", "+preparedSchemaName, preparedDB.SecretNamespace); err != nil {
10961096
return fmt.Errorf("could not initialize default roles for database schema %s: %v", preparedSchemaName, err)
10971097
}
10981098
if preparedSchema.DefaultUsers {
10991099
if err := c.initDefaultRoles(defaultUsers,
11001100
preparedDbName+constants.OwnerRoleNameSuffix,
11011101
preparedDbName+"_"+preparedSchemaName,
1102-
constants.DefaultSearchPath+", "+preparedSchemaName); err != nil {
1102+
constants.DefaultSearchPath+", "+preparedSchemaName, preparedDB.SecretNamespace); err != nil {
11031103
return fmt.Errorf("could not initialize default users for database schema %s: %v", preparedSchemaName, err)
11041104
}
11051105
}
@@ -1109,10 +1109,19 @@ func (c *Cluster) initPreparedDatabaseRoles() error {
11091109
return nil
11101110
}
11111111

1112-
func (c *Cluster) initDefaultRoles(defaultRoles map[string]string, admin, prefix string, searchPath string) error {
1112+
func (c *Cluster) initDefaultRoles(defaultRoles map[string]string, admin, prefix, searchPath, secretNamespace string) error {
11131113

11141114
for defaultRole, inherits := range defaultRoles {
11151115

1116+
namespace := c.Namespace
1117+
//if namespaced secrets are allowed
1118+
if secretNamespace != "" {
1119+
if c.Config.OpConfig.EnableCrossNamespaceSecret {
1120+
namespace = secretNamespace
1121+
} else {
1122+
c.logger.Warn("secretNamespace ignored because enable_cross_namespace_secret set to false. Creating secrets in cluster namespace.")
1123+
}
1124+
}
11161125
roleName := prefix + defaultRole
11171126

11181127
flags := []string{constants.RoleFlagNoLogin}
@@ -1135,7 +1144,7 @@ func (c *Cluster) initDefaultRoles(defaultRoles map[string]string, admin, prefix
11351144
newRole := spec.PgUser{
11361145
Origin: spec.RoleOriginBootstrap,
11371146
Name: roleName,
1138-
Namespace: c.Namespace,
1147+
Namespace: namespace,
11391148
Password: util.RandomPassword(constants.PasswordLength),
11401149
Flags: flags,
11411150
MemberOf: memberOf,

0 commit comments

Comments
 (0)