<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Docker 容器默認root賬號運行,很不安全!

          共 3577字,需瀏覽 8分鐘

           ·

          2021-12-27 20:21

          默認情況下,容器中的進程以 root 用戶權(quán)限運行,并且這個 root 用戶和宿主機中的 root 是同一個用戶。聽起來是不是很可怕,因為這就意味著一旦容器中的進程有了適當?shù)臋C會,它就可以控制宿主機上的一切!本文我們將嘗試了解用戶名、組名、用戶 id(uid)和組 id(gid)如何在容器內(nèi)的進程和主機系統(tǒng)之間映射,這對于系統(tǒng)的安全來說是非常重要的。

          說明:本文的演示環(huán)境為 ubuntu 16.04 (下圖來自互聯(lián)網(wǎng))。

          先來了解下?uid gid

          uid 和 gid 由 Linux 內(nèi)核負責管理,并通過內(nèi)核級別的系統(tǒng)調(diào)用來決定是否應(yīng)該為某個請求授予特權(quán)。比如當進程試圖寫入文件時,內(nèi)核會檢查創(chuàng)建進程的 uid 和 gid,以確定它是否有足夠的權(quán)限修改文件。注意,內(nèi)核使用的是** uid gid****,而不是用戶名和組名**。簡單起見,本文中剩下的部分只拿 uid 進行舉例,系統(tǒng)對待 gid 的方式和 uid 基本相同。

          很多同學(xué)簡單地把 docker 容器理解為輕量的虛擬機,雖然這簡化了理解容器技術(shù)的難度但是也容易帶來很多的誤解。事實上,與虛擬機技術(shù)不同:同一主機上運行的所有容器共享同一個內(nèi)核(主機的內(nèi)核)。容器化帶來的巨大價值在于所有這些獨立的容器(其實是進程)可以共享一個內(nèi)核。這意味著即使由成百上千的容器運行在 docker 宿主機上,但**內(nèi)核控制的**** uid gid **則仍然只有一套。所以同一個 uid 在宿主機和容器中代表的是同一個用戶(即便在不同的地方顯示了不同的用戶名)。注意,由于普通的用來顯示用戶名的 Linux 工具并不屬于內(nèi)核(比如 id 等命令),所以我們可能會看到同一個 uid 在不同的容器中顯示為不同的用戶名。但是對于相同的 uid 不能有不同的特權(quán),即使在不同的容器中也是如此。

          如果你已經(jīng)了解了 Linux 的 user namespace 技術(shù),參考《Linux Namespace :User》,你需要注意的是到目前為止,docker 默認并沒有啟用 user namesapce,這也是本文討論的情況。筆者會在接下來的文章中介紹如何配置 docker 啟用 user namespace。

          容器中默認使用** root **用戶

          如果不做相關(guān)的設(shè)置,容器中的進程默認以 root 用戶權(quán)限啟動,下面的 demo 使用 ubuntu 鏡像運行 sleep 程序:

          $?docker?run?-d?--name?sleepme?ubuntu?sleep?infinity

          注意上面的命令中并沒有使用 sudo。筆者在宿主機中的登錄用戶是 nick,uid 為 1000:

          在宿主機中查看 sleep 進程的信息:

          $?ps?aux?|?grep?sleep

          sleep 進程的有效用戶名稱是 root,也就是說 sleep 進程具有 root 權(quán)限。然后進入容器內(nèi)部看看,看到的情況和剛才一樣,sleep 進程也具有 root 權(quán)限:

          那么,容器內(nèi)的 root 用戶和宿主機上的 root 用戶是同一個嗎?答案是:是的,它們對應(yīng)的是同一個 uid。原因我們在前面已經(jīng)解釋過了:整個系統(tǒng)共享同一個內(nèi)核,而內(nèi)核只管理一套 uid 和 gid。

          其實我們可以通過數(shù)據(jù)卷來簡單的驗證上面的結(jié)論。在宿主機上創(chuàng)建一個只有 root 用戶可以讀寫的文件:

          然后掛載到容器中:

          $?docker?run?--rm?-it?-w=/testv-v?$(pwd)/testv:/testv?ubuntu

          在容器中可以讀寫該文件:

          我們可以通過 Dockerfile 中的 USER 命令或者是 ?docker run 命令的 --user 參數(shù)指定容器中進程的用戶身份。下面我們分別來探究這兩種情況。

          ** Dockerfile **中指定用戶身份

          我們可以在 Dockerfile 中添加一個用戶 appuser,并使用 USER 命令指定以該用戶的身份運行程序,Dockerfile 的內(nèi)容如下:

          FROM?ubuntuRUN?useradd?-r?-u?1000?-g?appuserUSER?appuserENTRYPOINT?\["sleep",?"infinity"\]

          編譯成名稱為 test 的鏡像:

          $?docker?build?-t?test?.

          用 test 鏡像啟動一個容器:

          $?docker?run?-d?--name?sleepme?test

          在宿主機中查看 sleep 進程的信息:

          這次顯示的有效用戶是 nick,這是因為在宿主機中,uid 為 1000 的用戶的名稱為 nick。再進入到容器中看看:

          $?docker?exec?-it?sleepme?bash

          容器中的當前用戶就是我們設(shè)置的 appuser,如果查看容器中的 /etc/passwd 文件,你會發(fā)現(xiàn) appuser 的 uid 就是 1000,這和宿主機中用戶 nick 的 uid 是一樣的。讓我們再創(chuàng)建一個只有用戶 nick 可以讀寫的文件:

          同樣以數(shù)據(jù)卷的方式把它掛載到容器中:

          $?docker?run?-d?--name?sleepme?-w=/testv-v?$(pwd)/testv:/testv?test

          在容器中** testfile 的所有者居然變成了 appuser**,當然 appuser 也就有權(quán)限讀寫該文件。

          這里到底發(fā)生了什么?而這些又這說明了什么?首先,宿主機系統(tǒng)中存在一個 uid 為 1000 的用戶 nick。其次容器中的程序是以 appuser 的身份運行的,這是由我們通過 USER appuser 命令在 Dockerfile 程序中指定的。事實上,系統(tǒng)內(nèi)核管理的 uid 1000 只有一個,在宿主機中它被認為是用戶 nick,而在容器中,它則被認為是用戶 appuser。所以有一點我們需要清楚:在容器內(nèi)部,用戶 appuser 能夠獲取容器外部用戶 nick 的權(quán)利和特權(quán)。在宿主機上授予用戶 nick 或 uid 1000 的特權(quán)也將授予容器內(nèi)的 appuser。

          從命令行參數(shù)中自定用戶身份

          我們還可以通過 docker run 命令的 --user 參數(shù)指定容器中進程的用戶身份。比如執(zhí)行下面的命令:

          $?docker?run?-d?--user?1000--name?sleepme?ubuntu?sleep?infinity

          因為我們在命令行上指令了參數(shù) --user 1000,所以這里 sleep 進程的有效用戶顯示為 nick。進入到容器內(nèi)部看一下:

          $?docker?exec?-it?sleepme?bash

          這是個什么情況?用戶名稱居然顯示為 "I have noname!"!去查看 /etc/passwd 文件,里面果然沒有 uid 為 1000 的用戶。即便沒有用戶名稱,也絲毫不影響該用戶身份的權(quán)限,它依然可以讀寫只有 nick 用戶才能讀寫的文件,并且用戶信息也由 uid 代替了用戶名:

          需要注意的是,在創(chuàng)建容器時通過 docker run --user指定的用戶身份會覆蓋掉 Dockerfile 中指定的值。我們重新通過 test 鏡像來運行兩個容器:

          $?docker?run?-d?test

          查看 sleep 進程信息:

          $?docker?run?--user?0?-dtest

          再次查看 sleep 進程信息:

          指定了 --urser 0 參數(shù)的進程顯示有效用戶為 root,說明命令行參數(shù) --user0 覆蓋掉了 Dockerfile 中 USER 命令的設(shè)置。

          總結(jié)

          從本文中的示例我們可以了解到,容器中運行的進程同樣具有訪問主機資源的權(quán)限(docker 默認并沒有對用戶進行隔離),當然一般情況下容器技術(shù)會把容器中進程的可見資源封鎖在容器中。但是通過我們演示的對數(shù)據(jù)卷中文件的操作可以看出,一旦容器中的進程有機會訪問到宿主機的資源,它的權(quán)限和宿主機上用戶的權(quán)限是一樣的。所以比較安全的做法是為容器中的進程指定一個具有合適權(quán)限的用戶,而不要使用默認的 root 用戶。當然還有更好的方案,就是應(yīng)用 Linux 的 user namespace 技術(shù)隔離用戶,筆者會在接下來的文章中介紹如何配置 docker 開啟 user namespace 的支持。

          文章轉(zhuǎn)載:Devops技術(shù)棧
          (版權(quán)歸原作者所有,侵刪)


          點擊下方“閱讀原文”查看更多

          瀏覽 73
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  麻豆国产91 在线播放 | 久久高清成人电影 | 在线操b 国产乱子伦-区二区三区熟睡91 | 无码人妻一区二区蜜桃视频 | 免费一级黄色视频网站 |