Jason Rich Darmawan
Jason Rich Darmawan

Reputation: 2081

How to send passphrase for ssh-add with GitHub Actions?

My goal is to store private key with passphrase in GitHub secrets, but I don't know how to enter the passphrase through GitHub actions.

What I've tried:

  1. I created a private key without passphrase and store it in GitHub secrets.

.github/workflows/docker-build.yml

# This is a basic workflow to help you get started with Actions

name: CI

# Controls when the action will run. 
on:
  # Triggers the workflow on push or pull request events but only for the master branch
  push:
    branches: [ master ]

  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  # This workflow contains a single job called "build"
  build:
    # The type of runner that the job will run on
    runs-on: ubuntu-latest

    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
      - uses: actions/checkout@v2

      # Runs a set of commands using the runners shell
      - name: Run a multi-line script
        run: |
          eval $(ssh-agent -s)
          echo "${{ secrets.SSH_PRIVATE_KEY }}" |  ssh-add -
          ssh -o StrictHostKeyChecking=no root@${{ secrets.HOSTNAME }} "rm -rf be-bankaccount; git clone https://github.com/kidfrom/be-bankaccount.git; cd be-bankaccount; docker build -t be-bankaccount .; docker-compose up -d;"

Upvotes: 7

Views: 7369

Answers (2)

rupweb
rupweb

Reputation: 3328

For me I had to create a sub directory of ssh private key and passphrase

- name: Create SSH key
  env:
    SSH_PRIVATE_KEY: ${{secrets.SSH_PRIVATE_KEY}}
  run: |
    mkdir -p ~/.ssh
    chmod 700 ~/.ssh
    echo "$SSH_PRIVATE_KEY" > ~/.ssh/private.key
    sudo chmod 400 ~/.ssh/private.key
    echo 'echo ${{secrets.SSH_PWD}}' > ~/.ssh/passphrase && chmod 700 ~/.ssh/passphrase

Then use the passphrase file in the new dir as an echo command to pass to SSH_ASKPASS and ssh-add like @kamranicus answer above

- name: SSH dependency
    run: |
      echo 'Start the SSH agent'
      eval `ssh-agent -s`
      echo 'Add the private key'
      cat ~/.ssh/private.key | tr -d '\r' | DISPLAY=None SSH_ASKPASS=~/.ssh/passphrase ssh-add -

Upvotes: 0

kamranicus
kamranicus

Reputation: 4387

I finally figured this out because I didn't want to go to the trouble of updating all my servers with a passphrase-less authorized key. Ironically, it probably took me longer to do this but now I can save you the time.

The two magic ingredients are: using SSH_AUTH_SOCK to share between GH action steps and using ssh-add with DISPLAY=None and SSH_ASKPASS set to an executable script that sends your passphrase via stdin.

For your question specifically, you do not need SSH_AUTH_SOCK because all your commands run within a single job step. However, for more complex workflows, you'll need it set.

Here's an example workflow:

name: ssh with passphrase example

env:
  # Use the same ssh-agent socket value across all jobs
  # Useful when a GH action is using SSH behind-the-scenes
  SSH_AUTH_SOCK: /tmp/ssh_agent.sock

jobs:
  job1:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout repository
      uses: actions/checkout@v2
      
    # Start ssh-agent but set it to use the same ssh_auth_sock value.
    # The agent will be running in all steps after this, so it
    # should be one of the first.
    - name: Setup SSH passphrase
      env:
        SSH_PASSPHRASE: ${{secrets.SSH_PASSPHRASE}}
        SSH_PRIVATE_KEY: ${{secrets.SSH_PRIVATE_KEY}}
      run: |
        ssh-agent -a $SSH_AUTH_SOCK > /dev/null
        echo 'echo $SSH_PASSPHRASE' > ~/.ssh_askpass && chmod +x ~/.ssh_askpass
        echo "$SSH_PRIVATE_KEY" | tr -d '\r' | DISPLAY=None SSH_ASKPASS=~/.ssh_askpass ssh-add - >/dev/null

    # Debug print out the added identities. This will prove SSH_AUTH_SOCK
    # is persisted across job steps
    - name: Print ssh-add identities
      runs: ssh-add -l

  job2:

    # NOTE: SSH_AUTH_SOCK will be set, but the agent itself is not
    # shared across jobs, each job is a new container sandbox
    # so you still need to setup the passphrase again
    steps: ...

Resources I referenced:

Upvotes: 10

Related Questions