StatefulSet fsGroup config option to allow non-root spilo (#531)
* StatefulSet fsGroup config option to allow non-root spilo * Allow Postgres CRD to overide SpiloFSGroup of the Operator. * Document FSGroup of a Pod cannot be changed after creation.
This commit is contained in:
parent
5a0e95ac45
commit
ec5b1d4d58
|
|
@ -31,6 +31,7 @@ configKubernetes:
|
||||||
# node_readiness_label: ""
|
# node_readiness_label: ""
|
||||||
# oauth_token_secret_name: postgresql-operator
|
# oauth_token_secret_name: postgresql-operator
|
||||||
# pod_environment_configmap: ""
|
# pod_environment_configmap: ""
|
||||||
|
# spilo_fsgroup: "103"
|
||||||
pod_management_policy: "ordered_ready"
|
pod_management_policy: "ordered_ready"
|
||||||
pdb_name_format: "postgres-{cluster}-pdb"
|
pdb_name_format: "postgres-{cluster}-pdb"
|
||||||
pod_role_label: spilo-role
|
pod_role_label: spilo-role
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,13 @@ These parameters are grouped directly under the `spec` key in the manifest.
|
||||||
custom docker image that overrides the **docker_image** operator parameter.
|
custom docker image that overrides the **docker_image** operator parameter.
|
||||||
It should be a [Spilo](https://github.com/zalando/spilo) image. Optional.
|
It should be a [Spilo](https://github.com/zalando/spilo) image. Optional.
|
||||||
|
|
||||||
|
* **spiloFSGroup**
|
||||||
|
the Persistent Volumes for the spilo pods in the StatefulSet will be owned
|
||||||
|
and writable by the group ID specified. This will override the **spilo_fsgroup**
|
||||||
|
operator parameter. This is required to run Spilo as a non-root process, but
|
||||||
|
requires a custom spilo image. Note the FSGroup of a Pod cannot be changed
|
||||||
|
without recreating a new Pod.
|
||||||
|
|
||||||
* **enableMasterLoadBalancer**
|
* **enableMasterLoadBalancer**
|
||||||
boolean flag to override the operator defaults (set by the
|
boolean flag to override the operator defaults (set by the
|
||||||
`enable_master_load_balancer` parameter) to define whether to enable the load
|
`enable_master_load_balancer` parameter) to define whether to enable the load
|
||||||
|
|
|
||||||
|
|
@ -228,6 +228,11 @@ configuration they are grouped under the `kubernetes` key.
|
||||||
that should be assigned to the Postgres pods. The priority class itself must
|
that should be assigned to the Postgres pods. The priority class itself must
|
||||||
be defined in advance. Default is empty (use the default priority class).
|
be defined in advance. Default is empty (use the default priority class).
|
||||||
|
|
||||||
|
* **spilo_fsgroup**
|
||||||
|
the Persistent Volumes for the spilo pods in the StatefulSet will be owned and writable by the group ID specified.
|
||||||
|
This is required to run Spilo as a non-root process, but requires a custom spilo image. Note the FSGroup of a Pod
|
||||||
|
cannot be changed without recreating a new Pod.
|
||||||
|
|
||||||
* **spilo_privileged**
|
* **spilo_privileged**
|
||||||
whether the Spilo container should run in privileged mode. Privileged mode is
|
whether the Spilo container should run in privileged mode. Privileged mode is
|
||||||
used for AWS volume resizing and not required if you don't need that
|
used for AWS volume resizing and not required if you don't need that
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ spec:
|
||||||
limits:
|
limits:
|
||||||
cpu: 300m
|
cpu: 300m
|
||||||
memory: 300Mi
|
memory: 300Mi
|
||||||
|
# spiloFSGroup: 103
|
||||||
patroni:
|
patroni:
|
||||||
initdb:
|
initdb:
|
||||||
encoding: "UTF8"
|
encoding: "UTF8"
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ configuration:
|
||||||
cluster_domain: cluster.local
|
cluster_domain: cluster.local
|
||||||
oauth_token_secret_name: postgresql-operator
|
oauth_token_secret_name: postgresql-operator
|
||||||
pod_role_label: spilo-role
|
pod_role_label: spilo-role
|
||||||
|
# spilo_fsgroup: 103
|
||||||
spilo_privileged: false
|
spilo_privileged: false
|
||||||
cluster_labels:
|
cluster_labels:
|
||||||
application: spilo
|
application: spilo
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ type KubernetesMetaConfiguration struct {
|
||||||
PodServiceAccountRoleBindingDefinition string `json:"pod_service_account_role_binding_definition,omitempty"`
|
PodServiceAccountRoleBindingDefinition string `json:"pod_service_account_role_binding_definition,omitempty"`
|
||||||
PodTerminateGracePeriod Duration `json:"pod_terminate_grace_period,omitempty"`
|
PodTerminateGracePeriod Duration `json:"pod_terminate_grace_period,omitempty"`
|
||||||
SpiloPrivileged bool `json:"spilo_privileged,omitemty"`
|
SpiloPrivileged bool `json:"spilo_privileged,omitemty"`
|
||||||
|
SpiloFSGroup *int64 `json:"spilo_fsgroup,omitempty"`
|
||||||
WatchedNamespace string `json:"watched_namespace,omitempty"`
|
WatchedNamespace string `json:"watched_namespace,omitempty"`
|
||||||
PDBNameFormat config.StringTemplate `json:"pdb_name_format,omitempty"`
|
PDBNameFormat config.StringTemplate `json:"pdb_name_format,omitempty"`
|
||||||
SecretNameTemplate config.StringTemplate `json:"secret_name_template,omitempty"`
|
SecretNameTemplate config.StringTemplate `json:"secret_name_template,omitempty"`
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,8 @@ type PostgresSpec struct {
|
||||||
TeamID string `json:"teamId"`
|
TeamID string `json:"teamId"`
|
||||||
DockerImage string `json:"dockerImage,omitempty"`
|
DockerImage string `json:"dockerImage,omitempty"`
|
||||||
|
|
||||||
|
SpiloFSGroup *int64 `json:"spiloFSGroup,omitempty"`
|
||||||
|
|
||||||
// vars that enable load balancers are pointers because it is important to know if any of them is omitted from the Postgres manifest
|
// vars that enable load balancers are pointers because it is important to know if any of them is omitted from the Postgres manifest
|
||||||
// in that case the var evaluates to nil and the value is taken from the operator config
|
// in that case the var evaluates to nil and the value is taken from the operator config
|
||||||
EnableMasterLoadBalancer *bool `json:"enableMasterLoadBalancer,omitempty"`
|
EnableMasterLoadBalancer *bool `json:"enableMasterLoadBalancer,omitempty"`
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,11 @@ func (in *CloneDescription) DeepCopy() *CloneDescription {
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *KubernetesMetaConfiguration) DeepCopyInto(out *KubernetesMetaConfiguration) {
|
func (in *KubernetesMetaConfiguration) DeepCopyInto(out *KubernetesMetaConfiguration) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
if in.SpiloFSGroup != nil {
|
||||||
|
in, out := &in.SpiloFSGroup, &out.SpiloFSGroup
|
||||||
|
*out = new(int64)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
out.OAuthTokenSecretName = in.OAuthTokenSecretName
|
out.OAuthTokenSecretName = in.OAuthTokenSecretName
|
||||||
out.InfrastructureRolesSecretName = in.InfrastructureRolesSecretName
|
out.InfrastructureRolesSecretName = in.InfrastructureRolesSecretName
|
||||||
if in.ClusterLabels != nil {
|
if in.ClusterLabels != nil {
|
||||||
|
|
@ -402,6 +407,11 @@ func (in *PostgresSpec) DeepCopyInto(out *PostgresSpec) {
|
||||||
out.Volume = in.Volume
|
out.Volume = in.Volume
|
||||||
in.Patroni.DeepCopyInto(&out.Patroni)
|
in.Patroni.DeepCopyInto(&out.Patroni)
|
||||||
out.Resources = in.Resources
|
out.Resources = in.Resources
|
||||||
|
if in.SpiloFSGroup != nil {
|
||||||
|
in, out := &in.SpiloFSGroup, &out.SpiloFSGroup
|
||||||
|
*out = new(int64)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
if in.EnableMasterLoadBalancer != nil {
|
if in.EnableMasterLoadBalancer != nil {
|
||||||
in, out := &in.EnableMasterLoadBalancer, &out.EnableMasterLoadBalancer
|
in, out := &in.EnableMasterLoadBalancer, &out.EnableMasterLoadBalancer
|
||||||
*out = new(bool)
|
*out = new(bool)
|
||||||
|
|
|
||||||
|
|
@ -432,6 +432,7 @@ func generatePodTemplate(
|
||||||
initContainers []v1.Container,
|
initContainers []v1.Container,
|
||||||
sidecarContainers []v1.Container,
|
sidecarContainers []v1.Container,
|
||||||
tolerationsSpec *[]v1.Toleration,
|
tolerationsSpec *[]v1.Toleration,
|
||||||
|
spiloFSGroup *int64,
|
||||||
nodeAffinity *v1.Affinity,
|
nodeAffinity *v1.Affinity,
|
||||||
terminateGracePeriod int64,
|
terminateGracePeriod int64,
|
||||||
podServiceAccountName string,
|
podServiceAccountName string,
|
||||||
|
|
@ -445,6 +446,11 @@ func generatePodTemplate(
|
||||||
terminateGracePeriodSeconds := terminateGracePeriod
|
terminateGracePeriodSeconds := terminateGracePeriod
|
||||||
containers := []v1.Container{*spiloContainer}
|
containers := []v1.Container{*spiloContainer}
|
||||||
containers = append(containers, sidecarContainers...)
|
containers = append(containers, sidecarContainers...)
|
||||||
|
securityContext := v1.PodSecurityContext{}
|
||||||
|
|
||||||
|
if spiloFSGroup != nil {
|
||||||
|
securityContext.FSGroup = spiloFSGroup
|
||||||
|
}
|
||||||
|
|
||||||
podSpec := v1.PodSpec{
|
podSpec := v1.PodSpec{
|
||||||
ServiceAccountName: podServiceAccountName,
|
ServiceAccountName: podServiceAccountName,
|
||||||
|
|
@ -452,6 +458,7 @@ func generatePodTemplate(
|
||||||
Containers: containers,
|
Containers: containers,
|
||||||
InitContainers: initContainers,
|
InitContainers: initContainers,
|
||||||
Tolerations: *tolerationsSpec,
|
Tolerations: *tolerationsSpec,
|
||||||
|
SecurityContext: &securityContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
if shmVolume {
|
if shmVolume {
|
||||||
|
|
@ -831,6 +838,12 @@ func (c *Cluster) generateStatefulSet(spec *acidv1.PostgresSpec) (*v1beta1.State
|
||||||
tolerationSpec := tolerations(&spec.Tolerations, c.OpConfig.PodToleration)
|
tolerationSpec := tolerations(&spec.Tolerations, c.OpConfig.PodToleration)
|
||||||
effectivePodPriorityClassName := util.Coalesce(spec.PodPriorityClassName, c.OpConfig.PodPriorityClassName)
|
effectivePodPriorityClassName := util.Coalesce(spec.PodPriorityClassName, c.OpConfig.PodPriorityClassName)
|
||||||
|
|
||||||
|
// determine the FSGroup for the spilo pod
|
||||||
|
effectiveFSGroup := c.OpConfig.Resources.SpiloFSGroup
|
||||||
|
if spec.SpiloFSGroup != nil {
|
||||||
|
effectiveFSGroup = spec.SpiloFSGroup
|
||||||
|
}
|
||||||
|
|
||||||
// generate pod template for the statefulset, based on the spilo container and sidecars
|
// generate pod template for the statefulset, based on the spilo container and sidecars
|
||||||
if podTemplate, err = generatePodTemplate(
|
if podTemplate, err = generatePodTemplate(
|
||||||
c.Namespace,
|
c.Namespace,
|
||||||
|
|
@ -839,6 +852,7 @@ func (c *Cluster) generateStatefulSet(spec *acidv1.PostgresSpec) (*v1beta1.State
|
||||||
spec.InitContainers,
|
spec.InitContainers,
|
||||||
sidecarContainers,
|
sidecarContainers,
|
||||||
&tolerationSpec,
|
&tolerationSpec,
|
||||||
|
effectiveFSGroup,
|
||||||
nodeAffinity(c.OpConfig.NodeReadinessLabel),
|
nodeAffinity(c.OpConfig.NodeReadinessLabel),
|
||||||
int64(c.OpConfig.PodTerminateGracePeriod.Seconds()),
|
int64(c.OpConfig.PodTerminateGracePeriod.Seconds()),
|
||||||
c.OpConfig.PodServiceAccountName,
|
c.OpConfig.PodServiceAccountName,
|
||||||
|
|
@ -1340,6 +1354,7 @@ func (c *Cluster) generateLogicalBackupJob() (*batchv1beta1.CronJob, error) {
|
||||||
[]v1.Container{},
|
[]v1.Container{},
|
||||||
[]v1.Container{},
|
[]v1.Container{},
|
||||||
&[]v1.Toleration{},
|
&[]v1.Toleration{},
|
||||||
|
nil,
|
||||||
nodeAffinity(c.OpConfig.NodeReadinessLabel),
|
nodeAffinity(c.OpConfig.NodeReadinessLabel),
|
||||||
int64(c.OpConfig.PodTerminateGracePeriod.Seconds()),
|
int64(c.OpConfig.PodTerminateGracePeriod.Seconds()),
|
||||||
c.OpConfig.PodServiceAccountName,
|
c.OpConfig.PodServiceAccountName,
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur
|
||||||
result.PodEnvironmentConfigMap = fromCRD.Kubernetes.PodEnvironmentConfigMap
|
result.PodEnvironmentConfigMap = fromCRD.Kubernetes.PodEnvironmentConfigMap
|
||||||
result.PodTerminateGracePeriod = time.Duration(fromCRD.Kubernetes.PodTerminateGracePeriod)
|
result.PodTerminateGracePeriod = time.Duration(fromCRD.Kubernetes.PodTerminateGracePeriod)
|
||||||
result.SpiloPrivileged = fromCRD.Kubernetes.SpiloPrivileged
|
result.SpiloPrivileged = fromCRD.Kubernetes.SpiloPrivileged
|
||||||
|
result.SpiloFSGroup = fromCRD.Kubernetes.SpiloFSGroup
|
||||||
result.ClusterDomain = fromCRD.Kubernetes.ClusterDomain
|
result.ClusterDomain = fromCRD.Kubernetes.ClusterDomain
|
||||||
result.WatchedNamespace = fromCRD.Kubernetes.WatchedNamespace
|
result.WatchedNamespace = fromCRD.Kubernetes.WatchedNamespace
|
||||||
result.PDBNameFormat = fromCRD.Kubernetes.PDBNameFormat
|
result.PDBNameFormat = fromCRD.Kubernetes.PDBNameFormat
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ type Resources struct {
|
||||||
PodLabelWaitTimeout time.Duration `name:"pod_label_wait_timeout" default:"10m"`
|
PodLabelWaitTimeout time.Duration `name:"pod_label_wait_timeout" default:"10m"`
|
||||||
PodDeletionWaitTimeout time.Duration `name:"pod_deletion_wait_timeout" default:"10m"`
|
PodDeletionWaitTimeout time.Duration `name:"pod_deletion_wait_timeout" default:"10m"`
|
||||||
PodTerminateGracePeriod time.Duration `name:"pod_terminate_grace_period" default:"5m"`
|
PodTerminateGracePeriod time.Duration `name:"pod_terminate_grace_period" default:"5m"`
|
||||||
|
SpiloFSGroup *int64 `name:"spilo_fsgroup"`
|
||||||
PodPriorityClassName string `name:"pod_priority_class_name"`
|
PodPriorityClassName string `name:"pod_priority_class_name"`
|
||||||
ClusterDomain string `name:"cluster_domain" default:"cluster.local"`
|
ClusterDomain string `name:"cluster_domain" default:"cluster.local"`
|
||||||
SpiloPrivileged bool `name:"spilo_privileged" default:"false"`
|
SpiloPrivileged bool `name:"spilo_privileged" default:"false"`
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue