怎么對(duì)docker容器中的用戶進(jìn)行隔離?針對(duì)這個(gè)問(wèn)題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問(wèn)題的小伙伴找到更簡(jiǎn)單易行的方法。
讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來(lái)自于我們對(duì)這個(gè)行業(yè)的熱愛(ài)。我們立志把好的技術(shù)通過(guò)有效、簡(jiǎn)單的方式提供給客戶,將通過(guò)不懈努力成為客戶在信息化領(lǐng)域值得信任、有價(jià)值的長(zhǎng)期合作伙伴,公司提供的服務(wù)項(xiàng)目有:域名注冊(cè)、虛擬主機(jī)、營(yíng)銷軟件、網(wǎng)站建設(shè)、孝南網(wǎng)站維護(hù)、網(wǎng)站推廣。
為欽北等地區(qū)用戶提供了全套網(wǎng)頁(yè)設(shè)計(jì)制作服務(wù),及欽北網(wǎng)站建設(shè)行業(yè)解決方案。主營(yíng)業(yè)務(wù)為成都網(wǎng)站設(shè)計(jì)、網(wǎng)站制作、外貿(mào)營(yíng)銷網(wǎng)站建設(shè)、欽北網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠(chéng)的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!
User namespace 的用戶映射
在配置 docker daemon 啟用 user namespace 前,我需要先來(lái)了解一些關(guān)于從屬(subordinate)用戶/組和映射(remapping)的概念。從屬用戶和組的映射由兩個(gè)配置文件來(lái)控制,分別是 /etc/subuid 和 /etc/subgid。看下它們的默認(rèn)內(nèi)容:在配置 docker daemon 啟用 user namespace 前,我需要先來(lái)了解一些關(guān)于從屬(subordinate)用戶/組和映射(remapping)的概念:
對(duì)于 subuid,這一行記錄的含義為:
用戶 nick,在當(dāng)前的 user namespace 中具有 65536 個(gè)從屬用戶,用戶 ID 為 100000-165535,在一個(gè)子 user namespace 中,這些從屬用戶被映射成 ID 為 0-65535 的用戶。subgid 的含義和 subuid 相同。
比如說(shuō)用戶 nick 在宿主機(jī)上只是一個(gè)具有普通權(quán)限的用戶。我們可以把他的一個(gè)從屬 ID(比如 100000 )分配給容器所屬的 user namespace,并把 ID 100000 映射到該 user namespace 中的 uid 0。此時(shí)即便容器中的進(jìn)程具有 root 權(quán)限,但也僅僅是在容器所在的 user namespace 中,一旦到了宿主機(jī)中,你頂多也就有 nick 用戶的權(quán)限而已。
當(dāng)開(kāi)啟 docker 對(duì) user namespace 的支持時(shí)(docker 的 userns-remap 功能),我們可以指定不同的用戶映射到容器中。比如我們專門創(chuàng)建一個(gè)用戶 dockeruser,然后手動(dòng)設(shè)置其 subuid 和 subgid:
nick:100000:65536 dockeruser:165536:65536
并把它指定給 docker daemon:
{ "userns-remap": "dockeruser" }
請(qǐng)注意 subuid 的設(shè)置信息,我們?yōu)?dockeruser 設(shè)置的從屬 ID 和 nick 用戶是不重疊的,實(shí)際上任何用戶的從屬 ID 設(shè)置都是不能重疊的。
或者一切從簡(jiǎn),讓 docker 為我們包辦這些繁瑣的事情,直接把 docker daemon 的 userns-rempa 參數(shù)指定為 "default":
{ "userns-remap": "default" }
這時(shí),docker 會(huì)自動(dòng)完成其它的配置。
配置 docker daemon 啟用用戶隔離
這里筆者采取簡(jiǎn)單的方式,讓 docker 創(chuàng)建默認(rèn)的用戶用于 user namespace。我們需要先創(chuàng)建 /etc/docker/daemon.json 文件:
$ sudo touch /etc/docker/daemon.json
然后編輯其內(nèi)容如下(如果該文件已經(jīng)存在,僅添加下面的配置項(xiàng)即可),并重啟 docker 服務(wù):
{ "userns-remap": "default" }
$ sudo systemctl restart docker.service
下面我們來(lái)驗(yàn)證幾個(gè)關(guān)于用戶隔離的幾個(gè)點(diǎn)。
首先驗(yàn)證 docker 創(chuàng)建了一個(gè)名為 dockremap 的用戶:
然后查看 /etc/subuid 和 /etc/subgid 文件中是否添加了新用戶 dockremap 相關(guān)的項(xiàng):
接下來(lái)我們發(fā)現(xiàn)在 /var/lib/docker 目錄下新建了一個(gè)目錄: 165536.165536,查看該目錄的權(quán)限:
165536 是由用戶 dockremap 映射出來(lái)的一個(gè) uid。查看 165536.165536 目錄的內(nèi)容:
與 /var/lib/docker 目錄下的內(nèi)容基本一致,說(shuō)明啟用用戶隔離后文件相關(guān)的內(nèi)容都會(huì)放在新建的 165536.165536 目錄下。
通過(guò)上面的檢查,我們可以確認(rèn) docker daemon 已經(jīng)啟用了用戶隔離的功能。
宿主機(jī)中的 uid 與容器中 uid
在 docker daemon 啟用了用戶隔離的功能后,讓我們看看宿主機(jī)中的 uid 與容器中 uid 的變化。
$ docker run -d --name sleepme ubuntu sleep infinity
uid 165536 是用戶 dockremap 的一個(gè)從屬 ID,在宿主機(jī)中并沒(méi)有什么特殊權(quán)限。然而容器中的用戶卻是 root,這樣的結(jié)果看上去很完美:
新創(chuàng)建的容器會(huì)創(chuàng)建 user namespace
在 docker daemon 啟用用戶隔離的功能前,新創(chuàng)建的容器進(jìn)程和宿主機(jī)上的進(jìn)程在相同的 user namespace 中。也就是說(shuō) docker 并沒(méi)有為容器創(chuàng)建新的 user namespace:
上圖中的容器進(jìn)程 sleep 和宿主機(jī)上的進(jìn)程在相同的 user namespace 中(沒(méi)有開(kāi)啟用戶隔離功能的場(chǎng)景)。
在 docker daemon 啟用用戶隔離的功能后,讓我們查看容器中進(jìn)程的 user namespace:
上圖中的 4404 就是我們剛啟動(dòng)的容器中 sleep 進(jìn)程的 PID。可以看出,docker 為容器創(chuàng)建了新的 user namespace。在這個(gè) user namespace 中,容器中的用戶 root 就是天神,擁有至高無(wú)上的權(quán)力!
訪問(wèn)數(shù)據(jù)卷中的文件
我們可以通過(guò)訪問(wèn)數(shù)據(jù)卷中的文件來(lái)證明容器中 root 用戶究竟具有什么樣的權(quán)限?創(chuàng)建四個(gè)文件,分別屬于用戶 root 、165536 和 nick。rootfile 只有 root 用戶可以讀寫,用戶 nick 具有 nickfile 的讀寫權(quán)限,uid 165536 具有文件 165536file 的讀寫權(quán)限,任何用戶都可以讀寫 testfile 文件:
下面把這幾個(gè)文件以數(shù)據(jù)卷的方式掛載到容器中,并檢查從容器中訪問(wèn)它們的權(quán)限:
$ docker run -it --name test -w=/testv -v $(pwd)/testv:/testv ubuntu
容器中的 root 用戶只能訪問(wèn) 165536file 和 testfile,說(shuō)明這個(gè)用戶在宿主機(jī)中只有非常有限的權(quán)限。
在容器中禁用 user namespace
一旦為 docker daemon 設(shè)置了 "userns-remap" 參數(shù),所有的容器默認(rèn)都會(huì)啟用用戶隔離的功能(默認(rèn)創(chuàng)建一個(gè)新的 user namespace)。有些情況下我們可能需要回到?jīng)]有開(kāi)啟用戶隔離的場(chǎng)景,這時(shí)可以通過(guò) --userns=host 參數(shù)為單個(gè)的容器禁用用戶隔離功能。--userns=host 參數(shù)主要給下面三個(gè)命令使用:
docker container create docker container run docker container exec
比如執(zhí)行下的命令:
$ docker run -d --userns=host --name sleepme ubuntu sleep infinity
查看進(jìn)程信息:
進(jìn)程的有效用戶又成 root 了,并且也沒(méi)有為進(jìn)程創(chuàng)建新的 user namespace:
已知問(wèn)題
User namespace 屬于比較高級(jí)的功能,目前 docker 對(duì)它的支持還算不上完美,下面是已知的幾個(gè)和現(xiàn)有功能不兼容的問(wèn)題:
共享主機(jī)的 PID 或 NET namespace(--pid=host or --network=host)
外部的存儲(chǔ)、數(shù)據(jù)卷驅(qū)動(dòng)可能不兼容、不支持 user namespace
使用 --privileged 而不指定 --userns=host
總結(jié)
Docker 是支持 user namespace 的,并且配置的方式也非常簡(jiǎn)便。在開(kāi)啟 user namespace 之后我們享受到了安全性的提升,但同時(shí)也會(huì)因?yàn)榉N種限制讓其它的個(gè)別功能出現(xiàn)問(wèn)題。這時(shí)我們需要作出選擇,告別一刀切的決策,讓合適的功能出現(xiàn)的合適的場(chǎng)景中。
關(guān)于怎么對(duì)docker容器中的用戶進(jìn)行隔離問(wèn)題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒(méi)有解開(kāi),可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關(guān)知識(shí)。