1) clair介绍
关于clair
Clair是CoreOS 2016年发布的一款开源容器漏洞扫描工具。该工具可以交叉检查Docker镜像的操作系统以及上面安装的任何包是否与任何已知不安全的包版本相匹配。漏洞是从特定操作系统的通用漏洞披露(CVE)数据库获取。
通过从镜像文件系统中抽取静态信息以及维护一个组成镜像的不同层之间的差异列表,可以大大减少分析时间,而且不需要实际运行可能存在漏洞的容器。如果镜像所依赖的一个靠下的层存在漏洞,那么该镜像就会被识别为有漏洞,而且,通过使用图存储,可以避免重新分析镜像。
clair的目标是能够从一个更加透明的维度去看待基于容器化的基础框架的安全性。Clair=clear + bright + transparent
与 Clair 集成, 添加漏洞扫描功能(可以设置漏洞级别, 当漏洞级别达到一定程度时, 限制镜像的拉取) .
Clair总体工作原理
Clair主要包括以下模块:
- 获取器(Fetcher)- 从公共源收集漏洞数据
- 检测器(Detector)- 指出容器镜像中包含的Feature
- 容器格式器(Image Format)- Clair已知的容器镜像格式,包括Docker,ACI
- 通知钩子(Notification Hook)- 当新的漏洞被发现时或者已经存在的漏洞发生改变时通知用户/机器
- 数据库(Databases)- 存储容器中各个层以及漏洞
- Worker - 每个Post Layer都会启动一个worker进行Layer Detect
Clair整体处理流程如下:
- Clair定期从配置的源获取漏洞元数据然后存进数据库。
- 客户端使用Clair API处理镜像,获取镜像的特征并存进数据库。
- 客户端使用Clair API从数据库查询特定镜像的漏洞情况,为每个请求关联漏洞和特征,避免需要重新扫描镜像。
- 当更新漏洞元数据时,将会有系统通知产生。另外,还有webhook用于配置将受影响的镜像记录起来或者拦截其部署。
Clair漏洞等级说明如下:
- Unknown:社区暂未给出优先级或者Clair当前未同步支持
- Negligible:几乎无任何影响的漏洞,不会单独给出一个针对性的修复更新版本 Low 低风险等级,一般会在更高风险等级漏洞修复版本中修复
- Medium:中风险等级,如跨域、用户权限暴露等,会有针对性版本修复
- High:高风险等级,漏洞在大多数人默认的安装版本中出现,如服务出错、数据丢失、root权限恶意获取等
- Critical:最高风险等级,几乎所有版本都存在某漏洞,如造成用户大量数据丢失
2) 安装
cd /usr/local/harbor
# 关闭harbor
docker-compose stop
# 添加扫描插件
./prepare --with-clair
./prepare --with-clair --with-chartmuseum
# 重启Harbor服务
docker-compose -f docker-compose.yml up -d
3) 最佳实践
1.以非Root用户运行容器镜像
如果 Dockerfile 中没有指定 USER ,Docker 默认将会以超级用户 root 的身份运行容器,容器所属的命名空间(namespace)因此映射为 root 所有,这意味着容器有可能获取 Docker 宿主机的超级管理权限。不仅如此,以 root 用户身份运行容器,还扩大了攻击面,如果容器应用中存在安全漏洞,很容易造成权限提升。
在实践中,一般不需要容器拥有 root 权限。为了尽量降低安全威胁,创建专门的用户和用户组,在 Dockerfile 中使用 USER 指定用户,确保以最小权限的用户身份运行容器应用。
2.使用自己的私有注册中心
私有注册中心可以让您获得更完善的镜像的管理方式,并且通常提供更高级的功能,可以帮助确保库存安全。例如:
- 复杂的镜像扫描工具,用于识别威胁和未修补的漏洞。
- 严格的治理,例如基于角色的访问控制(RBAC)和合规性监视。
- 数字签名,镜像认证和其他防篡改功能。
- 用于开发,测试和生产多环境的镜像仓库。
相比之下,诸如Docker Hub之类的公共注册表一般仅提供基本服务-您必须信任镜像发布者,而镜像发布者可能未遵循相同的高安全标准。
这样,您最终可能会得到包含恶意或过时代码的镜像,并最终获得对数据泄露敞开大门的容器环境。
3.设定镜像的标签,保证镜像的不可更改性
每个 Docker 镜像可以有多个标签(tag),代表该镜像的不同变体。最常见的标签是 latest ,表示这是该镜像的最新版本。镜像标签是可更改的,也就是说镜像的作者可以多次发布相同标签的镜像。优先选用最详细的镜像标签,“:8.0.1-alpine” 等标签,不要使用像 latest 这样过于泛泛的标签。
4.选择最小的基础镜像
Docker hub上的某些镜像比其他的镜像更简化。比如在ubuntu仓库中,有些镜像的大小是部分版本的2倍以上。选用最小化基础镜像,即只包含项目确实需要的系统工具和库的镜像,就能最小化系统的攻击面,确保所用操作系统是安全的。
5.不要在容器镜像中包含机密信息
有时候,构建包含应用的容器镜像时,需要用到一些机密信息,例如从私有仓库拉取代码所需的 SSH 私钥,或者安全私有软件包所需的令牌。如果 Dockerfile 中包含复制机密信息的命令,构建镜像时,这行命令对应的中间容器会被缓存,导致机密数据也被缓存,有可能造成机密信息泄漏。因此,像令牌和密钥这样的机密信息必须保存在 Dockerfile 之外。
避免无意中复制机密信息:如果文件夹中有敏感文件,要么先移除这些文件,要么将这些文件包含在 .dockerignore 中,复制时会忽略这些文件。如果文件夹中有敏感文件,要么先移除这些文件,要么将这些文件包含在 .dockerignore 中,复制时会忽略这些文件
6.使用 COPY ,不要使用 ADD
从宿主机复制文件到容器镜像中的 Docker 命令有两个:COPY 和 ADD ,这两个命令本质上很相似,但具体功能并不相同:
- COPY - 将本地文件或者目录(递归)复制到容器镜像中的目标目录,复制来源和目标都必须明确指定。
- ADD - 与 COPY 类似的功能,有两个不同:(1)如果复制来源是本地压缩文件,ADD 将把该文件解压缩到目标目录;(2)ADD 也可以将远程 URL 指定的文件下载到目标目录。
为了避免可能导致的安全问题,请记住 COPY 和 ADD 的不同:
- 使用 ADD 从远程 URL 下载文件,存在中间人攻击的风险,文件内容有可能因此被篡改。必须确保远程 URL 必须是安全的 TLS 链接,校验远程 URL 的来源和身份。译者注:实际上,官方文档并不鼓励使用 ADD 添加远程文件。
- 如果复制的是本地压缩文件, ADD 自动将它解压缩到目标目录,这有可能触发 zip 炸弹或者 zip 任意文件覆盖漏洞。
- 相比较而言,使用 COPY 复制文件或目录,会创建一个缓存的中间镜像层,优化镜像构建的速度。
7.使用 LABEL 指定镜像元数据
镜像元数据有助于用户更好地理解和使用该镜像。最常见的元数据是 maintainer ,它说明了镜像维护者的电邮地址和名字。
8.签名和校验镜像,防范中间人攻击
Docker 镜像的认证颇具挑战性。在生产环境使用这些镜像运行我们的代码,意味着我们对这些镜像的极大信任。因此,必须保证我们拉取的容器镜像确实是发布者发布的镜像,没有被任何人篡改。发生镜像篡改,有可能是因为 Docker 客户端和镜像中心之间的中间人攻击,或者是发布者的身份被人盗用并在镜像中心发布了恶意镜像。
9.使用多阶段构建小而安全的镜像
使用 Dockerfile 构建应用容器镜像时,会生成很多只是构建时需要的镜像层,包括编译时所需的开发工具和库,运行单元测试所需的依赖、临时文件、机密信息等等。
如果保留这些镜像层,不仅会增加镜像的大小,影响镜像下载速度,而且会因为安装更多软件包而面临更大的攻击危险。这对用到的镜像也是成立的——需要使用一个专门构建应用的镜像,但不会用它来运行应用代码。
Go 语言就是一个很好的例子。构建一个 Go 应用需要用到 Go 编译器。编译得到的 Go 应用能够在任何操作系统上直接运行,没有任何依赖,包括 scratch 镜像。
Docker 因此提供了多阶段构建的功能,允许在构建过程中使用多个临时镜像,只保留最后一个镜像。这样,用户得到两个镜像:
- 第一个镜像——非常大的镜像,包含了构建应用和运行测试所需的所有依赖;
- 第二个镜像——非常小的镜像,只包含运行应用所需的极少数依赖。
10.使用静态分析工具
使用静态分析工具,能够避免常见的错误,建立工程师自动遵循的最佳实践指南。
例如,hadolint 分析 Dockerfile 并列出不符合最佳实践规则的地方。在集成开发环境(IDE)中使用 hadolint 更好。例如,安装 VS Code 的 hadolint 扩展后,编写 Dockerfile 时,边写边检查,既快又好。