docker的安全管理與TLS/LLS加密通信


Docker 安全與日志管理

一:Docker 容器與虛擬機的區別

1.1 容器的安全性問題

容器的安全性問題的根源在於容器和宿主機共享內核。如果容器里的應用導致ELinux內核崩潰,那么整個系統可能都會崩潰。與虛擬機是不同的,虛擬機並沒有與主機共享內核,虛擬機崩潰一般不會導致宿主機崩潰。



1.2 隔離與共享

虛擬機通過添加Hypervisor層(虛擬化中間層),虛擬出網卡、內存、cpu等虛擬硬件,再在其上建立虛擬機,每個虛擬機都有自己的系統內核。虛擬機通過Hypervisor進行隔離

而Docker容器則是通過隔離的方式,將文件系統、進程、設備、網絡等資源進行隔離,再對權限、cpu資源等進行控制,最終讓容器之間互不影響,容器無法影響宿主機。Docker 通過Namespace進行隔離

容器與宿主機共享內核、文件系統、硬件等資源。



1.3 性能與損耗

與虛擬機相比,容器資源損耗要少。同樣的宿主機下,能夠建立容器的數量要比虛擬機多。

但是,虛擬機的安全性要比容器稍好,要從虛擬機攻破到宿主機或其他虛擬機,需要先攻破Hypervisor層,這是極其困難的。

而docker 容器與宿主機共享內核、文件系統等資源,更有可能對其他容器、宿主機產生影響。

不同點 Docker容器 虛擬機
啟動速度 快,幾秒鍾 慢,幾分鍾
運行性能 接近原生(直接在內核中運行) 運行與Hypervisor上,50%左右損失
磁盤占用 小,甚至幾十kb(根據鏡像層的情況) 非常大,上GB
並發性 一台宿主機可以啟動成百上千個容器 最多幾十個虛擬機
隔離性 進程級別 系統級別(更徹底)
操作系統很 主要支持Linux 幾乎所有
封裝程度 只打包項目代碼和依賴關系,共享宿主機內核 完整的操作系統,與宿主機隔離



二:Docker 存在的安全問題

2.1 Docker 自身漏洞

Docker自身漏洞作為一款應用Docker本身實現上會有代碼缺陷。CVE官方記錄Docker歷史版本共有超過20項漏洞,可參見Docker官方網站。黑客常用的攻擊手段主要有代碼執行、權限提升、信息泄露、權限繞過等。目前Docker版本更迭非常快, Docker用戶可將Docker升級為最新版本。



2.2 Docker 源碼問題

Docker提供了Docker hub,可以讓用戶上傳創建的鏡像,以便其他用戶下載,快速搭建環境。但同時也帶來了一些安全問題。例如下面三種方式:

  1. 黑客上傳惡意鏡像

    • 如果有黑客在制作的鏡像中植入木馬、后門等惡意軟件,那么環境從一開始就已經不安全了,后續更沒有什么安全可言。
  2. 鏡像使用有漏洞的軟件

    • DockerHub上能下載的鏡像里面, 758的鏡像都安裝了有漏洞的軟件。所以下載鏡像后,需要檢查里面軟件的版本信息,對應的版本是否存在漏洞,並及時更新打上補丁。
  3. 中間人攻擊篡改鏡像

    • 鏡像在傳輸過程中可能被篡改, 目前新版本的Docker已經提供了相應的校驗機制來預防這個問題。



三: Docker 架構缺陷與安全機制

Docker本身的架構與機制就可能產生問題,例如這樣一種攻擊場景,黑客已經控制了宿主機上的一些容器,或者獲得了通過在公有雲上建立容器的方式,然后對宿主機或其他容器發起攻擊。

3.1 容器之間的局域網攻擊

主機上的容器之間可以構成局域網,因此針對局域網的ARP欺騙、端口掃描、廣播風暴等攻擊方式便可以用上。

所以,在一個主機上部署多個容器需要合理的配置網絡安全,比如設置iptables規則。



3.2 DDos攻擊耗盡資源

cgroups安全機制就是要防止此類攻擊的,不要為單一的容器分配過多的資源即可避免此類問題。



3.3 有漏洞的系統調用

Docker與虛擬機的一個重要的區別就是Docker與宿主機共用一個操作系統內核。

一旦宿主內核存在可以越權或者提權漏洞,盡管Docker使用普通用戶執行,在容器被入侵時,攻擊者還可以利用內核漏洞跳到宿主機做更多的事情。



3.4 共享root用戶權限

如果以root用戶權限運行容器(docker run --privileged) ,容器內的root用戶也就擁有了宿主機的root權限



四: Docker 安全基准線標准

下面從內核、主機、網絡、鏡像、容器以及其它等6個方面總結Docker安全基線標准。

4.1 內核級別

  1. 及時更新內核。
  2. User NameSpace (容器內的root權限在容器之外處於非高權限狀態)。
  3. cgroups (對資源的配額和度量) ,設置CPU、內存、磁盤1o等資源限制。
  4. 通過啟用SELinux/AppArmor/GRSEC (控制文件訪問權限)適當的強化系統來增加額外的安全性。
  5. Capability (權限划分) ,比如划分指定的CPU給容器。
  6. Seccomp (限定系統調用) ,限制不必要的系統調用。
  7. 禁止將容器的命名空間與宿主機進程命名空間共享,比如host網絡模式。



4.2 主機級別

  1. 為容器創建獨立分區,比如創建在分布式文件系統上。
  2. 僅運行必要的服務,注意盡量避免在容器中運行 ssh 服務。
  3. 禁止上將宿主機 上敏感目錄映射到容器,-yv創建數據卷時需要注意。
  4. 對 Docker 守護進程、相關文件和目錄進行審計,防止有病毒或木馬文件生成。
  5. 設置適當的默認文件描述符數。(文件描述符∶簡稱fd,當應用程序請求內核打開/新建一一個文件時,內核會返回個文件描述符用於對應這個系統資源,理論上系統內存多大就應該可以打開多少個文件描述符,但是實際情況是,內核會有系統級限制,以及用戶級限制,不讓某一個應用程序進程消耗掉所有的文件資源,可以使用ulimit -n 查看)
  6. 用戶權限為 root 的 Docker 相關文件的訪問權限應該為 644 或者更低權限。(7)周期性檢查每個主機的容器清單,並清理不必要的容器。



4.3網絡級別

  1. 通過iptables設定規則實現禁止或允許容器之間網絡流量。
  2. 允許Docker修改iptables.
  3. 禁止將Docker綁定到其他已使用的IP/Port或者Unix Socket.
  4. 禁止在容器上映射特權端口。
  5. 容器上只開放所需要的端口。
  6. 禁止在容器上使用host網絡模式。
  7. 若宿主機有多個網卡,將容器進入流量綁定到特定的主機網卡上。
    1. docker network create --subnet=172.18.0.0/16 --opt "com.docker.network.bridqe .name"="docker1" mynetwork
    2. docker run -itd --net mynetwork --ip 172.18.0.100 centos:7 /bin/bash
    3. iptables -t nat -A POSTROUTING -s 172.18.0.100 -o ens36 -j SNAT --to-source 192.168.80.10



4.4 鏡像級別

  1. 創建本地私有鏡像倉庫服務器。
  2. 鏡像中軟件都為最新版本,建議根據實際情況使用對應版本,業務穩定優先。
  3. 使用可信鏡像文件,並通過安全通道下載。
  4. 重新構建鏡像而非對容器和鏡像打補丁,銷毀異常容器重新構建。
  5. 合理管理鏡像標簽,及時移除不再使用的鏡像。
  6. 使用鏡像掃描。
  7. 使用鏡像簽名。



4.5 容器級別

  1. 容器最小化,操作系統鏡像最小集。
  2. 容器以單一主進程的方式運行。
  3. 禁止--privileged標記使用特權容器。
  4. 禁止在容器上運行ssh服務,盡量使用docker exec進入容器。
  5. 以只讀的方式掛載容器的根目錄系統, -v宿主機目錄:容器目錄:ro.
  6. 明確定義屬於容器的數據盤符。
  7. 通過設置on-failure限制容器嘗試重啟的次數,容器反復重啟容易丟失數據, --restart=on-failure:3
  8. 限制在容器中可用的進程數, docker run -m限制內存的使用,以防止fork炸彈。(fork炸彈,迅速增長子進程,耗盡系統進程數量) 經典的fork炸彈: . () { .| .&};



4.6 其他設置

  1. 定期對宿主機系統及容器進行安全審計。
  2. 使用最少資源和最低權限運行容器,此為Docker容器安全的核心思想。
  3. 避免在同一宿主機上部署大量容器,維持在一個能夠管理的數量。
  4. 監控Docker容器的使用,性能以及其他各項指標,比如zabbix
  5. 增加實時威脅檢測和事件報警響應功能,比如zabbix.
  6. 使用中心和遠程日志收集服務,比如ELK 。

由於安全屬於非常具體的技術,這里不再贅述,可直接參閱Docker官方文檔, https://docs.docker.com/engine/security



五: 容器相關的常用安全配置

5.1 容器最小化

如果僅在容器中運行必要的服務,像SSH等服務是不能輕易開啟去連接容器的。通常使用一下方式進入容器

docker exec -it 容器ID bash



5.2 Docker遠程的API訪問控制

Docker 的遠程調用API 接口存在未授權訪問漏洞,至少應該限制外網訪問。建議使用Socket 方式訪問。

在docker 服務配置文件中指定監聽內網IP

[root@host103 ~]#vim /usr/lib/systemd/system/docker.service
13行修改
13:// ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H tcp://192.168.23.103:2375



重啟docker

[root@host103 ~]# systemctl daemon-reload 
[root@host103 ~]# systemctl restart docke

[root@host103 ~]# netstat  -natp | grep 2375
tcp        0      0 192.168.23.103:2375     0.0.0.0:*               LISTEN      77808/dockerd 


在宿主機的firewalld上做ip訪問控制。source address 指定客戶端地址

[root@host103 ~]# firewall-cmd --permanent --add-rich-rule="rule family="ipv4" source address="192.168.23.104" port protocol="tcp" port="2375" accept"
success

[root@host103 ~]# firewall-cmd --reload
success


在客戶端實現遠程授權訪問

#在host103主機docker 客戶端啟動容器
[root@host103 ~]# docker run -itd  --name test1 centos:7   bas
[root@host103 ~]# docker run -itd  --name test2  centos:7   ba
[root@host103 ~]# docker ps 
CONTAINER ID   IMAGE      COMMAND   CREATED         STATUS    
e816df360df1   centos:7   "bash"    4 seconds ago   Up 3 secon
acfda848249f   centos:7   "bash"    8 seconds ago   Up 8 sec

#可以使用 -H選項指定ip和端口,能夠使用遠程的docker
[root@host104 ~]# docker -H tcp://192.168.23.103:2375 ps 
CONTAINER ID   IMAGE      COMMAND   CREATED          STAT
e816df360df1   centos:7   "bash"    13 seconds ago   Up 1
acfda848249f   centos:7   "bash"    17 seconds ago   Up

image-20211020102709125

image-20211020103003816



六: 限制流量流向

使用防火牆過濾器限制Docker容器的源IP 地址范圍與外界通信

[root@host103 ~]# firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.100.0/24" reject"
success

生產環境中的大量問題是因為Docker容器端口外放引起的漏洞,除了操作系統賬戶權限控制上的問題,更在於對Docker Daemon的進程管理上存在隱患。

目前常用的Docker版本都支持Docker Daemon管理宿主機iptables的,而且一旦啟動進程加上-p host port:guest port

的端口映射, Docker Daemon會直接增加對應的FORWARD Chain並且-j ACCEPT,而默認的DROP規則是在INPUT鏈做的,對docker沒法限制,這就留下了很嚴重的安全隱患。因此建議:

(1)不在有外網ip的機器上使用Docker服務。

(2)使用k8s等docker編排系統管理Docker容器。

(3)宿主機上Docker daemon啟動命令加一個--iptables=false,然后把常用iptables規則寫進文件里,再用iptables-restore重定向輸入去刷新規則。



七 鏡像安全

一般情況下,要確保只從受信任的庫中獲取鏡像,推薦使用harbor私有倉庫。

如果公司使用的不是自己的鏡像源,需要使用Docker鏡像安全掃描工具Clair,對下載的鏡像進行檢查。通過與CVE數據庫同步掃描鏡像,驗證鏡像的md5等特征值,確認一致后再基於鏡像進一步構建。一旦發現漏洞則通知用戶處理,或者直接阻止鏡像繼續構建。

也可以使用linux自帶的md5sum工具

img



八: DockerClient 端與DockerDaemon 的通信安全

8.1 SSL/TLS的通信過程

為了防止鏈路劫持、會話劫持等問題導致Docker通信時被中間人攻,, c/s兩端應該通過TLs加密方式通訊。

通過在服務端上創建t1s密鑰證書,再下發給客戶端,客戶端通過私鑰訪問容器,這樣就保證的docker通訊的安全性。

使用證書訪問的工作流程:

  1. 客戶端發起請求,連接到服務器的進程端口。
  2. 服務器必須要有一套數字證書(證書內容有公鑰、證書頒發機構、失效日期等) 。
  3. 服務器將自己的數字證書發送給客戶端(公鑰在證書里面,私鑰由服務器持有)。
  4. 客戶端收到數字證書之后,會驗證證書的合法性。如果證書驗證通過,就會生成一個隨機的密鑰對,用證書的公鑰加密。
  5. 客戶端將公鑰加密后的密鑰發送到服務器。
  6. 服務器接收到客戶端發來的密文密鑰之后,用自己之前保留的私鑰對其進行非對稱解密,解密之后就得到客戶端的密鑰,然后用客戶端密鑰對返回數據進行對稱加密,這樣傳輸的數據都是密文了
  7. 服務器將加密后的密文數據返回到客戶端。
  8. 客戶端收到后,用自己的密鑰對其進行對稱解密,得到服務器返回的數據。

8.2 創建ca證書過程

首先創建ca證書, ca證書只是一個官方認證的證書,接下來要創建server, client節點的證書。此時創建證書有三步:

(1)設置私鑰,確保安全加密

(2)使用私鑰簽名,確保身份真實不可抵賴

(3)使用ca證書制作證書

注意,docker 的go 版本要再1.15版本以下


8.3創建目錄,生成ca證書

8.3.1 創建目錄,生成私鑰文件

#卸載原docker-ce docker-ce-cli,安裝20.10.5-3的版本
[root@host103 ~]#yum remove -y docker-ce-cli docker-ce 
[root@host103 ~]#yum install -y docker-ce-cli-20.10.5-3.el7.x86_64 docker-ce
#docker version查看到的docker 信息中,go版本不可以高於1.15
[root@host103 ~]#docker version

#創建目錄
[root@host103 ~]# mkdir /tls
[root@host103 ~]# cd /tls/

#使用openssl 生成私鑰
[root@host103 tls]# openssl genrsa -aes256 -out ca-key.pem 4096
Generating RSA private key, 4096 bit long modulus
..............................................................................++
.......................................................................++
e is 65537 (0x10001)
#驗證密碼輸入123123
Enter pass phrase for ca-key.pem:123123
Verifying - Enter pass phrase for ca-key.pem:123123

genrsa:使用RSA算法產生私鑰

-aes256:使用256位密鑰的AEs算法對私鑰進行加密,這樣每次使用私鑰文件都將輸入密碼,可省略

-out:輸出文件的路徑,若未指定輸出文件,則為標准輸出

4096:指定私鑰長度,默認為1024。該項必須為命令行的最后一項參數

image-20211020195220254

image-20211020115356562


8.3.2 創建ca證書

#創建ca證書
[root@host103 tls]# openssl  req -new -x509 -days 1000 -key ca-key.pem -sha256 -subj "/CN=*" -out ca.pem
#驗證密碼,是之前的123123
Enter pass phrase for ca-key.pem: 123123


[root@host103 tls]# ls
ca-key.pem  ca.pem

req:執行證書簽發命令-new:新證書簽發請求

-x509:生成x509格式證書,專用於創建私有cA時使用

-days:證書的有效時長,單位是天

-key:指定私鑰路徑

-sha256:證書摘要采用sha256算法

-subj: 證書相關的用戶信息 (subject的縮寫)

-out:輸出文件的路徑

image-20211020115626179

image-20211020120017267


8.4  用ca證書簽發server端證書 

#創建服務器私鑰
[root@host103 tls]# openssl genrsa -out server-key.pem 4096
Generating RSA private key, 4096 bit long modulus
...................................................++
..............++
e is 65537 (0x10001)

#生成證書簽名請求文件(csr文件)
[root@host103 tls]# openssl req -new -key server-key.pem -sha256 -subj "/CN=*" -out server.csr
[root@host103 tls]# ls
ca-key.pem  ca.pem  server.csr  server-key.pem


#使用ca證書與私鑰證書簽發服務端簽名證書(密碼123123)
[root@host103 tls]# openssl x509 -req -days 1000 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem
Signature ok
subject=/CN=*
Getting CA Private Key
Enter pass phrase for ca-key.pem:123123


[root@host103 tls]# ls
ca-key.pem  ca.pem  ca.srl  server-cert.pem  server.csr  server-key.pem

x509:生成x509格式證書

-req:輸入csr文件

-in:要輸入的csr文件

-CA:指定ca證書的路徑

-CAkey:指定ca證書的私鑰路徑

-CAcreateserial:表示創建證書序列號文件,創建的序列號文件默認名稱為ca.srl

image-20211020121416367



8.5用ca 證書簽發client端證書

#生成客戶端私鑰
[root@host103 tls]# openssl genrsa -out client-key.pem 4096
Generating RSA private key, 4096 bit long modulus
......++
............++
e is 65537 (0x10001)
#生成了客戶端私鑰client-key.pem
[root@host103 tls]# ls
ca-key.pem  ca.pem  ca.srl  client-key.pem  server-cert.pem  server.csr  server-key.pem

#生成證書簽名請求文件client-csr
[root@host103 tls]# openssl req -new -key client-key.pem -subj "/CN=client" -out client.csr
[root@host103 tls]# ls
ca-key.pem  ca.pem  ca.srl  client.csr  client-key.pem  server-cert.pem  server.csr  server-key.pem

#創建擴展配置文件extfile.cnf,使得密鑰適合客戶端身份驗證
[root@host103 tls]# echo extendedKeyUsage=clientAuth > extfile.cnf

#使用ca證書簽發客戶端簽名證書。密碼123123
[root@host103 tls]# openssl x509 -req -days 1000 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out client-cert.pem -extfile extfile.cnf
Signature ok
subject=/CN=client
Getting CA Private Key
Enter pass phrase for ca-key.pem:

[root@host103 tls]# ls
ca-key.pem  ca.pem  ca.srl  client-cert.pem  client.csr  client-key.pem  extfile.cnf  server-cert.pem  server.csr  server-key.pem


#刪除兩個證書簽名請求文件和擴展配置文件
[root@host103 tls]# rm -rf ca.srl client.csr extfile.cnf server.csr 
[root@host103 tls]# ls
ca-key.pem  ca.pem  client-cert.pem  client-key.pem  server-cert.pem  server-key.pem

image-20211020141011021



8.6 配置docker服務配置文件,重啟docker

[root@host103 tls]# vim /lib/systemd/system/docker.service 
#修改13行
ExecStart=/usr/bin/dockerd  --tlsverify  --tlscacert=/tls/ca.pem --tlscert=/tls/server-cert.pem --tlskey=/tls/server-key.pem -H fd:// --containerd=/run/containerd/containerd.sock -H tcp://0.0.0.0:2376

#重啟docker配置
[root@host103 tls]# systemctl daemon-reload 
[root@host103 tls]# systemctl restart docker 

[root@host103 tls]# netstat -natp | grep 2376
tcp6       0      0 :::2376                 :::*                    LISTEN      81977/dockerd    
[root@host103 tls]# setenforce 0



8.7 復制ca證書和客戶端私鑰,客戶端簽名證書到客戶端主機,並修改服務端主機名,做hosts映射

# 復制ca證書和客戶端私鑰,客戶端簽名證書到客戶端主機
[root@host103 tls]# scp ca.pem 192.168.23.104:/etc/docker/
[root@host103 tls]# scp client-cert.pem 192.168.23.104:/etc/docker/
[root@host103 tls]# scp client-key.pem 192.168.23.104:/etc/docker/

#配置服務端主機名和ip映射
[root@host103 tls]# echo '127.0.0.1  host103' >> /etc/hosts


#本地連接
[root@host103 tls]# docker --tlsverify --tlscacert=ca.pem --tlscert=server-cert.pem --tlskey=server-key.pem -H tcp://host103:2376 images
REPOSITORY   TAG       IMAGE ID   CREATED   SIZE

#本地連接
[root@host103 tls]# docker --tlsverify --tlscacert=ca.pem --tlscert=server-cert.pem --tlskey=server-key.pem -H tcp://host103:2376 pull nginx

[root@host103 tls]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED      SIZE
nginx        latest    87a94228f133   8 days ago   133MB

image-20211020195407139



8.8客戶端遠程訪問

[root@client ~]#yum remove -y docker-ce-cli docker-ce 
[root@client ~]#yum install -y docker-ce-cli-20.10.5-3.el7.x86_64 docker-ce

[root@client ~]# echo '192.168.23.103 host103' > /etc/hosts

[root@client ~]# cd /etc/docker/
[root@client docker]# ls
ca.pem  client-cert.pem  client-key.pem  daemon.json  key.json

[root@client docker]# docker --tlsverify --tlscacert=ca.pem --tlscert=client-cert.pem --tlskey=client-key.pem -H tcp://host103:2376 images
REPOSITORY   TAG       IMAGE ID       CREATED      SIZE
nginx        latest    87a94228f133   8 days ago   133MB

image-20211020193407719

image-20211020195322863



如果訪問報錯如下:

rpc error: code = Unavailable desc = connection error: desc = "transport: authentication handshake failed: x509: certificate relies on legacy Common Name field, use SANs or temporarily enable Common Name matching with GODEBUG=x509ignoreCN=0"

則是因為docker版本過高,其go版本高於1.15,因為為 go 1.15 版本開始廢棄 CommonName



九:避免Docker 容器中信息泄露  

近幾年 Github 上大量泄露個人或企業各種賬號密碼,出現這種問題一般都使用 dockerfile 或者 docker-compose 文件創建容器。 如果這些文件中存在賬號密碼等認證信息,一旦 Docker 容器對外開放,則這些宿主機上的敏感信息也會隨之泄露。
因此可以通過以下方式檢查容器創建模板的內容。

# check created users
grep authorized_keys $dockerfile

# check OS users
grep "etc/group" $dockerfile

# Check sudo users
grep "etc/sudoers.d" $dockerfile

# Check ssh key pair
grep ".ssh/.*id_rsa" $dockerfile


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM