<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                # 第6章 安全 安全一直都是個困難重重的領域。優秀的安全專家會在追求完美和生產上線之間尋求恰當的平衡,并促進開發團隊考慮安全問題。 Docker在安全方面一直備受關注,因其“實用為先,安全在后”的模式總是會招致非議。此外,它并不具備單一的強安全模式及響應,而是依賴于多個層次,其中一些層次可能尚不存在或無法用于應用程序中。官方的[安全文檔](http://docs.docker.com/articles/security/) 也非常缺乏,因此用戶需要更多的支持。 這反映出了Linux的安全現狀,在市面上有大量選擇。盡管這些選擇不全是容器專用的,但是容器添加了更多工具,以至于比非容器化環境面臨的安全問題更為復雜。 容器或一般性微服務構架的安全評估,離不開對威脅模型(threat model)的理解。不同情況下,這些模型的形式也不同,不過其中很多都具有共通之處。 如果打算運行不受信任的代碼,可能是作為服務提供商,或運行一個PaaS平臺,人們可能會故意上傳惡意代碼,這與小團隊開發和托管一個應用程序的要求有所不同。大型企業的情況則不一樣,其監管要求代表著某些形式的隔離是強制性的。 如果你是一家服務提供商,目前虛擬化是隔離惡意代碼最成熟的技術。不是說它沒有安全問題,而是問題的數量很少且攻擊面更小。這并不意味著容器不能作為解決方案的一部分,特別是如果正在提供某種語言的運行時(如Ruby或Node.js),下面所講的很多技術也是完全適用的。容器是隔離的延伸形式,可以作為一個層次化防護,進一步減少攻擊面。 Google在[Borg論文](http://static.googleusercontent.com/media/research.google.com/en//pubs/archive/43438.pdf)中解釋了他們如何為受信任的內部作業提供完全不同的架構:“我們使用Linux chroot牢籠作為同一機器上多個任務之間的主要安全隔離機制”,這種安全性的形式比容器更脆弱,與之相反:“Google應用引擎(GAE)和Google計算引擎(GCE)使用虛擬機和安全沙箱技術運行外部軟件。我們在一個作為Borg任務運行的KVM進程中運行每個托管的虛擬機”。 那些關注圍繞容器構建微服務架構的安全性的大型和小型公司會特別關心這一章。 安全是一個復雜的領域,需要評估運行中應用程序的內容。不存在什么靈丹妙藥,深度防御才是關鍵,這就是本章將涵蓋多種不同方法來加強應用程序安全性的原因。很多方法最終會變成用戶使用的工具,但是理解它們保護或不保護的范圍,以及能否使用更具體的方案取代通用方案仍然非常重要。 Linux容器不是一個單一實體,與FreeBSD的[牢籠](https://www.freebsd.org/cgi/man.cgi?format=html&query=jail%282%29)(jail)不同,后者采用單一系統調用來創建和配置容器。相反,Linux容器是一組工具,可以進一步加強進程隔離,并遠遠超過傳統的Unix用戶ID機制和權限。 容器從根本上是構建于命名空間、cgroup及權能(capability)之上的。 Linux容器的核心是一系列的“命名空間”,效仿于Plan 9操作系統的思想。一個進程命名空間隱藏了所有命名空間之外的進程,給用戶分配了一組新的進程ID,包括新的init(`pid 1`)。一個網絡命名空間隱藏了系統的網絡接口,并以一個新的集合取而代之。這里的安全方面是,如果一個項目沒有可以引用的名字,就不能與之進行交互,也就形成了隔離。 系統中不是所有東西都命名空間化了,還存在大量全局狀態。例如,時鐘就不具備命名空間,所以如果有容器設置了系統時間,將影響內核中運行的所有東西。這些程序絕大多數只能被以root運行的進程影響。 另外一個問題是,Linux內核接口非常龐大,有些錯誤會藏身其中。具有超過300個系統調用,以及數以千計的各類`ioctl`操作,只要有一個存在用戶輸入驗證錯誤,就會導致內核漏洞。 不過,有很多方法可以用來降低這些風險,接下來我們會對此做一些介紹。 最基本的建議是及時使用安全補丁更新內核。我們并不是很清楚哪些修改會造成安全問題,因為可能很多錯誤已經造成漏洞,只是還沒被人發現。這意味著用戶需要經常性地重啟容器宿主機,因此也將重啟所有的容器。 顯然,用戶不會想要同時重啟整個集群,這會造成所有服務下線,造成分布式系統法定節點缺失,因此需要考慮如何進行管理。CoreOS機器運行著`etcd`,當它們檢測自己處于一個集群中時,會從`etcd`中獲取一個[重啟鎖](https://coreos.com/docs/cluster-management/setup/update-strategies/),因此每次只會有一臺機器重啟。其他系統也需要一個類似的交錯重啟機制。 用戶必須保持宿主機內核和宿主機操作系統被更新,并且保持對運行中的容器進行安全更新修補則是一個關鍵要求。 如果用戶所運行的“胖”容器包含了整個宿主機操作系統,如RHEL或Ubuntu,要保持它們被更新就非常簡單。只需要像對待虛擬機那樣運行同樣的工具軟件即可。雖然這無法利用到基于容器的工作流,但至少是個很好理解的問題。 人們擔心的情況是,Docker的使用是否會造成開發人員把內容不明的隨機容器放置到生產環境中。顯然,這不是用戶希望發生的事。容器必須從頭可重現地構建,如果組件中存在安全問題且無法在運行時更新的話,則必須重新構建。 最接近傳統做法的方法是拿傳統的發行版,使用類似Puppet這樣的工具對其進行配置,然后將其作為一個基礎Docker鏡像。 微服務的路線是讓容器只包含靜態鏈接的二進制文件,如使用Go生產的,這樣的構建過程就只是簡單地利用更新后的依賴對應用程序進行重新構建。然后,升級問題就變成了構建時依賴管理問題。Java應用程序也與此類似。 在這些極端情況之間還存在著大量其他模型。重要的是要有一個模型,并且最理想的是有測試,可以測試構建產物。例如,在[`bash` shellshock bug](http://en.wikipedia.org/wiki/Shellshock_%28software_bug%29)被發現之后,用戶希望能檢查生產環境中的容器,并測試它們是否包含bash且存在漏洞。 Unix長期以來都用著一個設計糟糕的特權提升機制,文件可以被標記上`suid`或`guid`,在這種情況下,程序將以程序的屬主(或組)身份運行,而非運行該程序的用戶。通常這用于以root運行那些需要特殊權限的程序。如果程序編寫得很好,那么它們會盡快丟棄這個root狀態,在解析任何用戶輸入之前,并盡可能縮小使用范圍。如果不是這么做,就存在被破壞的危險。 典型的可`suid`成root的二進制文件包括`su`、`sudo`、`mount`及`ping`。這些文件大多數在容器內是不需要的,因此可以對其進行刪除、移除suid位,或使用`nosuid`選項掛載容器根目錄以忽略它們。這是安全測試套件可以測試的東西。 需要注意的是,專門設計用于運行在容器內的發行版可以解決這類問題,但尚不多見。目前的發行版會假定這些基礎命令都是必需的。有些輕量級容器基礎系統使用了[Busybox](http://www.busybox.net/)核心小工具,這類工具沒有安全地實現`suid`程序,未丟棄特權,因此千萬不要在運行時啟用`suid`。 使用下面的命令可以查找系統中所有的`suid`和`guid`文件: ``` find / -xdev -perm -4000 -a -type f -print find / -xdev -perm -2000 -a -type f -print ``` 容器的設計原則是保證容器內沒有需要root權限的東西。尤其不要使用`docker run --privileged ...`,這將使用完全的root權限運行容器,并能執行宿主機可以操作的任何事情。 權能(見6.7節)是在需要時將root的權能子集賦予進程的一種方法。 用戶命名空間(見6.12節)旨在提供一匹神奇的“不是root的root”獨角獸,允許root的使用。6.12節中會詳細討論這一魔法。 遺憾的是,很多現存的容器都需要root權限,往往為了一些其實只需要修復即可的不好原因。其中一個例子是[Docker registry](https://github.com/docker/docker-registry/issues/915),它會在一個root擁有的目錄中創建鎖文件,除非用戶禁用搜索功能,否則這個問題依然存在。 Linux對于root擁有的權能具有一些細粒度的權限,可以獨立地分配給容器。capabilities(7)的[幫助頁](http://linux.die.net/man/7/capabilities)中羅列了各個權能對應的操作。例如: `docker run --cap-add=NET_ADMIN ubuntu sh -c "ip link eth0 down"`將只使用`NET_ADMIN`權限來停止容器內的`eth0`接口,而這是完成此項操作的最低要求。可以以此運行那些需要suid的二進制文件,而不需要以root身份運行整個容器,但總的來說還是應該避免這么做,為了保持最大化的安全性,容器應在不帶權能的情況下運行。 權能限制的是可以采取的操作類型,而seccomp過濾器則是完全移除了使用特定系統調用或特定參數調用的能力。 這一方案的困難之處在于確定應用程序需要使用的調用。用戶可以使用跟蹤的方式,不過必須覆蓋100%的代碼,而這很難做到。用戶的代碼可能會改變,使用的調用也可能改變。因此,對于一般用途的用例來說,最簡單的策略是使用黑名單,過濾那些管理專用的,并且一般不為應用程序所用或完全過時的系統調用。大約25%的調用可以歸入這些類別。 截至本書編寫時,只有Docker lxc后端具有運行seccomp過濾器的鉤子,默認的[libcontainer](https://github.com/docker/libcontainer/)后端則沒有。在Docker倉庫的[contrib目錄](https://github.com/docker/docker/blob/487a417d9fd074d0e78876072c7d1ebfd398ea7a/contrib/mkseccomp.sample)中有一些過濾器示例。為應用程序設置自身的過濾器也是可能的。 Linux支持多個內核安全框架,其中最著名的是由NAS設計的與Red Hat Linux一起發行的SELinux。與Ubuntu一起發行的AppArmor與此類似。 SELinux是一個實現強制[訪問控制](https://en.wikipedia.org/wiki/Mandatory_access_control)策略的框架。需要注意的是,它只是一個框架,必須定義實際的策略。但定義策略的人少之又少,其過程不僅復雜,且缺乏文檔。因此,多數人使用的是供應商提供的策略。事實上,盡管存在一本解釋SELinux的[填色書](http://opensource.com/business/13/11/selinux-policy-guide),Google搜索建議中最受歡迎的依然是“關閉”。 如果你不是在一個長期運作的組織里工作,如這些策略的發源地——美國國防部,定義確實管用的安全策略是件很困難的事。不過,原則上可以將其應用在隔離不同類型數據的訪問上,對于PCI合規而言,是HR數據或個人信息。遺憾的是,支持這些用途的工具還相當缺乏。 不過,我們建議盡可能不要禁用供應商策略,并且要理解如何標記允許訪問的項目。供應商策略好過沒有策略。容器的策略相對較新,可能不會一直很好地工作。 Docker從1.3版本開始支持SELinux,不過默認是關閉的。`docker --selinux-enabled`將啟用這個功能,而類似`--security-opt="label:user:USER"`的選項可以在運行容器時設置用戶、角色、類型及標簽。 內核cgroup功能是由Google創建的,用于在Borg調度器(Kubernetes的前身)中運行規模化的應用程序。 一個cgroup限制著分配給一組進程(通常是一個容器)的資源。cgroup控制器集合數量龐大而復雜,不過重要的幾個與CPU時間、內存和存儲被限制有關。 最簡單的是內存和CPU訪問限制。可通過`docker run -m 128m`來設置內存用量。通過`docker run --cpuset=0-3`來設置容器運行所在的CPU,而通過`docker run --cpu-shares=512`來分配CPU時間共享。 重要的一點是,要停掉占用了所有內存、IO帶寬和CPU時間的應用程序,它將影響同一臺宿主機上運行的其他應用程序。 根據容器設置的方式,可能還存在一些干擾。例如,除非徹底地分配了CPU,否則緩存將是共享的,而如果共享了IO設備,如網絡或磁盤,則存在IO競爭。這種情況會帶來多大的影響取決于負載以及超額申請的資源數量,不過通常這是一個吞吐量的問題,而非安全問題,不過[旁路攻擊](https://en.wikipedia.org/wiki/Side-channel_attack)還是有可能發生。 Docker 1.6增加了`cgroup-parent`選項,它可以將容器附加到現存cgroup中。這意味著用戶可以在Docker之外使用其他工具管理cgroup,然后選擇要添加到容器中的cgroup。這使得用戶可以使用所有的cgroup控制,而無需在意它們是否在Docker命令行中公開。 Docker 1.6引入了控制每個容器`ulimit`的能力。這是一個在每個進程基礎上控制資源的古老的Unix功能。需要注意的是`ulimit`也可以用來配置最大的處理器數量。出于不同目的,在資源控制上`ulimit`可能比cgroup更為簡單,系統管理員更熟悉。 此前,容器會繼承Docker進程的`ulimit`,這個限制一般都設置得相當高。現在可以用以下命令來設置可創建進程數的默認`ulimit`:軟限制為1024,硬限制為2048。 `docker -d --default-ulimit nproc=1024:2048`軟限制是要強制執行的限制值,不過進程可以對其進行提高,最高至硬限制值。 然后,可以在每個容器級別上覆蓋這些限制值,例如: `docker run -d --ulimit nproc=2048:4096 httpd`這將提高`httpd`容器的進程`ulimit`。 相比其他命名空間,用戶命名空間加入Linux內核的時間要遲一些,也較為復雜。 其思想與其他命名空間形式類似,只是用于用戶ID(uid)和組ID(gid)。特別是,處于用戶命名空間內的容器中的root用戶和uid 0,可以映射到宿主機不同的非特權用戶上。 這意味著,容器的root用戶在宿主機系統中只是一個普通用戶,無法做任何特殊的事情。那么它如何能稱為root?對于屬于其容器的資源來說,它就是root,如容器的網卡,因此它可以重新配置容器的網卡,或綁定到80端口上。 這引入了更多復雜性,由于uid只是存儲在文件系統中并分配權限給文件,因此對于不同的命名空間,它們的意義有所不同。這也意味著這項功能從引入到適合生產環境使用之間經歷了長時間的延誤。這樣的延誤意味著它錯過了REHL 7.0的最后期限,無法得到來自Docker的直接支持,不過預計不會很久,在lxc驅動程序里也會得到部分支持。 用戶命名空間另一個不太明顯的優點是創建命名空間完全不需要root權限。這讓Docker守護進程可以減少內部需要以root運行的代碼量。 在拉取請求[\#12648](https://github.com/docker/docker/pull/12648)中引入了最基礎的功能:容器內root用戶不對應宿主機系統的root用戶,但由于用戶命名空間代碼與libnetwork代碼存在沖突,這一請求錯過了Docker 1.7的最后期限,只能延后到Docker 1.8[\[1\]](part0012.xhtml#anchor61)。用戶命名空間更復雜的功能就差得更遠了。 Docker 1.3引入了Docker[鏡像驗證](http://blog.docker.com/2014/10/docker-1-3-signed-images-process-injection-security-options-mac-shared-directories/)的路線圖的最初部分。這僅是個開始,其目標是追尋Linux包管理器的路線,打造一個完整的模型。在這個模型中用戶有一組信任的密鑰,其中可能包括了受信任的供應商以及用戶所在組織的簽名,未經簽名的鏡像則不允許運行。 當前的實現還只是一個開始,驗證簽名失敗時它給出警告,但不會阻止未簽名包的安裝,因此它無法提供任何實際的安全性價值。不過,它只是路線圖的一個開端,可以在簽名鏡像問題[\#2700](https://github.com/docker/docker/issues/2700)上查看其計劃,并對其實現進行跟蹤。 默認情況下,Docker守護進程只能通過本地Unix域套接字進行訪問,這意味著可以在本地通過套接字的權限控制其訪問,而遠程訪問是完全不可能的。 訪問Docker守護進程將獲取整臺計算機完整的root權限,因此用戶能以root身份運行Docker容器來執行宿主機上的任何命令,所以對訪問的保護尤為重要。 如果用戶使用`-H`選項強行將Docker綁定到一個TCP端口上以便進行遠程控制(而不是通過ssh進行控制),那么用戶需要使用iptables和SSL來控制其他訪問。對多數用例而言,不推薦這么做。 要了解容器的運行情況,包括發現安全相關的問題,容器的監控非常重要。本書中有專門的一章講述監控,讀者可以從那里開始設計自己的監控策略。 如果容器需要訪問提供硬件或虛擬設備訪問的設備結點,可以通過`--device`選項傳遞所需的設備并設置權限。 例如,`docker run --device=/dev/snd:/dev/snd:r ...`將添加`/dev/snd`音頻設備到容器中,使其在容器中只讀。 由于設備節點允許`ioctl`訪問,同時下層內核驅動程序中可能存在問題,它們成為了攻擊面的一部分,尤其是特殊設備。因此,只提供需要的設備及最小的權限是最佳的策略。 在使用默認的`libcontainer`驅動程序時,Docker會很小心地以只讀權限掛載必要的虛擬文件系統。如果用戶使用的是lxc驅動程序,則這一步需要自己完成。如果容器內具有root權限,對類似`/sys`和`/proc/bus`這類文件系統的寫權限可能造成宿主機受損。 不要在容器里運行ssh。要習慣從宿主機上管理它們。這不僅簡化了容器,還消除了權限的復雜度的級別。習慣在需要時使用Docker提供的工具來查看容器運行情況。 簡化的容器更易于管理,并且從宿主機進入容器也相當簡單。實際上,Docker最終可以非常好地管理進程,而ssh是不必要的,還會增加復雜度。 服務需要使用密鑰去訪問其他服務,如訪問AWS的密鑰,或用于驗證它們是否可以加入集群或訪問資源。密鑰管理很難,是個有待解決的問題,現在存在著或好或壞的方法,同時一些有用的工具正如雨后春筍般出現。 密鑰應當只在必要時進行分發,如果它們被發現,最不可能的訪問也會受到威脅。密鑰應定期進行輪換,限制偶發缺口的持續時間。密鑰不應被簽入源代碼中,因為更新密鑰不應要求做一次新部署,而且它們最終將出現在公共的GitHub倉庫中。 能夠對密鑰訪問進行審計也是一個理想的目標,這樣可以跟蹤其使用。 出現的服務包括來自[SquareKeywhiz](https://corner.squareup.com/2015/04/keywhiz.html)和來自Hashicorp的[Vault](https://www.vaultproject.io/)。Kubernetes也有一份優秀的關于密鑰管理的[設計文檔](https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/design/secrets.md),可作為密鑰管理框架的基礎。 如果運行在宿主機或虛擬機上的所有服務對相同的數據都具有相同級別的訪問權限,可能就不太需要擔心隔離的問題了。畢竟,這不會比單體應用程序更糟,單體應用程序的組件并沒有真正的隔離。 雖然微服務可以讓用戶構建一個具備高級別的特權分離的更安全的架構,但對于不需要訪問敏感數據的應用程序,這并不是首要目標。用戶需要將安全方面的努力放在能帶來最大收益的地方。 面向用戶的服務面臨著不可信的輸入,顯然是一個薄弱點,應與重要數據的所有訪問隔離開。與PCI合規相關的端點不應與其他服務運行在同一臺宿主機上,并且應隔離到自己的集群,以減少審計邊界。 在第7章中,我們將細述Docker中鏡像的構建。 - - - - - - [\[1\]](part0012.xhtml#ac61) 該請求最終合并入Docker 1.9。——譯者注
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看