目的
OpenShift は標準では、Port 80 を Listen するコンテナを動かす事は許可してなかったはず(どうもこれは 1023番以下の well known port の事のような気がする) ...と思ってググってみたものの情報が見つからなかった(見つけられなかった) ので、あらためて確認してみる。
使用したファイル類
以下のレポジトリからビルドしたものを使用
実験 (動かない事の確認)
実験用コンテナの作成
以下の Dockerfile をビルド
# FROM registry.access.redhat.com/ubi8/ubi:latest
FROM redhat/ubi8
MAINTAINER "yuhkih"
RUN dnf install -y nginx
COPY index.html /usr/share/nginx/html/index.html
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
CMD ["-g","daemon off;"]
ENTRYPOINT ["nginx"]
ビルド
docker build . -t yuhkih/nginx-port80:latest
Docker Hub にプッシュ
docker push yuhkih/nginx-port80
以上で実験用のコンテナの準備は完了。
OpenShift の作業
OpenShift の新しいプロジェクトを作成
一般ユーザーでログイン。
oc login https://api.f5cluster.m51o.p1.openshiftapps.com:6443 -u yuhkih -p xxxxxxx
projectを作成。
oc new-project testp
コンテナを oc new-app
でデプロイ
oc new-app --image=docker.io/yuhkih/nginx-port80 -l=app=test
Pod がエラーになっている。
$ oc get pods
NAME READY STATUS RESTARTS AGE
nginx-port80-78f75798bc-qjftq 0/1 CrashLoopBackOff 7 (5m2s ago) 15m
$
Logを確認。 Permission Denied
になっている。
$ oc logs nginx-port80-78f75798bc-qjftq
2023/06/26 02:43:10 [emerg] 1#0: bind() to 0.0.0.0:80 failed (13: Permission denied)
nginx: [emerg] bind() to 0.0.0.0:80 failed (13: Permission denied)
$
権限を与えて動かしてみる
cluster-admin での作業
本筋は別の Port を Listen させる事だが、適当なSCC (Security Context Contrain)
を与えて動かしてみる。
project
の管理者に権限を与えるのは、クラスター
の管理者の仕事なので cluster-admin
の権限のユーザーで作業を行う。
Pod
の権限は Pod
を起動する Serivce Account
に紐付く。何もしない場合は default
という Service Account
で動いている。
まず、このPod
を動かすための新しいService Account
を作成する。
cluster-admin
ユーザーでログイン。
oc login https://api.f5cluster.m51o.p1.openshiftapps.com:6443 -u cluster-admin -p xxxxxxx
testp
projectに移動
oc project testp
testsa
という Service Account を作成する
oc create sa testsa
Service Account
に SCC
の anyuid
を与えてみる。
$ oc adm policy add-scc-to-user anyuid -z testsa
clusterrole.rbac.authorization.k8s.io/system:openshift:scc:anyuid added: "saport80"
$
SCC
と SA
の紐付は clusterrolebindings
リソースに記載される。わかりにくい。
$ oc describe clusterrolebindings system:openshift:scc:anyuid
Name: system:openshift:scc:anyuid
Labels: <none>
Annotations: <none>
Role:
Kind: ClusterRole
Name: system:openshift:scc:anyuid
Subjects:
Kind Name Namespace
---- ---- ---------
ServiceAccount testsa testp
$
projectの管理ユーザーでの作業
ここからは cluster-admin
ではなく、project
の管理ユーザー (project
の作成者) で作業を行う。
project
の作成者でログイン。
oc login https://api.f5cluster.m51o.p1.openshiftapps.com:6443 -u yuhkih -p xxxxxxx
Deployment
の名前を確認。(oc new-app
で以下の Deployment が自動で作られている。便利。)
$ oc get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-port80 0/1 1 0 22m
$
Deployment
に作成した SA
の saport80
を紐付ける。
oc set serviceaccount deployment nginx-port80 saport80
コンテナが起動したのを確認。anyuid
で起動させる事ができた。
$ oc get pods
NAME READY STATUS RESTARTS AGE
nginx-port80-54746447ff-n4k5t 0/1 ContainerCreating 0 9s
nginx-port80-78f75798bc-qjftq 0/1 CrashLoopBackOff 11 (113s ago) 32m
$ oc get pods
NAME READY STATUS RESTARTS AGE
nginx-port80-54746447ff-n4k5t 1/1 Running 0 32s
$
本筋はコンテナで公開するポートを変更しておく事。
コンテナレベルで変更しても公開するポートは 80/443 にできるし、後々のトラブルも減る。
restricted-v2
SCC は、現在 14種類ある。
oc get scc
NAME PRIV CAPS SELINUX RUNASUSER FSGROUP SUPGROUP PRIORITY READONLYROOTFS VOLUMES
anyuid false <no value> MustRunAs RunAsAny RunAsAny RunAsAny 10 false ["configMap","csi","downwardAPI","emptyDir","ephemeral","persistentVolumeClaim","projected","secret"]
hostaccess false <no value> MustRunAs MustRunAsRange MustRunAs RunAsAny <no value> false ["configMap","csi","downwardAPI","emptyDir","ephemeral","hostPath","persistentVolumeClaim","projected","secret"]
hostmount-anyuid false <no value> MustRunAs RunAsAny RunAsAny RunAsAny <no value> false ["configMap","csi","downwardAPI","emptyDir","ephemeral","hostPath","nfs","persistentVolumeClaim","projected","secret"]
hostnetwork false <no value> MustRunAs MustRunAsRange MustRunAs MustRunAs <no value> false ["configMap","csi","downwardAPI","emptyDir","ephemeral","persistentVolumeClaim","projected","secret"]
hostnetwork-v2 false ["NET_BIND_SERVICE"] MustRunAs MustRunAsRange MustRunAs MustRunAs <no value> false ["configMap","csi","downwardAPI","emptyDir","ephemeral","persistentVolumeClaim","projected","secret"]
machine-api-termination-handler false <no value> MustRunAs RunAsAny MustRunAs MustRunAs <no value> false ["downwardAPI","hostPath"]
node-exporter true <no value> RunAsAny RunAsAny RunAsAny RunAsAny <no value> false ["*"]
nonroot false <no value> MustRunAs MustRunAsNonRoot RunAsAny RunAsAny <no value> false ["configMap","csi","downwardAPI","emptyDir","ephemeral","persistentVolumeClaim","projected","secret"]
nonroot-v2 false ["NET_BIND_SERVICE"] MustRunAs MustRunAsNonRoot RunAsAny RunAsAny <no value> false ["configMap","csi","downwardAPI","emptyDir","ephemeral","persistentVolumeClaim","projected","secret"]
pcap-dedicated-admins false ["NET_ADMIN","NET_RAW"] RunAsAny RunAsAny RunAsAny RunAsAny <no value> false ["awsElasticBlockStore","azureDisk","azureFile","cephFS","cinder","configMap","csi","downwardAPI","emptyDir","ephemeral","fc","flexVolume","flocker","gcePersistentDisk","gitRepo","glusterfs","iscsi","nfs","persistentVolumeClaim","photonPersistentDisk","portworxVolume","projected","quobyte","rbd","scaleIO","secret","storageOS","vsphere"]
privileged true ["*"] RunAsAny RunAsAny RunAsAny RunAsAny <no value> false ["*"]
restricted false <no value> MustRunAs MustRunAsRange MustRunAs RunAsAny <no value> false ["configMap","csi","downwardAPI","emptyDir","ephemeral","persistentVolumeClaim","projected","secret"]
restricted-v2 false ["NET_BIND_SERVICE"] MustRunAs MustRunAsRange MustRunAs RunAsAny <no value> false ["configMap","csi","downwardAPI","emptyDir","ephemeral","persistentVolumeClaim","projected","secret"]
splunkforwarder true ["*"] RunAsAny RunAsAny RunAsAny RunAsAny <no value> false ["*"]
$
# 全部で 14種類ある
$ oc get scc | grep -v NAME | wc -l
14
$
良く見ると restricted-v2
では、 NET_BIND_SERVICE
が Capability として追加されている。
これの restricted-v2
は、OpenShift のデフォルトなので、何もしなくても Port 80 を LISTEN する Pod を起動できたのでは?と思ったのですが、以下の Kubernetes の issue があるため、そのままでは動作しないそう。
中身を見ると長い経緯があるため、簡単には解決しないような気が...
NET_BIND_SERVICE
を許可した動作をさせたい場合は、spec.containers.securityContext.capabilities.add
等を使って Deployment に定義する事で動作させることができた。
<省略>
app: test
deployment: nginx-port80
spec:
containers:
- image: docker.io/yuhkih/nginx-port80
imagePullPolicy: IfNotPresent
name: nginx-port80
ports:
- containerPort: 80
protocol: TCP
restartPolicy: Always
schedulerName: default-scheduler
securityContext:
capabilities:
add: ["NET_BIND_SERVICE"]
<省略>