使用最新的安全增強技術進行 Docker 調優

類別: IT
標籤: docker

自從我寫完Docker安全系列的那兩篇文章之後, 已經過去有一段時間了. 本文主要是來談談在那之後Docker的新的變化, 包含一些新增的特性的介紹.

調整Capabilities

在上一篇文章中, 我提到過容器的隔離是基於Linux的Capability機制實現的.

Linux的Capability機制允許你將超級使用者相關的高階許可權劃分成為不同的小單元. 目前Docker容器預設只用到了以下的Capability.

CHOWN, DAC_OVERRIDE, FSETID, FOWNER, MKNOD, NET_RAW, SETGID,  SETUID, SETFCAP, SETPCAP, NET_BIND_SERVICE, SYS_CHROOT, KILL,  AUDIT_WRITE

有些情況下,你也許需要調整上面羅列的特性。比如你正在構建一個容器,你用它來執行ntpd或是crony,為此它們要能夠修改宿主的系統時間。由於不具備 CAP_SYS_TIME 特性,容器無法工作。為了應對這種情況,在Docker之前的版本中,容器必須以提權模式執行(使用 --privileged 選項),這會禁用所有安全機制。

在Docker的1.3版中,新添了 --cap-add 和 --cap-drop 選項。要讓一個ntpd容器跑起來,你現在只要執行以下命令:

docker run -d --cap-add SYS_TIME ntpd

就可以將 SYS_TIME 特性新增到你的容器中。

再舉個例子,如果你確定你的容器不會改變任何程式的UID和GID,那完全可以將這些特性從你的容器中移除,這樣會更安全:

docker run --cap-drop SETUID --cap-drop SETGID --cap-drop FOWNER fedora /bin/sh

命令示例,用於檢視啟用的特性:

# pscap | grep 2912

執行結果示例:

5417 2912 root sh chown, dac_override, fsetid, kill, setpcap, net_bind_service, net_raw, sys_chroot, mknod, audit_write, setfcap

或者你可以先移除所有特性,然後再把一個新增回去:

docker run --cap-drop ALL --cap-add SYS_TIME ntpd /bin/sh

檢視啟用的特性:

# pscap | grep 2382

5417 2382 root sh sys_time

SELinux標籤調整

和特性類似,我們增加了在執行時調整SELinux標籤的功能。

如果你看過圖解SELinux一書,你就知道我們可以根據類別和MCS/MLS等級來區分程式。我們使用類別來保護宿主不受容器影響。而我們也能通過調整類別來控制容器的哪些網路埠能夠輸入和輸出。目前我們所有執行著的容器都是svirt_net_lxc_t。該類別允許所有網路埠都能處於監聽狀態,也允許所有網路埠都能對外發起連線。我們可以通過調整SELinux類別標籤來增強容器的安全性。

針對常規SELinux和Apache httpd,我們預設只允許Apache程式在Apache埠(http_port_t)上進行監聽。

# sudo sepolicy network -t http_port_t

http_port_t: tcp: 80,81,443,488,8008,8009,8443,9000

與此同時,埠上的所有傳出連線也被我們遮蔽了。這有助於我們對Apache程式的鎖定,即使有黑客利用像ShellShock那樣的安全漏洞破壞了應用程式,我們也能防止應用程式變成製造垃圾資訊的機器人,同時阻止程式對其他系統發起攻擊。就像《Hotel California》中所唱的那樣:“你可以隨時入住,但休想離開”。

然而,對於容器而言,如果你在一個容器中執行Apache服務程式,一旦應用程式被成功入侵,Apache程式將會連線任何網路埠併成為製造垃圾資訊的機器人,也可能會通過網路攻擊其他宿主和容器。

為使用SELinux的容器建立新的策略類別相當容易。首先你需要建立一個SELinux TE(Type  Enforcement)檔案:

# cat > docker_apache.te << _EOF

policy_module(docker_apache,1.0)

# This template interface creates the docker_apache_t type as a

# type which can be run as a docker container. The template

# gives the domain the least privileges required to run.

virt_sandbox_domain_template(docker_apache)

# I know that the apache daemon within the container will require

# some capabilities to run. Luckily I already have policy for

# Apache and I can query SELinux for the capabilities.

# sesearch -AC -s httpd_t -c capability

allow  docker_apache_t self: capability { chown dac_override kill setgid  setuid net_bind_service sys_chroot sys_nice sys_tty_config } ;

# These are the rules required to allow the container to listen

# to Apache ports on the network.

allow docker_apache_t self:tcp_socket create_stream_socket_perms;

allow docker_apache_t self:udp_socket create_socket_perms;

corenet_tcp_bind_all_nodes(docker_apache_t)

corenet_tcp_bind_http_port(docker_apache_t)

corenet_udp_bind_all_nodes(docker_apache_t)

corenet_udp_bind_http_port(docker_apache_t)

# Apache needs to resolve names against a DNS server

sysnet_dns_name_resolve(docker_apache_t)

# Permissive domains allow processes to not be blocked by SELinux

# While developing and testing your policy you probably want to

# run the container in permissive mode.

# You want to remove this rule, when you are confident in the

# policy.

permissive docker_apache_t;

_EOF

# make -f /usr/share/selinux/devel/Makefile docker_apache.pp

# semodule -i docker_apache.pp

現在,你可以使用新的類別執行容器:

# docker run -d --security-opt type:docker_apache_t httpd

這樣就使得這個容器執行在比一般容器更嚴格的SELinux安全機制下。要注意的是,你也許要關注下審計日誌,確認你的應用是否需要額外的SELinux放行規則。

你可以通過audit2allow命令新增這些規則,將這些規則追加到已有的 .te 檔案中,然後重新編譯安裝。

# grep docker_apache_t /var/log/audit/audit.log | audit2allow >> docker_apache.te

# make -f /usr/share/selinux/devel/Makefile docker_apache.pp

# semodule -i docker_apache.pp

多級安全模式

目前,我們使用MCS分離以確保出容器並不允許互動或者與其他容器互動,除非他是通過網路。某些政府系統要求不同型別的政策MLS(多級安全)。使用MLS,你標記基於他們將被看見的資料級別的處理。MLS說,如果你的容器將被處理Topsecret資料,那麼它應該執行在Topsecret.我們增加了選項到Docker,允許管理員設定的容器在特定的水平上執行。其中應該滿足MLS系統的需求。

docker run -d --security-opt label:level:TopSecret --security

這將能使Docker容器兩者都執行於交替型別,和水平上,並且會防止容器使用並不是在同一標籤上的資料。通過鑑定,在這一點上這並沒有消失,但是我們將願意幫助第三方MLS使用者建立解決方案。

 

調整空間

在其他安全論壇上,我已經討論瞭如何把名稱空間(namespaces)可以被認為是一種安全機制,由於它會消除一個程式在系統(PID名稱空間)上看到其他程式的能力。網路空間(network namespace)可以消除從你的名稱空間看到其他網路的能力。IPC(程式間通訊)名稱空間具有阻止Container呼叫其它容器IPC的能力。

Docker現在已經有能力放鬆這些限制。你可以和容器共享主機名稱空間:

--pid=host 讓容器共享主機pid名稱空間

--net=host 讓容器共享主機網路名稱空間

--ipc=host 讓容器共享主機ipc名稱空間

請注意,為了讓上述的設定生效,讓容器共享主機的PID或IPC名稱空間, 我們還需要禁用SELinux許可權分隔限制。

docker run -ti --pid=host --net=host --ipc=host rhel7 /bin/sh

你可能想要讀有關這個主題的額外資訊Super Privileged Containers

使用最新的安全增強技術進行 Docker 調優原文請看這裡

推薦文章