还没对Docker加以限制?埋下的安全隐患了解一下
眾所周知,Docker使用Namespace進(jìn)行環(huán)境隔離、使用CGroup進(jìn)行資源限制。但是在實(shí)際應(yīng)用中,還是有很多企業(yè)或者組織沒(méi)有使用Namespace或者CGroup對(duì)容器加以限制,從而埋下安全隱患。
本文將簡(jiǎn)單介紹Namespace和CGroup的基本原理,再通過(guò)具體配置和應(yīng)用向讀者展示如何應(yīng)用這些技術(shù)保護(hù)Docker容器安全,不過(guò)Namespace和CGroup并不是萬(wàn)能的,他們只是保障Docker容器安全的多種方案中的一類(lèi)而已。
一、Namespace
1、概述
我們可以給容器分配有限的資源,這有助于限制系統(tǒng)和惡意攻擊者可用的系統(tǒng)資源。每個(gè)容器所能獲取的組件有:
- 網(wǎng)絡(luò)堆棧;
- 進(jìn)程空間;
- 文件系統(tǒng)實(shí)例。
可通過(guò)使用Namespace來(lái)實(shí)現(xiàn)限制資源。Namespace就像一個(gè)“視圖”,它只顯示系統(tǒng)上所有資源的一個(gè)子集。這提供了一種隔離形式:在容器中運(yùn)行的進(jìn)程不能看到或影響其他容器中的進(jìn)程或者宿主本身。
以下是一些常見(jiàn)的Namespace類(lèi)型實(shí)例。
Namespace例子:
Cgroup CLONE_NEWCGROUP 限制root目錄 IPC CLONE_NEWIPC System V IPC, POSIX消息隊(duì)列 Network CLONE_NEWNET 網(wǎng)絡(luò)設(shè)備、棧、端口等 Mount CLONE_NEWNS 掛載點(diǎn) PID CLONE_NEWPID 進(jìn)程ID User CLONE_NEWUSER 用戶(hù)和組ID UTS CLONE_NEWUTS 主機(jī)名和NIS域名Docker run命令有幾個(gè)參數(shù)和Namespace相關(guān):
IPC:--ipc string IPC namespace to use PID:--pid string PID namespace to use User:--userns string User namespace to use UTS:--uts string UTS namespace to use2、確定當(dāng)前Docker用戶(hù)
默認(rèn)情況下,Docker守護(hù)程序在主機(jī)上以root用戶(hù)身份運(yùn)行。通過(guò)列出所有進(jìn)程,你可以識(shí)別Docker守護(hù)程序運(yùn)行的用戶(hù)。
ps aux | grep docker由于守護(hù)程序以root身份運(yùn)行,因此啟動(dòng)的任何容器將具有與主機(jī)的root用戶(hù)相同的安全上下文。
docker run --rm alpine id這樣是有安全風(fēng)險(xiǎn)的:如果root用戶(hù)擁有的文件可從容器訪問(wèn),則可以由正在運(yùn)行的容器修改。
3、刪除文件
下面讓我們看看用root用戶(hù)運(yùn)行容器的具體風(fēng)險(xiǎn)。
首先,在我們的主機(jī)上創(chuàng)建touch命令的副本。
sudo cp /bin/touch /bin/touch.bak && ls -lha /bin/touch.bak由于容器的/hos目錄和宿主的/bin是同一個(gè),因此可以從容器刪除宿主上的文件,不信你試試。
docker run -it -v /bin/:/host/ alpine rm -f /host/touch.bak結(jié)果,該命令被刪的一干二凈。
ls -lha /bin/touch.bak在這種情況下,容器能夠從主機(jī)刪除觸摸二進(jìn)制文件。
4、更改容器用戶(hù)
可以通過(guò)更改用戶(hù)、組上下文以及使用非特權(quán)用戶(hù)運(yùn)行的容器來(lái)規(guī)避以上風(fēng)險(xiǎn)。
docker run --user = 1000:1000 --rm alpine id作為無(wú)特權(quán)用戶(hù),將無(wú)法刪除二進(jìn)制文件。
$ docker run -it -v /bin/:/host/ alpine rm -f /host/touch.bak $ docker run --user=1000:1000 --rm alpine id uid=1000 gid=1000 $ sudo cp /bin/touch /bin/touch.bak $ docker run --user=1000:1000 -it -v /bin:/host/ alpine rm -f /host/touch.bak rm: can't remove '/host/touch.bak': Permission denied但是,如果我們?cè)谌萜鲀?nèi)部需要訪問(wèn)根目錄,那么我們?nèi)匀粫?huì)將自己暴露給前一個(gè)場(chǎng)景。這是Namespace出現(xiàn)的原因。
5、啟用用戶(hù)Namespace
Docker建議不要在啟用Namespace模式和禁用Namespace模式之間來(lái)回切換Docker daemon,執(zhí)行此操作可能會(huì)導(dǎo)致鏡像權(quán)限出現(xiàn)問(wèn)題。
Namespace是Linux內(nèi)核安全功能,該功能允許Namespace或容器內(nèi)的root用戶(hù)訪問(wèn)主機(jī)上的非特權(quán)用戶(hù)ID。
6、任務(wù)
使用參數(shù)userns-remap啟動(dòng)Docker daemon時(shí),將啟用Namespace。運(yùn)行以下命令以修改Docker daemon設(shè)置并重新啟動(dòng)該進(jìn)程。
curlhtps:/ist. githubusercontent com/Benall/bb878c99d06a63cd8ed4d1c0a694 1df4/raw/76136ffbca341846619086cfe40ab8e01368347daemon.json -O /etc/dockerldaemon.json& sudoservice dockerrestart使用cat /etc/docker/daemon.json查看設(shè)置。
cat /etc/docker/daemon.json {"bip":"172.18.0.1/24","debug": true,"storage-driver": "overlay","userns-remap": "1000:1000","insecure-registries": ["registry.test.training.katacoda.com:4567"] }重新啟動(dòng)后,你可以使用以下命令驗(yàn)證Namespace是否到位。
docker info | grep "Root Dir" WARNING: No swap limit support Docker Root Dir: /var/lib/docker/100000.100000Docker將不再以root用戶(hù)身份存儲(chǔ)數(shù)據(jù)。相反,所有內(nèi)容都作為映射用戶(hù)進(jìn)行處理。Docker Root Dir定義了Docker為映射用戶(hù)存儲(chǔ)數(shù)據(jù)的位置。
注意:在現(xiàn)有系統(tǒng)上啟用此功能時(shí),需要重新下載Docker Images。
7、Namespace保護(hù)
啟用Namespace后,Docker dameon將以其他用戶(hù)身份運(yùn)行。
ps aux | grep dockerd
啟動(dòng)容器時(shí),容器內(nèi)的用戶(hù)將具有root權(quán)限。
docker run --rm alpine id但是,用戶(hù)將無(wú)法修改主機(jī)上運(yùn)行的任何內(nèi)容。
sudo cp / bin / touch /bin/touch.bak docker run -it -v / bin /:/ host / alpine rm -f /host/touch.bak與此前不同,我們的ps命令仍然存在。
ls -lha /bin/touch.bak通過(guò)使用Namespace,可以將Docker root用戶(hù)分開(kāi),并提供比以前更強(qiáng)的安全性和隔離性。
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video) $ sudo cp /bin/touch /bin/touch.bak $ docker run -it -v /bin/:/host/ alpine rm -f /host/touch.bak rm: can't remove '/host/touch.bak': Permission denied $ ls -lha /bin/touch.bak -rwxr-xr-x 1 root root 63K Aug 27 03:59 /bin/touch.bak8、使用網(wǎng)絡(luò)Namespace
雖然CGroup可以限制進(jìn)程使用的資源,但還需要Namespace控制進(jìn)程的訪問(wèn)權(quán)限。
1)例子
啟動(dòng)容器時(shí),將定義并創(chuàng)建網(wǎng)絡(luò)接口。這為容器提供了唯一的IP地址和接口。
[root@host01 ~]# docker run -it alpine ip addr show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft forever 14: eth0@if15: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UPlink/ether 02:42:ac:12:00:03 brd ff:ff:ff:ff:ff:ffinet 172.18.0.3/24 brd 172.18.0.255 scope global eth0valid_lft forever preferred_lft forever通過(guò)將命名空間更改為主機(jī),而不是容器的網(wǎng)絡(luò)與其接口隔離,該進(jìn)程將可以訪問(wèn)主機(jī)網(wǎng)絡(luò)接口。
[root@host01 ~]# docker run -it --net=host alpine ip addr show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft foreverinet6 ::1/128 scope hostvalid_lft forever preferred_lft forever 2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP qlen 1000link/ether 02:42:ac:11:00:11 brd ff:ff:ff:ff:ff:ffinet 172.17.0.17/16 brd 172.17.255.255 scope global enp0s3valid_lft forever preferred_lft foreverinet6 fe80::b3ad:ecc4:2399:7a54/64 scope linkvalid_lft forever preferred_lft forever 3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UPlink/ether 02:42:cd:78:f0:22 brd ff:ff:ff:ff:ff:ffinet 172.18.0.1/24 brd 172.18.0.255 scope global docker0valid_lft forever preferred_lft foreverinet6 fe80::e9ad:a1a7:8b68:a0d1/64 scope linkvalid_lft forever preferred_lft forever 5: veth158bc01@if4: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue master docker0 stateUPlink/ether 9e:bc:3d:01:53:95 brd ff:ff:ff:ff:ff:ffinet6 fe80::ca3e:49ea:e1d0:8755/64 scope linkvalid_lft forever preferred_lft forever如果進(jìn)程監(jiān)聽(tīng)端口,它們將在宿主接口上被監(jiān)聽(tīng)并映射到容器。
9、使用Pid命名空間
與網(wǎng)絡(luò)一樣,容器可以看到的進(jìn)程也取決于它所屬的命名空間。更改Pid命名空間,將允許容器與超出其正常范圍的進(jìn)程進(jìn)行交互。
1)例子
第一個(gè)容器將在其進(jìn)程名稱(chēng)空間中運(yùn)行。因此,它可以訪問(wèn)的唯一進(jìn)程是在容器中啟動(dòng)的進(jìn)程。
[root@host01 ~]# docker run -it alpine ps aux PID USER TIME COMMAND1 root 0:00 ps aux將命名空間更改為主機(jī),容器還可以查看系統(tǒng)上運(yùn)行的所有其他進(jìn)程。
[root@host01 ~]# docker run -it --pid=host alpine ps aux PID USER TIME COMMAND1 root 0:00 /usr/lib/systemd/systemd2 root 0:00 [kthreadd]4 root 0:00 [kworker/0:0H]6 root 0:00 [mm_percpu_wq]7 root 0:00 [ksoftirqd/0]8 root 0:00 [rcu_sched]9 root 0:00 [rcu_bh]10、共享命名空間
有時(shí)需要提供容器訪問(wèn)主機(jī)命名空間,如調(diào)試工具,但這被認(rèn)為是不安全的做法。這是因?yàn)槟阏诖蚱瓶赡芤肼┒吹娜萜靼踩P汀?/p>
相反,如果需要,請(qǐng)使用共享命名空間來(lái)僅訪問(wèn)容器所需的命名空間。
1)例子
第一個(gè)容器啟動(dòng)Nginx服務(wù)器。這將定義一個(gè)新的網(wǎng)絡(luò)和進(jìn)程命名空間。Nginx服務(wù)器將自身綁定到新定義的網(wǎng)絡(luò)接口的端口80。
docker run -d --name http nginx:alpine其他容器現(xiàn)在可以使用語(yǔ)法容器重用此命名空間:<name>。curl命令下面可以訪問(wèn)在localhost上運(yùn)行的HTTP服務(wù)器,因?yàn)樗鼈児蚕硐嗤木W(wǎng)絡(luò)接口。
docker run --net = container:http benhall / curl curl -s localhost<!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style>body {width: 35em;margin: 0 auto;font-family: Tahoma, Verdana, Arial, sans-serif;} </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p><p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p><p><em>Thank you for using nginx.</em></p> </body>它還可以查看共享容器中的進(jìn)程并與之交互。
docker run --pid=container:http alpine ps aux PID USER TIME COMMAND1 root 0:00 nginx: master process nginx -g daemon off;6 100 0:00 nginx: worker process7 root 0:00 ps aux這對(duì)于調(diào)試工具很有用,例如strace。這允許你在不更改或重新啟動(dòng)應(yīng)用程序的情況下為特定容器提供更多權(quán)限。
二、CGroup
1、概述
CGroup可為系統(tǒng)中所運(yùn)行的任務(wù)或進(jìn)程的用戶(hù)群組分配資源,比如CPU事件、系統(tǒng)內(nèi)存、網(wǎng)絡(luò)帶寬或者這些資源的組合。一般可以分為下面幾種類(lèi)型:
- Resource limitation: 限制資源使用,比如內(nèi)存使用上限以及文件系統(tǒng)的緩存限制。
- Prioritization: 優(yōu)先級(jí)控制,比如:CPU利用和磁盤(pán)IO吞吐。
- Accounting: 一些審計(jì)或一些統(tǒng)計(jì),主要目的是為了計(jì)費(fèi)。
- Control: 掛起進(jìn)程,恢復(fù)執(zhí)行進(jìn)程。
以下是一些常見(jiàn)的cgroup類(lèi)型示例。
CGroups例子:
--cpu-shares #限制cpu共享 --cpuset-cpus #指定cpu占用 --memory-reservation #指定保留內(nèi)存 --kernel-memory #內(nèi)核占用內(nèi)存 --blkio-weight (block IO) #blkio權(quán)重 --device-read-iops #設(shè)備讀iops --device-write-iops #設(shè)備寫(xiě)iopsdocker run中與CGroup相關(guān)的參數(shù)如下:
block IO:--blkio-weight value Block IO (relative weight), between 10 and 1000--blkio-weight-device value Block IO weight (relative device weight) (default [])--cgroup-parent string Optional parent cgroup for the container CPU:--cpu-percent int CPU percent (Windows only)--cpu-period int Limit CPU CFS (Completely Fair Scheduler) period--cpu-quota int Limit CPU CFS (Completely Fair Scheduler) quota-c, --cpu-shares int CPU shares (relative weight)--cpuset-cpus string CPUs in which to allow execution (0-3, 0,1)--cpuset-mems string MEMs in which to allow execution (0-3, 0,1) Device: --device value Add a host device to the container (default [])--device-read-bps value Limit read rate (bytes per second) from a device (default [])--device-read-iops value Limit read rate (IO per second) from a device (default [])--device-write-bps value Limit write rate (bytes per second) to a device (default [])--device-write-iops value Limit write rate (IO per second) to a device (default []) Memory: --kernel-memory string Kernel memory limit-m, --memory string Memory limit--memory-reservation string Memory soft limit--memory-swap string Swap limit equal to memory plus swap: '-1' to enable unlimited swap--memory-swappiness int Tune container memory swappiness (0 to 100) (default -1)2、定義內(nèi)存限制
可以通過(guò)定義上限邊界來(lái)幫助限制應(yīng)用程序的內(nèi)存泄漏或其他程序bug。
1)例子
docker run -d --name mb100 --memory 100m alpine top da4db4fd6b70501783c172b7459227c6c8e0426784acf1da26760d80eb2403b0容器的內(nèi)存使用可通過(guò)docker stats命令查看。
docker stats --no-stream CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS da4db4fd6b70 mb100 0.00% 440KiB / 100MiB 0.43% 6.21kB / 90B 1.06MB / 0B 13、定義CPU份額
雖然內(nèi)存限制定義了設(shè)置的最大值,但CPU限制基于共享。這些份額是一個(gè)進(jìn)程應(yīng)該與另一個(gè)進(jìn)程在處理時(shí)間上分配的權(quán)重。
如果CPU處于空閑狀態(tài),則該進(jìn)程將使用所有可用資源。如果第二個(gè)進(jìn)程需要CPU,則將根據(jù)權(quán)重共享可用的CPU時(shí)間。
1)例子
下面是啟動(dòng)具有不同共享權(quán)重的容器的示例。
--cpu-shares參數(shù)定義0-768之間的共享。如果容器定義了768的份額,而另一個(gè)容器定義了256的份額,則第一個(gè)容器將具有50%的份額,而另一個(gè)容器具有25%的可用份額。這些數(shù)字是由于CPU共享的加權(quán)方法而不是固定容量。在第一個(gè)容器下方將允許擁有50%的份額。第二個(gè)容器將限制在25%。
docker run -d --name c768 --cpuset-cpus 0 --cpu-shares 768 benhall/stress docker run -d --name c256 --cpuset-cpus 0 --cpu-shares 256 benhall/stress sleep 5 docker stats --no-stream CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 41fa6c06b148 c256 24.77% 736KiB / 737.6MiB 0.10% 2.1kB / 180B 0B / 0B 3 4555c9a0c612 c768 74.33% 732KiB / 737.6MiB 0.10% 2.19kB / 484B 0B / 0B 3 da4db4fd6b70 mb100 0.00% 444KiB / 100MiB 0.43% 12.7kB / 90B 1.06MB / 0B 1 docker rm -f c768 c256有一點(diǎn)很重要,就是只要沒(méi)有其他進(jìn)程在,即便是定義了權(quán)重,啟動(dòng)的進(jìn)程也能獲得共享的100%的資源。
4、其他限制
諸如讀寫(xiě)IP的限制,可以按照參考文檔配置測(cè)試,測(cè)試效果如上面的cpu和內(nèi)存限制。
?
?
蘇先生ii:專(zhuān)注于Java開(kāi)發(fā)技術(shù)的研究與知識(shí)分享!
————END————
轉(zhuǎn)載于:https://www.cnblogs.com/Java-no-1/p/11264200.html
總結(jié)
以上是生活随笔為你收集整理的还没对Docker加以限制?埋下的安全隐患了解一下的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 如何写一个优质的网站标题title?
- 下一篇: 坚持不是苦差事,而是一种享受