Hashicorp Vault 集成
Hashicorp Vault 是一个密钥管理系统 (KMS),它允许您自行管理一组密钥(凭据)、配置项以及对这些密钥的访问。
Travis CI 可以在您的 Travis CI 构建的构建、测试或部署阶段从您的 Hashicorp Vault 实例获取所需的密钥,而不是将它们存储在 Travis CI 中。
如果您所在的组织更倾向于完全控制密钥的访问权限,或者希望在一个密钥管理系统 (KMS) 中方便地管理 CI/CD 管道中所需的密钥,那么这将非常有用。
先决条件 #
您将需要
- 一个启用了 KV 引擎并支持 KV2 API 的 Hashicorp Vault 实例的 URL(请参阅 Hashicorp Vault 文档)。
- Hashicorp Vault 实例 API 必须接受来自公共网络的传入请求;请参阅我们的 IP 地址页面,了解必须允许哪些内容以及有关配置网络规则的一些建议。
- Hashicorp Vault 中所需密钥的路径。
- 一个令牌;通过 API 或通过 Hashicorp Vault CLI 登录 Hashicorp Vault 后获得(请保密!)。
- 在将令牌授予 Travis CI 之前,我们建议您查看 Hashicorp Vault 帐户对密钥集的访问权限;最佳实践是将其限制在构建/测试/部署任务所需的项目中,您希望 Travis CI 执行这些任务。请考虑在 Hashicorp Vault 中使用一个专用帐户,该帐户仅访问与 CI/CD 相关的少量密钥。
- 使用 Travis CI 加密令牌以供进一步使用
- 请使用 travis-cli 加密密钥,并在您的
.travis.yml
文件中使用加密后的字符串;在初始版本中,我们有意将其限制为向您的 KMS 提供访问令牌的唯一方式。
- 请使用 travis-cli 加密密钥,并在您的
集成是如何工作的? #
集成基于与 Hashicorp Vault API 的通信。Travis CI 中唯一存储的密钥是访问令牌(以加密形式)。
如果您使用的是专用 Hashicorp Vault 帐户,并且密钥需要在多个存储库之间共享,我们建议您考虑通过将其存储在一个存储库中来管理 Hashicorp Vault 访问令牌,并在您的组织中 将其导入其他存储库的构建配置。这样,您可以集中管理 Hashicorp Vault 访问令牌。但是,请注意,导入的共享配置将可用于构建矩阵中的所有作业。
首先,在您存储库的 .travis.yml
中定义一组简单的项目。然后,一旦 Travis CI 处理构建请求,就会发生以下步骤
- 首先,在构建期间解密访问令牌。
- 在特定构建作业开始时,
.travis.yml
中定义的密钥将下载到特定的构建作业中,并在构建作业日志中进行屏蔽(以避免意外泄露这些密钥)。- 密钥将在特定构建作业的持续时间内存在,从而限制了可以使用这些密钥的时间。因此,请考虑从 Hashicorp Vault 获取密钥,并在 作业矩阵 中尽可能少的构建作业中根据需要处理这些密钥。
- 从 Hashicorp Vault 的“密钥”节点获取密钥。
- 仅获取已定义的密钥;如果未定义密钥路径,则不会从 Vault 实例获取任何内容。
- KV 引擎中的 Hashicorp Vault 密钥以键值对的形式出现。密钥将转换为 Travis CI 构建作业中的环境变量名称;密钥值是环境变量的值。
- 请注意:如果 Hashicorp Vault 中存在重复的密钥,并且通过
.travis.yml
中的定义获取这些密钥,则最后一个获取的值将覆盖前面的值;.travis.yml
中的出现顺序是从上到下处理的。 - 环境变量由路径中的最后一个引用加上密钥组成,例如,如果 Hashicorp Vault 中存在一个 /ns1/project_id/secret_key_a 密钥,其中密钥为“message”,则在 Travis CI 构建作业中创建的环境变量名称将为:SECRET_KEY_A_MESSAGE
- 请注意:如果 Hashicorp Vault 中存在重复的密钥,并且通过
- 获取密钥后,您可以在构建作业中使用它们;密钥的值将在 Travis CI 构建作业日志中进行屏蔽。
用法 #
Travis Ci 在 .travis.yml
中引入了新的 vault
节点。它可以在文件的根级别使用,也可以作为作业矩阵的一部分使用。
# use vault node to configure connection and secrets obtained from the Hashicorp Vault
vault:
api_url: https://[your hashicorp vault endpoint here]
token:
secure: "..." # encrypted token value, alphanumeric string
secrets: # configure which secrets to obtain
# either define it via calling out the Hashicorp Vault namespace and providing relative paths to the secrets/namespace
namespace: ns1
- project_id/secret_key_a
- project_id/another_key
# or define it by providing a list of paths relative to the ‘secrets’ node in the Hashicorp Vault
- ns1/project_id/secret_key_a
- ns1/project_id/another_key
# Remember always to obtain only secrets necessary for the specific build job!
请参阅下面的用法示例
单个 .travis.yml
文件 #
作为构建定义中所有作业可访问的数据
os: linux
dist: focal
# vault data at the root level of `.travis.yml` makes it available for all jobs in the build
vault:
token:
secure: "Your encrypted token goes here."
api_url: https://your-vault-api.endpoint
secrets:
- ns1/project_id/secret_key_a
script:
#assuming that under /ns1/project_id/secret_key_a a secret with key ‘message’ is present
- echo $SECRET_KEY_A_MESSAGE
作为仅在一个作业中可访问的数据
os: linux
dist: focal
jobs:
include:
- name: “Vault job” # make vault secrets and connections only in this job
vault:
token:
secure: "Your encrypted token goes here.”
api_url: https://your-vault-api.endpoint
secrets:
- ns1/project_id/secret_key_a
script:
- echo $SECRET_KEY_A_KEYNAME
- name: "Another job" # this env variable contains nothing
script:
- echo $SECRET_KEY_A_KEYNAME
导入的共享构建配置 #
vault:
token:
secure: "Your encrypted token goes here."
api_url: https://your-vault-api.endpoint
import:
- source: vault-secrets.yml
mode: deep_merge_prepend #deep_merge for overwriting the values in vault-secrets.yml
os: linux
dist: focal
jobs:
Include:
- name: "Vault job utilizing imported values job" # vault connection details come from imported vault-secrets.yml
secrets:
- ns1/project_id/secret_key_a
script:
- echo $SECRET_KEY_A_MESSAGE
- name: “Vault job overwriting imported values.”
vault:
token:
secure: "another encrypted token goes here.”
api_url: https://different-vault-api.endpoint
secrets:
- ns1/project_id/secret_key_b
script:
- echo $SECRET_KEY_B_SOMEKEY
请注意:导入的内容可用于您的整个构建(.travis.yml
),除非它被您 travis.yml
中的某些作业显式覆盖。YAML 锚点无法导入并在主 .travis.yml
中使用 - 请参阅 导入共享构建配置 页面了解更多信息。
常见问题 #
我可以在 UI 中将 Hashicorp Vault 令牌定义为环境变量吗? #
目前不行。目前,作为一项强制性实践,我们保持对令牌的限制性规则,该令牌强制作为 Travis CI 密钥
提供给您的 Hashicorp Vault。但是,我们希望最大程度地降低在强制执行保护特别容易受到攻击的数据(例如对您的密钥管理系统的访问令牌)的实践时意外泄露您的密钥的风险。因此,如果您在 UI 中定义环境变量,如果构建作业没有看到 vault.token.secure
,则它将不会连接到 Vault。默认情况下,它会阻止在构建作业日志中打印其解密内容,而不管 UI(存储库设置)中的选项是什么。
由于总有办法规避安全措施,因此我们希望听到您的意见,并了解将来是否应该放松仅在 vault.token.secure
下添加 Vault 令牌的限制。
我可以将 Hashicorp Vault 令牌作为加密的环境变量与派生存储库共享吗? #
目前不行。将来,我们计划允许它与派生存储库共享(用于从派生存储库到基本存储库提交 Pull Request 的协作模型)。但是,我们打算先观察一段时间您对此事的反馈。
是否仅支持 KV2 API 版本的 Hashicorp Vault 密钥值 API? #
为了支持旧版安装,内置了对 KV API 的支持。但是,它尚未经过广泛测试。请谨慎使用,并自行承担风险。
vault:
api_url: url
token:
secure: secure_token
secrets:
- kv_api_ver: kv1 #optional, kv1 or kv2, default is kv2, single value
- project_id2/secret_key