diff --git a/charts/postgreslet/templates/_helpers.tpl b/charts/postgreslet/templates/_helpers.tpl index 362e8b03..1831d07a 100644 --- a/charts/postgreslet/templates/_helpers.tpl +++ b/charts/postgreslet/templates/_helpers.tpl @@ -71,3 +71,10 @@ Create the name of the service account to use {{- default "default" .Values.serviceAccount.name }} {{- end }} {{- end }} + +{{/* +Create the name of the custom pod security policy to use +*/}} +{{- define "postgreslet.pspName" -}} +{{- default (include "postgreslet.fullname" .) .Values.postgreslet.customPspName }} +{{- end }} diff --git a/charts/postgreslet/templates/configmap.yaml b/charts/postgreslet/templates/configmap.yaml index ffe25d21..4eaff2ad 100644 --- a/charts/postgreslet/templates/configmap.yaml +++ b/charts/postgreslet/templates/configmap.yaml @@ -5,6 +5,7 @@ data: METRICS_ADDR_SVC_MGR: {{ .Values.postgreslet.metricsAddr | quote }} PARTITION_ID: {{ .Values.postgreslet.partitionId | quote }} TENANT: {{ .Values.postgreslet.tenant | quote }} + CUSTOM_PSP_NAME: {{ include "postgreslet.pspName" . | quote }} kind: ConfigMap metadata: name: {{ include "postgreslet.fullname" . }} diff --git a/charts/postgreslet/templates/deployment.yaml b/charts/postgreslet/templates/deployment.yaml index 4b61d86c..0b110159 100644 --- a/charts/postgreslet/templates/deployment.yaml +++ b/charts/postgreslet/templates/deployment.yaml @@ -44,6 +44,7 @@ spec: - --enable-leader-election=$(ENABLE_LEADER_ELECTION) - --partition-id=$(PARTITION_ID) - --tenant=$(TENANT) + - --custom-psp-name=$(CUSTOM_PSP_NAME) envFrom: - configMapRef: name: {{ include "postgreslet.fullname" . }} diff --git a/charts/postgreslet/templates/podsecuritypolicy.yaml b/charts/postgreslet/templates/podsecuritypolicy.yaml new file mode 100644 index 00000000..b4910598 --- /dev/null +++ b/charts/postgreslet/templates/podsecuritypolicy.yaml @@ -0,0 +1,20 @@ +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ include "postgreslet.pspName" . }} +spec: + allowPrivilegeEscalation: true + fsGroup: + rule: RunAsAny + runAsUser: + rule: RunAsAny + seLinux: + rule: RunAsAny + supplementalGroups: + rule: RunAsAny + volumes: + - hostPath + - secret + - persistentVolumeClaim + - configMap + - emptyDir \ No newline at end of file diff --git a/charts/postgreslet/values.yaml b/charts/postgreslet/values.yaml index d833dce8..2d66593e 100644 --- a/charts/postgreslet/values.yaml +++ b/charts/postgreslet/values.yaml @@ -65,4 +65,7 @@ postgreslet: # tenant specifies which tenant this postgreslet is responsable for, postgres resources from other tenants will be ignored tenant: sample-tenant # metricsAddr defines the listen address of the metrics endpoint - metricsAddr: ":8080" \ No newline at end of file + metricsAddr: ":8080" + # customPspName The name to use for our custom psp + # If not set, a name is generated using the fullname template + customPspName: "" \ No newline at end of file diff --git a/main.go b/main.go index 39e5c47a..a920ed48 100644 --- a/main.go +++ b/main.go @@ -45,7 +45,7 @@ func init() { } func main() { - var metricsAddrCtrlMgr, metricsAddrSvcMgr, partitionID, tenant, ctrlClusterKubeconfig string + var metricsAddrCtrlMgr, metricsAddrSvcMgr, partitionID, tenant, ctrlClusterKubeconfig, pspName string var enableLeaderElection bool flag.StringVar(&metricsAddrSvcMgr, "metrics-addr-svc-mgr", ":8080", "The address the metric endpoint of the service cluster manager binds to.") flag.StringVar(&metricsAddrCtrlMgr, "metrics-addr-ctrl-mgr", "0", "The address the metric endpoint of the control cluster manager binds to.") @@ -55,6 +55,7 @@ func main() { flag.StringVar(&partitionID, "partition-id", "", "The partition ID of the worker-cluster.") flag.StringVar(&tenant, "tenant", "", "The tenant name.") flag.StringVar(&ctrlClusterKubeconfig, "controlplane-kubeconfig", "/var/run/secrets/postgreslet/kube/config", "The path to the kubeconfig to talk to the control plane") + flag.StringVar(&pspName, "custom-psp-name", "postgres-operator-psp", "The namem of our custom PodSecurityPolicy. Will be added to the ClusterRoles.") flag.Parse() ctrl.SetLogger(zap.New(zap.UseDevMode(true))) @@ -110,7 +111,7 @@ func main() { os.Exit(1) } - opMgr, err := operatormanager.New(svcClusterMgr.GetClient(), "external/svc-postgres-operator.yaml", scheme, ctrl.Log.WithName("OperatorManager")) + opMgr, err := operatormanager.New(svcClusterMgr.GetClient(), "external/svc-postgres-operator.yaml", scheme, ctrl.Log.WithName("OperatorManager"), pspName) if err != nil { setupLog.Error(err, "unable to create `OperatorManager`") os.Exit(1) diff --git a/pkg/operatormanager/operatormanager.go b/pkg/operatormanager/operatormanager.go index 43c14111..3fe5c4d3 100644 --- a/pkg/operatormanager/operatormanager.go +++ b/pkg/operatormanager/operatormanager.go @@ -29,6 +29,11 @@ import ( // operatorPodMatchingLabels is for listing operator pods var operatorPodMatchingLabels = client.MatchingLabels{"name": "postgres-operator"} +// The serviceAccount name to use for the database pods. +// TODO: create new account per namespace +// TODO: use different account for operator and database +const serviceAccountName string = "postgres-operator" + // OperatorManager manages the operator type OperatorManager struct { client.Client @@ -37,10 +42,11 @@ type OperatorManager struct { Log logr.Logger meta.MetadataAccessor *runtime.Scheme + pspName string } // New creates a new `OperatorManager` -func New(client client.Client, fileName string, scheme *runtime.Scheme, log logr.Logger) (*OperatorManager, error) { +func New(client client.Client, fileName string, scheme *runtime.Scheme, log logr.Logger, pspName string) (*OperatorManager, error) { bb, err := ioutil.ReadFile(fileName) if err != nil { return nil, fmt.Errorf("error while reading operator yaml file: %v", err) @@ -61,6 +67,7 @@ func New(client client.Client, fileName string, scheme *runtime.Scheme, log logr list: list, Scheme: scheme, Log: log, + pspName: pspName, }, nil } @@ -194,6 +201,14 @@ func (m *OperatorManager) createNewRuntimeObject(ctx context.Context, objs []run // ClusterRole is not namespaced. key.Namespace = "" err = m.Get(ctx, key, &rbacv1.ClusterRole{}) + // Add our psp + pspPolicyRule := rbacv1.PolicyRule{ + APIGroups: []string{"extensions"}, + Verbs: []string{"use"}, + Resources: []string{"podsecuritypolicies"}, + ResourceNames: []string{m.pspName}, + } + v.Rules = append(v.Rules, pspPolicyRule) case *rbacv1.ClusterRoleBinding: m.Log.Info("handling ClusterRoleBinding") // Set the namespace of the ServiceAccount in the ClusterRoleBinding. @@ -251,6 +266,8 @@ func (m *OperatorManager) createNewRuntimeObject(ctx context.Context, objs []run func (m *OperatorManager) editConfigMap(cm *v1.ConfigMap, namespace, s3BucketURL string) { cm.Data["logical_backup_s3_bucket"] = s3BucketURL cm.Data["watched_namespace"] = namespace + // TODO don't use the same serviceaccount for operator and databases, see #88 + cm.Data["pod_service_account_name"] = serviceAccountName } // ensureCleanMetadata ensures obj has clean metadata