如何在GitLab CI中隐藏SSH私钥?

编程语言 2026-07-11

我想在GitLab CI管道作业中通过SSH连接到一台服务器。

我的流水线中有这个:

reset_database:
  stage: .pre
  image: kroniak/ssh-client:latest
  resource_group: portal_test_vm_lock
  before_script:
    - |
      eval $(ssh-agent -s)
      set +x
      chmod 600 "$SENTINEL_DB_RESET_SSH_KEY"
      ssh-add "$SENTINEL_DB_RESET_SSH_KEY"
      set -x
      mkdir -p ~/.ssh
      chmod 700 ~/.ssh
      touch ~/.ssh/known_hosts
      if ! grep -q "$PORTAL_INSTANCE" ~/.ssh/known_hosts; then
        ssh-keyscan "$PORTAL_INSTANCE" >> ~/.ssh/known_hosts
      fi
  script:
    - ssh ssh root@$PORTAL_INSTANCE /path/to/script.sh "$CI_PIPELINE_ID"

现在,我想把我的私钥作为一个变量添加进来,它看起来是这样的:

-----BEGIN OPENSSH PRIVATE KEY-----
my
private
key==
-----END OPENSSH PRIVATE KEY-----

我原本以为可以把它作为变量放在自托管的GitLab的 CI/CD设置中,但由于空白字符/换行符,无法对它进行掩码。

这看起来很奇怪,因为把私钥作为机密似乎是一个常见的用例。我尝试把密钥去掉空白字符后再添加,像这样:

myprivatekey==

然而在尝试使用时,这样做引发了错误:

Error loading key "/builds/testing/portal/sentinel.tmp/SENTINEL_DB_RESET_SSH_KEY": error in libcrypto

如何在GitLab管道中将SSH私钥添加为被屏蔽的变量?


我也在考虑使用base64的变通方法,但它们的输出仍会产生换行。

另外,这还可能导致密钥泄露,因为只有它的base64表示形式会被掩码。

解决方案

我将这两种方法结合起来:

  • 将私钥的作用域限定为仅能执行特定脚本
  • 将密钥的base64编码表示作为被屏蔽的变量

1.将私钥的作用域限定为仅能执行特定命令

限制纯文本SSH密钥潜在损害的一种方法,是将其作用域限定为仅能执行特定命令。

在服务器的 ~/.ssh/authorized_keys 上,您可以强制它只执行一个特定命令,例如:

command="/your/path/script.sh",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-ed25519 public_key_content your-key-name

您仍然可以通过 SSH_ORIGINAL_COMMAND 传递参数,我想使用流水线ID,因此在我的脚本中是这样的:

RUN_ID=${SSH_ORIGINAL_COMMAND:-"manual-run"}

只需通过以下命令触发作业:

ssh root@host "YOUR_RUN_ID"

2.使用Base64编码对私钥进行掩码

此外,我把这一步与base64编码结合起来。首先,我通过以下方式把私钥写成一行字符串:

base64 my-private-key | tr -d '\n'

我把这个字符串作为被屏蔽的变量添加进来(不是一个文件,但你也可以用文件来做),然后通过以下方式创建我的实际密钥:

echo "$DB_RESET_SSH_KEY" | base64 -d > reset_db_key

然后我就可以使用它。

虽然只有base64表示形式会被掩码,但任何有权限访问流水线的人仍可能通过将秘密按相反的顺序输出等方式来泄露它们。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章