This is an automated email from the ASF dual-hosted git repository.

pingsutw pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/submarine.git


The following commit(s) were added to refs/heads/master by this push:
     new 9bb5a761 SUBMARINE-1179. Add 
PodSecurityPolicies/SecurityContextConstraints support for RunAsAnyUser in 
submarine
9bb5a761 is described below

commit 9bb5a76124fac3202d36b21c42c1a46f96878e57
Author: cdmikechen <cdmikec...@hotmail.com>
AuthorDate: Sat Apr 9 15:54:33 2022 +0800

    SUBMARINE-1179. Add PodSecurityPolicies/SecurityContextConstraints support 
for RunAsAnyUser in submarine
    
    ### What is this PR for?
    We need to add PodSecurityPolicies(k8s) or 
SecurityContextConstraints(openshift) to let pod run as a user with default 
user in docker container. Otherwise, pod may cause permission problems (like no 
permission error).
    
    ### What type of PR is it?
    Bug Fix
    
    ### Todos
    * [x] - Add two params in helm values.yaml: `clusterType` and 
`podSecurityPolicy.create`
    * [x] - Change operator dockerfile to support shell params 
`SUBMARINE_CLUSTER_TYPE`  and `SUBMARINE_POD_SECURITY_POLICY_ENABLE`
    * [x] - Add PodSecurityPolicy (OpenShift has a default scc anyuid so that 
we need not to add)
    * [x] - The processing of operator is reconstructed: create deployment run 
after RBAC created
    * [x] - Add RunAsAnyUser policy in database\minio\server
    
    ### What is the Jira issue?
    https://issues.apache.org/jira/projects/SUBMARINE/issues/SUBMARINE-1179
    
    ### How should this be tested?
    <!--
    * First time? Setup Travis CI as described on 
https://submarine.apache.org/contribution/contributions.html#continuous-integration
    * Strongly recommended: add automated unit tests for any new or changed 
behavior
    * Outline any manual steps to test the PR here.
    -->
    ### Screenshots (if appropriate)
    
    ### Questions:
    * Do the license files need updating? No
    * Are there breaking changes for older versions? Yes
    * Does this need new documentation? No
    
    Author: cdmikechen <cdmikec...@hotmail.com>
    
    Signed-off-by: Kevin Su <pings...@apache.org>
    
    Closes #921 from cdmikechen/SUBMARINE-1179-new and squashes the following 
commits:
    
    07a005ab [cdmikechen] Fix pod startup error when minikube supports Pod 
Security Policy
    005f690c [cdmikechen] add submarine/finalizers in rbac
    03678664 [cdmikechen] fix docker build
    8fdff7d2 [cdmikechen] SUBMARINE-1179. Add 
PodSecurityPolicies/SecurityContextConstraints for submarine
---
 .gitignore                                         |   4 +-
 dev-support/docker-images/operator/Dockerfile      |  11 +-
 helm-charts/submarine/templates/_helpers.tpl       |  11 ++
 .../submarine/templates/{_helpers.tpl => psp.yaml} |  39 +++---
 helm-charts/submarine/templates/pv.yaml            |  17 +++
 helm-charts/submarine/templates/rbac-kubeflow.yaml |  82 +++++++++++++
 helm-charts/submarine/templates/rbac.yaml          |  22 ++++
 .../submarine/templates/submarine-operator.yaml    |   5 +
 helm-charts/submarine/values.yaml                  |  10 ++
 submarine-cloud-v2/README.md                       |   2 +
 .../artifacts/submarine/submarine-database.yaml    |   1 +
 .../artifacts/submarine/submarine-minio.yaml       |   1 +
 .../artifacts/submarine/submarine-mlflow.yaml      |   1 +
 .../submarine/submarine-storage-rbac.yaml          |  40 +++---
 .../artifacts/submarine/submarine-tensorboard.yaml |   1 +
 submarine-cloud-v2/main.go                         |  16 ++-
 submarine-cloud-v2/pkg/controller/controller.go    |  39 +++++-
 .../pkg/controller/controller_builder.go           |   2 +
 .../pkg/controller/controller_builder_config.go    |  16 +++
 .../pkg/controller/submarine_observer_rbac.go      |   2 +-
 .../pkg/controller/submarine_server.go             |  38 +-----
 .../pkg/controller/submarine_server_rbac.go        |  50 +++++++-
 .../pkg/controller/submarine_storage_rbac.go       | 135 +++++++++++++++++++++
 23 files changed, 459 insertions(+), 86 deletions(-)

diff --git a/.gitignore b/.gitignore
index 60e35b5c..312d4aa7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -86,6 +86,8 @@ submarine-cloud/bin/*
 submarine-cloud-v2/vendor/*
 submarine-cloud-v2/submarine-operator
 submarine-cloud-v2/helm-charts/submarine-operator/charts/*
+# add operator docker build tmp
+dev-support/docker-images/operator/tmp/
 
 # vscode file
 .project
@@ -102,4 +104,4 @@ submarine-cloud-v2/helm-charts/submarine-operator/charts/*
 *.log
 
 # installation binary
-submarine-serve/installation/istioctl
\ No newline at end of file
+submarine-serve/installation/istioctl
diff --git a/dev-support/docker-images/operator/Dockerfile 
b/dev-support/docker-images/operator/Dockerfile
index e2627842..3f2795a5 100644
--- a/dev-support/docker-images/operator/Dockerfile
+++ b/dev-support/docker-images/operator/Dockerfile
@@ -14,17 +14,20 @@
 # limitations under the License.
 
 FROM golang:1.16.2 AS build-image
-MAINTAINER Apache Software Foundation <dev@submarine.apache.org>
 
 ADD tmp/submarine-cloud-v2 /usr/src
 
 WORKDIR /usr/src
 
-RUN GOOS=linux go build -o submarine-operator
+# use CGO_ENABLED=0 to support alpine image
+RUN GOOS=linux CGO_ENABLED=0 go build -o submarine-operator
+
+# we use alpine to support shell params
+FROM alpine
+MAINTAINER Apache Software Foundation <dev@submarine.apache.org>
 
-FROM gcr.io/distroless/base-debian10
 ADD tmp/submarine-cloud-v2/artifacts /usr/src/artifacts
 WORKDIR /usr/src
 COPY --from=build-image /usr/src/submarine-operator /usr/src/submarine-operator
 
-CMD ["/usr/src/submarine-operator", "-incluster=true"]
+CMD /usr/src/submarine-operator -incluster=true 
-clustertype=${SUBMARINE_CLUSTER_TYPE:kubernetes} 
-createpsp=${SUBMARINE_POD_SECURITY_POLICY_ENABLE:-true}
diff --git a/helm-charts/submarine/templates/_helpers.tpl 
b/helm-charts/submarine/templates/_helpers.tpl
index 8f67df56..277d3fa2 100644
--- a/helm-charts/submarine/templates/_helpers.tpl
+++ b/helm-charts/submarine/templates/_helpers.tpl
@@ -31,3 +31,14 @@ parameters:
 {{ end }}
 {{ end }}
 {{ end }}
+
+{{/*
+Return the apiVersion for PodSecurityPolicy.
+*/}}
+{{- define "podSecurityPolicy.apiVersion" -}}
+{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
+{{- print "policy/v1beta1" -}}
+{{- else -}}
+{{- print "extensions/v1beta1" -}}
+{{- end -}}
+{{- end -}}
diff --git a/helm-charts/submarine/templates/_helpers.tpl 
b/helm-charts/submarine/templates/psp.yaml
similarity index 63%
copy from helm-charts/submarine/templates/_helpers.tpl
copy to helm-charts/submarine/templates/psp.yaml
index 8f67df56..dd6cf072 100644
--- a/helm-charts/submarine/templates/_helpers.tpl
+++ b/helm-charts/submarine/templates/psp.yaml
@@ -15,19 +15,26 @@
 # limitations under the License.
 #
 
-{{/*
-Set up storage class fields
-*/}}
-{{ define "storageClass.fields" }}
-{{ with .Values.storageClass }}
-reclaimPolicy: {{ .reclaimPolicy | default "Delete" }}
-volumeBindingMode: {{ .volumeBindingMode | default "Immediate" }}
-provisioner: {{ .provisioner | default "k8s.io/minikube-hostpath" }}
-{{ if .parameters }}
-parameters:
-  {{ range $key, $val := .parameters }}
-  {{ $key }}: {{ $val | quote }}
-  {{ end }}
-{{ end }}
-{{ end }}
-{{ end }}
+{{- if .Values.podSecurityPolicy.create }}
+kind: PodSecurityPolicy
+apiVersion: {{ template "podSecurityPolicy.apiVersion" . }}
+metadata:
+  name: submarine-anyuid
+spec:
+  privileged: false
+  volumes:
+    - configMap
+    - downwardAPI
+    - emptyDir
+    - persistentVolumeClaim
+    - projected
+    - secret
+  seLinux:
+    rule: RunAsAny
+  runAsUser:
+    rule: RunAsAny
+  supplementalGroups:
+    rule: RunAsAny
+  fsGroup:
+    rule: RunAsAny
+{{- end }}
diff --git a/helm-charts/submarine/templates/pv.yaml 
b/helm-charts/submarine/templates/pv.yaml
index f138ed9c..b03ae11d 100644
--- a/helm-charts/submarine/templates/pv.yaml
+++ b/helm-charts/submarine/templates/pv.yaml
@@ -1,3 +1,20 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
 {{- if eq .Values.storageClass.provisioner "kubernetes.io/no-provisioner"}}
 apiVersion: v1
 kind: PersistentVolume
diff --git a/helm-charts/submarine/templates/rbac-kubeflow.yaml 
b/helm-charts/submarine/templates/rbac-kubeflow.yaml
new file mode 100644
index 00000000..00f0af33
--- /dev/null
+++ b/helm-charts/submarine/templates/rbac-kubeflow.yaml
@@ -0,0 +1,82 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+{{- if .Values.podSecurityPolicy.create }}
+kind: ClusterRole
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+  name: kubeflow-operator-anyuid
+rules:
+{{- if (eq "openshift" .Values.clusterType) }}
+  - apiGroups:
+      - security.openshift.io
+    resources:
+      - securitycontextconstraints
+    verbs:
+      - use
+    resourceNames:
+      - anyuid
+{{- else }}
+  - apiGroups:
+      - policy
+    resources:
+      - podsecuritypolicies
+    verbs:
+      - use
+    resourceNames:
+      - submarine-anyuid
+{{- end }}
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  name: tf-job-operator-anyuid
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: kubeflow-operator-anyuid
+subjects:
+  - kind: ServiceAccount
+    name: tf-job-operator
+    namespace: {{ .Release.Namespace }}
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  name: pytorch-operator-anyuid
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: kubeflow-operator-anyuid
+subjects:
+  - kind: ServiceAccount
+    name: pytorch-operator
+    namespace: {{ .Release.Namespace }}
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  name: notebook-controller-anyuid
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: kubeflow-operator-anyuid
+subjects:
+  - kind: ServiceAccount
+    name: notebook-controller-service-account
+    namespace: {{ .Release.Namespace }}
+{{- end }}
diff --git a/helm-charts/submarine/templates/rbac.yaml 
b/helm-charts/submarine/templates/rbac.yaml
index 02dec67c..2c854efb 100644
--- a/helm-charts/submarine/templates/rbac.yaml
+++ b/helm-charts/submarine/templates/rbac.yaml
@@ -25,6 +25,7 @@ rules:
     resources:
       - submarines
       - submarines/status
+      - submarines/finalizers
     verbs:
       - "*"
   - apiGroups:
@@ -90,6 +91,27 @@ rules:
       - customresourcedefinitions/status
     verbs:
       - "*"
+{{- if .Values.podSecurityPolicy.create }}
+{{- if (eq "openshift" .Values.clusterType) }}
+  - apiGroups:
+      - security.openshift.io
+    resources:
+      - securitycontextconstraints
+    verbs:
+      - use
+    resourceNames:
+      - anyuid
+{{- else }}
+  - apiGroups:
+      - policy
+    resources:
+      - podsecuritypolicies
+    verbs:
+      - use
+    resourceNames:
+      - submarine-anyuid
+{{- end }}
+{{- end }}
 ---
 apiVersion: v1
 kind: ServiceAccount
diff --git a/helm-charts/submarine/templates/submarine-operator.yaml 
b/helm-charts/submarine/templates/submarine-operator.yaml
index 3c7b5875..5a7b2bef 100644
--- a/helm-charts/submarine/templates/submarine-operator.yaml
+++ b/helm-charts/submarine/templates/submarine-operator.yaml
@@ -42,6 +42,11 @@ spec:
           name: "{{ .Values.name }}"
           resources: {}
           imagePullPolicy: IfNotPresent
+          env:
+            - name: SUBMARINE_POD_SECURITY_POLICY_ENABLE
+              value: "{{ .Values.podSecurityPolicy.create }}"
+            - name: SUBMARINE_CLUSTER_TYPE
+              value: {{ .Values.clusterType }}
       serviceAccountName: submarine-operator
 status: {}
 {{ end }}
diff --git a/helm-charts/submarine/values.yaml 
b/helm-charts/submarine/values.yaml
index 534d2083..8366e5c8 100644
--- a/helm-charts/submarine/values.yaml
+++ b/helm-charts/submarine/values.yaml
@@ -30,3 +30,13 @@ storageClass:
   provisioner: k8s.io/minikube-hostpath
   # parameters describe volumes belonging to the storage class
   parameters:
+
+# k8s cluster type. can be: kubernetes or openshift
+clusterType: kubernetes
+
+# PodSecurityPolicy configuration
+# ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/
+podSecurityPolicy:
+  # Specifies whether a PodSecurityPolicy should be created,
+  # This configuration enables the database/minio/server to set 
securityContext.runAsUser
+  create: true
diff --git a/submarine-cloud-v2/README.md b/submarine-cloud-v2/README.md
index 7dbfe86f..4e4ff176 100644
--- a/submarine-cloud-v2/README.md
+++ b/submarine-cloud-v2/README.md
@@ -32,6 +32,8 @@ Golang version: `1.16.2`
 go mod vendor
 # Run the cluster
 minikube start --vm-driver=docker --cpus 8 --memory 4096 --kubernetes-version 
v1.21.2
+# Or if you want to support Pod Security Policy 
(https://minikube.sigs.k8s.io/docs/tutorials/using_psp), you can use the 
following command to start cluster
+minikube start 
--extra-config=apiserver.enable-admission-plugins=PodSecurityPolicy 
--addons=pod-security-policy --vm-driver=docker --cpus 8 --memory 4096 
--kubernetes-version v1.21.2
 ```
 
 ## Set up storage class fields
diff --git a/submarine-cloud-v2/artifacts/submarine/submarine-database.yaml 
b/submarine-cloud-v2/artifacts/submarine/submarine-database.yaml
index a6efafe7..b368e935 100644
--- a/submarine-cloud-v2/artifacts/submarine/submarine-database.yaml
+++ b/submarine-cloud-v2/artifacts/submarine/submarine-database.yaml
@@ -60,6 +60,7 @@ spec:
       labels:
         app: "submarine-database"
     spec:
+      serviceAccountName: "submarine-storage"
       containers:
         - name: "submarine-database"
           image: "apache/submarine:database-0.7.0"
diff --git a/submarine-cloud-v2/artifacts/submarine/submarine-minio.yaml 
b/submarine-cloud-v2/artifacts/submarine/submarine-minio.yaml
index a7641062..799fc096 100644
--- a/submarine-cloud-v2/artifacts/submarine/submarine-minio.yaml
+++ b/submarine-cloud-v2/artifacts/submarine/submarine-minio.yaml
@@ -57,6 +57,7 @@ spec:
       labels:
         app: submarine-minio
     spec:
+      serviceAccountName: "submarine-storage"
       containers:
       - name: submarine-minio-container
         image: minio/minio:RELEASE.2021-02-14T04-01-33Z
diff --git a/submarine-cloud-v2/artifacts/submarine/submarine-mlflow.yaml 
b/submarine-cloud-v2/artifacts/submarine/submarine-mlflow.yaml
index dbc513a9..dfe05ee2 100644
--- a/submarine-cloud-v2/artifacts/submarine/submarine-mlflow.yaml
+++ b/submarine-cloud-v2/artifacts/submarine/submarine-mlflow.yaml
@@ -58,6 +58,7 @@ spec:
       labels:
         app: submarine-mlflow
     spec:
+      serviceAccountName: "submarine-storage"
       initContainers:
       - name: check-database-connection
         image: busybox:1.28
diff --git a/helm-charts/submarine/templates/_helpers.tpl 
b/submarine-cloud-v2/artifacts/submarine/submarine-storage-rbac.yaml
similarity index 62%
copy from helm-charts/submarine/templates/_helpers.tpl
copy to submarine-cloud-v2/artifacts/submarine/submarine-storage-rbac.yaml
index 8f67df56..9d4e113e 100644
--- a/helm-charts/submarine/templates/_helpers.tpl
+++ b/submarine-cloud-v2/artifacts/submarine/submarine-storage-rbac.yaml
@@ -1,3 +1,5 @@
+---
+# Source: submarine/templates/rbac.yaml
 #
 # Licensed to the Apache Software Foundation (ASF) under one or more
 # contributor license agreements.  See the NOTICE file distributed with
@@ -15,19 +17,25 @@
 # limitations under the License.
 #
 
-{{/*
-Set up storage class fields
-*/}}
-{{ define "storageClass.fields" }}
-{{ with .Values.storageClass }}
-reclaimPolicy: {{ .reclaimPolicy | default "Delete" }}
-volumeBindingMode: {{ .volumeBindingMode | default "Immediate" }}
-provisioner: {{ .provisioner | default "k8s.io/minikube-hostpath" }}
-{{ if .parameters }}
-parameters:
-  {{ range $key, $val := .parameters }}
-  {{ $key }}: {{ $val | quote }}
-  {{ end }}
-{{ end }}
-{{ end }}
-{{ end }}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: "submarine-storage"
+rules: []
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: submarine-storage
+---
+kind: RoleBinding
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+  name: "submarine-storage"
+subjects:
+  - kind: ServiceAccount
+    name: "submarine-storage"
+roleRef:
+  kind: Role
+  name: "submarine-storage"
+  apiGroup: rbac.authorization.k8s.io
diff --git a/submarine-cloud-v2/artifacts/submarine/submarine-tensorboard.yaml 
b/submarine-cloud-v2/artifacts/submarine/submarine-tensorboard.yaml
index ae60e57f..b49776b5 100644
--- a/submarine-cloud-v2/artifacts/submarine/submarine-tensorboard.yaml
+++ b/submarine-cloud-v2/artifacts/submarine/submarine-tensorboard.yaml
@@ -56,6 +56,7 @@ spec:
       labels:
         app: submarine-tensorboard
     spec:
+      serviceAccountName: "submarine-storage"
       containers:
       - name: submarine-tensorboard-container
         image: tensorflow/tensorflow:1.11.0
diff --git a/submarine-cloud-v2/main.go b/submarine-cloud-v2/main.go
index 607a12f5..486dda54 100644
--- a/submarine-cloud-v2/main.go
+++ b/submarine-cloud-v2/main.go
@@ -38,9 +38,11 @@ import (
 )
 
 var (
-       masterURL  string
-       kubeconfig string
-       incluster  bool
+       masterURL               string
+       kubeconfig              string
+       incluster               bool
+       clusterType             string
+       createPodSecurityPolicy bool
 )
 
 func initKubeConfig() (*rest.Config, error) {
@@ -88,6 +90,8 @@ func main() {
        // Create a Submarine operator
        submarineController := NewSubmarineController(
                incluster,
+               clusterType,
+               createPodSecurityPolicy,
                kubeClient,
                submarineClient,
                traefikClient,
@@ -110,6 +114,8 @@ func main() {
 
 func NewSubmarineController(
        incluster bool,
+       clusterType string,
+       createPodSecurityPolicy bool,
        kubeClient *kubernetes.Clientset,
        submarineClient *clientset.Clientset,
        traefikClient *traefikclientset.Clientset,
@@ -120,6 +126,8 @@ func NewSubmarineController(
        bc := controller.NewControllerBuilderConfig()
        bc.
                InCluster(incluster).
+               WithClusterType(clusterType).
+               WithCreatePodSecurityPolicy(createPodSecurityPolicy).
                WithKubeClientset(kubeClient).
                WithSubmarineClientset(submarineClient).
                WithTraefikClientset(traefikClient).
@@ -143,4 +151,6 @@ func init() {
        flag.BoolVar(&incluster, "incluster", false, "Run submarine-operator 
in-cluster")
        flag.StringVar(&kubeconfig, "kubeconfig", 
os.Getenv("HOME")+"/.kube/config", "Path to a kubeconfig. Only required if 
out-of-cluster.")
        flag.StringVar(&masterURL, "master", "", "The address of the Kubernetes 
API server. Overrides any value in kubeconfig. Only required if 
out-of-cluster.")
+       flag.StringVar(&clusterType, "clustertype", "kubernetes", "K8s cluster 
type, can be kubernetes or openshift")
+       flag.BoolVar(&createPodSecurityPolicy, "createpsp", true, "Specifies 
whether a PodSecurityPolicy should be created. This configuration enables the 
database/minio/server to set securityContext.runAsUser")
 }
diff --git a/submarine-cloud-v2/pkg/controller/controller.go 
b/submarine-cloud-v2/pkg/controller/controller.go
index bbb965ed..cf7bd038 100644
--- a/submarine-cloud-v2/pkg/controller/controller.go
+++ b/submarine-cloud-v2/pkg/controller/controller.go
@@ -29,6 +29,7 @@ import (
 
        appsv1 "k8s.io/api/apps/v1"
        corev1 "k8s.io/api/core/v1"
+       rbacv1 "k8s.io/api/rbac/v1"
        "k8s.io/apimachinery/pkg/api/equality"
        "k8s.io/apimachinery/pkg/api/errors"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -60,6 +61,7 @@ const (
        tensorboardName             = "submarine-tensorboard"
        mlflowName                  = "submarine-mlflow"
        minioName                   = "submarine-minio"
+       storageName                 = "submarine-storage"
        ingressName                 = serverName + "-ingress"
        databasePvcName             = databaseName + "-pvc"
        tensorboardPvcName          = tensorboardName + "-pvc"
@@ -80,6 +82,7 @@ const (
        tensorboardYamlPath         = artifactPath + 
"submarine-tensorboard.yaml"
        rbacYamlPath                = artifactPath + "submarine-rbac.yaml"
        observerRbacYamlPath        = artifactPath + 
"submarine-observer-rbac.yaml"
+       storageRbacYamlPath         = artifactPath + 
"submarine-storage-rbac.yaml"
 )
 
 var dependents = []string{serverName, tensorboardName, mlflowName, minioName}
@@ -99,6 +102,22 @@ const (
        MessageResourceSynced = "Submarine synced successfully"
 )
 
+// Default k8s anyuid role rule
+var k8sAnyuidRoleRule = rbacv1.PolicyRule{
+       APIGroups:     []string{"policy"},
+       Verbs:         []string{"use"},
+       Resources:     []string{"podsecuritypolicies"},
+       ResourceNames: []string{"submarine-anyuid"},
+}
+
+// Openshift anyuid role rule
+var openshiftAnyuidRoleRule = rbacv1.PolicyRule{
+       APIGroups:     []string{"security.openshift.io"},
+       Verbs:         []string{"use"},
+       Resources:     []string{"securitycontextconstraints"},
+       ResourceNames: []string{"anyuid"},
+}
+
 // Controller is the controller implementation for Submarine resources
 type Controller struct {
        // kubeclientset is a standard kubernetes clientset
@@ -130,7 +149,9 @@ type Controller struct {
        // Kubernetes API.
        recorder record.EventRecorder
 
-       incluster bool
+       incluster               bool
+       clusterType             string
+       createPodSecurityPolicy bool
 }
 
 func (c *Controller) Run(threadiness int, stopCh <-chan struct{}) error {
@@ -437,27 +458,33 @@ func (c *Controller) validateSubmarine(submarine 
*v1alpha1.Submarine) error {
 
 func (c *Controller) createSubmarine(submarine *v1alpha1.Submarine) error {
        var err error
-       err = c.createSubmarineServer(submarine)
+       // We create rbac first, this ensures that any dependency based on it 
will not go wrong
+       err = c.createSubmarineServerRBAC(submarine)
        if err != nil && !errors.IsAlreadyExists(err) {
                return err
        }
 
-       err = c.createSubmarineDatabase(submarine)
+       err = c.createSubmarineStorageRBAC(submarine)
        if err != nil && !errors.IsAlreadyExists(err) {
                return err
        }
 
-       err = c.createIngress(submarine)
+       err = c.createSubmarineObserverRBAC(submarine)
        if err != nil && !errors.IsAlreadyExists(err) {
                return err
        }
 
-       err = c.createSubmarineServerRBAC(submarine)
+       err = c.createSubmarineServer(submarine)
        if err != nil && !errors.IsAlreadyExists(err) {
                return err
        }
 
-       err = c.createSubmarineObserverRBAC(submarine)
+       err = c.createSubmarineDatabase(submarine)
+       if err != nil && !errors.IsAlreadyExists(err) {
+               return err
+       }
+
+       err = c.createIngress(submarine)
        if err != nil && !errors.IsAlreadyExists(err) {
                return err
        }
diff --git a/submarine-cloud-v2/pkg/controller/controller_builder.go 
b/submarine-cloud-v2/pkg/controller/controller_builder.go
index 8d3ab63f..17b8fca2 100644
--- a/submarine-cloud-v2/pkg/controller/controller_builder.go
+++ b/submarine-cloud-v2/pkg/controller/controller_builder.go
@@ -63,6 +63,8 @@ func (cb *ControllerBuilder) initialize() *ControllerBuilder {
        workqueue := 
workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), 
"Submarines")
 
        cb.controller.incluster = cb.config.incluster
+       cb.controller.clusterType = cb.config.clusterType
+       cb.controller.createPodSecurityPolicy = 
cb.config.createPodSecurityPolicy
        cb.controller.recorder = recorder
        cb.controller.workqueue = workqueue
 
diff --git a/submarine-cloud-v2/pkg/controller/controller_builder_config.go 
b/submarine-cloud-v2/pkg/controller/controller_builder_config.go
index 2212fb5f..337616bc 100644
--- a/submarine-cloud-v2/pkg/controller/controller_builder_config.go
+++ b/submarine-cloud-v2/pkg/controller/controller_builder_config.go
@@ -31,6 +31,8 @@ import (
 
 type BuilderConfig struct {
        incluster                     bool
+       clusterType                   string
+       createPodSecurityPolicy       bool
        kubeclientset                 kubernetes.Interface
        submarineclientset            clientset.Interface
        traefikclientset              traefik.Interface
@@ -58,6 +60,20 @@ func (bc *BuilderConfig) InCluster(
        return bc
 }
 
+func (bc *BuilderConfig) WithClusterType(
+       clusterType string,
+) *BuilderConfig {
+       bc.clusterType = clusterType
+       return bc
+}
+
+func (bc *BuilderConfig) WithCreatePodSecurityPolicy(
+       createPodSecurityPolicy bool,
+) *BuilderConfig {
+       bc.createPodSecurityPolicy = createPodSecurityPolicy
+       return bc
+}
+
 func (bc *BuilderConfig) WithKubeClientset(
        kubeclientset kubernetes.Interface,
 ) *BuilderConfig {
diff --git a/submarine-cloud-v2/pkg/controller/submarine_observer_rbac.go 
b/submarine-cloud-v2/pkg/controller/submarine_observer_rbac.go
index 5f651192..b845b242 100644
--- a/submarine-cloud-v2/pkg/controller/submarine_observer_rbac.go
+++ b/submarine-cloud-v2/pkg/controller/submarine_observer_rbac.go
@@ -57,7 +57,7 @@ func newSubmarineObserverRoleBinding(submarine 
*v1alpha1.Submarine) *rbacv1.Role
 // createSubmarineObserverRBAC is a function to create RBAC for 
submarine-observer which will be binded on service account: default.
 // Reference: 
https://github.com/apache/submarine/blob/master/helm-charts/submarine/templates/rbac.yaml
 func (c *Controller) createSubmarineObserverRBAC(submarine 
*v1alpha1.Submarine) error {
-       klog.Info("[createSubmarineServerRBAC]")
+       klog.Info("[createSubmarineObserverRBAC]")
 
        // Step1: Create Role
        role, err := c.roleLister.Roles(submarine.Namespace).Get(observerName)
diff --git a/submarine-cloud-v2/pkg/controller/submarine_server.go 
b/submarine-cloud-v2/pkg/controller/submarine_server.go
index e71ee0b8..a0370eaf 100644
--- a/submarine-cloud-v2/pkg/controller/submarine_server.go
+++ b/submarine-cloud-v2/pkg/controller/submarine_server.go
@@ -30,19 +30,6 @@ import (
        "k8s.io/klog/v2"
 )
 
-func newSubmarineServerServiceAccount(submarine *v1alpha1.Submarine) 
*corev1.ServiceAccount {
-       serviceAccount, err := ParseServiceAccountYaml(serverYamlPath)
-       if err != nil {
-               klog.Info("[Error] ParseServiceAccountYaml", err)
-       }
-
-       serviceAccount.ObjectMeta.OwnerReferences = []metav1.OwnerReference{
-               *metav1.NewControllerRef(submarine, 
v1alpha1.SchemeGroupVersion.WithKind("Submarine")),
-       }
-
-       return serviceAccount
-}
-
 func newSubmarineServerService(submarine *v1alpha1.Submarine) *corev1.Service {
        service, err := ParseServiceYaml(serverYamlPath)
        if err != nil {
@@ -111,28 +98,7 @@ func newSubmarineServerDeployment(submarine 
*v1alpha1.Submarine) *appsv1.Deploym
 func (c *Controller) createSubmarineServer(submarine *v1alpha1.Submarine) 
error {
        klog.Info("[createSubmarineServer]")
 
-       // Step1: Create ServiceAccount
-       serviceaccount, err := 
c.serviceaccountLister.ServiceAccounts(submarine.Namespace).Get(serverName)
-       // If the resource doesn't exist, we'll create it
-       if errors.IsNotFound(err) {
-               serviceaccount, err = 
c.kubeclientset.CoreV1().ServiceAccounts(submarine.Namespace).Create(context.TODO(),
 newSubmarineServerServiceAccount(submarine), metav1.CreateOptions{})
-               klog.Info("     Create ServiceAccount: ", serviceaccount.Name)
-       }
-
-       // If an error occurs during Get/Create, we'll requeue the item so we 
can
-       // attempt processing again later. This could have been caused by a
-       // temporary network failure, or any other transient reason.
-       if err != nil {
-               return err
-       }
-
-       if !metav1.IsControlledBy(serviceaccount, submarine) {
-               msg := fmt.Sprintf(MessageResourceExists, serviceaccount.Name)
-               c.recorder.Event(submarine, corev1.EventTypeWarning, 
ErrResourceExists, msg)
-               return fmt.Errorf(msg)
-       }
-
-       // Step2: Create Service
+       // Step1: Create Service
        service, err := 
c.serviceLister.Services(submarine.Namespace).Get(serverName)
        // If the resource doesn't exist, we'll create it
        if errors.IsNotFound(err) {
@@ -153,7 +119,7 @@ func (c *Controller) createSubmarineServer(submarine 
*v1alpha1.Submarine) error
                return fmt.Errorf(msg)
        }
 
-       // Step3: Create Deployment
+       // Step2: Create Deployment
        deployment, err := 
c.deploymentLister.Deployments(submarine.Namespace).Get(serverName)
        // If the resource doesn't exist, we'll create it
        if errors.IsNotFound(err) {
diff --git a/submarine-cloud-v2/pkg/controller/submarine_server_rbac.go 
b/submarine-cloud-v2/pkg/controller/submarine_server_rbac.go
index 61e0bb81..12268a26 100644
--- a/submarine-cloud-v2/pkg/controller/submarine_server_rbac.go
+++ b/submarine-cloud-v2/pkg/controller/submarine_server_rbac.go
@@ -30,7 +30,20 @@ import (
        "k8s.io/klog/v2"
 )
 
-func newSubmarineServerRole(submarine *v1alpha1.Submarine) *rbacv1.Role {
+func newSubmarineServerServiceAccount(submarine *v1alpha1.Submarine) 
*corev1.ServiceAccount {
+       serviceAccount, err := ParseServiceAccountYaml(serverYamlPath)
+       if err != nil {
+               klog.Info("[Error] ParseServiceAccountYaml", err)
+       }
+
+       serviceAccount.ObjectMeta.OwnerReferences = []metav1.OwnerReference{
+               *metav1.NewControllerRef(submarine, 
v1alpha1.SchemeGroupVersion.WithKind("Submarine")),
+       }
+
+       return serviceAccount
+}
+
+func newSubmarineServerRole(c *Controller, submarine *v1alpha1.Submarine) 
*rbacv1.Role {
        role, err := ParseRoleYaml(rbacYamlPath)
        if err != nil {
                klog.Info("[Error] ParseRole", err)
@@ -39,6 +52,15 @@ func newSubmarineServerRole(submarine *v1alpha1.Submarine) 
*rbacv1.Role {
                *metav1.NewControllerRef(submarine, 
v1alpha1.SchemeGroupVersion.WithKind("Submarine")),
        }
 
+       if c.createPodSecurityPolicy {
+               // If cluster type is openshift and need create pod security 
policy, we need add anyuid scc, or we add k8s psp
+               if c.clusterType == "openshift" {
+                       role.Rules = append(role.Rules, openshiftAnyuidRoleRule)
+               } else {
+                       role.Rules = append(role.Rules, k8sAnyuidRoleRule)
+               }
+       }
+
        return role
 }
 
@@ -59,11 +81,32 @@ func newSubmarineServerRoleBinding(submarine 
*v1alpha1.Submarine) *rbacv1.RoleBi
 func (c *Controller) createSubmarineServerRBAC(submarine *v1alpha1.Submarine) 
error {
        klog.Info("[createSubmarineServerRBAC]")
 
-       // Step1: Create Role
+       // Step1: Create ServiceAccount
+       serviceaccount, err := 
c.serviceaccountLister.ServiceAccounts(submarine.Namespace).Get(serverName)
+       // If the resource doesn't exist, we'll create it
+       if errors.IsNotFound(err) {
+               serviceaccount, err = 
c.kubeclientset.CoreV1().ServiceAccounts(submarine.Namespace).Create(context.TODO(),
 newSubmarineServerServiceAccount(submarine), metav1.CreateOptions{})
+               klog.Info("     Create ServiceAccount: ", serviceaccount.Name)
+       }
+
+       // If an error occurs during Get/Create, we'll requeue the item so we 
can
+       // attempt processing again later. This could have been caused by a
+       // temporary network failure, or any other transient reason.
+       if err != nil {
+               return err
+       }
+
+       if !metav1.IsControlledBy(serviceaccount, submarine) {
+               msg := fmt.Sprintf(MessageResourceExists, serviceaccount.Name)
+               c.recorder.Event(submarine, corev1.EventTypeWarning, 
ErrResourceExists, msg)
+               return fmt.Errorf(msg)
+       }
+
+       // Step2: Create Role
        role, err := c.roleLister.Roles(submarine.Namespace).Get(serverName)
        // If the resource doesn't exist, we'll create it
        if errors.IsNotFound(err) {
-               role, err = 
c.kubeclientset.RbacV1().Roles(submarine.Namespace).Create(context.TODO(), 
newSubmarineServerRole(submarine), metav1.CreateOptions{})
+               role, err = 
c.kubeclientset.RbacV1().Roles(submarine.Namespace).Create(context.TODO(), 
newSubmarineServerRole(c, submarine), metav1.CreateOptions{})
                klog.Info("     Create Role: ", role.Name)
        }
 
@@ -80,6 +123,7 @@ func (c *Controller) createSubmarineServerRBAC(submarine 
*v1alpha1.Submarine) er
                return fmt.Errorf(msg)
        }
 
+       // Step3: Create Role Binding
        rolebinding, rolebinding_err := 
c.rolebindingLister.RoleBindings(submarine.Namespace).Get(serverName)
        // If the resource doesn't exist, we'll create it
        if errors.IsNotFound(rolebinding_err) {
diff --git a/submarine-cloud-v2/pkg/controller/submarine_storage_rbac.go 
b/submarine-cloud-v2/pkg/controller/submarine_storage_rbac.go
new file mode 100644
index 00000000..05a38adf
--- /dev/null
+++ b/submarine-cloud-v2/pkg/controller/submarine_storage_rbac.go
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package controller
+
+import (
+       "context"
+       "fmt"
+       v1alpha1 
"github.com/apache/submarine/submarine-cloud-v2/pkg/apis/submarine/v1alpha1"
+
+       corev1 "k8s.io/api/core/v1"
+       rbacv1 "k8s.io/api/rbac/v1"
+       "k8s.io/apimachinery/pkg/api/errors"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       "k8s.io/klog/v2"
+)
+
+func newSubmarineStorageRole(c *Controller, submarine *v1alpha1.Submarine) 
*rbacv1.Role {
+       role, err := ParseRoleYaml(storageRbacYamlPath)
+       if err != nil {
+               klog.Info("[Error] ParseRole", err)
+       }
+       role.ObjectMeta.OwnerReferences = []metav1.OwnerReference{
+               *metav1.NewControllerRef(submarine, 
v1alpha1.SchemeGroupVersion.WithKind("Submarine")),
+       }
+
+       // If cluster type is openshift and need create pod security policy, we 
need add anyuid scc, or we add k8s psp
+       if c.clusterType == "openshift" {
+               role.Rules = append(role.Rules, openshiftAnyuidRoleRule)
+       } else {
+               role.Rules = append(role.Rules, k8sAnyuidRoleRule)
+       }
+
+       return role
+}
+
+func newSubmarineStorageRoleBinding(submarine *v1alpha1.Submarine) 
*rbacv1.RoleBinding {
+       roleBinding, err := ParseRoleBindingYaml(storageRbacYamlPath)
+       if err != nil {
+               klog.Info("[Error] ParseRoleBinding", err)
+       }
+       roleBinding.ObjectMeta.OwnerReferences = []metav1.OwnerReference{
+               *metav1.NewControllerRef(submarine, 
v1alpha1.SchemeGroupVersion.WithKind("Submarine")),
+       }
+
+       return roleBinding
+}
+
+func newSubmarineStorageServiceAccount(submarine *v1alpha1.Submarine) 
*corev1.ServiceAccount {
+       serviceAccount, err := ParseServiceAccountYaml(storageRbacYamlPath)
+       if err != nil {
+               klog.Info("[Error] ParseServiceAccountYaml", err)
+       }
+
+       serviceAccount.ObjectMeta.OwnerReferences = []metav1.OwnerReference{
+               *metav1.NewControllerRef(submarine, 
v1alpha1.SchemeGroupVersion.WithKind("Submarine")),
+       }
+
+       return serviceAccount
+}
+
+// createSubmarineStorageRBAC is a function to create RBAC for 
submarine-database and submarine-minio which will be binded on service account: 
submarine-storage.
+// Reference: 
https://github.com/apache/submarine/blob/master/submarine-cloud-v2/artifacts/submarine/submarine-storage-rbac.yaml
+func (c *Controller) createSubmarineStorageRBAC(submarine *v1alpha1.Submarine) 
error {
+       klog.Info("[createSubmarineStorageRBAC]")
+
+       // Step1: Create ServiceAccount
+       serviceaccount, err := 
c.serviceaccountLister.ServiceAccounts(submarine.Namespace).Get(storageName)
+       // If the resource doesn't exist, we'll create it
+       if errors.IsNotFound(err) {
+               serviceaccount, err = 
c.kubeclientset.CoreV1().ServiceAccounts(submarine.Namespace).Create(context.TODO(),
 newSubmarineStorageServiceAccount(submarine), metav1.CreateOptions{})
+               klog.Info("     Create ServiceAccount: ", serviceaccount.Name)
+       }
+
+       // Step2: Pod Security Policy if needed
+       if c.createPodSecurityPolicy {
+               // Step2.1: Create Role
+               role, err := 
c.roleLister.Roles(submarine.Namespace).Get(storageName)
+               // If the resource doesn't exist, we'll create it
+               if errors.IsNotFound(err) {
+                       role, err = 
c.kubeclientset.RbacV1().Roles(submarine.Namespace).Create(context.TODO(), 
newSubmarineStorageRole(c, submarine), metav1.CreateOptions{})
+                       klog.Info("     Create Role: ", role.Name)
+               }
+
+               // If an error occurs during Get/Create, we'll requeue the item 
so we can
+               // attempt processing again later. This could have been caused 
by a
+               // temporary network failure, or any other transient reason.
+               if err != nil {
+                       return err
+               }
+
+               if !metav1.IsControlledBy(role, submarine) {
+                       msg := fmt.Sprintf(MessageResourceExists, role.Name)
+                       c.recorder.Event(submarine, corev1.EventTypeWarning, 
ErrResourceExists, msg)
+                       return fmt.Errorf(msg)
+               }
+
+               // Step2.2: Create Role Binding
+               rolebinding, rolebinding_err := 
c.rolebindingLister.RoleBindings(submarine.Namespace).Get(storageName)
+               // If the resource doesn't exist, we'll create it
+               if errors.IsNotFound(rolebinding_err) {
+                       rolebinding, rolebinding_err = 
c.kubeclientset.RbacV1().RoleBindings(submarine.Namespace).Create(context.TODO(),
 newSubmarineStorageRoleBinding(submarine), metav1.CreateOptions{})
+                       klog.Info("     Create RoleBinding: ", rolebinding.Name)
+               }
+
+               // If an error occurs during Get/Create, we'll requeue the item 
so we can
+               // attempt processing again later. This could have been caused 
by a
+               // temporary network failure, or any other transient reason.
+               if rolebinding_err != nil {
+                       return rolebinding_err
+               }
+
+               if !metav1.IsControlledBy(rolebinding, submarine) {
+                       msg := fmt.Sprintf(MessageResourceExists, 
rolebinding.Name)
+                       c.recorder.Event(submarine, corev1.EventTypeWarning, 
ErrResourceExists, msg)
+                       return fmt.Errorf(msg)
+               }
+       }
+
+       return nil
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@submarine.apache.org
For additional commands, e-mail: dev-h...@submarine.apache.org

Reply via email to