Github Actions - 如何使用SSH部署到远程服务器

44

我在DO上有一个暂存服务器。

我想将我的Node应用程序构建并部署到该服务器上。

name: Build & Deploy
on:
  push:
    tags:
      - 'v1.*.0'
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Create SSH key
        run: |
          mkdir -p ~/.ssh/
          echo "$DO_GITHUB_PRIVATE_KEY" > ../github_do.key
          sudo chmod 600 ../github_do.key
          ssh-keyscan -H ${{secrets.DEPLOY_SERVER}} > ~/.ssh/known_hosts
        shell: bash
        env:
          DO_GITHUB_PRIVATE_KEY: ${{secrets.DO_GITHUB_PRIVATE_KEY}}
      - uses: actions/setup-node@v1
        with:
          node-version: 12.x
      - name: Install Packages
        run: yarn install --frozen-lockfile
      - name: Build artifacts
        env:
          DEPLOY_SSH_KEY_PATH: ${{ github.workspace }}/../github_do.key
        run: |
          yarn shipit production fast-deploy

我所做的是生成一对新的SSH私钥和公钥。

我将私钥保存在github机密变量DO_GITHUB_PRIVATE_KEY中。

我将公钥添加到我的预备服务器的authorized_keys文件中。

当操作被触发时,它会在此处失败:

@ v***.256.0
Create release path "/home/***/***/releases/2020-03-0***-v***.256.0"
Running "mkdir -p /home/***/***/releases/2020-03-0***-v***.256.0" on host "***".
@***-err ***@***: Permission denied (publickey,gssapi-keyex,gssapi-with-mic).
'fast-deploy:updateRemote' errored after ***.32 s
Error: Command failed: ssh -i /home/runner/work/***/***/../github_do.key ***@*** "mkdir -p /home/***/***/releases/2020-03-0***-v***.256.0"
4个回答

59

我已经解决了!显然,密钥受到密码保护。

这是整个过程:

  1. 生成新的密钥

ssh-keygen -t rsa -b 4096 -C "user@host" -q -N ""

  1. 更新主机的authorized_keys

    ssh-copy-id -i ~/.ssh/id_rsa.pub user@host

  2. 进入服务器并运行

ssh-keyscan host

  1. 将输出复制到github secret(我们称其为SSH_KNOWN_HOSTS)中
  2. 将私钥复制到github secret(我们称其为SSH_PRIVATE_KEY)中

在您的workflow.yml文件中

#workflow.yaml
...
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Create SSH key
        run: |
          mkdir -p ~/.ssh/
          echo "$SSH_PRIVATE_KEY" > ../private.key
          sudo chmod 600 ../private.key
          echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts
        shell: bash
        env:
          SSH_PRIVATE_KEY: ${{secrets.SSH_PRIVATE_KEY}}
          SSH_KNOWN_HOSTS: ${{secrets.SSH_KNOWN_HOSTS}}
          SSH_KEY_PATH: ${{ github.workspace }}/../private.key
 

然后你可以使用ssh命令:ssh -i $SSH_KEY_PATH user@host

希望这能为某些人节省几个小时:]

编辑

回答评论(如何更新GitHub secrets)

为了添加GitHub secrets,您有两个选项:

  1. 通过GitHub用户界面,https://github.com/{user}/{repo}/settings/secrets/
  2. 通过GitHub API,我正在使用github-secret-dotenv库将我的secrets与本地的.env文件同步(触发前操作)

虽然我喜欢这种方法,但貌似这意味着在项目中拥有私钥。我建议按照https://help.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets#limits-for-secrets中描述的方法添加gpg技巧来避免将明文密钥放入项目中。 - chachan
1
它不在源代码中,而是保存在 Github 秘密中。 - felixmosh
1
我已经在我的答案中添加了这个。 - felixmosh
我得到了 mkdir -p ~/.ssh/ ##[error]No such file or directory。有任何想法为什么会这样? - lewislbr
1
@lewislbr 你可能需要在步骤列表的顶部添加 uses: actions/checkout@v1 - JBaczuk
显示剩余6条评论

16

felixmoshCas的回答,但这感觉是更好的实现方式。不要将known_hosts文件上传到Github托管的运行程序中,而应在运行时填充~/.ssh/known_hosts文件。它更加灵活,可能会处理IP更改等问题。我已经测试过它,它对我有效。

- name: Write SSH keys
  run: |
    install -m 600 -D /dev/null ~/.ssh/id_rsa
    echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
    ssh-keyscan -H host.example.com > ~/.ssh/known_hosts

或者,更好的选择是,

- name: Write SSH keys
  run: |
    install -m 600 -D /dev/null ~/.ssh/id_rsa
    echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
    host='host.example.com'
    hosts="$(dig +short "$host" | grep -v '\.$' | sed -z 's|\n|,|g')$host"
    ssh-keyscan -H "$hosts" > ~/.ssh/known_hosts

这可以确保主机的所有IP都记录在known_hosts中。

只需替换host.example.com即可轻松完成。


我发现一个问题,通过生成known_hosts文件,它会绕过您已验证主机的安全性,这样如果主机不是同一台计算机,您将不知道。也许在SSH配置中使用HostKeyAlias可能是一个解决方案:https://serverfault.com/a/895661 - Cas
@Cas,我阅读了serverfault.com的帖子。不确定作者为什么在建议使用“HostKeyAlias”时同时使用了“host”。像echo“HostKeyAlias host.example.com”>.ssh/config这样的东西是否有效?还是我需要同时使用“host”和“HostKeyAlias”? - touhidurrr
两者都需要,因为Host指令表示ssh配置的新部分或指令,并带有该主机名的HostKeyAlias选项。 然而,再次查看后,也许CheckHostIP no更加简单明了。 - Cas
那我应该建议在编辑中使用 host myserver.example.com HostKeyAlias myserver.example.com 吗? - touhidurrr

15

felixmosh的答案很有用,但我进一步简化了它,使用id_rsa将自动被ssh使用,而无需中介环境变量即可替换密钥:

  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/download-artifact@v2
        with:
          name: build
          path: build
      - name: Create SSH key
        run: |
          install -m 600 -D /dev/null ~/.ssh/id_rsa
          echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
          echo "${{ secrets.SSH_KNOWN_HOSTS }}" > ~/.ssh/known_hosts
      - name: Deploy with rsync
        run: rsync -rav --delete build/ user@host:/

1
经过几个小时的故障排除,我终于解决了使用GitHub Actions自动化代码部署的问题。以下是你可以使用的脚本,只需将环境变量替换为你自己的即可。
run: |
      which ssh-agent || (sudo apk update && sudo apk add openssh-client)
      which rsync || (sudo apk update && sudo apk add rsync)
      mkdir -p ~/.ssh
      chmod 700 ~/.ssh
      touch ~/.ssh/private.key
      touch ~/.ssh/known_hosts
      chmod 600 ~/.ssh/private.key
      echo -e "${{ vars.DEV_SSH_PRIVATE_KEY }}" | tr -d '\r' > ~/.ssh/private.key
      # Append keyscan output into known hosts
      ssh-keyscan ${{ vars.DEV_PUBLIC_IP_ADDRESS }} >> ~/.ssh/known_hosts
      chmod 644 ~/.ssh/known_hosts
  - run: |
      eval $(ssh-agent -s)
      ssh-add ~/.ssh/private.key
      echo "Deploy to dev environment"
      rsync --rsync-path=/usr/bin/rsync --delete -avuz --exclude=".*" ./docker-compose/docker-compose-prod.yml ${{ vars.REMOTE_USER }}@${{ vars.DEV_PUBLIC_IP_ADDRESS }}:$BASE_DEV_SERVER_PATH/docker-compose-prod.yml

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接