dongjoon-hyun commented on code in PR #783:
URL: 
https://github.com/apache/spark-kubernetes-operator/pull/783#discussion_r3714942238


##########
build-tools/helm/spark-kubernetes-operator/templates/tests/test-rbac.yaml:
##########
@@ -48,17 +95,29 @@ metadata:
     {{- include "spark-operator.commonLabels" . | nindent 4 }}
   annotations:
     "helm.sh/hook": test
-    "helm.sh/hook-delete-policy": 
before-hook-creation,hook-succeeded,hook-failed
+    "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
 spec:
   containers:
     - name: kubectl
       image: bitnamisecure/kubectl:latest
-      command: ['bash', '-c' ]
-      args: [
-        'kubectl auth can-i create pods -n {{ .Release.Namespace }}',
-        'kubectl auth can-i create configmaps -n {{ .Release.Namespace }}',
-        'kubectl auth can-i create services -n {{ .Release.Namespace }}',
-        'kubectl auth can-i create persistentvolumeclaims -n {{ 
.Release.Namespace }}'
-      ]
+      command: ['bash', '-c']
+      args:
+        - |
+          set -ex
+
+          kubectl auth can-i watch  pods --namespace={{ .Release.Namespace }}
+          kubectl auth can-i create pods --namespace={{ .Release.Namespace }}
+          kubectl auth can-i watch  services --namespace={{ .Release.Namespace 
}}
+          kubectl auth can-i create services --namespace={{ .Release.Namespace 
}}
+          kubectl auth can-i watch  configmaps --namespace={{ 
.Release.Namespace }}
+          kubectl auth can-i create configmaps --namespace={{ 
.Release.Namespace }}
+          kubectl auth can-i watch  persistentvolumeclaims --namespace={{ 
.Release.Namespace }}
+          kubectl auth can-i create persistentvolumeclaims --namespace={{ 
.Release.Namespace }}
+          kubectl auth can-i watch  statefulsets.apps --namespace={{ 
.Release.Namespace }}
+          kubectl auth can-i create statefulsets.apps --namespace={{ 
.Release.Namespace }}
+
+          # Spark workloads must not reach beyond their own namespace.
+          ! kubectl auth can-i create clusterroles.rbac.authorization.k8s.io
+          ! kubectl auth can-i '*' '*' --all-namespaces

Review Comment:
   Same issue as above: under `set -e` a `!`-prefixed command that fails does 
not stop the script, so the `clusterroles` assertion here is never enforced.
   
   ```suggestion
             # Spark workloads must not reach beyond their own namespace. `set 
-e`
             # ignores a failing `!` pipeline, so assert each denial explicitly.
             if kubectl auth can-i create 
clusterroles.rbac.authorization.k8s.io; then exit 1; fi
             if kubectl auth can-i '*' '*' --all-namespaces; then exit 1; fi
   ```



##########
build-tools/helm/spark-kubernetes-operator/templates/tests/test-rbac.yaml:
##########
@@ -21,21 +21,68 @@ metadata:
     {{- include "spark-operator.commonLabels" . | nindent 4 }}
   annotations:
     "helm.sh/hook": test
-    "helm.sh/hook-delete-policy": 
before-hook-creation,hook-succeeded,hook-failed
+    # Keep a failed pod so its log can be read; a passing one is cleaned up.
+    "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
 spec:
   containers:
     - name: kubectl
       image: bitnamisecure/kubectl:latest
-      command: ['bash', '-c' ]
-      args: [
-        'kubectl auth can-i list sparkapplications --all-namespaces',
-        'kubectl auth can-i list sparkclusters --all-namespaces',
-        'kubectl auth can-i create pods --all-namespaces',
-        'kubectl auth can-i create services --all-namespaces',
-        'kubectl auth can-i create configmaps --all-namespaces',
-        'kubectl auth can-i create persistentvolumeclaims',
-        'kubectl auth can-i create events --all-namespaces'
-      ]
+      command: ['bash', '-c']
+      args:
+        - |
+          # Every assertion must live in this one script: `bash -c` runs only 
its
+          # first operand and turns the rest into positional parameters.
+          # -e fails the pod on the first "no", which is what `kubectl auth 
can-i`
+          # exits with; -x echoes each assertion into the log beside its 
answer.
+          set -ex
+
+          kubectl auth can-i watch  pods --all-namespaces
+          kubectl auth can-i create pods --all-namespaces
+          kubectl auth can-i watch  services --all-namespaces
+          kubectl auth can-i create services --all-namespaces
+          kubectl auth can-i watch  configmaps --all-namespaces
+          kubectl auth can-i create configmaps --all-namespaces
+          kubectl auth can-i watch  persistentvolumeclaims --all-namespaces
+          kubectl auth can-i create persistentvolumeclaims --all-namespaces
+          kubectl auth can-i watch  events --all-namespaces
+          kubectl auth can-i create events --all-namespaces
+          kubectl auth can-i watch  statefulsets.apps --all-namespaces
+          kubectl auth can-i create statefulsets.apps --all-namespaces
+          kubectl auth can-i watch  horizontalpodautoscalers.autoscaling 
--all-namespaces
+          kubectl auth can-i create horizontalpodautoscalers.autoscaling 
--all-namespaces
+          kubectl auth can-i watch  sparkapplications.spark.apache.org 
--all-namespaces
+          kubectl auth can-i create sparkapplications.spark.apache.org 
--all-namespaces
+          kubectl auth can-i watch  sparkclusters.spark.apache.org 
--all-namespaces
+          kubectl auth can-i create sparkclusters.spark.apache.org 
--all-namespaces
+          kubectl auth can-i watch  ingresses.networking.k8s.io 
--all-namespaces
+          kubectl auth can-i create ingresses.networking.k8s.io 
--all-namespaces
+          kubectl auth can-i watch  networkpolicies.networking.k8s.io 
--all-namespaces
+          kubectl auth can-i create networkpolicies.networking.k8s.io 
--all-namespaces
+          kubectl auth can-i watch  poddisruptionbudgets.policy 
--all-namespaces
+          kubectl auth can-i create poddisruptionbudgets.policy 
--all-namespaces
+          {{- if gt (int .Values.operatorDeployment.replicas) 1 }}
+
+          # Leases back leader election, so the rules only grant them for a
+          # replicated operator.
+          kubectl auth can-i watch  leases.coordination.k8s.io --all-namespaces
+          kubectl auth can-i create leases.coordination.k8s.io --all-namespaces
+          {{- end }}
+
+          # The Gateway API grant is unconditional, but `kubectl auth can-i`
+          # answers "no" for a resource type the cluster does not serve, so 
only
+          # assert it where the CRDs are installed.
+          if kubectl api-resources --api-group=gateway.networking.k8s.io 
--no-headers -o name | grep -q httproutes; then
+            kubectl auth can-i watch  httproutes.gateway.networking.k8s.io 
--all-namespaces
+            kubectl auth can-i create httproutes.gateway.networking.k8s.io 
--all-namespaces
+            kubectl auth can-i watch  grpcroutes.gateway.networking.k8s.io 
--all-namespaces
+            kubectl auth can-i create grpcroutes.gateway.networking.k8s.io 
--all-namespaces
+          fi
+
+          # The operator must not be cluster-admin. These also prove the suite 
is
+          # able to observe a denial at all.
+          ! kubectl auth can-i create clusterroles.rbac.authorization.k8s.io
+          ! kubectl auth can-i delete nodes
+          ! kubectl auth can-i '*' '*' --all-namespaces

Review Comment:
   `set -e` does not fire on a pipeline preceded by `!` (POSIX/bash: "the shell 
does not exit if the failed command is part of a pipeline preceded by the `!` 
reserved word"). So if the SA *can* create clusterroles or delete nodes, these 
two lines return 1 but the script keeps going — only the last line is enforced, 
and only because its status happens to be the script's exit status. That's the 
same "assertion that never fails" class of bug this PR is fixing.
   
   An `if ...; then exit 1; fi` makes each denial mandatory. (Note `can-i X && 
exit 1` doesn't work either: on a denial the list itself exits 1, which would 
fail the pod when it's the last command.)
   
   ```suggestion
             # able to observe a denial at all. `set -e` ignores a failing `!`
             # pipeline, so each denial must be asserted with an explicit exit.
             if kubectl auth can-i create 
clusterroles.rbac.authorization.k8s.io; then exit 1; fi
             if kubectl auth can-i delete nodes; then exit 1; fi
             if kubectl auth can-i '*' '*' --all-namespaces; then exit 1; fi
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to