如何为生产环境安全地使用Docker?
让我们看一下如何在生产环境中加固和保护Docker。
虽然 Docker使软件开发人员和DevOps工程师能够快速构建和部署应用程序,但它也提供了大量攻击面供 cyber hackers利用。
我们将从以下几点来看如何在Linux平台上保护Docker。
- 配置缺陷
- 远程代码执行
- 缓冲区溢出
- 镜像伪造等等。
我们将使用以下工具,比如 Docker’s notary server来签名镜像,以及 Docker bench security来检查主机、守护进程配置等等。
在我们开始保护之前,让我们先了解一些基础知识。
什么是容器技术?
容器技术允许开发人员或DevOps工程师将应用程序打包,以便它可以在与其他进程隔离的依赖环境中运行。
市场上有许多容器技术,比如 Apache Mesos、lxc和 Docker。虽然它们都属于容器技术的范畴,但它们的功能不同。
虚拟机和虚拟环境的区别
虚拟机主机与虚拟环境主机完全不同。在虚拟机上,每个容器化的应用程序都有自己的库和操作系统,而在虚拟环境主机上(如lxc和docker),应用程序默认共享Linux内核。
Docker是什么?
Docker是一种容器技术,被数百万人用于创建Web应用程序,并从测试环境部署到生产环境。
Docker引擎
Docker引擎由三个组件组成。
- 服务器:这个组件是一个长时间运行的进程或守护进程,负责管理镜像和容器。
- REST API:这个接口使得docker守护进程和docker客户端工具能够通信。
- Docker客户端工具:Docker客户端工具利用REST API组件通知docker守护进程操作容器化的应用程序。
Docker受信任的注册表
Docker受信任的注册表是Docker提供给企业平台业务的一个镜像存储解决方案。它与docker hub不同。docker hub托管在云端,而docker受信任的注册表是一个本地存储解决方案,用于存储企业数据。
Docker内容可信性
Docker内容可信性提供了使用数据签名来发送和接收来自远程docker注册表(如docker hub)的镜像。
Linux命名空间
Linux命名空间是Linux内核的一个特性,它将在虚拟环境主机上运行的容器化应用程序或进程与其他进程隔离开来。
Linux控制组(Cgroups)
Linux控制组是Linux内核的一个特性,允许您为主机上的活动进程分配资源,如CPU时间、网络带宽、系统内存等。
功能
在Linux中,内核子系统中有一个安全功能,可以设置或执行以限制特权进程,例如由UID 1的用户执行的进程。虽然特权进程或用户可以绕过可任意访问控制权限,但它们无法绕过功能规则。
现在让我们专注于安全问题。
保护Docker主机
在本节中,我们将看看如何保护Docker所在的主机。
扫描Linux内核
在Linux平台上托管docker之前,您首先需要检查内核。有几个开源工具,如 Lynis和 OpenVAS,您可以使用它们来扫描Linux内核。
使用git clone
命令从Github复制或克隆Lynis项目。
git clone https://github.com/CISOfy/lynis.git
接下来,使用以下命令导航到lynis
目录并审核Linux系统。
cd lynis; ./lynis audit system
加固 Linux 内核
在对 Linux 内核进行系统漏洞扫描后,您可以通过 grsecurity 来为内核添加另一个额外的保护层。它提供了以下安全功能。
- 防止缓冲区溢出利用
- 防止 /tmp 竞争漏洞
- 限制 /proc 不泄露有关进程所有者的信息。
- 防止在内核中执行任意代码等。
起初,您可以从 grsecurity 免费获取补丁并将其应用于当前的内核。但是现在它不再提供免费补丁。
在虚拟机中安装 Docker
您可以通过在虚拟机内部安装 Docker 来为 Linux 主机增加额外的保护层,而不是直接在 Linux 主机上安装 Docker。通过这样做,即使主机内核存在漏洞问题,也不会影响 Docker 容器。
保护根权限
默认情况下,Docker 需要 root 权限来创建和管理容器。恶意脚本可以利用这个攻击面来在 Linux 主机上升级为超级用户,并最终访问敏感文件/文件夹、镜像、证书等。
为了防止这种情况发生,我们可以使用以下命令。我们可以决定丢弃诸如 setgid
和 setuid
这样的能力,以防止其他程序或进程将其 GID 更改为另一个 GID,从而导致升级特权。您还可以查看 here 获取 Linux 能力定义的列表。
以下命令运行 apache web 服务器容器,并通过 --cap-drop
丢弃 setgid
和 setuid
能力,以防止 apache 容器将其 GID 和 UID 更改为另一个 UID 和 GID。
在这个上下文中,GID 和 UID 分别指的是 组 ID
和 用户 ID
。
docker run -d --cap-drop SETGID --cap-drop SETUID apache
Docker 用户
除了阻止其他程序或进程外,您还可以创建一个用户来管理 Docker 操作,例如 docker run
,而不是通过超级用户进行管理。
您可以通过以下命令添加或创建一个 Docker 用户:
sudo groupadd docker
以上命令创建了一个名为 docker
的组。
接下来,使用以下命令创建一个用户:
sudo useradd mike
最后使用以下命令将用户 mike
添加到组 docker
以管理 Docker 操作。
sudo usermod -aG docker mike
使用 Cgroups 管理容器
在生产环境中,您可能会有多个容器。
如果您的主机上没有安装 cgroups
,可以使用以下命令进行安装,然后参考 here(对于 Ubuntu)了解如何配置它。
sudo apt-get install cgroup-bin cgroup-lite cgroup-tools cgroupfs-mount libcgroup1
我们可以通过 --cpu-shares
和 --cpuset-cpus
分配有限的 CPU 资源给容器
以下命令示例显示 prodnginx
容器进程仅在第一个核心上执行,通过 --cpuset-cpus
,并且通过 --cpu-shares
分配了 20 个 CPU,而 proxnginx
容器进程在前两个 CPU 核心上执行,同样分配了 20 个 CPU。
docker run -d --name prodnginx --cpuset-cpus=0 --cpu-shares=20 nginx
docker run -d --name testnginx --cpuset-cpus=2 --cpu-shares=20 nginx
然后输入命令 docker stats
查看 prodnginx
和 testnginx
容器的 CPU 使用情况。
容器ID 名称 CPU% 内存使用/限制 内存% 网络I/O 块I/O
845bea7263fb prodnginx 57.69% 1.258MiB / 985.2MiB 0.13% 578B / 0B 1.33MB / 0B
189ba15e8258 testnginx 55.85% 1.25MiB / 985.2MiB 0.13% 578b / 0B 1.33MB / 0B
在拥有多个运行容器的docker主机上,为docker主机定义CPU共享是一个好主意。
使用命名空间管理容器
命名空间可以防止容器以特权用户身份运行,从而有助于避免特权升级攻击。
我们可以通过使用/etc/subuid和/etc/subgid文件来启用docker中的命名空间,如下所示。
创建一个用户使用adduser命令
sudo adduser dockremap
为用户dockremap设置一个subuid
sudo sh -c ‘echo dockremap:400000:65536 > /etc/subuid'
然后为用户dockremap设置subgid
sudo sh -c ‘echo dockremap:400000:65536 > /etc/subgid'
打开daemon.json文件,并填写以下内容,将userns-remap属性与用户dockremap关联起来
vi /etc/docker/daemon.json
{
“userns-remap”: “dockremap”
}
按:wq保存并关闭daemon.json文件,最后重新启动docker以在docker主机上启用命名空间
sudo /etc/init.d/docker restart
保护Docker守护程序
还需要配置Docker守护程序,以确保docker客户端与docker守护程序之间通过TLS进行安全通信。
使用以下命令打开daemon.json文件,并复制粘贴以下内容(将IP替换为实际IP),如下所示
vi daemon.json
{
“debug”: false,
“tls”: true,
“tlscert”: “/var/docker/server.pem”,
“tlskey”: “/var/docker/serverkey.pem”,
“hosts”: [“tcp://192.168.16.5:2376”]
}
保护Docker组件
让我们看看如何使用工具(link_15和link_16)来签署镜像,以避免镜像伪造。此外,还需要扫描镜像以确保镜像不会带有漏洞。
我们将使用Docker的notary服务器来签署和验证镜像,并使用link_17来扫描镜像以查找漏洞。
使用Notary服务器验证镜像
在我们可以使用Notary服务器签署镜像之前,我们需要下载和安装docker-compose。我们将使用link_18来设置notary服务器。
运行以下命令下载最新版本的Docker Compose
sudo curl -L “https://github.com/docker/compose/releases/download/1.25.4/docker-compose-$(uname -s)-$(uname -m)” -o /usr/local/bin/docker-compose
将可执行权限应用于docker-compose,如下所示
sudo chmod 700 /usr/local/bin/docker-compose
您可以通过以下命令测试是否成功安装docker-compose
docker-compose –version
现在我们可以通过docker-compose安装notary服务器
git clone https://github.com/theupdateframework/notary.git
上述命令将克隆或复制notary服务器来自link_19
通过以下命令启动notary服务器和签名器
docker-compose build
docker-compose up -d
- 然后使用以下命令将配置和测试证书复制到本地的公证目录
mkdir -p ~/.notary && cp cmd/notary/config.json cmd/notary/root-ca.crt ~/.notary
- 现在运行以下命令将公证服务器连接到docker客户端
export DOCKER_CONTENT_TRUST=1
export DOCKER_CONTENT_TRUST_SERVER=https://notaryserver:4443
- 通过以下命令生成授权密钥对
docker trust key generate mike --dir ~./docker/trust
- 现在让我们创建一个目标新密钥,以防存储库不存在
docker trust signer add --key ~/.docker/trust/mike.pub mike mikedem0/whalesay
- 然后,您可以使用命令
docker trust sign
来签署您的docker镜像。您需要从docker hub拉取docker镜像,并使用命令docker pull
和docker tag
重新标记。
docker trust sign mikedem0/nginx:latest
您还可以扫描docker镜像以查找漏洞和配置缺陷。您可以查看here以了解如何使用Anchor Engine扫描漏洞,并查看Docker Bench Security以检查配置缺陷。
希望以上内容能让您对用于生产环境的Docker安全有所了解。您也可以查看这个Udemy课程hacking and securing Docker containers。