---
# System prepended metadata

title: Running Nginx with Kubernetes Restricted Pod Security Standards

---

# 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"
    ```
    > <font color=red>注意，`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)
    > ```
    </font>

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
    ```

