Add toggle to allow namespaced secrets

This commit is contained in:
Rafia Sabih 2021-06-06 13:03:31 +02:00
parent f0472fd443
commit a992494fbf
8 changed files with 64 additions and 46 deletions

View File

@ -515,6 +515,8 @@ spec:
type: integer
useLoadBalancer: # deprecated
type: boolean
enableNamespacedSecret:
type: boolean
users:
type: object
additionalProperties:

View File

@ -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

View File

@ -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):

View File

@ -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

View File

@ -730,6 +730,9 @@ var PostgresCRDResourceValidation = apiextv1.CustomResourceValidation{
Type: "boolean",
Description: "Deprecated",
},
"enableNamespacedSecret": {
Type: "boolean",
},
"users": {
Type: "object",
AdditionalProperties: &apiextv1.JSONSchemaPropsOrBool{

View File

@ -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"`

View File

@ -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)

View File

@ -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)
}
}
}