Add toggle to allow namespaced secrets
This commit is contained in:
		
							parent
							
								
									f0472fd443
								
							
						
					
					
						commit
						a992494fbf
					
				|  | @ -515,6 +515,8 @@ spec: | |||
|                       type: integer | ||||
|               useLoadBalancer:  # deprecated | ||||
|                 type: boolean | ||||
|               enableNamespacedSecret: | ||||
|                 type: boolean | ||||
|               users: | ||||
|                 type: object | ||||
|                 additionalProperties: | ||||
|  |  | |||
|  | @ -197,6 +197,16 @@ class K8s: | |||
|                 pod_phase = pods[0].status.phase | ||||
|             time.sleep(self.RETRY_TIMEOUT_SEC) | ||||
| 
 | ||||
|     def wait_for_namespace_creation(self, namespace='default'): | ||||
|         ns_found = False | ||||
|         while ns_found != True: | ||||
|             ns = self.api.core_v1.list_namespace().items | ||||
|             for n in ns: | ||||
|                 if n.metadata.name == namespace: | ||||
|                     ns_found = True | ||||
|                     break | ||||
|             time.sleep(self.RETRY_TIMEOUT_SEC) | ||||
| 
 | ||||
|     def get_logical_backup_job(self, namespace='default'): | ||||
|         return self.api.batch_v1_beta1.list_namespaced_cron_job(namespace, label_selector="application=spilo") | ||||
| 
 | ||||
|  | @ -362,17 +372,6 @@ class K8sBase: | |||
| 
 | ||||
|             time.sleep(self.RETRY_TIMEOUT_SEC) | ||||
| 
 | ||||
|     def wait_for_namespace_creation(self, namespace='default'): | ||||
|         ns_found = False | ||||
|         while ns_found != True: | ||||
|             ns = self.api.core_v1.list_namespaces() | ||||
|             for n in ns: | ||||
|                 if n == "appspace": | ||||
|                     ns_found = True | ||||
|                     break | ||||
| 
 | ||||
|             time.sleep(self.RETRY_TIMEOUT_SEC) | ||||
| 
 | ||||
|     def get_service_type(self, svc_labels, namespace='default'): | ||||
|         svc_type = '' | ||||
|         svcs = self.api.core_v1.list_namespaced_service(namespace, label_selector=svc_labels, limit=1).items | ||||
|  |  | |||
|  | @ -314,7 +314,7 @@ class EndToEndTestCase(unittest.TestCase): | |||
|         'postgresqls', 'acid-minimal-cluster', | ||||
|         { | ||||
|             'spec': { | ||||
|                 'enableConnectionPooler': False | ||||
|                 c | ||||
|             } | ||||
|         }) | ||||
| 
 | ||||
|  | @ -592,23 +592,24 @@ class EndToEndTestCase(unittest.TestCase): | |||
|             Test secrets in different namespace | ||||
|         ''' | ||||
|         app_namespace = "appspace" | ||||
|         k8s = self.k8s | ||||
|         # k8s = self.k8s | ||||
|         v1_appnamespace = client.V1Namespace(metadata=client.V1ObjectMeta(name=app_namespace)) | ||||
|         k8s.api.core_v1.create_namespace(v1_appnamespace) | ||||
|         k8s.wait_for_namespace_creation(app_namespace) | ||||
|         self.k8s.api.core_v1.create_namespace(v1_appnamespace) | ||||
|         self.k8s.wait_for_namespace_creation(app_namespace) | ||||
| 
 | ||||
|         k8s.api.custom_objects_api.patch_namespaced_custom_object( | ||||
|         self.k8s.api.custom_objects_api.patch_namespaced_custom_object( | ||||
|             'acid.zalan.do', 'v1', 'default', | ||||
|             'postgresqls', 'acid-minimal-cluster', | ||||
|             { | ||||
|                 'spec': { | ||||
|                     'enableNamespacedSecret': True, | ||||
|                     'users':{ | ||||
|                         'appspace.db_user': [], | ||||
|                     } | ||||
|                 } | ||||
|             }) | ||||
|         self.eventuallyEqual(lambda: k8s.count_secrets_with_label("cluster_name=acid-minimal-cluster,application=spilo", app_namespace), | ||||
|                              1, "Secret not created for user in namespace", app_namespace) | ||||
|         self.eventuallyEqual(lambda: self.k8s.count_secrets_with_label("cluster_name=acid-minimal-cluster,application=spilo", app_namespace), | ||||
|                              1, "Secret not created for user in namespace") | ||||
| 
 | ||||
|     @timeout_decorator.timeout(TEST_TIMEOUT_SEC) | ||||
|     def test_lazy_spilo_upgrade(self): | ||||
|  |  | |||
|  | @ -12,7 +12,10 @@ spec: | |||
|   dockerImage: registry.opensource.zalan.do/acid/spilo-13:2.0-p7 | ||||
|   teamId: "acid" | ||||
|   numberOfInstances: 2 | ||||
|   enableNamespacedSecret: True | ||||
|   users:  # Application/Robot users | ||||
|     appspace.db_user: [] | ||||
|     appspace.db_user.with.dots: [] | ||||
|     zalando: | ||||
|     - superuser | ||||
|     - createdb | ||||
|  |  | |||
|  | @ -730,6 +730,9 @@ var PostgresCRDResourceValidation = apiextv1.CustomResourceValidation{ | |||
| 						Type:        "boolean", | ||||
| 						Description: "Deprecated", | ||||
| 					}, | ||||
| 					"enableNamespacedSecret": { | ||||
| 						Type: "boolean", | ||||
| 					}, | ||||
| 					"users": { | ||||
| 						Type: "object", | ||||
| 						AdditionalProperties: &apiextv1.JSONSchemaPropsOrBool{ | ||||
|  |  | |||
|  | @ -53,27 +53,28 @@ type PostgresSpec struct { | |||
| 	// load balancers' source ranges are the same for master and replica services
 | ||||
| 	AllowedSourceRanges []string `json:"allowedSourceRanges"` | ||||
| 
 | ||||
| 	NumberOfInstances     int32                       `json:"numberOfInstances"` | ||||
| 	Users                 map[string]UserFlags        `json:"users,omitempty"` | ||||
| 	MaintenanceWindows    []MaintenanceWindow         `json:"maintenanceWindows,omitempty"` | ||||
| 	Clone                 *CloneDescription           `json:"clone,omitempty"` | ||||
| 	ClusterName           string                      `json:"-"` | ||||
| 	Databases             map[string]string           `json:"databases,omitempty"` | ||||
| 	PreparedDatabases     map[string]PreparedDatabase `json:"preparedDatabases,omitempty"` | ||||
| 	SchedulerName         *string                     `json:"schedulerName,omitempty"` | ||||
| 	NodeAffinity          *v1.NodeAffinity            `json:"nodeAffinity,omitempty"` | ||||
| 	Tolerations           []v1.Toleration             `json:"tolerations,omitempty"` | ||||
| 	Sidecars              []Sidecar                   `json:"sidecars,omitempty"` | ||||
| 	InitContainers        []v1.Container              `json:"initContainers,omitempty"` | ||||
| 	PodPriorityClassName  string                      `json:"podPriorityClassName,omitempty"` | ||||
| 	ShmVolume             *bool                       `json:"enableShmVolume,omitempty"` | ||||
| 	EnableLogicalBackup   bool                        `json:"enableLogicalBackup,omitempty"` | ||||
| 	LogicalBackupSchedule string                      `json:"logicalBackupSchedule,omitempty"` | ||||
| 	StandbyCluster        *StandbyDescription         `json:"standby,omitempty"` | ||||
| 	PodAnnotations        map[string]string           `json:"podAnnotations,omitempty"` | ||||
| 	ServiceAnnotations    map[string]string           `json:"serviceAnnotations,omitempty"` | ||||
| 	TLS                   *TLSDescription             `json:"tls,omitempty"` | ||||
| 	AdditionalVolumes     []AdditionalVolume          `json:"additionalVolumes,omitempty"` | ||||
| 	NumberOfInstances      int32                       `json:"numberOfInstances"` | ||||
| 	EnableNamespacedSecret *bool                       `json:"enableNamespacedSecret,omitempty"` | ||||
| 	Users                  map[string]UserFlags        `json:"users,omitempty"` | ||||
| 	MaintenanceWindows     []MaintenanceWindow         `json:"maintenanceWindows,omitempty"` | ||||
| 	Clone                  *CloneDescription           `json:"clone,omitempty"` | ||||
| 	ClusterName            string                      `json:"-"` | ||||
| 	Databases              map[string]string           `json:"databases,omitempty"` | ||||
| 	PreparedDatabases      map[string]PreparedDatabase `json:"preparedDatabases,omitempty"` | ||||
| 	SchedulerName          *string                     `json:"schedulerName,omitempty"` | ||||
| 	NodeAffinity           *v1.NodeAffinity            `json:"nodeAffinity,omitempty"` | ||||
| 	Tolerations            []v1.Toleration             `json:"tolerations,omitempty"` | ||||
| 	Sidecars               []Sidecar                   `json:"sidecars,omitempty"` | ||||
| 	InitContainers         []v1.Container              `json:"initContainers,omitempty"` | ||||
| 	PodPriorityClassName   string                      `json:"podPriorityClassName,omitempty"` | ||||
| 	ShmVolume              *bool                       `json:"enableShmVolume,omitempty"` | ||||
| 	EnableLogicalBackup    bool                        `json:"enableLogicalBackup,omitempty"` | ||||
| 	LogicalBackupSchedule  string                      `json:"logicalBackupSchedule,omitempty"` | ||||
| 	StandbyCluster         *StandbyDescription         `json:"standby,omitempty"` | ||||
| 	PodAnnotations         map[string]string           `json:"podAnnotations,omitempty"` | ||||
| 	ServiceAnnotations     map[string]string           `json:"serviceAnnotations,omitempty"` | ||||
| 	TLS                    *TLSDescription             `json:"tls,omitempty"` | ||||
| 	AdditionalVolumes      []AdditionalVolume          `json:"additionalVolumes,omitempty"` | ||||
| 
 | ||||
| 	// deprecated json tags
 | ||||
| 	InitContainersOld       []v1.Container `json:"init_containers,omitempty"` | ||||
|  |  | |||
|  | @ -41,7 +41,7 @@ import ( | |||
| var ( | ||||
| 	alphaNumericRegexp    = regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9]*$") | ||||
| 	databaseNameRegexp    = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_]*$") | ||||
| 	userRegexp            = regexp.MustCompile(`^[a-z0-9]+\.?[-_a-z0-9]+[a-z0-9]$`) | ||||
| 	userRegexp            = regexp.MustCompile(`^[a-z0-9]([-_a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-_a-z0-9]*[a-z0-9])?)*$`) | ||||
| 	patroniObjectSuffixes = []string{"config", "failover", "sync"} | ||||
| ) | ||||
| 
 | ||||
|  | @ -1111,10 +1111,13 @@ func (c *Cluster) initRobotUsers() error { | |||
| 		} | ||||
| 		namespace := c.Namespace | ||||
| 
 | ||||
| 		//more than one dot in the username is reported invalid by regexp
 | ||||
| 		if strings.Contains(username, ".") { | ||||
| 			splits := strings.Split(username, ".") | ||||
| 			namespace = splits[0] | ||||
| 		//if namespaced secrets are allowed
 | ||||
| 		if c.Postgresql.Spec.EnableNamespacedSecret != nil && | ||||
| 			*c.Postgresql.Spec.EnableNamespacedSecret { | ||||
| 			if strings.Contains(username, ".") { | ||||
| 				splits := strings.Split(username, ".") | ||||
| 				namespace = splits[0] | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		flags, err := normalizeUserFlags(userFlags) | ||||
|  |  | |||
|  | @ -870,6 +870,7 @@ func TestCrossNamespacedSecrets(t *testing.T) { | |||
| 			Volume: acidv1.Volume{ | ||||
| 				Size: "1Gi", | ||||
| 			}, | ||||
| 			EnableNamespacedSecret: boolToPointer(true), | ||||
| 			Users: map[string]acidv1.UserFlags{ | ||||
| 				"appspace.db_user": {}, | ||||
| 				"db_user":          {}, | ||||
|  | @ -920,11 +921,16 @@ func TestCrossNamespacedSecrets(t *testing.T) { | |||
| func TestValidUsernames(t *testing.T) { | ||||
| 	testName := "test username validity" | ||||
| 
 | ||||
| 	invalidUsernames := []string{"_", ".", ".user", "appspace.", "appspace.user.extra", "user_", "_user", "-user", "user-", ",", "-", ",user", "user,", "namespace,user"} | ||||
| 
 | ||||
| 	invalidUsernames := []string{"_", ".", ".user", "appspace.", "user_", "_user", "-user", "user-", ",", "-", ",user", "user,", "namespace,user"} | ||||
| 	validUsernames := []string{"user", "appspace.user", "appspace.dot.user", "user_name", "app_space.user_name"} | ||||
| 	for _, username := range invalidUsernames { | ||||
| 		if isValidUsername(username) { | ||||
| 			t.Errorf("%s Invalid username is allowed: %s", testName, username) | ||||
| 		} | ||||
| 	} | ||||
| 	for _, username := range validUsernames { | ||||
| 		if !isValidUsername(username) { | ||||
| 			t.Errorf("%s Valid username is not allowed: %s", testName, username) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue