Skip to content

antony@notes:~/kubernetes$ cat "Running-Nginx-with-Kubernetes-Restricted-Pod-Security-Standards.md"

Running Nginx with Kubernetes Restricted Pod Security Standards

2025-12-05· kubernetes

Running Nginx with Kubernetes Restricted Pod Security Standards

1. 先決條件

  • K8s 已安裝完畢
  • 請使用 kubernetes-admin 的 user 操作 K8s
  • 作業系統已安裝 podman,並且可以上網

2. 建立 Nginx App Container Image

  1. 創建並切換工作目錄

    mkdir -p "$HOME"/wulin/nginx; cd "$HOME"/wulin/nginx
  2. 撰寫 Dockerfile

    nano Dockerfile

    檔案內容:

    # 使用輕量版 Alpine 且包含 OpenTelemetry 支援的 Nginx 基礎映像
    FROM docker.io/library/nginx:1.29.3-alpine-otel
    
    # 定義參數
    ARG user=bigred
    ARG uid=1001
    ARG gid=1001
    ARG port=8080
    
    # 合併 RUN 指令以減少圖層 (Layers) 並縮小體積
    # 使用 set -e 確保任何指令失敗時停止建置
    RUN set -e && \
        # 1. 新增使用者與群組
        addgroup -g ${gid} -S ${user} && \
        adduser -u ${uid} -S -G ${user} ${user} && \
        # 2. 建立必要的暫存與 PID 目錄
        mkdir -p /var/run/nginx \
                 /var/cache/nginx/client_temp \
                 /var/cache/nginx/proxy_temp \
                 /var/cache/nginx/fastcgi_temp \
                 /var/cache/nginx/scgi_temp \
                 /var/cache/nginx/uwsgi_temp && \
        # 3. 修改設定檔
        sed -i -E "s/listen\s+80;/listen ${port};/g" /etc/nginx/conf.d/default.conf && \
        sed -i "s|/var/run/nginx.pid|/var/run/nginx/nginx.pid|g" /etc/nginx/nginx.conf && \
        # 4. 權限調整
        chown -R ${uid}:${gid} \
            /var/cache/nginx \
            /var/run/nginx \
            /var/log/nginx \
            /run && \
        # 5. 清理不必要的暫存檔 (Alpine 特性,若有安裝套件時使用)
        rm -rf /tmp/*
    
    # 定義 run 成 app container 後內定執行的使用者
    USER ${user}
    
    # 宣告對外開的 tcp port number
    EXPOSE ${port}
    
    # 定義 run 成 app container 後內定執行的啟動命令
    CMD ["nginx", "-g", "daemon off;"]
  3. 建立 App Container Image

    podman build --build-arg user=bigred \
      --build-arg uid=1001 \
      --build-arg gid=1001 \
      --build-arg port=8080 \
      --squash \
      --tag nginx:1.29.3-alpine-otel-nonroot .
  4. 執行 Nginx App Container

    podman run --name nginx \
      --detach \
      --publish 8080:8080 \
      localhost/nginx:1.29.3-alpine-otel-nonroot
  5. 檢視 App Container 運作狀態

    podman ps -a

    執行結果:

    CONTAINER ID  IMAGE                                       COMMAND               CREATED       STATUS        PORTS                   NAMES
    28bde4893f9b  localhost/nginx:1.29.3-alpine-otel-nonroot  nginx -g daemon o...  1 second ago  Up 2 seconds  0.0.0.0:8080->8080/tcp  nginx
  6. 驗證 Nginx 網站是否可以正常連接

    curl -sI localhost:8080 | head -n 1

    執行結果:

    HTTP/1.1 200 OK
  7. 登入 quay.io

    podman login quay.io
  8. 修改 Nginx Image tag

    podman tag localhost/nginx:1.29.3-alpine-otel-nonroot quay.io/hahappyman/nginx:1.29.3-alpine-otel-nonroot
  9. 將 Nginx Image 上傳到 quay.io

    podman push quay.io/hahappyman/nginx:1.29.3-alpine-otel-nonroot

3. 設定 Namespace 強制執行 Restricted Pod Security Standards (PSS)

  1. 建立 namespace

    kubectl create ns mytest
  2. 設定 Namespace 強制執行 Restricted Pod Security Standards

    kubectl label --overwrite ns mytest \
      pod-security.kubernetes.io/enforce=restricted \
      pod-security.kubernetes.io/enforce-version=v1.34
  3. 檢視是否成功

    kubectl describe ns mytest

    執行結果:

    Name:         mytest
    Labels:       kubernetes.io/metadata.name=mytest
                  pod-security.kubernetes.io/enforce=restricted
                  pod-security.kubernetes.io/enforce-version=v1.34
    Annotations:  <none>
    Status:       Active
    
    No resource quota.
    
    No LimitRange resource.

4. 將 Nginx 部署至強制執行 Restricted PSS 的 namespace

  1. 撰寫 nginx pod yaml

    nano nginx-pod.yaml

    檔案內容如下:

    apiVersion: v1
    kind: Pod
    metadata:
      name: restricted-nginx-pod
      namespace: mytest
      labels:
        app: restricted-nginx
    spec:
      containers:
      - name: restricted-nginx-container
        image: quay.io/hahappyman/nginx:1.29.3-alpine-otel-nonroot
        securityContext:
          privileged: false
          allowPrivilegeEscalation: false
          capabilities:
            drop:
            - "ALL"
          runAsNonRoot: true
          runAsUser: 1001
          seccompProfile:
            type: "RuntimeDefault"

    注意,runAsNonRoot 會用 user id 判斷 App Container 是否有透過非 root 的帳號去執行,所以當 App Container image 內定執行的使用者指定的是 user name 不是 user id,就必須要再額外設定 runAsUser 指定 uid 去執行,否則你會遇到以下錯誤訊息:

    Error: container has runAsNonRoot and image has non-numeric user (bigred), cannot verify user is non-root (pod: "restricted-nginx-pod_mytest(d40b3343-1027-48c2-9b7d-e9acac1c7524)", container: restricted-nginx-container)
  2. 部署 Nginx Pod

    kubectl apply -f nginx-pod.yaml

    執行結果:

    pod/restricted-nginx-pod created
  3. 確認 Nginx Pod 運作狀態是否正常

    kubectl -n mytest get pods -o wide

    執行結果:

    NAME                   READY   STATUS    RESTARTS   AGE   IP             NODE         NOMINATED NODE   READINESS GATES
    restricted-nginx-pod   1/1     Running   0          22s   10.244.3.113   kubeadm-w1   <none>           <none>
  4. 驗證網站是否能正常連線

    curl -sI http://10.244.3.113:8080 | head -n 1

    執行結果:

    HTTP/1.1 200 OK
  5. 在 nginx 所在的 worker node 上查詢 container user uid

    sudo crictl inspect --name restricted-nginx-container | jq '.info.runtimeSpec.process.user.uid'

    執行結果:

    1001