Skip to content

SSH through cloudflare access

Previously, I've created and run a cloudflared tunnel for web server exposure on the rpi4b-ubuntu platform.

In this article, I'll try to configure remote SSH through the Cloudflare zero-trust application and tunnel route, reusing a public hostname.

Official guidelines#

Connect with SSH through Cloudflare Tunnel

Cloudflare Zero Trust offers two solutions to provide secure access to SSH servers:

  • Private subnet routing with Cloudflare WARP to Tunnel
  • Public hostname routing with cloudflared access

Connect to SSH server with cloudflared access

Cloudflare Tunnel can also route applications through a public hostname, which allows users to connect to the application without the WARP client. This method requires having cloudflared installed on both the server machine and on the client machine, as well as an active zone on Cloudflare. The traffic is proxied over this connection, and the user logs in to the server with their Cloudflare Access credentials.

Connect the server to Cloudflare

  1. Create a Cloudflare Tunnel by following our dashboard setup guide.

  2. In the Public Hostnames tab, choose a domain from the drop-down menu and specify any subdomain (for example, ssh.example.com).

  3. For Service, select SSH and enter localhost:22. If the SSH server is on a different machine from where you installed the tunnel, enter <server IP>:22.

  4. Select Save hostname.

  5. (Recommended) Add a self-hosted application to Cloudflare Access in order to manage access to your server.

As the tunnel is ready, I will focus on the final recommendation of adding a self-hosted application for the SSH session.

DNS route to ssh#

When cloudflared receives an incoming request, it evaluates each ingress rule from top to bottom to find which rule matches the request. Rules can match either the hostname or path of an incoming request, or both.

Wildcards

You can use wildcards to match traffic to multiple subdomains or paths. For example, if you set the hostname key to *.example.com, both test.example.com and try.example.com will route traffic to your origin.

Open the Cloudflare Dashboard, click Websites and choose a domain (e.g. dummy.com), then click DNS - Records in the left panel, the CNAME record lists the following.

Type Name Content Proxy status TTL
CNAME dummy.com 79983784-9f0c-4fd7-b28c-cbdfc066f584.cfargotunnel.com Proxied Auto

You can change the name dummy.com to a wildcard *. This will make it easier to configure the subdomains that map to the intranet SSH service.

Type Name Content Proxy status TTL
CNAME * 79983784-9f0c-4fd7-b28c-cbdfc066f584.cfargotunnel.com Proxied Auto

In this case, the tunnel route is now actually *.dummy.com, which corresponds to all the sub-domains, such as ssh.dummy.com.

A more practical solution is to add another CNAME record that configures subdomain ssh(.dummy.com) routing to the same target cfargotunnel.

Type Name Content Proxy status TTL
CNAME dummy.com 79983784-9f0c-4fd7-b28c-cbdfc066f584.cfargotunnel.com Proxied Auto
CNAME ssh 79983784-9f0c-4fd7-b28c-cbdfc066f584.cfargotunnel.com Proxied Auto

Apart from the DNS routing solution, you can of course create another dedicated tunnel cloudflared tunnel --hostname ssh.dummy.com --url ssh://localhost:22 for SSH as an alternative.

Config tunnel ingress rules#

Return to the machine running the cloudflared service.

Last time, we've just exposed web server through the cloudflared tunnel:

config.yml
tunnel: cft
credentials-file: /home/pifan/.cloudflared/79983784-9f0c-4fd7-b28c-cbdfc066f584.json
url: http://localhost:81

To expose the SSH service, we need to reorganize the config.yml and configure ingress rules for traffic routing.

$ sudo vim /etc/ssh/sshd_config

tunnel: cft
credentials-file: /home/pifan/.cloudflared/79983784-9f0c-4fd7-b28c-cbdfc066f584.json

ingress:
    - hostname: dummy.com
      service: http://localhost
    - hostname: ssh.dummy.com
      service: ssh://localhost:22
    - service: http_status:404

To validate the ingress rules in your configuration file, run:

$ cloudflared tunnel ingress validate
Validating rules from /home/pifan/.cloudflared/config.yml
OK

To verify that cloudflared will proxy the right traffic to the right local service, use cloudflared tunnel ingress rule.
This checks a URL against every rule, from first to last, and shows the first rule that matches.

$ cloudflared tunnel ingress rule https://dummy.com/
Using rules from /home/pifan/.cloudflared/config.yml
Matched rule #0
        hostname: dummy.com
        service: http://localhost

$ cloudflared tunnel ingress rule ssh://ssh.dummy.com
Using rules from /home/pifan/.cloudflared/config.yml
Matched rule #1
        hostname: ssh.dummy.com
        service: ssh://localhost:22

Restart the cloudflared service for the rules to take effect immediately.

$ sudo systemctl restart cloudflared

Add an Access Application#

Open Cloudflare Dashboard, Click Zero Trust to enter Cloudflare One page, select an account to log in.

Click Access - Applications in the left panel, find the + Add an Application button on the right and click. On your first attempt, you'll have to choose a plan before proceeding.

Steps: Select type > Configure application > Add policies > Setup.

To grant a user access to an application, simply add their email address to an Access policy.

  1. Select application type: Self-hosted

  2. Configure application:

    • Application Name: ssh@rpi4b-ubuntu
    • Session Duration: 24h
    • Subdomain: ssh
    • Domain: dummy.com
  3. Add policies:

    • Policy Name: Only You
    • Action: Allow
    • Session Duration: Same as application session timeout or 24h
    • Selector -> Email
    • Value -> Your Email Address(support multiple addresses)
  4. Additional settings:

    • Turn on Enable automatic cloudflared authentication
    • Browser rendering (Beta): SSH
  5. Add application.

Configure short-lived cert#

User management - Short-lived certificates

Still in the Zero Trust / Cloudflare One page, goto Access - Service Auth - SSH, select an application and click the Generate certificate button to generate a short-lived certificate.

Click the Application name in the Short-lived certificates area, copy the public key and paste it into /etc/ssh/ca.pub on rpi4b-ubuntu.

Assuming your policy email is [email protected], add the following lines to /etc/ssh/sshd_config on rpi4b-ubuntu running sshd service.

Match user gmail
  AuthorizedPrincipalsCommand /bin/echo 'cft'
  AuthorizedPrincipalsCommandUser nobody

Move on and carry out the following two steps:

  1. Uncomment PubkeyAuthentication yes
  2. Append TrustedUserCAKeys /etc/ssh/ca.pub

Then restart SSH service: sudo systemctl restart ssh.

Configure SSH client#

End users can connect to the SSH session without any configuration by using Cloudflare's browser-based terminal. Users visit the URL of the application and Cloudflare's terminal handles the short-lived certificate flow.

On an SSH client platform such as macOS, run cloudflared access ssh-config to print the required configuration command:

$ cloudflared access ssh-config --hostname ssh.dummy.com --short-lived-cert

Add to your /Users/faner/.ssh/config:
Match host ssh.dummy.com exec "/opt/homebrew/bin/cloudflared access ssh-gen --hostname %h"
  ProxyCommand /opt/homebrew/bin/cloudflared access ssh --hostname %h
  IdentityFile ~/.cloudflared/%h-cf_key
  CertificateFile ~/.cloudflared/%h-cf_key-cert.pub

Copy the SSH configuration generated above to ~/.ssh/config and try ssh to initiate a One-time PIN login.

Add the -v option to enable verbose mode, printing more detailed debugging messages.

$ ssh -v [email protected]

A browser window should have opened at the following URL:

https://ssh.dummy.com/cdn-cgi/access/cli?aud=82a2ef3493f83718ae779bf1658b1e574634f81b7ba3a88102d35545fe7ffb73&edge_token_transfer=true&redirect_url=https%3A%2F%2Fssh.dummy.com%3Faud%3D82a2ef3493f83718ae779bf1658b1e574634f81b7ba3a88102d35545fe7ffb73%26token%3DpUNqPtNXsokMC-eMAVSSzgd9P-fvefdty12IKF2_Oy4%253D&send_org_token=true&token=pUNqPtNXsokMC-eMAVSSzgd9P-fvefdty12IKF2_Oy4%3D

If the browser failed to open, please visit the URL above directly in your browser.

It will open the access URL in default browser and redirect to YOURGROUP.cloudflareaccess.com's sign-in page. On the Sign-in page, enter your email([email protected]) and click Send me a code.



CloudflareAccess-Signin-code

If the email is allowed by an Access policy, you will receive a PIN in your inbox. This secure PIN expires 10 minutes after the initial request.

Paste the PIN into the Access login page and select Sign in.



CloudflareAccess-Signin-enter

If the code was valid, you will be redirected to the application, and it will congratulate you on your success.


CloudflareAccess-Signin-success

As indicated, a token has been returned to the requesting machine. Run ls -l ~/.cloudflared/ to check the generated tokens and cf_keys.

$ ls -l ~/.cloudflared/
total 40
-rw-------@ 1 faner  staff   13 Jun 21 16:22 {Org-Name}.cloudflareaccess.com-org-token
-rw-------@ 1 faner  staff  874 Jun 21 16:22 ssh.dummy.com-{AUD-Tag}-token
-rw-------@ 1 faner  staff  227 Jun 21 16:05 ssh.dummy.com-cf_key
-rw-------@ 1 faner  staff  793 Jun 21 16:05 ssh.dummy.com-cf_key-cert.pub
-rw-------@ 1 faner  staff  161 Jun 21 16:05 ssh.dummy.com-cf_key.pub

Meanwhile, the console will prompt you to check and confirm the connection. Type yes or fingerprint(paste public key for verification).

The authenticity of host 'ssh.dummy.com (<no hostip for proxy command>)' can't be established.
ECDSA key fingerprint is SHA256:E6EQTRP/000BaadDaad1989FeedBabe0604DeadBeaf.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'ssh.dummy.com' (ECDSA) to the list of known hosts.

Next, you should be asked to enter the password for the SSH service.

debug1: Next authentication method: password
[email protected]'s password:

If nothing else, you'd have successfully connected to your SSH server and been greeted with a welcome message.

debug1: Authentication succeeded (password).
Authenticated to ssh.dummy.com (via proxy) using "password".

Welcome to Ubuntu 22.04.4 LTS (GNU/Linux 5.15.0-1055-raspi aarch64)

Side Notes: Visit Zero Trust / Cloudflare One to view application statistics, trends and analytics.

  1. Zero Trust Overview: View and check Top logins by application.
  2. Click My Team - Users to view account identity and session management. You can revoke sessions or remove user as needed.

references#

Multiplex#

Many services, one cloudflared
Highly available and highly scalable Cloudflare tunnels

How to set up subdomain through a tunnel?
Cloudflare tunnel with second domain issue
Is it possible to connect two tunnels to one domain?
How to set a second cloudflare tunnel to my subdomain?

Multiple tunnels per config?
Multiple Tunnels Same Server
Run 2 cloudflared instances on 1 machine
Multiple Tunnels, One Cloudflared instance
One Tunnel for Multiple Servers with Different Services
macos - Cloudflared tunnel for hosting Multiple Domains on a single PC
Best practices - running multiple websites/services on the same cloudflared tunnel IPv4 & IPv6?

Access SSH#

Create an Access application
Add non-HTTP applications

Connect to application using cloudflared
Create SSH connections with Cloudflare Access
Accessing Your Raspberry Pi Remotely Using Cloudflare

How to SSH into a server protected by Cloudflare DNS
HOW TO: SSH into Raspberry Pi remotely through Cloudflare tunnel (terminal and putty).
HOW TO: Remote access a Raspberry Pi using a Cloudflare tunnel (node-red and ssh).

使用cloudflare tunnel免费内网穿透,实现网站的外网访问和远程桌面
SSHing to my Raspberry Pi 400 from a browser, with Cloudflare Tunnel and Auditable Terminal
How to access your Raspberry Pi via SSH or VNC from anywhere in the World using CloudFlare's Zero Trust

Comments