确认在OpenShift上无法正常运行监听TCP80端口的容器
目标
OpenShift 默认情况下不允许运行监听端口80的容器(我有点觉得这是指1023以下的众所周知的端口),我尝试去谷歌了一下,但是没有找到相关信息(找不到),所以我将再次确认。
使用过的文件和文件夹
使用从以下存储库中构建的内容
确认事情不可动的实验
创建实验用容器
请构建以下 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
建立一个项目。
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
$
查看日志。权限被拒绝。
$ 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中的操作
我們的目標是讓另一個端口進行監聽,但在運行時提供合適的安全上下文約束(Security Context Contrain)來進行測試。
將權限授予項目的管理員是集群管理員的工作,因此我們將使用具有cluster-admin權限的用戶進行操作。
Pod的权限与启动Pod的Service Account相关联。如果不做任何操作,默认使用名为”default”的Service Account运行。
首先,创建一个新的服务帐户来运行此 Pod。
用 cluster-admin 用户登录。
oc login https://api.f5cluster.m51o.p1.openshiftapps.com:6443 -u cluster-admin -p xxxxxxx
将当前工程切换到testp项目中。
oc project testp
创建一个名为 testsa 的服务账户。
oc create sa testsa
给服务账户分配 SCC 的任意权限。
$ 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
$
在项目管理用户上的操作
从这里开始,不要使用 cluster-admin 而是使用项目的管理用户(即项目创建者)进行操作。
以项目创建者身份登录。
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
$
将在部署中创建的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,这样可以减少后续的麻烦。
限制-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)。
这个受限制的v2版本是OpenShift的默认版本,所以我以为无需做任何操作就可以启动一个监听端口80的Pod。但是由于下面的Kubernetes问题,似乎无法直接运行。
中身一看就知道经历了很长时间,所以感觉不会很容易解决…
如果想要允许 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"]
<省略>