Taskを実行するPodのユーザーがrootだったり非rootだったりとまちまちだったため、Security Context Constraints(SCC)の復習も兼ねて確認してみました。
まだまだ勉強中の身のため、おかしな点があればぜひツッコミお願い致します。
背景
WorkspaceをTask間で共有する際にユーザーがいい加減だと、例えば
- 何かのリポジトリをcloneしてWorkspaceに置く
- 次Taskでそのリポジトリに何か書き込みをする
といった状況で、Permission Deniedが頻出するようになります。
じゃあ一体どのユーザーでWorkspaceにアクセスしているんだ…?と気になったことが発端です。
検証環境
Red Hat OpenShift on IBM Cloud
OCPバージョンは4.7
検証内容
alpine:3.14
およびquay.io/ibmgaragecloud/cli-tools:v14
をベースイメージとしたTaskをそれぞれ作成し、コマンドid
を実行します。
なぜcli-tools
というイメージも確認するかというと、DockerfileでUIDの指定があるからです。Dockerfileはこちら
検証手順
- 検証用のプロジェクト作成。
yuki@LAPTOP-R0PDAE4U:~$ oc new-project check-uid
Now using project "check-uid" on server "https://c100-e.jp-tok.containers.cloud.ibm.com:30812".
You can add applications to this project with the 'new-app' command. For example, try:
oc new-app rails-postgresql-example
to build a new example application in Ruby. Or use kubectl to deploy a simple Kubernetes application:
kubectl create deployment hello-node --image=k8s.gcr.io/serve_hostname
-
alpine
およびquay.io/ibmgaragecloud/cli-tools:v14
をベースイメージとしたTask作成。どちらともid
を実行するだけ。
yuki@LAPTOP-R0PDAE4U:~$ oc apply -f - <<EOF
> apiVersion: tekton.dev/v1beta1
> kind: Task
> metadata:
> name: alpine
> spec:
> steps:
> - image: alpine:3.14
> name: check-user
> script: |
> id
> EOF
task.tekton.dev/alpine created
yuki@LAPTOP-R0PDAE4U:~$ oc apply -f - <<EOF
> apiVersion: tekton.dev/v1beta1
> kind: Task
> metadata:
> name: cli-tools
> spec:
> steps:
> - image: quay.io/ibmgaragecloud/cli-tools:v14
> name: check-user
> script: |
> id
> EOF
task.tekton.dev/cli-tools created
- Pipeline作成。上記2つのTaskを順に実行するだけ。
yuki@LAPTOP-R0PDAE4U:~$ oc apply -f - <<EOF
> apiVersion: tekton.dev/v1beta1
> kind: Pipeline
> metadata:
> name: check-user
> spec:
> tasks:
> - name: alpine
> taskRef:
> name: alpine
> kind: Task
> - name: cli-tools
> taskRef:
> name: cli-tools
> kind: Task
> runAfter:
> - alpine
> EOF
pipeline.tekton.dev/check-user created
- Pipeline起動。
yuki@LAPTOP-R0PDAE4U:~$ tkn pipeline start check-user
PipelineRun started: check-user-run-ltcg7
In order to track the PipelineRun progress run:
tkn pipelinerun logs check-user-run-ltcg7 -f -n check-uid
- 以下に記載したPipelineRunのログを確認すると、
alpine
ではuid=0、cli-tools
(DockerfileでUIDの指定がある)ではuid=10000になっていることが分かります。
yuki@LAPTOP-R0PDAE4U:~$ tkn pipelinerun logs check-user-run-ltcg7 -f -n check-uid
[alpine : check-user] + id
[alpine : check-user] uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video),1000870000
[cli-tools : check-user] + id
[cli-tools : check-user] uid=10000(devops) gid=0(root) groups=1000(sudo),1000870000
どうやら、実行ユーザーがイメージ内で指定されていないとrootユーザーで実行される様子。
OpenShiftはデフォルトだとランダムなUIDを割り振るので、なぜrootユーザーになるのか考えてみます。
なぜrootユーザーになるのか?
Taskを実行するPodのServiceAccount
コンテナを実行する権限は、SCCをServiceAccount(SA)に付与し、そのSAをPodで使うようにすることでコントロールできます。
ということで、まずTaskを実行したPodの中身を覗いてみます。
yuki@LAPTOP-R0PDAE4U:~$ oc get po check-user-run-ltcg7-alpine-q6ddt-pod-px8b8 -o yaml | grep -i serviceaccount
(略)
serviceAccount: pipeline
serviceAccountName: pipeline
pipeline
というServiceAccountを使用しているようです。
ServiceAccountに紐づくSCC
このServiceAccountにどんなSCCが付与されているか確認します。
確認方法はRolebindingをまず見てみれば良さそうです。SCCを使用するRoleを定義して、それをSAにバインドすることでSCC付与となるようです。いつもoc adm policy add-scc-to-user
で付与していましたが、この動作が裏で行われているってことなんですかね。。
(参考:https://access.redhat.com/documentation/ja-jp/openshift_container_platform/4.9/html/authentication_and_authorization/role-based-access-to-ssc_configuring-internal-oauth)
pipeline
SAにedit
ClusterRoleとpipelines-scc-clusterrole
ClusterRoleがバインドされていました。
yuki@LAPTOP-R0PDAE4U:~$ oc get rolebinding -o wide
NAME ROLE AGE USERS GROUPS SERVICEACCOUNTS
(略)
edit ClusterRole/edit 7d19h check-uid/pipeline
pipelines-scc-rolebinding ClusterRole/pipelines-scc-clusterrole 7d19h check-uid/pipeline
edit
ClusterRoleは一旦置いておき、pipelines-scc-clusterrole
ClusterRoleの中身を見てみます。
yuki@LAPTOP-R0PDAE4U:~$ oc get clusterrole pipelines-scc-clusterrole -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
(略)
name: pipelines-scc-clusterrole
(略)
rules:
- apiGroups:
- security.openshift.io
resourceNames:
- pipelines-scc
resources:
- securitycontextconstraints
verbs:
- use
pipelines-scc
というSCCが出てきました。これを使用するroleがpipeline
SAにバインドされているということで、pipeline
SAにpipelines-scc
SCCが付与されていることになります。
pipeline-scc
の詳細
$ oc get scc pipelines-scc
NAME PRIV CAPS SELINUX RUNASUSER FSGROUP SUPGROUP PRIORITY READONLYROOTFS VOLUMES
pipelines-scc false <no value> MustRunAs RunAsAny MustRunAs RunAsAny 10 false ["configMap","downwardAPI","emptyDir","persistentVolumeClaim","projected","secret"]
どのユーザーでコンテナを動かしてよいか、を示しているのはRUNASUSER
です。
ここがRunAsAny
となっているため、root含めどんなユーザーでも動かせる設定になっています。
(参考:https://access.redhat.com/documentation/ja-jp/openshift_container_platform/4.9/html-single/authentication_and_authorization/index#authorization-SCC-strategies_configuring-internal-oauth )
Pod内のYAML定義を眺めてもユーザーの指定はなかったため、その場合はDockerfile内のユーザー指定がそのまま反映されるようです。
(参考:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core の「runAsUser」の項目)
runAsUser
がrunAsAny
のSCCが付与された状態で、Podの定義やDockerfile内にユーザー指定がない場合はどうやらrootになるようです(Docker上だと特に何も指定しなければrootで動くという認識はあるのですが、それらしきドキュメントが見当たらず。。)
まとめ
冒頭の
Taskを実行するPodのユーザーがrootだったり非rootだったりとまちまちだった
というのは、pipeline-scc
というSCCの力により、
- UIDの指定がどこかに(Dockerfileなど)あればそのユーザーで実行される
- どこにもなければrootで実行される
という動作によるものであると言えそうです。
Workspaceを使ってPipelineを動かすならば、実行ユーザーも意識する必要があります。
ちなみにPipelineRunで実行ユーザーを指定できるようです。
https://tekton.dev/docs/pipelines/pipelineruns/#specifying-a-pod-template
これをやっておけばPermission Deniedで怒られなくなる…はず?いつか試します。