返回文章列表

Podman容器簽章與核心能力安全強化

本文探討如何利用 Podman 的 image trust 命令管理容器映像簽章,確保映像來源的安全性。同時,深入解析 Linux 核心能力的組態與自訂,以及與 SELinux 的整合應用,實作更精細的容器許可權控制和安全隔離。

容器技術 資安

容器安全日益受到重視,驗證映像真實性與最小許可權原則是確保容器安全的重要手段。Podman 提供 image trust 命令有效管理映像簽章,搭配適當的公鑰設定,能防止惡意或竄改過的映像執行。此外,Linux 核心能力允許更細緻的許可權控管,避免容器不必要的 root 許可權,降低安全風險。配合 SELinux 的強制存取控制機制,更能強化容器間的隔離性,提升整體系統安全性。實務上,需根據應用程式需求調整核心能力,並注意根使用者與非根使用者的差異。更進一步,整合 SELinux 可有效限制容器的行為,提供多層次的防護。

使用 Podman 管理容器簽名驗證

在容器安全領域,驗證容器映像的真實性是至關重要的。Podman 提供了 podman image trust 命令來管理和驗證容器映像的簽名。本文將介紹如何使用 Podman 的 image trust 命令來組態和管理容器映像的簽名驗證。

檢視目前的簽名驗證組態

首先,我們可以使用 podman image trust show 命令來檢視目前的簽名驗證組態:

$ podman image trust show
default accept
localhost:5000 signedBy [email protected]
http://localhost:8080 insecureAcceptAnything
http://localhost:8080

內容解密:

  • default accept:表示預設情況下,Podman 接受所有未經驗證的映像。
  • localhost:5000 signedBy [email protected]:表示從 localhost:5000 取得的映像需要由 [email protected] 簽名。
  • http://localhost:8080 insecureAcceptAnything:表示從 http://localhost:8080 取得的映像將被無條件接受,不進行簽名驗證。

組態新的簽名驗證

接下來,我們將下載 Red Hat 的公鑰並組態 UBI 映像的簽名驗證。

  1. 下載 Red Hat 公鑰

    $ sudo wget -O /etc/pki/rpm-gpg/RPM-GPG-KEY-redhat https://www.redhat.com/security/data/fd431d51.txt
    
  2. 組態 UBI 8 映像的簽名驗證

    $ sudo podman image trust set -f /etc/pki/rpm-gpg/RPM-GPG-KEY-redhat registry.access.redhat.com/ubi8
    

    內容解密:

    • 使用 podman image trust set 命令組態 registry.access.redhat.com/ubi8 映像的簽名驗證,使用指定的 Red Hat 公鑰進行驗證。

檢視更新後的組態

執行上述命令後,/etc/containers/policy.json 檔案將被更新,新增對 registry.access.redhat.com/ubi8 的簽名驗證組態:

{
  "default": [
    {
      "type": "insecureAcceptAnything"
    }
  ],
  "transports": {
    "docker": {
      "localhost:5000": [
        {
          "type": "signedBy",
          "keyType": "GPGKeys",
          "keyPath": "/tmp/pubkey.gpg"
        }
      ],
      "registry.access.redhat.com/ubi8": [
        {
          "type": "signedBy",
          "keyType": "GPGKeys",
          "keyPath": "/etc/pki/rpm-gpg/RPM-GPG-KEY-redhat"
        }
      ]
    },
    "docker-daemon": {
      "": [
        {
          "type": "insecureAcceptAnything"
        }
      ]
    }
  }
}

內容解密:

  • 新增了對 registry.access.redhat.com/ubi8 的簽名驗證組態,使用 /etc/pki/rpm-gpg/RPM-GPG-KEY-redhat 公鑰進行驗證。

組態 Red Hat sigstore

最後,我們需要組態 Red Hat sigstore 到 /etc/containers/registries.d/default.yaml 檔案中:

docker:
  registry.access.redhat.com:
    sigstore: https://access.redhat.com/webassets/docker/content/sigstore

內容解密:

  • 組態 Red Hat sigstore 的 URL,用於儲存和驗證映像簽名。

使用 Skopeo 管理簽名驗證

除了 Podman,Skopeo 也可用於管理簽名驗證。以下是使用 Skopeo 驗證映像簽名的範例:

$ skopeo copy --src-tls-verify=false docker://localhost:5000/custom_httpd containers-storage:localhost:5000/custom_httpd

內容解密:

  • 使用 Skopeo 從 localhost:5000 複製 custom_httpd 映像到本地儲存,不進行 TLS 驗證。

您也可以使用 Skopeo 簽署映像:

$ sudo GNUPGHOME=$HOME/.gnupg skopeo copy --dest-tls-verify=false --sign-by [email protected] containers-storage:localhost:5000/custom_httpd docker://localhost:5000/custom_httpd

內容解密:

  • 使用 Skopeo 簽署 custom_httpd 映像並推播到 localhost:5000,使用 [email protected] 的 GPG 金鑰進行簽署。

Linux 核心能力自訂

Linux 核心能力(Capabilities)是一種細粒度的許可權控制機制,允許對程式進行更精確的許可權管理,避免使用過於寬泛的 root 許可權。本文將探討 Linux 核心能力的基本概念、在容器中的應用,以及如何自訂容器的核心能力。

Linux 核心能力基礎

Linux 核心能力提供了一種將傳統 root 許可權細分為多個獨立能力的機制,每種能力控制著系統中特定的操作。例如:

  • CAP_MKNOD:允許使用 mknod() 系統呼叫建立特殊檔案。
  • CAP_NET_ADMIN:允許對系統網路組態進行多種特權操作,包括更改介面組態、啟用/停用混雜模式、編輯路由表等。
  • CAP_NET_RAW:允許執行緒使用原始(RAW)和封包(PACKET)通訊端,常用於像 ping 這樣的程式。
  • CAP_SYS_CHROOT:允許使用 chroot() 系統呼叫變更根目錄,並使用 setns() 系統呼叫變更掛載名稱空間。
  • CAP_DAC_OVERRIDE:允許繞過檔案讀取、寫入和執行的自主存取控制(DAC)檢查。

這些能力可以透過 setcap 命令賦予可執行檔。例如,為 /usr/bin/ping 賦予 CAP_NET_ADMINCAP_NET_RAW 能力:

$ sudo setcap 'cap_net_admin,cap_net_raw+p' /usr/bin/ping

使用 getcap 命令可以檢查檔案的能力:

$ getcap /usr/bin/ping
/usr/bin/ping cap_net_admin,cap_net_raw=p

內容解密:

  1. setcap 命令用於設定檔案的能力,+p 表示將指定的能力新增到「允許」(Permitted)集合中。
  2. getcap 命令用於檢視檔案的能力,輸出結果表明 /usr/bin/ping 具有 cap_net_admincap_net_raw 能力。

檢查行程的能力

可以透過檢查 /proc/<PID>/status 檔案來檢視行程的能力。例如,啟動一個 ping 行程後檢查其能力:

$ ping example.com > /dev/null 2>&1 &
$ grep 'Cap.*' /proc/$(pgrep ping)/status
CapInh: 0000000000000000
CapPrm: 0000000000003000
CapEff: 0000000000000000
CapBnd: 000000ffffffffff
CapAmb: 0000000000000000

使用 capsh --decode 命令可以解碼 CapPrm 欄位中的位元對映(bitmap):

$ capsh --decode=0000000000003000
0x0000000000003000=cap_net_admin,cap_net_raw

內容解密:

  1. CapPrm 表示行程的「允許」(Permitted)能力集合。
  2. 使用 capsh --decode 可以將十六進位的位元對映轉換為可讀的能力列表。

容器中的核心能力

預設情況下,Podman 使用定義在 /usr/share/containers/containers.conf 檔案中的一組 Linux 核心能力來執行容器。這些能力包括:

default_capabilities = [
"CHOWN",
"DAC_OVERRIDE",
"FOWNER",
"FSETID",
"KILL",
"NET_BIND_SERVICE",
"SETFCAP",
"SETGID",
"SETPCAP",
"SETUID",
"SYS_CHROOT"
]

可以透過以下命令驗證容器內的行程是否具備這些能力:

$ podman run -d --name cap_test docker.io/library/nginx
$ podman exec -it cap_test sh -c 'grep Cap /proc/1/status'
CapInh: 00000000800405fb
CapPrm: 00000000800405fb
CapEff: 00000000800405fb
CapBnd: 00000000800405fb
CapAmb: 0000000000000000

解碼後發現這些能力與預設組態相符。

內容解密:

  1. Podman 在執行容器時預設賦予容器內的行程一組核心能力。
  2. 可以透過檢查 /proc/1/status 檔案來確認容器內主行程的能力。

自訂容器的核心能力

可以透過兩種方式自訂容器的核心能力:靜態修改和動態調整。

  1. 靜態修改:編輯 /usr/share/containers/containers.conf 檔案,直接修改 default_capabilities 欄位。

  2. 動態調整:使用 Podman 的 --cap-add--cap-drop 選項。例如,移除容器的 CAP_DAC_OVERRIDE 能力:

    $ podman run -d --name cap_test2 --cap-drop=DAC_OVERRIDE docker.io/library/nginx
    

    檢查容器內行程的能力,可以看到 CAP_DAC_OVERRIDE 已被移除。

內容解密:

  1. --cap-drop 用於在執行容器時移除特定的核心能力。
  2. 可以透過檢查 /proc/<PID>/status 和使用 capsh --decode 命令驗證能力的變更。

容器安全強化:自訂Linux核心功能與SELinux整合應用

在容器化的環境中,強化安全性是確保系統穩固運作的關鍵。除了使用預設的安全措施,還可以透過自訂Linux核心功能(Capabilities)以及整合SELinux來進一步提升容器的安全性。

自訂Linux核心功能

Linux核心功能允許對容器的許可權進行細粒度控制。透過新增或移除特定的功能,可以在不授予容器過多許可權的情況下滿足其執行需求。

新增與移除核心功能

可以使用 --cap-add--cap-drop 選項來為容器新增或移除特定的核心功能。例如:

$ podman run -d --name cap_test3 \
--cap-drop=KILL \
--cap-drop=DAC_OVERRIDE \
--cap-add=NET_RAW \
--cap-add=NET_ADMIN \
docker.io/library/nginx

在這個例子中,容器 cap_test3 被設定為移除 KILLDAC_OVERRIDE 功能,同時新增 NET_RAWNET_ADMIN 功能。

謹慎移除預設功能

移除預設的核心功能時需要格外小心,因為某些功能對於容器的正常運作是必要的。例如,移除 CAP_CHOWN 功能可能會導致Nginx容器無法正常啟動:

$ podman run --name cap_test4 \
--cap-drop=CHOWN \
docker.io/library/nginx

輸出結果顯示Nginx程式無法更改 /var/cache/nginx/client_temp 目錄的所有權,因為 CAP_CHOWN 功能被移除。

#### 內容解密:

  • --cap-drop=CHOWN:移除 CAP_CHOWN 功能,使得Nginx程式無法更改檔案或目錄的所有權。
  • Nginx在啟動過程中需要更改某些目錄的所有權,因此移除 CAP_CHOWN 功能會導致其無法正常運作。
  • 這種錯誤通常發生在需要檔案系統操作許可權的應用程式中,例如Nginx需要管理其快取目錄。

根使用者與非根使用者的差異

並非所有核心功能都能在非根使用者(rootless)容器中生效。例如,嘗試在非根容器中新增 CAP_MKNOD 功能會被核心拒絕:

$ podman run -it --cap-add=MKNOD \
docker.io/library/busybox /bin/sh
/ # mkdir -p /test/dev
/ # mknod -m 666 /test/dev/urandom c 1 8
mknod: /test/dev/urandom: Operation not permitted

而在具有提升許可權的根使用者容器中,則可以成功新增該功能:

# podman run -it --cap-add=MKNOD \
docker.io/library/busybox /bin/sh
/ # mkdir -p /test/dev
/ # mknod -m 666 /test/dev/urandom c 1 8
/ # stat /test/dev/urandom
File: /test/dev/urandom
Size: 0 Blocks: 0 IO Block: 4096 character special file
Device: 31h/49d Inode: 530019 Links: 1 Device type: 1,8
Access: (0666/crw-rw-rw-) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2022-01-06 23:50:06.056650747 +0000
Modify: 2022-01-06 23:50:06.056650747 +0000
Change: 2022-01-06 23:50:06.056650747 +0000

#### 內容解密:

  • CAP_MKNOD 功能允許建立特殊檔案(如裝置檔案)。
  • 在非根使用者容器中,由於許可權限制,無法成功建立特殊檔案。
  • 在具有提升許可權的根使用者容器中,可以成功建立特殊檔案,並顯示其詳細資訊。

SELinux與容器的整合

SELinux(Security-Enhanced Linux)是一種強制性存取控制(MAC)機制,能夠進一步強化容器的隔離性。

SELinux的工作模式

SELinux預設工作在 Enforcing 模式下,會強制執行安全策略並阻止違規行為。也可以設定為 Permissive 模式,此時SELinux僅記錄違規行為而不阻止。

SELinux的存取控制型別

SELinux提供了多種存取控制型別,包括:

  • Type Enforcement (TE):根據程式和檔案的型別控制存取。
  • Role-Based Access Control (RBAC):根據SELinux使用者及其角色控制存取。
  • Multi-Level Security (MLS):根據敏感度等級控制存取。
  • Multi-Category Security (MCS):根據類別標籤控制存取,用於建立隔離的資源區間。

Type Enforcement的應用

在Type Enforcement中,系統檔案被標記為特定型別,而程式則被標記為特定域。SELinux根據這些標籤控制程式對檔案的存取。