如何使用 GitHub 操作提取机密?
How can I extract secrets using GitHub Actions?
我有一个相当基本的场景。我为此制作了一个专用的 ssh 密钥并将其添加到我的存储库机密中。
代码被推送到 master
GitHub 操作通过 echo "${{ secrets.SSH_KEY }}" > key
.
使用 ssh
将其上传到服务器
之后我可以使用这个密钥连接到我的服务器,例如ssh -i key devops@myserver.com lsb_release -a
问题是由于某些原因 GitHub 操作无法将其写入文件,它会将字符 ***
而不是实际的秘密值写入文件。因此显然我无法连接到我的服务器。
我如何使用这个秘密连接到 ssh?有没有不使用文件连接的方法?使用 GitHub 操作完成此常见场景的人可以阐明一些情况吗?
GitHub Actions 应该能够以这种方式将秘密写入文件。你看到星星的原因是日志被过滤了,所以如果一个秘密被记录,它在日志中被替换为三个星号。这是一种防止意外泄露机密的安全措施,因为日志通常是公开的。
但是,最好还是尽可能避免将秘密写入日志。你可以这样写你的命令,这样你就不会把秘密写入日志:
- run: 'echo "$SSH_KEY" > key'
shell: bash
env:
SSH_KEY: ${{secrets.SSH_KEY}}
您将在日志中看到的只是 echo "$SSH_KEY" > key
,而不是秘密或任何星号。
请注意,您需要在此处使用引号,因为 >
字符对于 YAML 来说是特殊的。
如果无法登录您的服务器,则可能是其他问题;在一般情况下,此技术确实适用于写入机密。
好的解决方案是使用 gpg 加密密钥,将其添加到存储库并使用密码在服务器上解密。密码当然应该存储为 github 项目机密。
我找到了一种方法来做到这一点。我们在一个项目中使用了 GatsbyJS,它依赖于
.env.production 环境变量文件。我试图通过他们作为
env:
到 github 操作,但这没有用,它们被忽略了。
这是我所做的。我用 base 64 编码了 .env.production 文件:
base64 -i .env.production
在 github 操作中将输出添加到环境变量。然后在我的行动中我这样做:
echo ${{ secrets.ENV_PRODUCTION_FILE }} | base64 -d > .env.production
这样我的 .env.production 文件的内容就结束了写入执行 github 操作的机器。
这里是如何解决使用存储在 GitHub 操作中的秘密安全登录 SSH 服务器的实际问题,名为 GITHUB_ACTIONS_DEPLOY
。
我们称其为“哔”,因为它会在您登录的服务器上发出响铃。当有人将代码推送到您的存储库时,您可能会使用这个字面意思来 ping 您家中的服务器。
- name: Beep
# if: github.ref == 'refs/heads/XXXX' # Maybe limit only this step to some branches
run: |
eval $(ssh-agent)
ssh-add - <<< "$SSH_KEY"
echo "* ssh-rsa XXX" >> /tmp/known_hosts # Get from your local ~/.ssh/known_hosts or from ssh-keyscan
ssh -o UserKnownHostsFile=/tmp/known_hosts user@example.com "echo '\a'"
env:
SSH_KEY: ${{ secrets.PMT_GITHUB_ACTIONS_DEPLOY }}
如果您实际上是在使用 SSH 作为 rsync 推送任务的一部分,请按以下步骤操作:
- name: Publish
if: github.ref == 'refs/heads/XXX'
run: |
eval $(ssh-agent)
ssh-add - <<< "$SSH_KEY"
echo "* ssh-rsa XXX" >> /tmp/known_hosts
rsync $FROM user@server:
env:
SSH_KEY: ${{ secrets.GITHUB_ACTIONS_DEPLOY }}
RSYNC_RSH: "ssh -o UserKnownHostsFile=/tmp/known_hosts"
我在 GHA 中使用 sed 来替换文件中的令牌,如下所示:
run: |-
sed -i "s/TOKEN/${{secrets.MY_SECRET}}/g" "thefile"
文件如下所示:
credentials "app.terraform.io" {
token = "TOKEN"
}
我有一个相当基本的场景。我为此制作了一个专用的 ssh 密钥并将其添加到我的存储库机密中。
代码被推送到
master
GitHub 操作通过
echo "${{ secrets.SSH_KEY }}" > key
. 使用 之后我可以使用这个密钥连接到我的服务器,例如
ssh -i key devops@myserver.com lsb_release -a
ssh
将其上传到服务器
问题是由于某些原因 GitHub 操作无法将其写入文件,它会将字符 ***
而不是实际的秘密值写入文件。因此显然我无法连接到我的服务器。
我如何使用这个秘密连接到 ssh?有没有不使用文件连接的方法?使用 GitHub 操作完成此常见场景的人可以阐明一些情况吗?
GitHub Actions 应该能够以这种方式将秘密写入文件。你看到星星的原因是日志被过滤了,所以如果一个秘密被记录,它在日志中被替换为三个星号。这是一种防止意外泄露机密的安全措施,因为日志通常是公开的。
但是,最好还是尽可能避免将秘密写入日志。你可以这样写你的命令,这样你就不会把秘密写入日志:
- run: 'echo "$SSH_KEY" > key'
shell: bash
env:
SSH_KEY: ${{secrets.SSH_KEY}}
您将在日志中看到的只是 echo "$SSH_KEY" > key
,而不是秘密或任何星号。
请注意,您需要在此处使用引号,因为 >
字符对于 YAML 来说是特殊的。
如果无法登录您的服务器,则可能是其他问题;在一般情况下,此技术确实适用于写入机密。
好的解决方案是使用 gpg 加密密钥,将其添加到存储库并使用密码在服务器上解密。密码当然应该存储为 github 项目机密。
我找到了一种方法来做到这一点。我们在一个项目中使用了 GatsbyJS,它依赖于
.env.production 环境变量文件。我试图通过他们作为
env:
到 github 操作,但这没有用,它们被忽略了。
这是我所做的。我用 base 64 编码了 .env.production 文件:
base64 -i .env.production
在 github 操作中将输出添加到环境变量。然后在我的行动中我这样做:
echo ${{ secrets.ENV_PRODUCTION_FILE }} | base64 -d > .env.production
这样我的 .env.production 文件的内容就结束了写入执行 github 操作的机器。
这里是如何解决使用存储在 GitHub 操作中的秘密安全登录 SSH 服务器的实际问题,名为 GITHUB_ACTIONS_DEPLOY
。
我们称其为“哔”,因为它会在您登录的服务器上发出响铃。当有人将代码推送到您的存储库时,您可能会使用这个字面意思来 ping 您家中的服务器。
- name: Beep
# if: github.ref == 'refs/heads/XXXX' # Maybe limit only this step to some branches
run: |
eval $(ssh-agent)
ssh-add - <<< "$SSH_KEY"
echo "* ssh-rsa XXX" >> /tmp/known_hosts # Get from your local ~/.ssh/known_hosts or from ssh-keyscan
ssh -o UserKnownHostsFile=/tmp/known_hosts user@example.com "echo '\a'"
env:
SSH_KEY: ${{ secrets.PMT_GITHUB_ACTIONS_DEPLOY }}
如果您实际上是在使用 SSH 作为 rsync 推送任务的一部分,请按以下步骤操作:
- name: Publish
if: github.ref == 'refs/heads/XXX'
run: |
eval $(ssh-agent)
ssh-add - <<< "$SSH_KEY"
echo "* ssh-rsa XXX" >> /tmp/known_hosts
rsync $FROM user@server:
env:
SSH_KEY: ${{ secrets.GITHUB_ACTIONS_DEPLOY }}
RSYNC_RSH: "ssh -o UserKnownHostsFile=/tmp/known_hosts"
我在 GHA 中使用 sed 来替换文件中的令牌,如下所示:
run: |-
sed -i "s/TOKEN/${{secrets.MY_SECRET}}/g" "thefile"
文件如下所示:
credentials "app.terraform.io" {
token = "TOKEN"
}