cloudflared Zero Trust SSH and RDP, and NAT-less HTTP

Setup RDP / SSH / HTTP forwarding - Zero Trust connections to server VMs behind an external IP without NAT

NAT is so 90ies… come on…

 

In simple terms: it’s a combination of

  • application level routing (Network Address Translation via a reverse tunnel which translates between HTTP and TCP, for example),

  • authentication (TOTP, PINs, …),

  • DNS management and

  • protocol encapsulation.

You can archive roughly the same with SSH reverse shells and tunnels. But you won’t because you want someone else to simplify this for you. At scale.

 

 

1. install cloudflared on the Server

 

https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/

I use the Systemd integration on Debian 12.

Use Case: cloudflared on a Linux KVM host

Schematically, the service architecture looks like this:

Cloudflare handles:

  • access on the Service Edge (perimeter)

  • DNS (probably)

  • tunnel termination (cloudflared uses QUIC or Wireguard)

    • channels get opened, HTTP ↔︎ TCP (for SSH or RDP) ↔︎ trusted request (identified)

    • HTTP ↔︎ request (reverse tunneled via the Service Edge, CDN - accelerated)

 

The KVM host handles:

  • internal IP networking and IP request forwarding (guest WAN access)

  • keeping cloudflared running, and syncing the config (host service)

 

If you use Cloudflare as a mere CDN, you have to ensure that requests don’t bypass the CDN front. Clients can override DNS entries and directly connect to the web servers. Sure, that may not be an issue for small-scale services. But it’s an issue because:

  • no Web App Firewall

  • no Rate Limits (for login brute forcing)

  • no DDoS protection

  • ….

Why pay for a CDN security-feature if an attacker needs 10s to bypass all the controls.

With the cloudflared approach, you don’t have that problem. Cloudflare publishes a list of IPv4 and IPv6 endpoints, which you can allow when you want to glue the CDN / Service Edge to your Load Balancer / web-front.

 

Restricting this channel via AWS Security Groups, IPtables etc. can be complex.

 

 

2. Setup the Zero Trust Service Edge and public hostnames for the Network tunnels

fuzzing.osroadwarrior.info

The Service Edge is served by Cloudflare.

Screenshot 2024-02-09 at 17.27.32.png
Cloudflare Zero Trust Service Edge authentication page - ushellnotpass

Login policies etc. are applied. This is a useless host. When people hear fuzzing, they associate Zero Days. I assure you, if I had many Zero Days, I’d be somewhere in the Bahamas. And I wouldn’t host them this way

 

 

Screenshot 2024-02-09 at 17.29.47.png
cloudflared config for public hostname points to the internal KVM guest IP, that is not NATed

 

A request comes in:

  1. DNS resolution of fuzzing.osroadwarrior.info to Service Edge

  2. Request gets forwarded to the public hostname of that tunnel service (HTTP)

  3. Request gets translated here (RDP), and routed to the cloudflared daemon

  4. The daemon takes the request and forwards it to our KVM guest (192.168/24)

  • a bidirectional connection is established (over multiple application and network level hops)

 

Behind the scenes, this is complex. Cloudflare does this at scale.

Let’s take a look at the DNS record:

> dig fuzzing.osroadwarrior.info +noall +answer ; <<>> DiG 9.10.6 <<>> fuzzing.osroadwarrior.info +noall +answer ;; global options: +cmd fuzzing.osroadwarrior.info. 300 IN A 104.21.6.147 fuzzing.osroadwarrior.info. 300 IN A 172.67.134.229

 

That is not the server IP, or the internal guest network IP. These IPs belong to Cloudflare Access / Zero Trust. The forwarding happens via these IPs.

 

 

3. Access the tunnel for RDP

Essentially, this is application level NATing. Or Zero Trust RDP

 

On my local laptop here, I may not be on the WARP+ network. WARP is the Wireguard-based VPN service, which is linked to the Zero Trust / Secure Gateway architecture. Essentially, you can use Cloudflare tools to interconnect various systems. With, or without VPN:

 

> cloudflared access rdp --hostname fuzzing.osroadwarrior.info --url rdp://localhost:3389

Then use localhost:3389 as the RDP “endpoint”. No VPN needed. If I use the VPN, I can refer to the 192.160/24 directly. I don’t need to use the Access pages. For HTTP requests, I can simply expose the public tunnel endpoint to the internet.

 

Limitations

  • this is similar to SSH reverse shells and tunneling, but much more comfortable and feature rich

    • that is, if you trust Cloudflare

  • I don’t think you should use cloudflared for high-throughput services. There, the IP-restricted LB / Web endpoint is the way to go

  • The cryptographic parameters seem to be sound at first glance

    • if you trust Cloudflare

  • you will need a Domain

  • you will need to re-think networking