refactor pooler tls support and set pooler pod security context (#2255)

* bump pooler image
* set pooler pod security context
* use hard coded RunAsUser 100 and RunAsGroup 101 for pooler pod
* unify generation of TLS secret mounts
* extend documentation on tls support
* add unit test for testing TLS support for pooler
* add e2e test for tls support
This commit is contained in:
Felix Kunde
2023-04-17 11:38:56 +02:00
committed by GitHub
parent 87b7ac0806
commit 0e7beb5fe5
16 changed files with 369 additions and 120 deletions
+47 -59
View File
@@ -3,7 +3,6 @@ package cluster
import (
"context"
"fmt"
"path/filepath"
"strings"
"time"
@@ -25,6 +24,9 @@ import (
"github.com/zalando/postgres-operator/pkg/util/retryutil"
)
var poolerRunAsUser = int64(100)
var poolerRunAsGroup = int64(101)
// ConnectionPoolerObjects K8s objects that are belong to connection pooler
type ConnectionPoolerObjects struct {
Deployment *appsv1.Deployment
@@ -261,6 +263,10 @@ func (c *Cluster) generateConnectionPoolerPodTemplate(role PostgresRole) (
makeDefaultConnectionPoolerResources(&c.OpConfig),
connectionPoolerContainer)
if err != nil {
return nil, fmt.Errorf("could not generate resource requirements: %v", err)
}
effectiveDockerImage := util.Coalesce(
connectionPoolerSpec.DockerImage,
c.OpConfig.ConnectionPooler.Image)
@@ -269,10 +275,6 @@ func (c *Cluster) generateConnectionPoolerPodTemplate(role PostgresRole) (
connectionPoolerSpec.Schema,
c.OpConfig.ConnectionPooler.Schema)
if err != nil {
return nil, fmt.Errorf("could not generate resource requirements: %v", err)
}
secretSelector := func(key string) *v1.SecretKeySelector {
effectiveUser := util.Coalesce(
connectionPoolerSpec.User,
@@ -344,62 +346,53 @@ func (c *Cluster) generateConnectionPoolerPodTemplate(role PostgresRole) (
// 2. Reference the secret in a volume
// 3. Mount the volume to the container at /tls
var poolerVolumes []v1.Volume
var volumeMounts []v1.VolumeMount
if spec.TLS != nil && spec.TLS.SecretName != "" {
// Env vars
crtFile := spec.TLS.CertificateFile
keyFile := spec.TLS.PrivateKeyFile
caFile := spec.TLS.CAFile
mountPath := "/tls"
mountPathCA := mountPath
getPoolerTLSEnv := func(k string) string {
keyName := ""
switch k {
case "tls.crt":
keyName = "CONNECTION_POOLER_CLIENT_TLS_CRT"
case "tls.key":
keyName = "CONNECTION_POOLER_CLIENT_TLS_KEY"
case "tls.ca":
keyName = "CONNECTION_POOLER_CLIENT_CA_FILE"
default:
panic(fmt.Sprintf("TLS env key for pooler unknown %s", k))
}
if crtFile == "" {
crtFile = "tls.crt"
return keyName
}
if keyFile == "" {
keyFile = "tls.key"
tlsEnv, tlsVolumes := generateTlsMounts(spec, getPoolerTLSEnv)
envVars = append(envVars, tlsEnv...)
for _, vol := range tlsVolumes {
poolerVolumes = append(poolerVolumes, v1.Volume{
Name: vol.Name,
VolumeSource: vol.VolumeSource,
})
volumeMounts = append(volumeMounts, v1.VolumeMount{
Name: vol.Name,
MountPath: vol.MountPath,
})
}
if caFile == "" {
caFile = "ca.crt"
}
if spec.TLS.CASecretName != "" {
mountPathCA = mountPath + "ca"
}
envVars = append(
envVars,
v1.EnvVar{
Name: "CONNECTION_POOLER_CLIENT_TLS_CRT", Value: filepath.Join(mountPath, crtFile),
},
v1.EnvVar{
Name: "CONNECTION_POOLER_CLIENT_TLS_KEY", Value: filepath.Join(mountPath, keyFile),
},
v1.EnvVar{
Name: "CONNECTION_POOLER_CLIENT_CA_FILE", Value: filepath.Join(mountPathCA, caFile),
},
)
// Volume
mode := int32(0640)
volume := v1.Volume{
Name: "tls",
VolumeSource: v1.VolumeSource{
Secret: &v1.SecretVolumeSource{
SecretName: spec.TLS.SecretName,
DefaultMode: &mode,
},
},
}
poolerVolumes = append(poolerVolumes, volume)
// Mount
poolerContainer.VolumeMounts = []v1.VolumeMount{{
Name: "tls",
MountPath: "/tls",
}}
}
poolerContainer.Env = envVars
poolerContainer.VolumeMounts = volumeMounts
tolerationsSpec := tolerations(&spec.Tolerations, c.OpConfig.PodToleration)
securityContext := v1.PodSecurityContext{}
// determine the User, Group and FSGroup for the pooler pod
securityContext.RunAsUser = &poolerRunAsUser
securityContext.RunAsGroup = &poolerRunAsGroup
effectiveFSGroup := c.OpConfig.Resources.SpiloFSGroup
if spec.SpiloFSGroup != nil {
effectiveFSGroup = spec.SpiloFSGroup
}
if effectiveFSGroup != nil {
securityContext.FSGroup = effectiveFSGroup
}
podTemplate := &v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
@@ -412,15 +405,10 @@ func (c *Cluster) generateConnectionPoolerPodTemplate(role PostgresRole) (
Containers: []v1.Container{poolerContainer},
Tolerations: tolerationsSpec,
Volumes: poolerVolumes,
SecurityContext: &securityContext,
},
}
if spec.TLS != nil && spec.TLS.SecretName != "" && spec.SpiloFSGroup != nil {
podTemplate.Spec.SecurityContext = &v1.PodSecurityContext{
FSGroup: spec.SpiloFSGroup,
}
}
nodeAffinity := c.nodeAffinity(c.OpConfig.NodeReadinessLabel, spec.NodeAffinity)
if c.OpConfig.EnablePodAntiAffinity {
labelsSet := labels.Set(c.connectionPoolerLabels(role, false).MatchLabels)