容器安全日益受到重視,驗證映像真實性與最小許可權原則是確保容器安全的重要手段。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 映像的簽名驗證。
下載 Red Hat 公鑰:
$ sudo wget -O /etc/pki/rpm-gpg/RPM-GPG-KEY-redhat https://www.redhat.com/security/data/fd431d51.txt組態 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_ADMIN 和 CAP_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
內容解密:
setcap命令用於設定檔案的能力,+p表示將指定的能力新增到「允許」(Permitted)集合中。getcap命令用於檢視檔案的能力,輸出結果表明/usr/bin/ping具有cap_net_admin和cap_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
內容解密:
CapPrm表示行程的「允許」(Permitted)能力集合。- 使用
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
解碼後發現這些能力與預設組態相符。
內容解密:
- Podman 在執行容器時預設賦予容器內的行程一組核心能力。
- 可以透過檢查
/proc/1/status檔案來確認容器內主行程的能力。
自訂容器的核心能力
可以透過兩種方式自訂容器的核心能力:靜態修改和動態調整。
靜態修改:編輯
/usr/share/containers/containers.conf檔案,直接修改default_capabilities欄位。動態調整:使用 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已被移除。
內容解密:
--cap-drop用於在執行容器時移除特定的核心能力。- 可以透過檢查
/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 被設定為移除 KILL 和 DAC_OVERRIDE 功能,同時新增 NET_RAW 和 NET_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根據這些標籤控制程式對檔案的存取。