Cloudflared tunnel not working in Github Action runner

I’ve tested the ssh key using SSH port 22 without cloudflared tunnel and know that I am able to connect from the Github runner host to my vpc host but when using cloudflared tunnel, it does not work. I’ve tried adding every possible HostKeyAlgorithms but still didn’t work. Is this an issue with the Github runner or cloudflare tunnel? I am able to connect to my vpc host using cloudflare tunnel fine from my local machines using the same ssh key so I know cloudflared tunnel is configured correctly on the vpc host.

Others are also having same issue on Stackoverflow without a solution.

---
name: test cloudflared

on:
  push:
    branches:
      - main
  pull_request:
    types: [opened, synchronize, reopened]

jobs:
  cloudflared:
    name: test cloudflared
    runs-on: ubuntu-latest
    timeout-minutes: 15

    defaults:
      run:
        shell: bash

    steps:
      - name: Checkout
        uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: install cloudflared
        run: |
          curl -L https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /usr/share/keyrings/cloudflare-archive-keyring.gpg >/dev/null
          echo "deb [signed-by=/usr/share/keyrings/cloudflare-archive-keyring.gpg] https://pkg.cloudflare.com/cloudflared $(lsb_release -cs) main" | sudo tee  /etc/apt/sources.list.d/cloudflared.list
          sudo apt update
          sudo apt-get install cloudflared

      - name: test cloudflared
        run: |
          which cloudflared
          whereis cloudflared
          /usr/local/bin/cloudflared --version

      - name: install-ssh-key
        uses: shimataro/ssh-key-action@v2
        with:
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          name: id_rsa
          known_hosts: ${{ secrets.KNOWN_HOSTS }}
          config: |
            Host testhost
              HostName ${{ vars.HOST }}
              User ${{ vars.USER }}
              IdentityFile ~/.ssh/id_rsa
              ProxyCommand /usr/local/bin/cloudflared access ssh --hostname %h

      - name: test ssh
        run: ssh -vvv testhost 'whoami'
OpenSSH_8.9p1 Ubuntu-3ubuntu0.4, OpenSSL 3.0.2 15 Mar 2022
debug1: Reading configuration data /home/runner/.ssh/config
debug1: /home/runner/.ssh/config line 2: Applying options for testhost
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 19: include /etc/ssh/ssh_config.d/*.conf matched no files
debug1: /etc/ssh/ssh_config line 21: Applying options for *
debug3: expanded UserKnownHostsFile '~/.ssh/known_hosts' -> '/home/runner/.ssh/known_hosts'
debug3: expanded UserKnownHostsFile '~/.ssh/known_hosts2' -> '/home/runner/.ssh/known_hosts2'
debug1: Executing proxy command: exec /usr/local/bin/cloudflared access ssh --hostname ssh.myhost.com
debug1: identity file /home/runner/.ssh/id_rsa type -1
debug1: identity file /home/runner/.ssh/id_rsa-cert type -1
debug1: Local version string SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.4
kex_exchange_identification: Connection closed by remote host
Connection closed by UNKNOWN port 65535
Error: Process completed with exit code 255.

Howdy!

I’ve recently been working on this sort of thing. I haven’t done much with running commands through SSH with this; I think a simple whoami should work, but I’ve found running commands via SSH to be sort of finicky on GitHub Actions WRT tty acquisition. So one’s mileage may vary depending on what commands actually need to be run.

That said, I was able to get SSH working through cloudflared so as to rsync a tar archive over to a location on the server. So depending on one’s exact use case, this might work for them.

A couple things I had to do to get it working were:

  1. Set up Service Token Auth in the ZT dashboard. That is, I had to create a Service Token ID and Secret pair under Access (and of course save the secret for later). Then, for the SSH application for the server, I needed to add a separate Service Auth Policy to its list of policies; in my case I only added the created Service Token under the list of includes.
  2. Use said Service Token in the cloudflared access ssh ProxyCommand in my SSH config. That’s done by passing the client ID/secret you got from Cloudflare in the first step without the header names. So if you have CF-Access-Client-Id: abc and CF-Access-Client-Secret: xyz from the Cloudflare dashboard, you would pass in the arguments --id abc --secret xyz to the cloudflared access ssh ProxyCommand – in addition to the hostname.
  3. Adding a couple more secrets to your repo to accommodate this, namely the aforementioned Service Token client/secret.

Here’s a gist of what my GitHub Actions look like, trimmed down somewhat. Obviously any other SSH settings like the key name/algorithm can differ.

Again, I know it’s been a few weeks, but I hope this helps anyone looking to do something similar!

Thanks for the solution. Although I am able to connect to my server from my local environment using your solution, I couldn’t get it to work from the Github Action runner. I have a couple of questions

  1. What method did you use to get the known_hosts?
  2. For step 1. when you say " for the SSH application for the server, I needed to add a separate Service Auth Policy to its list of policies", Is that by creating an Application in Access → Applications and then going to Access → Applications → Policies → Add a policy
    or
    Networks → Tunnels → Configure (tunnel) → Public Hostname → Edit (public hostname) → Additional application settings → Access → Protect with Access → Enabled → Add the SSH application

This is the error I’m getting on the rsync step

kex_exchange_identification: Connection closed by remote host
Connection closed by UNKNOWN port 65535
rsync: connection unexpectedly closed (0 bytes received so far) [sender]
rsync error: unexplained error (code 255) at io.c(231) [sender=3.2.7]
Error: Process completed with exit code 255.

edit: I recreated all my Github Action secrets and it works now! Thank you!

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.