您好,登錄后才能下訂單哦!
怎么對docker容器中的用戶進行隔離?針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
User namespace 的用戶映射
在配置 docker daemon 啟用 user namespace 前,我需要先來了解一些關于從屬(subordinate)用戶/組和映射(remapping)的概念。從屬用戶和組的映射由兩個配置文件來控制,分別是 /etc/subuid 和 /etc/subgid。看下它們的默認內容:在配置 docker daemon 啟用 user namespace 前,我需要先來了解一些關于從屬(subordinate)用戶/組和映射(remapping)的概念:
對于 subuid,這一行記錄的含義為:
用戶 nick,在當前的 user namespace 中具有 65536 個從屬用戶,用戶 ID 為 100000-165535,在一個子 user namespace 中,這些從屬用戶被映射成 ID 為 0-65535 的用戶。subgid 的含義和 subuid 相同。
比如說用戶 nick 在宿主機上只是一個具有普通權限的用戶。我們可以把他的一個從屬 ID(比如 100000 )分配給容器所屬的 user namespace,并把 ID 100000 映射到該 user namespace 中的 uid 0。此時即便容器中的進程具有 root 權限,但也僅僅是在容器所在的 user namespace 中,一旦到了宿主機中,你頂多也就有 nick 用戶的權限而已。
當開啟 docker 對 user namespace 的支持時(docker 的 userns-remap 功能),我們可以指定不同的用戶映射到容器中。比如我們專門創建一個用戶 dockeruser,然后手動設置其 subuid 和 subgid:
nick:100000:65536 dockeruser:165536:65536
并把它指定給 docker daemon:
{ "userns-remap": "dockeruser" }
請注意 subuid 的設置信息,我們為 dockeruser 設置的從屬 ID 和 nick 用戶是不重疊的,實際上任何用戶的從屬 ID 設置都是不能重疊的。
或者一切從簡,讓 docker 為我們包辦這些繁瑣的事情,直接把 docker daemon 的 userns-rempa 參數指定為 "default":
{ "userns-remap": "default" }
這時,docker 會自動完成其它的配置。
配置 docker daemon 啟用用戶隔離
這里筆者采取簡單的方式,讓 docker 創建默認的用戶用于 user namespace。我們需要先創建 /etc/docker/daemon.json 文件:
$ sudo touch /etc/docker/daemon.json
然后編輯其內容如下(如果該文件已經存在,僅添加下面的配置項即可),并重啟 docker 服務:
{ "userns-remap": "default" }
$ sudo systemctl restart docker.service
下面我們來驗證幾個關于用戶隔離的幾個點。
首先驗證 docker 創建了一個名為 dockremap 的用戶:
然后查看 /etc/subuid 和 /etc/subgid 文件中是否添加了新用戶 dockremap 相關的項:
接下來我們發現在 /var/lib/docker 目錄下新建了一個目錄: 165536.165536,查看該目錄的權限:
165536 是由用戶 dockremap 映射出來的一個 uid。查看 165536.165536 目錄的內容:
與 /var/lib/docker 目錄下的內容基本一致,說明啟用用戶隔離后文件相關的內容都會放在新建的 165536.165536 目錄下。
通過上面的檢查,我們可以確認 docker daemon 已經啟用了用戶隔離的功能。
宿主機中的 uid 與容器中 uid
在 docker daemon 啟用了用戶隔離的功能后,讓我們看看宿主機中的 uid 與容器中 uid 的變化。
$ docker run -d --name sleepme ubuntu sleep infinity
uid 165536 是用戶 dockremap 的一個從屬 ID,在宿主機中并沒有什么特殊權限。然而容器中的用戶卻是 root,這樣的結果看上去很完美:
新創建的容器會創建 user namespace
在 docker daemon 啟用用戶隔離的功能前,新創建的容器進程和宿主機上的進程在相同的 user namespace 中。也就是說 docker 并沒有為容器創建新的 user namespace:
上圖中的容器進程 sleep 和宿主機上的進程在相同的 user namespace 中(沒有開啟用戶隔離功能的場景)。
在 docker daemon 啟用用戶隔離的功能后,讓我們查看容器中進程的 user namespace:
上圖中的 4404 就是我們剛啟動的容器中 sleep 進程的 PID。可以看出,docker 為容器創建了新的 user namespace。在這個 user namespace 中,容器中的用戶 root 就是天神,擁有至高無上的權力!
訪問數據卷中的文件
我們可以通過訪問數據卷中的文件來證明容器中 root 用戶究竟具有什么樣的權限?創建四個文件,分別屬于用戶 root 、165536 和 nick。rootfile 只有 root 用戶可以讀寫,用戶 nick 具有 nickfile 的讀寫權限,uid 165536 具有文件 165536file 的讀寫權限,任何用戶都可以讀寫 testfile 文件:
下面把這幾個文件以數據卷的方式掛載到容器中,并檢查從容器中訪問它們的權限:
$ docker run -it --name test -w=/testv -v $(pwd)/testv:/testv ubuntu
容器中的 root 用戶只能訪問 165536file 和 testfile,說明這個用戶在宿主機中只有非常有限的權限。
在容器中禁用 user namespace
一旦為 docker daemon 設置了 "userns-remap" 參數,所有的容器默認都會啟用用戶隔離的功能(默認創建一個新的 user namespace)。有些情況下我們可能需要回到沒有開啟用戶隔離的場景,這時可以通過 --userns=host 參數為單個的容器禁用用戶隔離功能。--userns=host 參數主要給下面三個命令使用:
docker container create docker container run docker container exec
比如執行下的命令:
$ docker run -d --userns=host --name sleepme ubuntu sleep infinity
查看進程信息:
進程的有效用戶又成 root 了,并且也沒有為進程創建新的 user namespace:
已知問題
User namespace 屬于比較高級的功能,目前 docker 對它的支持還算不上完美,下面是已知的幾個和現有功能不兼容的問題:
共享主機的 PID 或 NET namespace(--pid=host or --network=host)
外部的存儲、數據卷驅動可能不兼容、不支持 user namespace
使用 --privileged 而不指定 --userns=host
總結
Docker 是支持 user namespace 的,并且配置的方式也非常簡便。在開啟 user namespace 之后我們享受到了安全性的提升,但同時也會因為種種限制讓其它的個別功能出現問題。這時我們需要作出選擇,告別一刀切的決策,讓合適的功能出現的合適的場景中。
關于怎么對docker容器中的用戶進行隔離問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。