allow secrets of default users in a different namespace
This commit is contained in:
		
							parent
							
								
									47dc0a9aee
								
							
						
					
					
						commit
						d65b5452e2
					
				|  | @ -394,6 +394,8 @@ spec: | |||
|                             type: boolean | ||||
|                           defaultRoles: | ||||
|                             type: boolean | ||||
|                     secretNamespace: | ||||
|                       type: string | ||||
|               replicaLoadBalancer:  # deprecated | ||||
|                 type: boolean | ||||
|               resources: | ||||
|  |  | |||
|  | @ -109,7 +109,11 @@ These parameters are grouped directly under  the `spec` key in the manifest. | |||
|   `SUPERUSER`, `REPLICATION`, `INHERIT`, `LOGIN`, `NOLOGIN`, `CREATEROLE`, | ||||
|   `CREATEDB`, `BYPASSURL`. A login user is created by default unless NOLOGIN is | ||||
|   specified, in which case the operator creates a role. One can specify empty | ||||
|   flags by providing a JSON empty array '*[]*'. Optional. | ||||
|   flags by providing a JSON empty array '*[]*'. If the config option | ||||
|   `enable_cross_namespace_secrets` is enabled you can specify the namespace in | ||||
|   the user name in the form `{namespace}.{username}` and the operator will | ||||
|   create the K8s secret in that namespace. The part after the first `.` is | ||||
|   considered to be the user name. Optional. | ||||
| 
 | ||||
| * **databases** | ||||
|   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. | |||
|   If you set the `all` special item, it will be mounted in all containers (postgres + sidecars). | ||||
|   Else you can set the list of target containers in which the additional volumes will be mounted (eg : postgres, telegraf) | ||||
| 
 | ||||
| ## Prepared Databases | ||||
| 
 | ||||
| The operator can create databases with default owner, reader and writer roles | ||||
| without the need to specifiy them under `users` or `databases` sections. Those | ||||
| parameters are grouped under the `preparedDatabases` top-level key. For more | ||||
| information, see [user docs](../user.md#prepared-databases-with-roles-and-default-privileges). | ||||
| 
 | ||||
| * **defaultUsers** | ||||
|   The operator will always create default `NOLOGIN` roles for defined prepared | ||||
|   databases, but if `defaultUsers` is set to `true` three additional `LOGIN` | ||||
|   roles with `_user` suffix will get created. Default is `false`. | ||||
| 
 | ||||
| * **extensions** | ||||
|   map of extensions with target database schema that the operator will install | ||||
|   in the database. Optional. | ||||
| 
 | ||||
| * **schemas** | ||||
|   map of schemas that the operator will create. Optional - if no schema is | ||||
|   listed, the operator will create a schema called `data`. Under each schema | ||||
|   key, it can be defined if `defaultRoles` (NOLOGIN) and `defaultUsers` (LOGIN) | ||||
|   roles shall be created that have schema-exclusive privileges. Both flags are | ||||
|   set to `false` by default. | ||||
| 
 | ||||
| * **secretNamespace** | ||||
|   for each default LOGIN role the operator will create a secret. You can | ||||
|   specify the namespace in which these secrets will get created, if | ||||
|   `enable_cross_namespace_secrets` is set to `true` in the config. Otherwise, | ||||
|   the cluster namespace is used. | ||||
| 
 | ||||
| ## Postgres parameters | ||||
| 
 | ||||
| Those parameters are grouped under the `postgresql` top-level key, which is | ||||
|  | @ -258,7 +291,9 @@ explanation of `ttl` and `loop_wait` parameters. | |||
| 
 | ||||
| Those parameters define [CPU and memory requests and limits](https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/) | ||||
| for the Postgres container. They are grouped under the `resources` top-level | ||||
| key with subgroups `requests` and `limits`. | ||||
| key with subgroups `requests` and `limits`. The whole section is optional, | ||||
| however if you specify a request or limit you have to define everything | ||||
| (unless you are not modifying the default CRD schema validation).  | ||||
| 
 | ||||
| ### Requests | ||||
| 
 | ||||
|  | @ -266,11 +301,11 @@ CPU and memory requests for the Postgres container. | |||
| 
 | ||||
| * **cpu** | ||||
|   CPU requests for the Postgres container. Optional, overrides the | ||||
|   `default_cpu_requests` operator configuration parameter. Optional. | ||||
|   `default_cpu_requests` operator configuration parameter. | ||||
| 
 | ||||
| * **memory** | ||||
|   memory requests for the Postgres container. Optional, overrides the | ||||
|   `default_memory_request` operator configuration parameter. Optional. | ||||
|   `default_memory_request` operator configuration parameter. | ||||
| 
 | ||||
| ### Limits | ||||
| 
 | ||||
|  | @ -278,11 +313,11 @@ CPU and memory limits for the Postgres container. | |||
| 
 | ||||
| * **cpu** | ||||
|   CPU limits for the Postgres container. Optional, overrides the | ||||
|   `default_cpu_limits` operator configuration parameter. Optional. | ||||
|   `default_cpu_limits` operator configuration parameter. | ||||
| 
 | ||||
| * **memory** | ||||
|   memory limits for the Postgres container. Optional, overrides the | ||||
|   `default_memory_limits` operator configuration parameter. Optional. | ||||
|   `default_memory_limits` operator configuration parameter. | ||||
| 
 | ||||
| ## Parameters defining how to clone the cluster from another one | ||||
| 
 | ||||
|  |  | |||
|  | @ -267,9 +267,7 @@ configuration they are grouped under the `kubernetes` key. | |||
| * **enable_cross_namespace_secrets** | ||||
|   To allow secrets in a different namespace other than the Postgres cluster | ||||
|   namespace. Once enabled, specify the namespace in the user name under the | ||||
|   `users` section in the form `{namespace}.{username}`. The operator will then | ||||
|   create the user secret in that namespace. The part after the first `.` is | ||||
|   considered to be the user name. The default is `false`. | ||||
|   `users` section in the form `{namespace}.{username}`. The default is `false`. | ||||
| 
 | ||||
| * **enable_init_containers** | ||||
|   global option to allow for creating init containers in the cluster manifest to | ||||
|  |  | |||
							
								
								
									
										24
									
								
								docs/user.md
								
								
								
								
							
							
						
						
									
										24
									
								
								docs/user.md
								
								
								
								
							|  | @ -139,9 +139,9 @@ secret, without ever sharing it outside of the cluster. | |||
| At the moment it is not possible to define membership of the manifest role in | ||||
| other roles. | ||||
| 
 | ||||
| To define the secrets for the users in a different namespace than that of the cluster, | ||||
| one can set `enable_cross_namespace_secret` and declare the namespace for the | ||||
| secrets in the manifest in the following manner, | ||||
| To define the secrets for the users in a different namespace than that of the | ||||
| cluster, one can set `enable_cross_namespace_secret` and declare the namespace | ||||
| for the secrets in the manifest in the following manner, | ||||
| 
 | ||||
| ```yaml | ||||
| spec: | ||||
|  | @ -150,7 +150,8 @@ spec: | |||
|    appspace.db_user: | ||||
|     - createdb | ||||
| ``` | ||||
| Here, anything before the first dot is taken as the namespace and the text after | ||||
| 
 | ||||
| Here, anything before the first dot is considered the namespace and the text after | ||||
| the first dot is the username. Also, the postgres roles of these usernames would | ||||
| be in the form of `namespace.username`. | ||||
| 
 | ||||
|  | @ -520,7 +521,7 @@ Then, the schemas are owned by the database owner, too. | |||
| 
 | ||||
| The roles described in the previous paragraph can be granted to LOGIN roles from | ||||
| the `users` section in the manifest. Optionally, the Postgres Operator can also | ||||
| create default LOGIN roles for the database an each schema individually. These | ||||
| create default LOGIN roles for the database and each schema individually. These | ||||
| roles will get the `_user` suffix and they inherit all rights from their NOLOGIN | ||||
| counterparts. Therefore, you cannot have `defaultRoles` set to `false` and enable | ||||
| `defaultUsers` at the same time. | ||||
|  | @ -550,6 +551,19 @@ Default access privileges are also defined for LOGIN roles on database and | |||
| schema creation. This means they are currently not set when `defaultUsers` | ||||
| (or `defaultRoles` for schemas) are enabled at a later point in time. | ||||
| 
 | ||||
| For all LOGIN roles the operator will create K8s secrets in the namespace | ||||
| specified in `secretNamespace`, if `enable_cross_namespace_secret` is set to | ||||
| `true` in the config. Otherwise, they are created in the same namespace like | ||||
| the Postgres cluster. | ||||
| 
 | ||||
| ```yaml | ||||
| spec: | ||||
|   preparedDatabases: | ||||
|     foo: | ||||
|       defaultUsers: true | ||||
|       secretNamespace: appspace | ||||
| ``` | ||||
| 
 | ||||
| ### Schema `search_path` for default roles | ||||
| 
 | ||||
| The schema [`search_path`](https://www.postgresql.org/docs/13/ddl-schemas.html#DDL-SCHEMAS-PATH) | ||||
|  |  | |||
|  | @ -390,6 +390,8 @@ spec: | |||
|                             type: boolean | ||||
|                           defaultRoles: | ||||
|                             type: boolean | ||||
|                     secretNamespace: | ||||
|                       type: string | ||||
|               replicaLoadBalancer:  # deprecated | ||||
|                 type: boolean | ||||
|               resources: | ||||
|  |  | |||
|  | @ -573,6 +573,9 @@ var PostgresCRDResourceValidation = apiextv1.CustomResourceValidation{ | |||
| 											}, | ||||
| 										}, | ||||
| 									}, | ||||
| 									"secretNamespace": { | ||||
| 										Type: "string", | ||||
| 									}, | ||||
| 								}, | ||||
| 							}, | ||||
| 						}, | ||||
|  |  | |||
|  | @ -95,6 +95,7 @@ type PreparedDatabase struct { | |||
| 	PreparedSchemas map[string]PreparedSchema `json:"schemas,omitempty"` | ||||
| 	DefaultUsers    bool                      `json:"defaultUsers,omitempty" defaults:"false"` | ||||
| 	Extensions      map[string]string         `json:"extensions,omitempty"` | ||||
| 	SecretNamespace string                    `json:"secretNamespace,omitempty"` | ||||
| } | ||||
| 
 | ||||
| // PreparedSchema describes elements to be bootstrapped per schema
 | ||||
|  |  | |||
|  | @ -1077,11 +1077,11 @@ func (c *Cluster) initPreparedDatabaseRoles() error { | |||
| 		} | ||||
| 
 | ||||
| 		// default roles per database
 | ||||
| 		if err := c.initDefaultRoles(defaultRoles, "admin", preparedDbName, searchPath.String()); err != nil { | ||||
| 		if err := c.initDefaultRoles(defaultRoles, "admin", preparedDbName, searchPath.String(), preparedDB.SecretNamespace); err != nil { | ||||
| 			return fmt.Errorf("could not initialize default roles for database %s: %v", preparedDbName, err) | ||||
| 		} | ||||
| 		if preparedDB.DefaultUsers { | ||||
| 			if err := c.initDefaultRoles(defaultUsers, "admin", preparedDbName, searchPath.String()); err != nil { | ||||
| 			if err := c.initDefaultRoles(defaultUsers, "admin", preparedDbName, searchPath.String(), preparedDB.SecretNamespace); err != nil { | ||||
| 				return fmt.Errorf("could not initialize default roles for database %s: %v", preparedDbName, err) | ||||
| 			} | ||||
| 		} | ||||
|  | @ -1092,14 +1092,14 @@ func (c *Cluster) initPreparedDatabaseRoles() error { | |||
| 				if err := c.initDefaultRoles(defaultRoles, | ||||
| 					preparedDbName+constants.OwnerRoleNameSuffix, | ||||
| 					preparedDbName+"_"+preparedSchemaName, | ||||
| 					constants.DefaultSearchPath+", "+preparedSchemaName); err != nil { | ||||
| 					constants.DefaultSearchPath+", "+preparedSchemaName, preparedDB.SecretNamespace); err != nil { | ||||
| 					return fmt.Errorf("could not initialize default roles for database schema %s: %v", preparedSchemaName, err) | ||||
| 				} | ||||
| 				if preparedSchema.DefaultUsers { | ||||
| 					if err := c.initDefaultRoles(defaultUsers, | ||||
| 						preparedDbName+constants.OwnerRoleNameSuffix, | ||||
| 						preparedDbName+"_"+preparedSchemaName, | ||||
| 						constants.DefaultSearchPath+", "+preparedSchemaName); err != nil { | ||||
| 						constants.DefaultSearchPath+", "+preparedSchemaName, preparedDB.SecretNamespace); err != nil { | ||||
| 						return fmt.Errorf("could not initialize default users for database schema %s: %v", preparedSchemaName, err) | ||||
| 					} | ||||
| 				} | ||||
|  | @ -1109,10 +1109,15 @@ func (c *Cluster) initPreparedDatabaseRoles() error { | |||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (c *Cluster) initDefaultRoles(defaultRoles map[string]string, admin, prefix string, searchPath string) error { | ||||
| func (c *Cluster) initDefaultRoles(defaultRoles map[string]string, admin, prefix, searchPath, secretNamespace string) error { | ||||
| 
 | ||||
| 	for defaultRole, inherits := range defaultRoles { | ||||
| 
 | ||||
| 		namespace := c.Namespace | ||||
| 		//if namespaced secrets are allowed
 | ||||
| 		if c.Config.OpConfig.EnableCrossNamespaceSecret && secretNamespace != "" { | ||||
| 			namespace = secretNamespace | ||||
| 		} | ||||
| 		roleName := prefix + defaultRole | ||||
| 
 | ||||
| 		flags := []string{constants.RoleFlagNoLogin} | ||||
|  | @ -1135,7 +1140,7 @@ func (c *Cluster) initDefaultRoles(defaultRoles map[string]string, admin, prefix | |||
| 		newRole := spec.PgUser{ | ||||
| 			Origin:     spec.RoleOriginBootstrap, | ||||
| 			Name:       roleName, | ||||
| 			Namespace:  c.Namespace, | ||||
| 			Namespace:  namespace, | ||||
| 			Password:   util.RandomPassword(constants.PasswordLength), | ||||
| 			Flags:      flags, | ||||
| 			MemberOf:   memberOf, | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue