天天看點

學習Docker的User Namespace

本文假設你已經了解了linux container,cgroup和基本的namespace概念。

user namespace是linux 3.8新增的一種namespace,用于隔離安全相關的辨別和屬性。使用了user namespace之後,程序在namespace内部和外部的uid/gid可以不一樣,常用來實作這種效果:程序在namespace外面是一個普通使用者,但是在namespace裡是root(uid=0),也就是程序在這個namespace裡擁有所有的權限,在namespace外面隻有普通使用者的權限了。

既然都是解決安全方面問題的,就不得不提另外兩個linux安全方面的功能,另外兩個常用的是capabilities和lsm (linux security module),其中capabilities和user namespace關系密切。通過調用帶<code>clone_newuser</code>參數的clone方法建立的子程序,自動擁有新user namespace裡所有capabilities。另外,程序通過unshare建立一個新的user namespace,或者通過setns加入一個已有的namespace,都自動擷取對應user namespace裡所有的capabilities。如果接下來程序通過execve啟動了新程式,就要按照capabilities計算規則重新計算新程序的capabilities。

上面的例子建立了一個子程序,其中包含了uts, pid, mount和user namespace。編譯并且運作上面的代碼

運作效果如下

學習Docker的User Namespace

可以看到,在container内部已經是root了。非常神奇的是,原來uid=1000的檔案,在container内部自動顯示成uid=0,原來uid=0的,自動變成uid=65534 (nobody),很完美。

代碼中關鍵的部分在<code>set_uid_map</code>中,要設定新建立user namespace和parent user namespace(這裡例子中是系統預設的namespace)中uid和gid的映射,隻要寫程序對應的兩個檔案即可:

/proc/pid/uid_map

/proc/pid/gid_map

這裡的pid是運作在user namespace中的程序id。寫入的格式是

<code>id-inside-ns id-outside-ns length</code>

id-inside-ns: namespace内部的uid/gid

id-outside-ns: namespace外部的uid/gid

length 映射範圍

有人可能主要到 上面的setcap操作,這一步也很關鍵,建立username也需要特定的capabilities才行,為了友善,這裡直接設定為<code>all</code>

待續

繼續閱讀