使用 Secret 安全分發憑證

本頁面演示如何安全地將敏感資料(例如密碼和加密金鑰)注入 Pod 中。

準備工作

你需要擁有一個 Kubernetes 叢集,並且 kubectl 命令列工具已配置為與你的叢集通訊。 建議在至少有兩個節點(不作為控制平面主機)的叢集上執行本教程。 如果你還沒有叢集,可以使用 minikube 建立一個,或者使用這些 Kubernetes 遊樂場之一

將你的 Secret 資料轉換為 Base64 格式

假設你有兩段 Secret 資料:使用者名稱 my-app 和密碼 39528$vdg7Jb。 首先,使用 Base64 編碼工具將你的使用者名稱和密碼轉換為 Base64 格式。 以下是使用常用 Base64 程式的示例

echo -n 'my-app' | base64
echo -n '39528$vdg7Jb' | base64

輸出顯示你的使用者名稱的 Base64 編碼為 bXktYXBw,密碼的 Base64 編碼為 Mzk1MjgkdmRnN0pi

建立 Secret

以下是你可用於建立包含使用者名稱和密碼的 Secret 的配置檔案

apiVersion: v1
kind: Secret
metadata:
  name: test-secret
data:
  username: bXktYXBw
  password: Mzk1MjgkdmRnN0pi
  1. 建立 Secret

    kubectl apply -f https://k8s.io/examples/pods/inject/secret.yaml
    
  2. 檢視 Secret 的相關資訊

    kubectl get secret test-secret
    

    輸出

    NAME          TYPE      DATA      AGE
    test-secret   Opaque    2         1m
    
  3. 檢視 Secret 的更詳細資訊

    kubectl describe secret test-secret
    

    輸出

    Name:       test-secret
    Namespace:  default
    Labels:     <none>
    Annotations:    <none>
    
    Type:   Opaque
    
    Data
    ====
    password:   13 bytes
    username:   7 bytes
    

使用 kubectl 直接建立 Secret

如果你想跳過 Base64 編碼步驟,可以使用 kubectl create secret 命令建立相同的 Secret。 例如

kubectl create secret generic test-secret --from-literal='username=my-app' --from-literal='password=39528$vdg7Jb'

這更方便。前面展示的詳細方法明確地展示了每個步驟的發生過程。

建立一個 Pod,透過卷訪問 Secret 資料

以下是你可用於建立 Pod 的配置檔案

apiVersion: v1
kind: Pod
metadata:
  name: secret-test-pod
spec:
  containers:
    - name: test-container
      image: nginx
      volumeMounts:
        # name must match the volume name below
        - name: secret-volume
          mountPath: /etc/secret-volume
          readOnly: true
  # The secret data is exposed to Containers in the Pod through a Volume.
  volumes:
    - name: secret-volume
      secret:
        secretName: test-secret
  1. 建立 Pod

    kubectl apply -f https://k8s.io/examples/pods/inject/secret-pod.yaml
    
  2. 驗證你的 Pod 是否正在執行

    kubectl get pod secret-test-pod
    

    輸出

    NAME              READY     STATUS    RESTARTS   AGE
    secret-test-pod   1/1       Running   0          42m
    
  3. 進入你的 Pod 中執行的容器的 Shell

    kubectl exec -i -t secret-test-pod -- /bin/bash
    
  4. Secret 資料透過掛載在 /etc/secret-volume 下的卷暴露給容器。

    在你的 Shell 中,列出 /etc/secret-volume 目錄中的檔案

    # Run this in the shell inside the container
    ls /etc/secret-volume
    

    輸出顯示兩個檔案,每個 Secret 資料對應一個

    password username
    
  5. 在你的 Shell 中,顯示 usernamepassword 檔案的內容

    # Run this in the shell inside the container
    echo "$( cat /etc/secret-volume/username )"
    echo "$( cat /etc/secret-volume/password )"
    

    輸出是你的使用者名稱和密碼

    my-app
    39528$vdg7Jb
    

修改你的映象或命令列,以便程式在 mountPath 目錄中查詢檔案。Secret data 對映中的每個鍵都成為此目錄中的檔名。

將 Secret 鍵對映到特定的檔案路徑

你還可以控制卷內 Secret 鍵對映到的路徑。使用 .spec.volumes[].secret.items 欄位來更改每個鍵的目標路徑

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: mypod
    image: redis
    volumeMounts:
    - name: foo
      mountPath: "/etc/foo"
      readOnly: true
  volumes:
  - name: foo
    secret:
      secretName: mysecret
      items:
      - key: username
        path: my-group/my-username

當你部署此 Pod 時,會發生以下情況

  • mysecret 中的 username 鍵在容器中可透過路徑 /etc/foo/my-group/my-username 訪問,而不是 /etc/foo/username
  • 該 Secret 物件中的 password 鍵未對映。

如果你使用 .spec.volumes[].secret.items 顯式列出鍵,請考慮以下事項

  • 只有在 items 中指定的鍵才會被對映。
  • 要使用 Secret 中的所有鍵,必須在 items 欄位中列出所有鍵。
  • 所有列出的鍵都必須存在於相應的 Secret 中。否則,卷將不會被建立。

設定 Secret 鍵的 POSIX 許可權

你可以為一個 Secret 鍵設定 POSIX 檔案訪問許可權位。如果你不指定任何許可權,預設使用 0644。你還可以為整個 Secret 卷設定預設的 POSIX 檔案模式,如果需要,可以針對每個鍵進行覆蓋。

例如,你可以像這樣指定預設模式

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: mypod
    image: redis
    volumeMounts:
    - name: foo
      mountPath: "/etc/foo"
  volumes:
  - name: foo
    secret:
      secretName: mysecret
      defaultMode: 0400

Secret 掛載在 /etc/foo;Secret 卷掛載建立的所有檔案都具有許可權 0400

使用 Secret 資料定義容器環境變數

你可以在容器中將 Secret 中的資料作為環境變數使用。

如果容器已經在一個環境變數中使用了 Secret,那麼除非容器重新啟動,否則 Secret 的更新將不會被容器看到。有第三方解決方案可以在 Secret 更改時觸發重新啟動。

使用單個 Secret 中的資料定義容器環境變數

  • 將環境變數定義為 Secret 中的鍵值對

    kubectl create secret generic backend-user --from-literal=backend-username='backend-admin'
    
  • 將 Secret 中定義的 backend-username 值分配給 Pod 規範中的 SECRET_USERNAME 環境變數。

    apiVersion: v1
    kind: Pod
    metadata:
      name: env-single-secret
    spec:
      containers:
      - name: envars-test-container
        image: nginx
        env:
        - name: SECRET_USERNAME
          valueFrom:
            secretKeyRef:
              name: backend-user
              key: backend-username
    
  • 建立 Pod

    kubectl create -f https://k8s.io/examples/pods/inject/pod-single-secret-env-variable.yaml
    
  • 在你的 Shell 中,顯示 SECRET_USERNAME 容器環境變數的內容。

    kubectl exec -i -t env-single-secret -- /bin/sh -c 'echo $SECRET_USERNAME'
    

    輸出類似於:

    backend-admin
    

使用多個 Secrets 中的資料定義容器環境變數

  • 與前面的例子一樣,首先建立 Secrets。

    kubectl create secret generic backend-user --from-literal=backend-username='backend-admin'
    kubectl create secret generic db-user --from-literal=db-username='db-admin'
    
  • 在 Pod 規範中定義環境變數。

    apiVersion: v1
    kind: Pod
    metadata:
      name: envvars-multiple-secrets
    spec:
      containers:
      - name: envars-test-container
        image: nginx
        env:
        - name: BACKEND_USERNAME
          valueFrom:
            secretKeyRef:
              name: backend-user
              key: backend-username
        - name: DB_USERNAME
          valueFrom:
            secretKeyRef:
              name: db-user
              key: db-username
    
  • 建立 Pod

    kubectl create -f https://k8s.io/examples/pods/inject/pod-multiple-secret-env-variable.yaml
    
  • 在你的 Shell 中,顯示容器環境變數。

    kubectl exec -i -t envvars-multiple-secrets -- /bin/sh -c 'env | grep _USERNAME'
    

    輸出類似於:

    DB_USERNAME=db-admin
    BACKEND_USERNAME=backend-admin
    

將 Secret 中的所有鍵值對配置為容器環境變數

  • 建立包含多個鍵值對的 Secret

    kubectl create secret generic test-secret --from-literal=username='my-app' --from-literal=password='39528$vdg7Jb'
    
  • 使用 envFrom 將 Secret 的所有資料定義為容器環境變數。Secret 中的鍵成為 Pod 中的環境變數名稱。

    apiVersion: v1
    kind: Pod
    metadata:
      name: envfrom-secret
    spec:
      containers:
      - name: envars-test-container
        image: nginx
        envFrom:
        - secretRef:
            name: test-secret
    
  • 建立 Pod

    kubectl create -f https://k8s.io/examples/pods/inject/pod-secret-envFrom.yaml
    
  • 在你的 Shell 中,顯示 usernamepassword 容器環境變數。

    kubectl exec -i -t envfrom-secret -- /bin/sh -c 'echo "username: $username\npassword: $password\n"'
    

    輸出類似於:

    username: my-app
    password: 39528$vdg7Jb
    

示例:使用 Secrets 為 Pod 提供生產/測試憑據

此示例演示了一個 Pod 使用包含生產憑據的 Secret,另一個 Pod 使用包含測試環境憑據的 Secret。

  1. 為生產環境憑據建立 Secret

    kubectl create secret generic prod-db-secret --from-literal=username=produser --from-literal=password=Y4nys7f11
    

    輸出類似於:

    secret "prod-db-secret" created
    
  2. 為測試環境憑據建立 Secret。

    kubectl create secret generic test-db-secret --from-literal=username=testuser --from-literal=password=iluvtests
    

    輸出類似於:

    secret "test-db-secret" created
    
  3. 建立 Pod 清單

    cat <<EOF > pod.yaml
    apiVersion: v1
    kind: List
    items:
    - kind: Pod
      apiVersion: v1
      metadata:
        name: prod-db-client-pod
        labels:
          name: prod-db-client
      spec:
        volumes:
        - name: secret-volume
          secret:
            secretName: prod-db-secret
        containers:
        - name: db-client-container
          image: myClientImage
          volumeMounts:
          - name: secret-volume
            readOnly: true
            mountPath: "/etc/secret-volume"
    - kind: Pod
      apiVersion: v1
      metadata:
        name: test-db-client-pod
        labels:
          name: test-db-client
      spec:
        volumes:
        - name: secret-volume
          secret:
            secretName: test-db-secret
        containers:
        - name: db-client-container
          image: myClientImage
          volumeMounts:
          - name: secret-volume
            readOnly: true
            mountPath: "/etc/secret-volume"
    EOF
    
  4. 透過執行以下命令將所有這些物件應用於 API 伺服器

    kubectl create -f pod.yaml
    

兩個容器的檔案系統上都將存在以下檔案,其中包含每個容器環境的值

/etc/secret-volume/username
/etc/secret-volume/password

你可以透過使用兩個 Service Account 進一步簡化基礎 Pod 規範

  1. prod-user 使用 prod-db-secret
  2. test-user 使用 test-db-secret

Pod 規範縮短為

apiVersion: v1
kind: Pod
metadata:
  name: prod-db-client-pod
  labels:
    name: prod-db-client
spec:
  serviceAccount: prod-db-client
  containers:
  - name: db-client-container
    image: myClientImage

參考

下一步

  • 瞭解更多關於 Secrets 的資訊。
  • 瞭解
最後修改於 2023 年 8 月 24 日下午 6:38 PST:使用 code_sample 簡碼代替 code 簡碼 (e8b136c3b3)