linux安全加固_【应用安全】Docker 安全配置(二)

我们在Docker 安全配置(一)文中对Docker的主机安全配置进行了详细的分析,本文我们将继续对Docker的容器和镜像安全进行分析。

b2974a3c7e0fc5c8df98624c6034e2b6.png

0x02 如何进行docker安全配置

2.4容器镜像和构建文件安全

2.4.1创建容器的用户

为容器镜像的Dockerfile中的容器创建非root用户。如果可能,指定非root用户身份运行容器是一个很好的做法。虽然用户命名空间映射可用,但是如果用户在容器镜像中指定了用户,则默认情况下容器将作为该用户运行,并且不需要特定的用户命名空间重新映射。

检查方法:执行以下命令,应该返回容器用户名或用户ID。如果为空,则表示容器以root身份运行。

docker ps --quiet | xargs docker inspect --format '{{ .Id }}:User={{.Config.User}}'

加固方法:

确保容器镜像的Dockerfile包含以下指令:USER 其中用户名或ID是指可以在容器基础镜像中找到的用户。如果在容器基础镜像中没有创建特定用户,则在USER指令之前添加useradd命令以添加特定用户。

例如,在Dockerfile中创建用户:

RUN useradd -d /home/username-m -s /bin/bash username USER username

2.4.2容器中不安装没有必要的软件包

容器往往是操作系统的最简的版本。不要安装任何不需要的软件。安装不必要的软件可能会增加容器的攻击风险。因此,除了容器的真正需要的软件之外,不要安装其他多余的软件。

检查方法:

步骤1:通过执行以下命令列出所有运行的容器实例:

docker ps --quiet

步骤2:对于每个容器实例,执行以下或等效的命令:

docker exec $INSTANCE_ID rpm -qa
docker exec $ INSTANCE_IDdpkg -l

加固方法:如果可能的话,考虑使用最小基本镜像而不是标准的Redhat / Centos /Debian镜像。可以选择BusyBox和Alpine。这不仅可以将您的镜像大小从> 150Mb修剪至20 Mb左右,还可以使用更少的工具和路径来提升权限。

2.4.3镜像中删除setuid和setgid权限

删除镜像中的setuid和setgid权限防止容器中的提权攻击。setuid和setgid可用于提升权限。虽然这些权限有时必须,应考虑为镜像中不需要的软件包删除这些权限。

检查方法:在镜像上运行以下命令以列出具有setuid和setgid权限的可执行文件:

docker run  find / -perm +6000 -type f -exec ls -ld {} \; 2> /dev/null

加固方法:只在需要可执行的文件上允许setuid和setgid权限。可在构建时通过在Dockerfile中添加以下命令来删除这些权限,最好添加在Dockerfile的末尾:

RUN find / -perm +6000-type f -exec chmod a-s {} \;|| true

2.4.4仅安装已经验证的软件包

在将软件包安装到镜像中之前,验证软件包可靠性。验证软件包的可靠性对于构建安全的容器镜像至关重要。不合法的软件包可能具有恶意或者存在一些可能被利用的已知漏洞。

检查方法:

第1步:运行以下命令以获取镜像列表:docker images

第2步:对上面列表中的每个镜像运行以下命令,并查看软件包的合法性docker history

加固方法:使用GPG密钥下载和验证您所选择的软件包或任何其他安全软件包分发机制。

2.5容器运行时保护

2.5.1启用AppArmor配置文件

AppArmor是一个高效且易于使用的Linux应用程序安全系统。它可以在很多Linux发行版上使用,例如Debian和Ubuntu。AppArmor通过执行安全策略(也称为AppArmor配置文件)来保护Linux操作系统和应用程序免受各种威胁。您可以为容器创建自己的AppArmor配置文件或使用Docker的默认AppArmor配置文件。

检查方法:执行以下命令应该为每个容器实例返回一个有效的AppArmor配置文件。

docker ps --quiet --all |xargs docker inspect --format '{{ .Id }}:AppArmorProfile={{ .AppArmorProfile}}'

加固方法:

如果AppArmor适用于你的Linux操作系统,可能需要遵循以下步骤:

1.验证是否安装了AppArmor。如果没有,请安装。

2.为Docker容器创建或导入AppArmor配置文件。

3.将此配置文件置于强制模式。

4.使用自定义的AppArmor配置文件启动Docker容器。例如,

docker run --interactive --tty --security-opt =“apparmor:PROFILENAME”centos /bin/bash

或者,可以保留Docker的默认apparmor配置文件

2.5.2设置SElinux安全选项

SELinux是一个有效且易于使用的Linux访问控制机制。默认情况下,它可以在很多Linux发行版上使用,如Red Hat和Fedora。SELinux提供强制访问控制(MAC)系统,大大增强了默认的自由访问控制(DAC)模型。因此,可以通过在Linux主机上启用SELinux(如果适用)来增加额外的安全防护。

检查方法:执行以下命令应返回当前为容器配置的所有安全选项。

docker ps --quiet --all |xargs docker inspect --format '{{ .Id }}:SecurityOpt={{ .HostConfig.SecurityOpt}}'

加固方法:如果SELinux适用于你的Linux操作系统,请使用它。可能需要遵循以下步骤:

1.设置SELinux状态。

2.设置SELinux策略。

3.为Docker容器创建或导入SELinux策略模板。

4.启用SELinux的守护程序模式下启动Docker。例如,

docker daemon --selinux-enabled

5.使用安全选项启动Docker容器。例如,

docker run --interactive --tty --security-opt label = level:TopSecretcentos /bin/bash

2.5.3 linux内核功能在容器内受限

Docker支持添加和删除功能,允许使用非默认配置文件。这可能会使Docker通过移除功能更加安全,或者通过增加功能来减少安全性。因此,建议除去容器进程明确要求的所有功能。例如,容器进程通常不需要如下所示的功能:NET_ADMIN SYS_ADMIN SYS_MODULE。

检查方法:执行以下命令验证添加和删除的Linux内核功能是否符合每个容器实例的容器进程所需的功能。

docker ps --quiet --all |xargs docker inspect --format '{{ .Id }}:CapAdd={{ .HostConfig.CapAdd }}CapDrop={{ .HostConfig.CapDrop }}'

加固方法:

执行以下命令添加所需的功能:

docker run --cap-add ={“Capability1”,“Capability2”}

例如,

docker run --interactive --tty --cap-add = {“NET_ADMIN”,“SYS_ADMIN”}centos:latest /bin/bash

执行以下命令删除不需要的功能:

docker run --cap-drop ={“Capability1”,“Capability2”}

例如,

docker run --interactive --tty --cap-drop = {“SETUID”,“SETGID”}centos:latest /bin/bash

或者,您可以选择删除所有功能并只添加所需功能:

docker run --cap-drop =all --cap-add = {“Capability 1”,“Capability 2”}

例如,

docker run --interactive --tty --cap-drop = all --cap-add ={“NET_ADMIN”,“SYS_ADMIN”}centos:latest /bin/bash

2.5.4不使用特权容器

使用--privileged标志将所有Linux内核功能提供给容器,从而覆盖-cap-add和-cap-drop标志。若无必须请不要使用它。--privileged标志给容器提供所有功能,并且还提升了cgroup控制器执行的所有限制。换句话说,容器可以做几乎主机可以做的一切。这个标志

存在允许特殊用例,就像在Docker中运行Docker一样。

检查方法:执行以下命令应为每个容器实例返回Privileged = false。

docker ps --quiet --all |xargs docker inspect --format '{{ .Id }}:Privileged={{ .HostConfig.Privileged}}'

加固方法:不要运行带有--privileged标志的容器。例如,不要启动如下容器:

docker run --interactive --tty --privileged centos /bin/bash

2.5.5 SSH不在容器中运行

SSH服务不应该在容器内运行。在容器内运行SSH可以增加安全管理的复杂性,难以管理SSH服务器的访问策略和安全合规性,难以管理各种容器的密钥和密码难以管理SSH服务器的安全升级,可以在不使用SSH的情况下对容器进行shell访问,避免不必要地增加安全管理的复杂性。

检查方法:

步骤1:通过执行以下命令列出所有运行的容器实例:

docker ps --quiet

步骤2:对于每个容器实例,执行以下命令:

docker exec $INSTANCE_ID ps -el

加固方法:从容器中卸载SSH服务器,并使用nsenter或其他任何命令(如docker exec或docker attach)与容器实例进行交互。

docker exec --interactive --tty $INSTANCE_ID sh OR dockerattach $INSTANCE_ID

2.5.6特权端口禁止映射到容器内

低于1024的TCP / IP端口号被认为是特权端口。由于各种安全原因,普通用户和进程不允许使用它们。默认情况下,如果用户没有明确声明容器端口进行主机端口映射,Docker会自动地将容器端口映射到主机上的49153-65535中。但是,如果用户明确声明它,Docker可以将容器端口映射到主机上的特权端口。这是因为容器使用不限制特权端口映射的NET_BIND_SERVICE Linux内核功能来执行。特权端口接收和发送各种敏感和特权的数据。允许docker使用它们可能会带来严重的影响。

检查方法:执行以下命令列出容器的所有运行实例及其端口映射,查看列表,并确保容器端口未映射到低于1024的主机端口号。

docker ps --quiet | xargsdocker inspect --format '{{.Id}}:Ports ={{.NetworkSettings.Ports}}'

加固方法:启动容器时,不要将容器端口映射到特权主机端口。另外,确保没有容器在Docker文件中特权端口映射声明。

2.5.7只映射必要的端口

容器镜像的Dockerfile定义了在容器实例上默认要打开的端口。端口列表可能与在容器内运行的应用程序相关。一个容器可以运行在Docker文件中为其镜像定义的端口,也可以任意传递运行时参数以打开一个端口列表。此外,Docker文件可能会进行各种更改,暴露的端口列表可能与在容器内运行的应用程序不相关。推荐做法是不要打开不需要的端口。

检查方法:执行以下命令列出容器的所有运行实例及其端口映射,查看列表,并确保映射的端口是容器真正需要的端口。

docker ps --quiet | xargs docker inspect --format '{{.Id}}:Ports ={{.NetworkSettings.Ports}}'

加固方法:修复容器镜像的Dockerfile,以便仅通过容器化应用程序公开所需的端口。也可以通过在启动容器时不使用-P(UPPERCASE)或--publish-all标志来完全忽略Dockerfile中定义的端口列表。使用-p(小写)或--publish标志来明确定义特定容器实例所需的端口。例如,

docker run --interactive --tty --publish 5000 -publish 5001 -publish 5002 centos /bin/bash

2.5.8不共享主机的网络命名空间

当设置为“--net = host”时,容器上的网络模式将容器放置在单独的网络堆栈中。这个选择告诉Docker不使用docker内部网络,那就意味着容器在可以完全访问主机的网络接口。

检查方法:执行以下命令命令返回NetworkMode = host,则意味着在启动容器时传递了--net = host选项。

docker ps --quiet --all |xargs docker inspect --format '{{ .Id }}:NetworkMode={{ .HostConfig.NetworkMode}}'

加固方法:启动容器时不要通过'--net = host'选项。

2.5.9确保容器的内存使用合理

默认情况下,Docker主机上的所有容器均等共享资源。通过使用Docker主机的资源管理功能,例如内存限制,您可以控制容器可能消耗的内存量。

检查方法:执行以下命令返回0,则表示内存无限制。如果上述命令返回非零值,则表示已有内存限制策略。

docker ps --quiet --all |xargs docker inspect --format '{{ .Id }}:Memory={{ .HostConfig.Memory }}'

加固方法:建议使用--memory参数运行容器。例如,可以运行一个容器如下:

docker run --interactive--tty --memory 256m centos /bin/bash

在上面的示例中,容器启动时的内存限制为256 MB。值得注意的是,如果存在内存限制,下面命令的输出将以科学计数形式返回值。

docker inspect --format ='{{。Config.Memory}}'7c5a2d4c7fe0

例如,如果上述容器实例的内存限制设置为256 MB,则上述命令的输出将为2.68435456e + 08而不是256m。应该使用科学计算器或编程方法来转换此值。

2.5.10正确设置容器上的CPU优先级

默认情况下,Docker主机上的所有容器均可共享资源。通过使用Docker主机的资源管理功能(如CPU共享),可以控制容器可能占用的主机CPU资源。

检查方法:执行以下命令返回0或1024,则表示CPU无限制。如果上述命令返回非1024值以外的非零值,则表示CPU已经限制。

docker ps --quiet --all |xargs docker inspect --format '{{ .Id }}:CpuShares={{ .HostConfig.CpuShares }}'

加固方法:管理容器之间的CPU份额。为此,请使用--cpu-shares参数启动容

器。例如,可以运行一个容器,如下所示:在上面的示例中,容器以其他容器使用的50%的CPU份额启动。因此,如果另一个容器的CPU份额为80%,则此容器的CPU份额为40%。

docker run --interactive --tty --cpu-shares 512 centos /bin/bash

注意:默认情况下,每个新容器将拥有1024个CPU份额。但是,如果运行审计部分中提到的命令,则此值显示为0。或者使用如下方法:

1.进入/sys/fs/cgroup/cpu/system.slice/目录。

2.使用docker ps检查容器实例ID。

3.在上面的目录中(在步骤1中),将有一个名称为docker-

ID> .scope的目录。例如,进入此目录。

docker -4acae729e8659c6be696ee35b2237cc1fe4edd2672e9186434c5116e1a6fbed6.scope

4.可以找到一个名为cpu.shares的文件。执行cat cpu.shares。可以看到

CPU的份额值。因此,在docker run命令中没有使用-c或--cpu-shares

参数配置CPU共享,该文件的值为1024。

2.5.11设置容器的根文件系统为只读

通过使用Docker运行的只读选项,容器的根文件系统应被视为“黄金镜像”。这样可以防止在容器运行时写入容器的根文件系统。启用此选项会迫使运行时的容器明确定义其数据写入策略,可减少安全风险,因为容器实例的文件系统不能被篡改或写入,除非它对文件系统文件夹和目录具有明确的读写权限。

检查方法:执行以下命令返回true,则表示容器的根文件系统是只读的。如果上述命令返回false,则意味着容器的根文件系统是可写的。

docker ps --quiet --all |xargs docker inspect --format '{{ .Id }}:ReadonlyRootfs={{.HostConfig.ReadonlyRootfs }}'

加固方法:在容器的运行时添加一个只读标志以强制容器的根文件系统以只读方式装入。

docker run  - read-only or ID> 

在容器的运行时启用只读选项,包括但不限于如下:

1.使用--tmpfs选项为非持久数据写入临时文件系统。

docker run --interactive--tty --read-only --tmpfs“/ run”--tmpfs“/tmp”centos /bin/bash

2.启用Docker rw在容器的运行时载入,以便将容器数据直接保存在Docker主机文件系统上。

docker run --interactive --tty --read-only -v /opt/app/data:/run/app/data:rw centos /bin/bash

3.使用Docker共享存储卷插件来存储Docker数据卷以保留容器数据。

docker volume create -dconvoy --opt o = size = 20GB my-named-volume docker run --interactive --tty--read-only -v my-named-volume:/run/app/data centos /bin/bash

4.在容器运行期间,将容器数据传输到容器外部,以便保持容器数据。包括托管数据库,网络文件共享和API。

2.5.12容器重启策略on-failure设置为5

在docker run命令中使用--restart标志,可以指定重启策略,以便在退出时确定是否重启容器。基于安全考虑,应该设置重启尝试次数限制为5次。

检查方法:执行以下命令返回RestartPolicyName = always,那么系统没有按需要进行配置。如果上述命令返回RestartPolicyName =no或仅RestartPolicyName = ,则重新启动策略未被使用,容器不会重新启动。如果上述命令返回RestartPolicyName = on-failure,则通过查看MaximumRetryCount验证重新启动尝试的次数是否设置为5或更少。

加固方法:如果一个容器需要自己重新启动,可以如下设置:

docker run --detach --restart= on-failure:5 nginx

2.6可信镜像

确保容器镜像是从头开始编写的,或者是基于通过安全仓库下载的另一个已建立且可信的基本镜像。官方存储库是由Docker社区或供应商优化的Docker镜像。可能还存在其他不安全的公共存储库。在从Docker和第三方获取容器镜像时,需谨慎使用。

检查方法:

步骤1 -检查Docker主机以查看执行以下命令使用的Docker镜像:docker images这将列出当前可用于Docker主机的所有容器镜像。访谈系统管理员并获取证据,证明镜像列表是通过安全的镜像仓库获到的,也可简单的从镜像的TAG名称来判断是否为可信镜像。

步骤2 -对于在Docker主机上找到的每个Docker镜像,检查镜像的构建方式,以验证是否来自可信来源:docker history

加固方法:配置和使用Docker内容信任。

检查Docker镜像历史记录以评估其在网络上运行的风险。

扫描Docker镜像以查找其依赖关系中的漏洞。

0x04总结

对docker进行安全配置可以有效的防范一些常见安全问题,按照基线标准做好安全配置能够减少安全事件的发生。国内常见的基线标准有中国信息安全等级保护,国际的标准有CIS_Docker_1.6_Benchmark_v1.0.0,不同的企业也可以根据自身企业业务制定符合自己企业的安全基线标准。

从Gartner分析报告可以看出,容器真正的问题在于docker的部署过程中缺乏安全团队的接入,并没有使用安全的部署方式进行部署,同时报告中也指出了docker安全需要对docker从创建到投产的整个生命周期进行安全安全防护。在docker的部署中对docker进行安全配置能够有效的减少安全威胁。对docker进行安全配置可以简单的分为一下几个方面:docker容器安全、docker镜像安全、docker主机安全。并且对docker镜像和主机定期更新安装安全补丁也同为重要。

参考链接

  • Gartner Identifies the Top Technologies for Security in 2017

  • CIS_Docker_1.6_Benchmark_v1.0.0

  • Docker 容器最佳安全实践白皮书(V1.0)

aef9ad4c9d0136c47614652fb0a91f12.gif

242c7f396dfe25f9eea0221736ed2f43.png

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值