私有化部署的 Runner 的安全

极狐GitLab CI/CD 流水线是处理简单或复杂 DevOps 自动化任务的工作流自动化引擎。由于这些流水线启用了远端代码执行服务,因此您应该实施以下流程以降低安全风险:

  • 一种配置整个技术栈安全性的系统方法。
  • 对平台的配置和使用进行持续的严格审查。

如果您计划在私有化部署的 Runner 上运行极狐GitLab CI/CD 作业,那么您的计算基础设施和网络存在安全风险。

Runner 执行 CI/CD 作业中定义的代码。任何对项目的仓库具有开发者角色的用户都可能会危及托管 Runner 的环境的安全性,无论是否有意。

如果您的私有化部署的 Runner 不是临时的并且用于多个项目,那么这种风险会更加严重。

  • 嵌入恶意代码的仓库中的作业可能会危及由非临时 Runner 处理的其他存储库的安全。
  • 根据执行器的不同,作业可以在 Runner 所在的虚拟机上安装恶意代码。
  • 暴露在受感染环境中运行的作业的 Secret 变量可能会被窃取,包括但不限于 CI_JOB_TOKEN。
  • 具有开发者角色的用户可以访问与项目关联的子模块,即使他们无权访问子模块的上游项目。

不同执行器的安全风险

根据您所用执行器的不同,您可能会遇到不同的安全风险。

使用 Shell 执行器

使用 shell 执行器运行构建时,您的 Runner 主机和网络存在高安全风险。 作业以极狐GitLab Runner 用户的权限运行, 并且可以从其他运行在服务器上的项目中窃取代码。 请仅使用它运行受信任的构建。

使用 Docker 执行器

Docker 在非特权模式下运行时可以认为是安全的。 为增加安全性,请在禁用 sudo 或移除 SETUIDSETGID 功能的 Docker 容器中以非根用户的身份运行作业。

您可以通过 cap_add/cap_drop 设置在非特权模式下配置更精细的权限。

cautionDocker 中的特权容器具有托管虚拟机的所有根功能。 有关更多信息,请查看有关运行时特权和 Linux 功能的官方 Docker 文档。

不建议以特权模式运行容器。

启用特权模式后,运行 CI/CD 作业的用户可以获得 Runner 的主机系统的完全根访问权限、安装和卸载卷的权限,并且可以运行嵌套容器。

通过启用特权模式,您实际上禁用了所有容器的安全机制并使您的主机暴露于特权升级,这可能会导致容器突破。

当 Runner 在多个组织之间共享时,风险尤其大。 例如,像 JiHuLab.com 这样的服务中的实例范围的 Runner,其中多个不同的组织可以同时工作。

如果您使用 Docker Machine 执行器,我们也强烈建议您使用 MaxBuilds = 1 设置, 这可以确保单个弹性伸缩的虚拟机(由特权模式引入的安全漏洞而可能受到威胁)只处理一项工作。

通过 if-not-present 拉取策略使用私有 Docker 镜像

使用高级配置:使用私有容器镜像库中描述的私有 Docker 映像支持时, 您应该使用 always 作为 pull_policy 值。特别是如果您使用 Docker 或 Kubernetes 执行器托管公共的且共享的 Runner,您应该使用 always 拉取策略。

在下面的例子中,我们将拉取策略设置为 if-not-present

  1. 用户 A 在 registry.example.com/image/name 中有一个私有镜像。
  2. 用户 A 在共享 Runner 上启动构建:构建接收容器库证书并在容器库中授权后拉取镜像。
  3. 镜像存储在共享 Runner 的主机上。
  4. 用户 B 无权访问 registry.example.com/image/name 中的私有镜像。
  5. 用户 B 在与用户 A 共享的 Runner 上启动使用此映像的构建:Runner 找到镜像的本地版本,并且即使由于缺少证书而无法拉取镜像,也依然使用它。

因此,如果您托管一个可供不同用户和项目(通过混合的私有和公共访问级别)使用的 Runner,您不应该使用 if-not-present 作为拉取策略值,而是使用:

  • never - 如果您想限制用户使用您预先下载的唯一镜像。
  • always - 如果您想让用户可以从任何镜像库下载任何镜像。

if-not-present 拉取策略应该供受信任的构建和用户通过指定 Runner 使用。

详情请参见拉取策略文档

安装 Docker 的系统

note适用于 0.5.0 以下或升级到新版本的安装。

在安装了 Docker 的 Linux 系统上安装极狐GitLab Runner 包时, gitlab-runner 创建一个有权限访问 Docker Daemon 的用户。 这使得使用 shell 执行器运行的作业能够以完全权限访问 docker, 并可能允许对服务器进行根访问。

使用 SSH 执行器

由于缺少 StrictHostKeyChecking 选项,SSH 执行器容易受到 MITM(中间人)攻击。 未来发版中会修复这个问题。

使用 Parallels 执行器

Parallels 执行器是最安全的选项,因为它使用完整的系统虚拟化,且虚拟机配置为在隔离虚拟化中运行或以隔离模式运行。它阻止访问所有外围设备和共享文件夹。

克隆 Runner

Runner 使用令牌识别极狐GitLab 服务器。如果您克隆 Runner,那么克隆的 Runner 可能会为该令牌挑选相同的作业。这是一个 “窃取” Runner 作业的可能攻击向量。

在共享环境上使用 GIT_STRATEGY: fetch 的安全风险

当您将 GIT_STRATEGY设置为 fetch 时,Runner 尝试重用 Git 仓库的本地工作副本。

使用本地副本可以提高 CI/CD 作业的性能。但是,任何有权访问该可重用副本的用户都可以添加在其他用户的流水线中执行的代码。

Git 将子模块(嵌入另一个仓库中的仓库)的内容存储在父仓库的 Git reflog 中。 因此,在最初克隆项目的子模块后,后续作业可以通过在其脚本中运行 git submodule update 来访问子模块的内容。 即使子模块已被删除并且启动该作业的用户无权访问子模块项目,也同样适用。

只有当您信任所有有权访问共享环境的用户时,您才应该使用 GIT_STRATEGY: fetch

安全加固选项

降低使用特权容器的安全风险

如果您必须运行需要使用 Docker 的 --privileged 标记的 CI/CD 作业,您可以采取以下步骤来降低安全风险:

  • 仅在隔离和临时虚拟机上运行启用了 --privileged 标记的 Docker 容器。
  • 配置专用的 Runner,用于执行需要使用 Docker 的 --privileged 标志的作业。然后将这些 Runner 配置为仅在受保护的分支上执行作业。

网络分段

极狐GitLab Runner 旨在运行用户控制的脚本。为了减少恶意作业的攻击面,您可以考虑在他们的网段上进行运行。这会将它与其他基础设施和服务进行网络隔离。

所有需求都是独一无二的,但对于云环境,这可能包括:

  • 在自己的网段配置 Runner 虚拟机。
  • 阻止从 Internet 到 Runner 虚拟机的 SSH 访问。
  • 限制 Runner 虚拟机之间的流量。
  • 过滤对云提供商元数据端点的访问。
note 所有 Runner 都需要与 JiHuLab.com 或您的极狐GitLab 实例进行出站网络连接。 大多数作业还需要与 Internet 进行出站网络连接以拉取依赖项。

保护 Runner 主机的安全

如果您为 Runner 使用静态主机,无论是裸机还是虚拟机,您都应该为主机操作系统实施安全最佳实践。

CI 作业上下文中执行的恶意代码可能会危及主机,因此安全协议可以减轻影响。您还需要保护文件或从能够使攻击者访问环境中其他端点的主机系统中删除 SSH 密钥等文件。