From 5b35ba94df342442f764981ad861ff19f9548247 Mon Sep 17 00:00:00 2001 From: Dennis Lapchenko Date: Tue, 8 Aug 2023 14:53:23 +0300 Subject: [PATCH] feat: Add pod_service_account_annotations --- .../crds/operatorconfigurations.yaml | 4 +++ .../templates/operatorconfiguration.yaml | 4 +++ charts/postgres-operator/values.yaml | 1 + docs/administrator.md | 31 ++++++++++++------- manifests/configmap.yaml | 1 + manifests/operatorconfiguration.crd.yaml | 4 +++ ...gresql-operator-default-configuration.yaml | 3 ++ .../v1/operator_configuration_type.go | 3 +- .../acid.zalan.do/v1/zz_generated.deepcopy.go | 7 +++++ pkg/controller/controller.go | 1 + pkg/controller/operator_config.go | 1 + pkg/util/config/config.go | 15 ++++----- 12 files changed, 56 insertions(+), 19 deletions(-) diff --git a/charts/postgres-operator/crds/operatorconfigurations.yaml b/charts/postgres-operator/crds/operatorconfigurations.yaml index 46d135fa5..2858bfd4e 100644 --- a/charts/postgres-operator/crds/operatorconfigurations.yaml +++ b/charts/postgres-operator/crds/operatorconfigurations.yaml @@ -305,6 +305,10 @@ spec: pod_service_account_name: type: string default: "postgres-pod" + pod_service_account_annotations: + type: object + additionalProperties: + type: string pod_service_account_role_binding_definition: type: string default: "" diff --git a/charts/postgres-operator/templates/operatorconfiguration.yaml b/charts/postgres-operator/templates/operatorconfiguration.yaml index 6d3b0eb83..5e79de656 100644 --- a/charts/postgres-operator/templates/operatorconfiguration.yaml +++ b/charts/postgres-operator/templates/operatorconfiguration.yaml @@ -20,6 +20,10 @@ configuration: pod_priority_class_name: {{ .Values.podPriorityClassName }} {{- end }} pod_service_account_name: {{ include "postgres-pod.serviceAccountName" . }} + {{- if .Values.podServiceAccount.annotations }} + pod_service_account_annotations: + {{ toYaml .Values.podServiceAccount.annotations | indent 6 }} + {{- end }} oauth_token_secret_name: {{ template "postgres-operator.fullname" . }} {{ tpl (toYaml .Values.configKubernetes) . | indent 4 }} postgres_pod_resources: diff --git a/charts/postgres-operator/values.yaml b/charts/postgres-operator/values.yaml index 05933a7a8..8be0a2873 100644 --- a/charts/postgres-operator/values.yaml +++ b/charts/postgres-operator/values.yaml @@ -453,6 +453,7 @@ podServiceAccount: # The name of the ServiceAccount to be used by postgres cluster pods # If not set a name is generated using the fullname template and "-pod" suffix name: "postgres-pod" + annotations: {} # priority class for operator pod priorityClassName: "" diff --git a/docs/administrator.md b/docs/administrator.md index c44d08f90..7b4a63e7f 100644 --- a/docs/administrator.md +++ b/docs/administrator.md @@ -1016,11 +1016,9 @@ The configuration parameters that we will be using are: * `wal_gs_bucket` -1. Create a custom Kubernetes service account to be used by Patroni running on -the postgres cluster pods, this service account should include an annotation -with the email address of the Google IAM service account used to communicate -with the GCS bucket, e.g. +1. If you want to use a custom Kubernetes service account for Patroni running on the postgres cluster pods, follow these steps: + a. Create the service account and include an annotation with the email address of the Google IAM service account used to communicate with the GCS bucket: ```yml apiVersion: v1 kind: ServiceAccount @@ -1031,21 +1029,32 @@ metadata: iam.gke.io/gcp-service-account: @.iam.gserviceaccount.com ``` -2. Specify the new custom service account in your [operator paramaters](./reference/operator_parameters.md) + b. Specify this custom service account in your [operator parameters](./reference/operator_parameters.md). + - If using manual deployment or kustomize, set `pod_service_account_name` in your configuration file as indicated in the [postgres-operator deployment](../manifests/postgres-operator.yaml#L37). + - If deploying the operator [using Helm](./quickstart.md#helm-chart), update the chart's values file: +```yml +... +podServiceAccount: + name: postgres-pod-custom +``` -If using manual deployment or kustomize, this is done by setting -`pod_service_account_name` in your configuration file specified in the -[postgres-operator deployment](../manifests/postgres-operator.yaml#L37) +2. If you prefer the operator to automatically create the service account with the correct annotation: -If deploying the operator [using Helm](./quickstart.md#helm-chart), this can -be specified in the chart's values file, e.g.: + a. Specify the required annotation under `podServiceAccount` in your configuration: + - If using manual deployment or kustomize, specify the `pod_service_account_annotations` directly in your configuration file. + - If deploying the operator [using Helm](./quickstart.md#helm-chart), update the chart's values file: ```yml ... podServiceAccount: - name: postgres-pod-custom + name: postgres-pod + annotations: + iam.gke.io/gcp-service-account: @.iam.gserviceaccount.com ``` + With this configuration, the operator will create a new service account named `postgres-pod` with the specified GCP service account annotation. + + 3. Setup your operator configuration values. Ensure that the operator's configuration is set up like the following: ```yml diff --git a/manifests/configmap.yaml b/manifests/configmap.yaml index 2388c22b2..19dbb5ea7 100644 --- a/manifests/configmap.yaml +++ b/manifests/configmap.yaml @@ -128,6 +128,7 @@ data: pod_role_label: spilo-role # pod_service_account_definition: "" pod_service_account_name: "postgres-pod" + pod_service_account_annotations: "keya:valuea" # pod_service_account_role_binding_definition: "" pod_terminate_grace_period: 5m # postgres_superuser_teams: "postgres_superusers" diff --git a/manifests/operatorconfiguration.crd.yaml b/manifests/operatorconfiguration.crd.yaml index f60d8426e..063af8a65 100644 --- a/manifests/operatorconfiguration.crd.yaml +++ b/manifests/operatorconfiguration.crd.yaml @@ -303,6 +303,10 @@ spec: pod_service_account_name: type: string default: "postgres-pod" + pod_service_account_annotations: + type: object + additionalProperties: + type: string pod_service_account_role_binding_definition: type: string default: "" diff --git a/manifests/postgresql-operator-default-configuration.yaml b/manifests/postgresql-operator-default-configuration.yaml index ad0f99da3..12529e10b 100644 --- a/manifests/postgresql-operator-default-configuration.yaml +++ b/manifests/postgresql-operator-default-configuration.yaml @@ -93,6 +93,9 @@ configuration: pod_role_label: spilo-role # pod_service_account_definition: "" pod_service_account_name: postgres-pod + # pod_service_account_annotations: + # keya: valuea + # keyb: valueb # pod_service_account_role_binding_definition: "" pod_terminate_grace_period: 5m secret_name_template: "{username}.{cluster}.credentials.{tprkind}.{tprgroup}" diff --git a/pkg/apis/acid.zalan.do/v1/operator_configuration_type.go b/pkg/apis/acid.zalan.do/v1/operator_configuration_type.go index d966aa1aa..3882ce882 100644 --- a/pkg/apis/acid.zalan.do/v1/operator_configuration_type.go +++ b/pkg/apis/acid.zalan.do/v1/operator_configuration_type.go @@ -55,7 +55,8 @@ type MajorVersionUpgradeConfiguration struct { // KubernetesMetaConfiguration defines k8s conf required for all Postgres clusters and the operator itself type KubernetesMetaConfiguration struct { - PodServiceAccountName string `json:"pod_service_account_name,omitempty"` + PodServiceAccountName string `json:"pod_service_account_name,omitempty"` + PodServiceAccountAnnotations map[string]string `json:"pod_service_account_annotations,omitempty"` // TODO: change it to the proper json PodServiceAccountDefinition string `json:"pod_service_account_definition,omitempty"` PodServiceAccountRoleBindingDefinition string `json:"pod_service_account_role_binding_definition,omitempty"` diff --git a/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go b/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go index a43c995c5..e65689873 100644 --- a/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go +++ b/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go @@ -153,6 +153,13 @@ func (in *ConnectionPoolerConfiguration) DeepCopy() *ConnectionPoolerConfigurati // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KubernetesMetaConfiguration) DeepCopyInto(out *KubernetesMetaConfiguration) { *out = *in + if in.PodServiceAccountAnnotations != nil { + in, out := &in.PodServiceAccountAnnotations, &out.PodServiceAccountAnnotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } if in.SpiloAllowPrivilegeEscalation != nil { in, out := &in.SpiloAllowPrivilegeEscalation, &out.SpiloAllowPrivilegeEscalation *out = new(bool) diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go index e46b9ee44..142e2ab5a 100644 --- a/pkg/controller/controller.go +++ b/pkg/controller/controller.go @@ -245,6 +245,7 @@ func (c *Controller) initPodServiceAccount() { c.PodServiceAccount.Name = c.opConfig.PodServiceAccountName } c.PodServiceAccount.Namespace = "" + c.PodServiceAccount.Annotations = c.opConfig.PodServiceAccountAnnotations } // actual service accounts are deployed at the time of Postgres/Spilo cluster creation diff --git a/pkg/controller/operator_config.go b/pkg/controller/operator_config.go index 8aaf8759c..4a9b67de3 100644 --- a/pkg/controller/operator_config.go +++ b/pkg/controller/operator_config.go @@ -68,6 +68,7 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur // kubernetes config result.CustomPodAnnotations = fromCRD.Kubernetes.CustomPodAnnotations result.PodServiceAccountName = util.Coalesce(fromCRD.Kubernetes.PodServiceAccountName, "postgres-pod") + result.PodServiceAccountAnnotations = util.CoalesceStrMap(fromCRD.Kubernetes.PodServiceAccountAnnotations, map[string]string{}) result.PodServiceAccountDefinition = fromCRD.Kubernetes.PodServiceAccountDefinition result.PodServiceAccountRoleBindingDefinition = fromCRD.Kubernetes.PodServiceAccountRoleBindingDefinition result.PodEnvironmentConfigMap = fromCRD.Kubernetes.PodEnvironmentConfigMap diff --git a/pkg/util/config/config.go b/pkg/util/config/config.go index 82b878b61..ce1b43553 100644 --- a/pkg/util/config/config.go +++ b/pkg/util/config/config.go @@ -169,13 +169,14 @@ type Config struct { LogicalBackup ConnectionPooler - WatchedNamespace string `name:"watched_namespace"` // special values: "*" means 'watch all namespaces', the empty string "" means 'watch a namespace where operator is deployed to' - KubernetesUseConfigMaps bool `name:"kubernetes_use_configmaps" default:"false"` - EtcdHost string `name:"etcd_host" default:""` // special values: the empty string "" means Patroni will use K8s as a DCS - DockerImage string `name:"docker_image" default:"ghcr.io/zalando/spilo-15:3.0-p1"` - SidecarImages map[string]string `name:"sidecar_docker_images"` // deprecated in favour of SidecarContainers - SidecarContainers []v1.Container `name:"sidecars"` - PodServiceAccountName string `name:"pod_service_account_name" default:"postgres-pod"` + WatchedNamespace string `name:"watched_namespace"` // special values: "*" means 'watch all namespaces', the empty string "" means 'watch a namespace where operator is deployed to' + KubernetesUseConfigMaps bool `name:"kubernetes_use_configmaps" default:"false"` + EtcdHost string `name:"etcd_host" default:""` // special values: the empty string "" means Patroni will use K8s as a DCS + DockerImage string `name:"docker_image" default:"ghcr.io/zalando/spilo-15:3.0-p1"` + SidecarImages map[string]string `name:"sidecar_docker_images"` // deprecated in favour of SidecarContainers + SidecarContainers []v1.Container `name:"sidecars"` + PodServiceAccountName string `name:"pod_service_account_name" default:"postgres-pod"` + PodServiceAccountAnnotations map[string]string `name:"pod_service_account_annotations"` // value of this string must be valid JSON or YAML; see initPodServiceAccount PodServiceAccountDefinition string `name:"pod_service_account_definition" default:""` PodServiceAccountRoleBindingDefinition string `name:"pod_service_account_role_binding_definition" default:""`