Tao
Tao

Contents

Complete Guide to Securing SSH Access with Cloudflare Zero Trust

Contents

In today’s IT world, securely accessing servers has always been a major challenge for businesses. Traditional SSH security models rely on exposing port 22 to the public internet and using tools like firewall rules, IP whitelists, and Fail2Ban for protection. But as cyber threats get more sophisticated, this old-school perimeter defense approach is facing serious challenges. This guide dives deep into a modern, more secure solution: using Cloudflare Zero Trust to build a zero trust architecture that protects SSH access.

Moving from traditional perimeter security to zero trust architecture represents a major shift in network security thinking. The core idea is ditching the old “trust but verify” approach and embracing “never trust, always verify.”

Traditional models are all about building a strong “castle” to protect internal resources. But once attackers breach the perimeter (like stealing an SSH key), they often get way too much trust and freedom to move around inside your network.

Zero trust SSH, on the other hand, aims to make your servers completely “invisible” to the public internet, eliminating the attack surface altogether. It doesn’t rely on network location for trust - instead, it strictly authenticates and authorizes every single access request, no matter where it comes from.

When applied to SSH access, zero trust principles show up in these key areas:

  • Authentication First: User identity must be verified before any traffic can reach the SSH server
  • Least Privilege Access: Users only get the minimum permissions needed to do their job
  • Device Health Checks: Access decisions consider not just who the user is, but also the security status of their device
  • Complete Logging and Monitoring: All access activities and sessions get logged and audited for visibility and compliance

Cloudflare’s zero trust SSH solution runs on three core components working together to create a powerful security system:

Cloudflare Tunnel (cloudflared): This is a lightweight daemon that sits on your origin server (or another machine on the same local network). It proactively creates a persistent, outbound-only encrypted connection to Cloudflare’s global network. Since the connection is initiated and maintained from inside your network, you don’t need to open any inbound firewall ports. This keeps your server’s IP address completely hidden from the public internet, eliminating direct network attacks from the get-go.

Cloudflare Access: This is your policy enforcement engine. Admins can define granular access policies in the Cloudflare Zero Trust dashboard, specifying exactly “who” can access “what” resources “under what conditions.” Cloudflare Access integrates with various identity providers (like Google Workspace, Okta, Microsoft Entra ID) and can evaluate device security status (like disk encryption, security software running), making dynamic, context-aware access decisions.

WARP Client: This is Cloudflare’s device client that gets installed on end-user devices (laptops, phones, etc.). In the recommended “Access for Infrastructure” model, the WARP client securely connects user devices to Cloudflare’s network and routes traffic to protected private resources (including SSH) through encrypted tunnels. It lets users seamlessly access servers in private networks as if they were local resources, while still enforcing Cloudflare Gateway security policies.

Using Cloudflare’s zero trust model to protect SSH access brings several major benefits:

  • No Exposed Ports: Since cloudflared creates outbound connections, your server firewall can block all inbound connections, massively reducing your attack surface.
  • Hidden Server IPs: Your server’s real IP address never gets exposed in DNS records or network traffic, effectively blocking direct DDoS attacks and malicious scanning.
  • Centralized Policy Management: All access policies are managed in one place through the Cloudflare Zero Trust dashboard, ensuring consistency and providing clear audit trails.
  • Enhanced Authentication: Integration with existing enterprise SSO systems and enforced multi-factor authentication (MFA) significantly strengthens authentication security.
  • Detailed Session Logging: Cloudflare can log every SSH connection authentication event and even record specific commands within sessions, providing unprecedented visibility for security audits and incident response.

Cloudflare offers multiple architectures for implementing zero trust SSH to fit different use cases and security requirements. Picking the right architecture is the first step to successful deployment. Here’s a detailed comparison of the three main architectures to help you make the best decision.

Feature SSH with Access for Infrastructure (WARP-to-Tunnel) Browser-Rendered Terminal Client-Side cloudflared Proxy
Primary Use Case Enterprise environments protecting company-managed devices accessing private networks. Quick, zero-install client access for contractors, third-party developers, or non-technical users. Flexible local terminal access for technical users (like DevOps engineers).
Client Requirements Must install and register Cloudflare WARP client. Any modern web browser. Must locally install cloudflared binary and standard SSH client.
Server Requirements cloudflared tunnel connected to a private network (defined by IP/CIDR). cloudflared tunnel configured with a public hostname and browser rendering enabled. cloudflared tunnel configured with a public hostname.
Security Posture Highest. Can combine device state checks to ensure only compliant company devices connect. High. Relies on strong authentication but can’t perform device state checks. High. Relies on strong authentication but security also depends on proper client configuration.
User Experience Seamless. Users directly use ssh user@private_ip in local terminal, experience identical to traditional SSH. Simple. Users access via browser URL to login, no local configuration needed. One-time setup required. Users need to add ProxyCommand to local ~/.ssh/config file.
Known Limitations Requires enterprise distribution and management of WARP clients. Has “username mismatch” issues; doesn’t support all terminal features (like custom fonts/colors). Requires users to locally install and maintain cloudflared.

Enterprise Unified Device Management: For organizations with established device management systems (MDM/EMM), we strongly recommend the SSH with Access for Infrastructure (WARP-to-Tunnel) model. This architecture represents the gold standard of zero trust security, with the core advantage of tightly coupling access control decisions with real-time device security status. The system can dynamically assess device compliance (including disk encryption status, OS version, security patch level, domain join status, etc.) and adjust access permissions in real-time, truly achieving the “never trust, always verify” core principle of zero trust.

External Collaboration and Temporary Access: For scenarios requiring system access for contractors, third-party developers, or temporary collaborators, Browser-Rendered Terminal is definitely the best solution. This approach’s standout advantage is completely eliminating the complexity of software distribution and device management - users need only a modern browser to get the full SSH experience. This significantly lowers the barrier to entry, reduces IT management burden, and avoids security risks from installing software on non-enterprise-managed devices. However, pay special attention to the “username mapping” challenge during deployment: the current implementation requires the user’s Cloudflare identity (usually the username part of their SSO email) to exactly match the Unix user account name on the target server for seamless short-lived certificate authentication.

Technical Teams and DevOps: For internal technical staff, especially development engineers and operations experts, the Client-Side cloudflared Proxy model provides the ideal balance. This architecture fully respects technical users’ autonomy in tool selection, allowing them to continue using carefully configured local terminal environments (like iTerm2 with tmux, Windows Terminal with WSL, or rich plugin Vim/Emacs workflows). While initial setup requires modifying the ~/.ssh/config file and setting up ProxyCommand, this one-time investment is completely acceptable for technically savvy users and provides long-term efficient work experience with complete local toolchain integration.

Many organizations weigh between Cloudflare Tunnel and traditional VPN when considering remote access solutions. While both enable remote access, their underlying philosophies, security models, and architectures are completely different.

Traditional VPN: Usually requires opening one or more inbound ports on network perimeter firewalls (like UDP 500/4500 for IPsec) and exposes the network’s public IP address to connecting clients. This makes the VPN gateway itself a potential attack target, vulnerable to scanning and DDoS attacks.

Cloudflare Tunnel: As mentioned earlier, it works through outbound connections with no open inbound ports needed. The server’s real IP is completely hidden behind Cloudflare’s network, with all traffic cleaned by Cloudflare, providing inherent strong DDoS protection.

This is a crucial distinction that directly relates to trust models.

Traditional VPN: Provides true end-to-end encryption. Traffic forms an encrypted tunnel between client and VPN server, where theoretically only the two endpoints can decrypt and view traffic content. This is critical for scenarios with strict data privacy requirements.

Cloudflare Tunnel: In this architecture, Cloudflare acts as a trusted intermediary (proxy). Traffic from client to Cloudflare edge is encrypted, and the tunnel from Cloudflare edge to origin server is also encrypted. However, at Cloudflare’s edge nodes, traffic can be decrypted for security inspection, such as applying Web Application Firewall (WAF) rules, Data Loss Prevention (DLP) policies, etc. This is a feature, but it also means you’re placing some trust in Cloudflare to handle your traffic.

Traditional VPN: Once users authenticate and connect to VPN, they typically get access to the entire internal network, just like being in the office. While firewall rules can provide restrictions, implementing fine-grained, application-based access control is complex. VPN’s advantage lies in protocol universality - it can transparently carry any network protocol like SMB/CIFS file shares, RDP, printing protocols, etc.

Cloudflare Tunnel: When combined with Cloudflare Access, it enables extremely granular access control. You can set independent access policies for each application (like a specific SSH host or internal website). This approach better aligns with zero trust’s least privilege principle. However, standard Tunnels mainly target specific TCP services (like SSH, RDP) and HTTP/S traffic. For scenarios requiring broad network-layer access, you might need more advanced solutions like WARP Connector.

This comparison reveals a fundamental architectural choice: Service Exposure vs. Network Extension. VPN’s essence is network extension - placing remote users within private network boundaries, continuing the traditional “trusted network” concept. Cloudflare Tunnel exemplifies service exposure, securely and selectively exposing specific services from internal networks to authenticated users, with Cloudflare acting as an intelligent and secure access proxy.

Choosing the Tunnel approach means your organization is explicitly moving toward a service-based zero trust model, which differs profoundly from traditional VPN in both security posture and management complexity.

This section provides detailed, actionable steps for configuring Cloudflare zero trust SSH on your servers, laying a solid foundation for subsequent client access.

cloudflared is the bridge connecting your server to Cloudflare’s network. Installing this daemon on your target SSH server or another machine on the same network is the first step.

Here are detailed installation commands for mainstream operating systems, integrating information from multiple reliable sources.

We recommend using the official repository for easy updates:

bash

# Add Cloudflare GPG key
sudo mkdir -p --mode=0755 /usr/share/keyrings
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null

# Add Cloudflare apt repository
echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared $(lsb_release -cs) main' | sudo tee /etc/apt/sources.list.d/cloudflared.list

# Update package list and install
sudo apt-get update
sudo apt-get install cloudflared

Alternatively, you can manually download the .deb package:

bash

wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared-linux-amd64.deb

Similarly, we recommend using the repository:

bash

sudo rpm --import https://pkg.cloudflare.com/cloudflare-main.gpg
sudo tee /etc/yum.repos.d/cloudflare.repo <<EOF
[cloudflare]
name=Cloudflare
baseurl=https://pkg.cloudflare.com/cloudflared/rpm
gpgcheck=1
gpgkey=https://pkg.cloudflare.com/cloudflare-main.gpg
enabled=1
EOF
sudo yum install cloudflared

Note: On immutable operating systems like Fedora Silverblue, installation may require special methods like layering and might encounter symlink-related errors.

The simplest method is using Homebrew:

bash

brew install cloudflared

Download the latest .msi installer or .exe binary from Cloudflare’s release page and follow the graphical or command-line instructions.

Cloudflare provides an official Docker image, perfect for containerized environments:

bash

docker pull cloudflare/cloudflared

After installation, you need to authenticate cloudflared so it can operate on behalf of your Cloudflare account. Run this command in your server’s terminal:

bash

cloudflared tunnel login

This command generates a URL. Copy and paste this URL into a browser on your local computer. The browser will guide you to log into your Cloudflare account and request authorization. Select the domain you want this tunnel associated with and approve.

After successful authorization, cloudflared downloads a certificate file called cert.pem to your server. This file is the trust credential between the daemon and your Cloudflare account, typically stored in the ~/.cloudflared/ or /etc/cloudflared/ directory. Keep this file secure.

To ensure the tunnel automatically runs after server restarts and stays stable, you must configure it as a system service.

systemd (Linux):

If you’re using token-managed tunnels for remote management, installing the service is simple:

bash

sudo cloudflared service install <YOUR_TUNNEL_TOKEN>

If you’re using locally managed tunnels (with config.yml), just run:

bash

sudo cloudflared service install

Then enable and start the service:

bash

sudo systemctl enable cloudflared
sudo systemctl start cloudflared
# Check service status
sudo systemctl status cloudflared

launchd (macOS) and Windows services: The installation process is similar, with cloudflared providing corresponding service management commands. Check the official documentation for detailed steps.

Tunnel creation and management mainly has two modes: remote management through the dashboard, or local management through command line and config files. Choosing which mode significantly impacts subsequent maintenance and automation workflows.

This is the most intuitive method, perfect for beginners:

  1. Log into Cloudflare Zero Trust dashboard, navigate to Networks > Tunnels.
  2. Click Create a tunnel.
  3. Select Cloudflared as the connector type, then name your tunnel (e.g., ssh-prod-server).
  4. After saving the tunnel, the dashboard displays an installation command containing a unique tunnel token.

bash

cloudflared service install <YOUR_TUNNEL_TOKEN>
  1. Execute this command on your server. The cloudflared service uses this token to connect to Cloudflare and automatically gets all subsequent configuration.
  2. Afterward, you can configure routing rules for this tunnel in the dashboard’s Public Hostnames or Private Networks tabs.

This method better suits automation and infrastructure-as-code (IaC) workflows.

Creating Tunnels:

Run this command on your server:

bash

cloudflared tunnel create <TUNNEL_NAME>

This command returns a tunnel UUID and generates a corresponding JSON credential file (like f9b4a...d3e.json) in the ~/.cloudflared/ directory.

Understanding the config.yml File:

This is the core of local management. You need to create a configuration file, typically at /etc/cloudflared/config.yml. A typical config.yml file structure for SSH access looks like this:

yaml

# Tunnel's unique identifier
tunnel: f9b4a1b1-0a43-47cf-b2af-97a3d906ad3e

# Path to tunnel credential file
credentials-file: /root/.cloudflared/f9b4a1b1-0a43-47cf-b2af-97a3d906ad3e.json

# Ingress rules define how traffic routes from public hostnames to local services
ingress:
  # Rule one: Route ssh.yourdomain.com SSH traffic to local port 22
  - hostname: ssh.yourdomain.com
    service: ssh://localhost:22

  # Rule two: Route web.yourdomain.com HTTP traffic to local port 8080
  - hostname: web.yourdomain.com
    service: http://localhost:8080

  # Catch-all rule: Return 404 for any requests not matching above hostnames
  # This is important security practice preventing tunnels from accidentally exposing unconfigured services
  - service: http_status:404

After configuration, run cloudflared as a service - it will read this file to start and configure the tunnel.

Important Note: A common confusion point is the difference between these two management modes. When tunnels are created in the dashboard and run with tokens (remote management), the cloudflared daemon pulls its configuration from the Cloudflare API and completely ignores local config.yml files. Many users find their local config.yml edits don’t take effect for this reason. Conversely, CLI-created tunnels (local management) completely depend on local config.yml content.

Therefore, you must choose one management mode at project start and stick with it. For environments requiring version control and automated deployment, local management is the better choice; for simple manual setups, remote management is more convenient. Clarifying this point can save significant troubleshooting time and effort.

The final step is configuring the SSH server itself to work with Cloudflare Access’s advanced features (like short-lived certificates).

Before any Cloudflare integration, we recommend following basic SSH security best practices, such as disabling password login in the /etc/ssh/sshd_config file:

ssh

PasswordAuthentication no
PermitRootLogin no

This is Cloudflare’s recommended most secure SSH authentication method, replacing traditional static SSH public keys with dynamically generated, extremely short-lived certificates.

Generate and Place CA Public Key:

  1. In the Cloudflare Zero Trust dashboard, navigate to Access > Service Auth.
  2. Under the SSH tab, generate a certificate for your SSH application. The dashboard will display a public key.
  3. Copy this public key.
  4. On your SSH server, paste this public key into /etc/ssh/ca.pub. You may need sudo privileges:

bash

sudo nano /etc/ssh/ca.pub

Configure sshd_config:

Edit the SSH daemon configuration file /etc/ssh/sshd_config. Add or ensure these two lines exist and aren’t commented out. These lines tell sshd to enable public key authentication and trust any certificates signed by the certificate authority (i.e., Cloudflare) specified in /etc/ssh/ca.pub:

ssh

PubkeyAuthentication yes
TrustedUserCAKeys /etc/ssh/ca.pub

Handling Different Usernames:

In some cases, a user’s Cloudflare login identity (like [email protected]) might differ from their Unix username on the server (like jdoe or admin). To handle this situation, sshd_config provides AuthorizedPrincipalsCommand or AuthorizedPrincipalsFile directives. These allow you to define a command or file that maps incoming certificate “principals” (i.e., Cloudflare user identity) to local users allowed to log in on the server. This is advanced configuration but crucial for solving the recurring username mismatch problem in the community.

Restart and Verify:

After saving sshd_config changes, you must restart the SSH service for configuration to take effect:

bash

# For Debian/Ubuntu
sudo systemctl restart ssh
# For RHEL/CentOS
sudo systemctl restart sshd

Use systemctl status sshd to check if the service is running normally.

After completing these server-side steps, your SSH server is ready for secure access through Cloudflare’s zero trust architecture.

With the server-side foundation established, the next step is configuring end-user devices so they can securely connect to SSH servers through Cloudflare. This section details three mainstream client access methods.

This is Cloudflare’s officially recommended flagship model for enterprise environments, providing the highest level of security and most seamless user experience.

This model’s core premise is that all user devices needing SSH server access must have the Cloudflare WARP client installed and registered to your organization’s Zero Trust account. This is typically done through bulk deployment and management via MDM/UEM solutions within enterprises.

This is the most critical and easily overlooked step when configuring this model. By default, to avoid interfering with user access to local network resources (like printers, NAS), the WARP client excludes traffic capture for private IP address ranges (RFC 1918, like 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16).

However, your SSH server is likely located in these private segments. Therefore, you must configure Split Tunnel rules in Settings > WARP Client > Device settings of the Zero Trust dashboard, explicitly including your SSH server’s IP address or CIDR network segment in WARP’s traffic routing scope.

For example, if your server IP is 10.1.2.3, you need to add a rule including 10.1.2.0/24 or more specifically 10.1.2.3/32 to the Include list. Only then will traffic be intercepted by the WARP client and sent to Cloudflare’s network for policy evaluation and routing when users attempt SSH connections to that IP.

This model’s biggest advantage is its transparency to end users. Once administrators complete all backend configuration, the user experience will be identical to traditional SSH. They just need to open their favorite terminal application and type the familiar command:

bash

ssh <username>@<private-ip-of-server>

No special proxy commands or complex client configuration needed. The WARP client silently handles all authentication and traffic proxying work in the background, completely transparent to users. This greatly reduces user learning costs and operational friction.

For technical users who don’t want or can’t use the WARP client, this method allows them to continue using native SSH clients while enjoying Cloudflare Access security benefits.

This method requires users to install the cloudflared binary on their local computers (Windows, macOS, or Linux). Installation methods are the same as server-side.

All the magic happens in the user’s SSH client configuration file ~/.ssh/config. By configuring ProxyCommand, you can instruct the SSH client to first establish connections through the cloudflared program when connecting to specific hosts.

For simple authentication not using short-lived certificates, the configuration is:

ssh

Host ssh.yourdomain.com
  ProxyCommand /usr/local/bin/cloudflared access ssh --hostname %h

Here, ssh.yourdomain.com is the public hostname you configured in Cloudflare Tunnel. ProxyCommand specifies the actual command executed when ssh ssh.yourdomain.com is called. %h is a placeholder replaced with the target hostname (i.e., ssh.yourdomain.com). You need to replace /usr/local/bin/cloudflared with cloudflared’s actual path on your system.

When using the most secure short-lived certificate authentication, configuration becomes slightly more complex since cloudflared needs to first generate certificates, then establish proxy connections:

ssh

Host ssh.yourdomain.com
  ProxyCommand /usr/local/bin/cloudflared access ssh --hostname %h
  IdentityFile ~/.cloudflared/%h-cf_key
  CertificateFile ~/.cloudflared/%h-cf_key-cert.pub

A more robust configuration method uses Match exec, which executes a command before connection to generate certificates, ensuring certificates are always current:

ssh

Match host ssh.yourdomain.com exec "/usr/local/bin/cloudflared access ssh-gen --hostname %h"
  ProxyCommand /usr/local/bin/cloudflared access ssh --hostname %h
  IdentityFile ~/.cloudflared/%h-cf_key

When users execute ssh [email protected], the SSH client first executes cloudflared access ssh-gen, which triggers browser-based Cloudflare Access login authentication. After successful authentication, cloudflared generates a short-lived certificate and corresponding private key, saving them in the ~/.cloudflared/ directory. Subsequently, ProxyCommand uses this newly generated certificate to proxy SSH connections through Cloudflare’s network.

Many users encounter “browser works, command line fails” issues fundamentally because of missing or incorrectly configured ProxyCommand. Standard SSH clients inherently can’t understand modern web authentication flows like OAuth, SAML, OIDC. The cloudflared access ssh command plays the role of an authentication shim here. It intercepts local SSH client connection requests, “translates” them into browser-based authentication flows that Cloudflare Access understands, obtains authentication tokens (JWT), then establishes actual proxy connections. Understanding cloudflared’s dual role - both proxy and authentication bridge - is key to troubleshooting such issues.

This method provides users with the simplest access experience, requiring no local client software installation - just a browser.

Configuration is very simple. In the Zero Trust dashboard, find the corresponding Access application, enter its settings, find Browser rendering under Additional settings, and set it to SSH.

Users simply visit the public hostname you configured for SSH service in their browser (e.g., https://ssh.yourdomain.com). The page automatically redirects to Cloudflare Access login interface. After users complete authentication through their identity provider (like entering email for one-time password, or through Google/Okta SSO), a fully functional terminal interface renders directly in the browser window, and users can immediately start working.

However, this seemingly perfect method has an important flaw: the “username mismatch” authentication flow problem. There’s extensive community discussion about this issue. The fundamental cause lies in the browser terminal’s authentication logic: it first completes user identity authentication (e.g., [email protected]) through Cloudflare Access and obtains a short-lived certificate for that identity’s email prefix (jane.doe). Then it uses this fixed username jane.doe to attempt SSH login to the server.

If the server actually needs username jdoe or admin, this certificate-based login attempt fails. After failure, the browser terminal falls back to prompting users to manually enter username and password/key, completely defeating the purpose of using short-lived certificates for seamless login.

In contrast, the CLI (ProxyCommand) method successfully handles different usernames because when users execute ssh [email protected], they’ve already provided the final target username admin before the authentication flow begins, and cloudflared can include this target username information in the certificate request.

Therefore, at the current stage, browser-rendered terminals can only provide truly seamless experience when the user’s Cloudflare identity email prefix exactly matches the Unix username on the server. This is a key limitation factor that must be considered when choosing architecture.

After successfully establishing connection channels, the next step is leveraging Cloudflare Access’s powerful features to refine access control and achieve true zero trust.

Cloudflare Access’s core is its flexible policy builder. Administrators can combine multiple rules to define who can access what.

Policies consist of an action (like Allow, Block, Bypass) and a set of rules. Rule logic relationships are:

  • Include (OR): Defines the initial user pool eligible for access. Users need only satisfy any one of multiple Include rules.
  • Exclude (NOT): Used to exclude specific users or groups from the user pool defined by Include. Any user satisfying Exclude rules will be denied access.
  • Require (AND): Adds additional conditions that must be satisfied on top of Include rules. Users must simultaneously satisfy all Require rules to gain access.

Selectors are specific conditions for building rules. Cloudflare provides rich selectors categorized as:

Identity: The most basic selectors, such as:

  • Emails (specific email addresses)
  • Emails ending in (all emails under specific domains)
  • Identity provider group (user groups from SSO providers like Okta or Google Workspace)

Device Posture: Key to achieving highest security level access. Through WARP client integration, you can set Require rules forcing user devices to meet specific conditions before connecting, such as:

  • Require WARP (must connect through WARP)
  • Disk encryption (disk must be encrypted)
  • Domain joined (device must join company domain)
  • Firewall (firewall must be enabled), etc.

Context: Based on connection-time environment information, such as:

  • Country (restrict access from specific countries/regions)
  • IP ranges (restrict access from specific IP address ranges)
  • Authentication Method (require users to authenticate via MFA)

Understanding policy execution order is crucial. Cloudflare Access first evaluates Bypass and Service Auth type policies. If no matches, it then evaluates Allow and Block policies from top to bottom. Once a user’s request matches any Allow or Block policy, evaluation stops and the corresponding action executes.

Integrating Cloudflare Access with your organization’s existing identity provider (IdP) is key to achieving single sign-on and centralized identity management.

Google Workspace is a core identity system used by many enterprises. Integrating it with Cloudflare Access allows leveraging existing user and group information to control SSH access. Here’s an integration process overview:

Configure in Google Cloud Platform (GCP):

  1. Create a new GCP project or use an existing one.
  2. Enable Admin SDK API, required for Cloudflare to get group information.
  3. Configure OAuth consent screen, set application name, and select “Internal” user type.
  4. Create an OAuth 2.0 client ID with type “Web application.”
  5. In “Authorized redirect URIs,” add your Cloudflare team domain callback URL (https://<your-team-name>.cloudflareaccess.com/cdn-cgi/access/callback).
  6. Record the generated client ID and client secret.

Configure in Cloudflare Zero Trust Dashboard:

  1. Navigate to Settings > Authentication, add a new login method, select Google Workspace.
  2. Enter the client ID and client secret obtained from GCP, plus your Google Workspace domain name.
  3. After saving, Cloudflare generates an authorization link. You (or your Google Workspace administrator) must visit this link to grant Cloudflare permission to read user and group information.

Use in Access Policies:

After completing integration, you can use Identity provider group selectors in Access policy Include or Require rules and directly select user groups synced from Google Workspace. This makes permission management extremely simple: just add or remove user group members in Google Workspace, and SSH access permissions automatically update.

For other IdPs supporting standard protocols (like Okta, Microsoft Entra ID, Auth0), integration follows similar patterns. You need to create a new application on the IdP side and configure related metadata like Entity ID, Assertion Consumer Service (ACS) URL, etc. Then fill this information plus application client ID/secret into Cloudflare’s generic SAML or OIDC connector configuration.

In any Access policy, you can add a Require rule setting the Authentication Method selector to mfa. This ensures only users who successfully completed multi-factor authentication on the IdP side can pass policy evaluation, adding a crucial security layer for sensitive SSH access.

Short-lived certificates are one of the most transformative security features in Cloudflare’s zero trust SSH solution. They completely change traditional SSH key management patterns.

Traditional SSH authentication relies on distributing and managing static public keys in server ~/.ssh/authorized_keys files. This brings huge operational burden and security risks: keys easily leak, forgetting to remove keys after employee departures causes permission residue, key rotation is difficult to execute. A stolen SSH key might provide long-term, unmonitored access.

The short-lived certificate mechanism is completely different. It shifts the trust foundation from scattered, static keys to a centralized, dynamic certificate authority (CA) - Cloudflare Access. Server-side no longer needs to manage hundreds or thousands of individual public keys; it only needs to trust one public key - Cloudflare’s CA public key.

The entire authentication flow embodies dynamic authorization’s core concept:

  1. User Initiates Connection: User initiates SSH connection request through WARP or cloudflared client.
  2. Cloudflare Access Authentication: Request redirects to Cloudflare Access for identity verification. User proves identity through SSO and MFA.
  3. Policy Evaluation: Cloudflare Access evaluates preset policies, checking if user identity, device status, etc. meet requirements.
  4. Certificate Issuance: If policy evaluation passes, Cloudflare’s CA dynamically issues an SSH certificate for that user and session. This certificate has extremely short validity, typically just minutes (e.g., 3 minutes).
  5. Certificate Delivery and Verification: cloudflared client delivers this short-lived certificate to target SSH server.
  6. Server Verification: SSH server receives the certificate and checks its signature. Since the server trusts Cloudflare’s CA (through pre-placed ca.pub file), it confirms signature validity and checks if the certificate’s principal is an allowed login user.
  7. Grant Access: After verification passes, SSH session establishes.

This model’s huge advantage is eliminating all challenges related to static SSH key management. Access permissions are dynamically granted and tightly bound to users’ real-time identity and device status. Even if certificates are intercepted, they quickly expire, greatly reducing risk. This is a fundamentally more secure access control model.

Since all SSH connections go through Cloudflare’s proxy, the platform can provide unparalleled visibility. Administrators can audit every login attempt (successful or not), and by enabling Gateway’s SSH command logging feature, can also record every command users execute in sessions. This is crucial for meeting compliance requirements (like SOC 2, ISO 27001) and conducting security incident investigations.

Even well-designed systems can encounter issues during actual deployment. This section aims to provide diagnostic approaches and solutions for common problems, helping you quickly identify and resolve issues.

Problem: cloudflared logs repeatedly show Failed to create new quic connection or similar timeout errors.

Cause: This is one of the most common tunnel connection issues. cloudflared defaults to using QUIC protocol (UDP-based) to communicate with Cloudflare edge nodes, typically using UDP port 7844. If the server’s network outbound firewall blocks this port, connections fail.

Solutions:

  • Preferred: Request network administrators to allow server outbound UDP 7844 port communication.
  • Alternative: If UDP ports can’t be opened, force cloudflared to use TCP-based HTTP/2 protocol. Edit cloudflared’s systemd service file (/etc/systemd/system/cloudflared.service), add --protocol http2 parameter after the cloudflared command in ExecStart line, then reload and restart service.

service

ExecStart=/usr/bin/cloudflared --protocol http2 --config /etc/cloudflared/config.yml tunnel run

Problem: Added or modified ingress rules in config.yml but they’re not taking effect. Accessing new hostnames returns 404 or other errors.

Diagnosis:

  • Syntax Check: Use cloudflared tunnel ingress validate command on server to check config.yml file syntax correctness.
  • Config File Path: This is a very subtle but common error. When cloudflared runs as service, it typically reads configuration from /etc/cloudflared/config.yml. But during manual testing, users might edit the file at ~/.cloudflared/config.yml. These are different file paths, causing service configuration not to update. Ensure you’re modifying the config file the service actually uses.
  • Management Mode Confusion: Again emphasizing, if your tunnel is remotely managed (running with tokens), it ignores local config.yml. All ingress rules must be configured in Zero Trust dashboard. Confirm your tunnel management mode.

Problem: Can access SSH through browser-rendered terminal but local terminal ssh [email protected] times out or fails.

Cause: 99% of this problem stems from client ~/.ssh/config file not being configured or incorrectly configured. As mentioned earlier, native SSH clients need cloudflared as ProxyCommand to handle Cloudflare Access authentication flows.

Solutions:

  1. Confirm cloudflared Installed: Ensure cloudflared is installed on client machine.
  2. Check ~/.ssh/config: Open this file, ensure there are correct entries for your SSH host.
  3. Path Issues: Is the cloudflared path specified in ProxyCommand correct? On Windows, path should be C:\\path\\to\\cloudflared.exe.
  4. Hostname Matching: Does the hostname in Host directive exactly match the name you’re trying to connect to?
  5. Verbose Logging: Use ssh -v [email protected] command to connect. The -v (verbose) parameter prints detailed debug information, showing whether ProxyCommand executes correctly and where cloudflared fails.

Problem: When using browser terminal, if Unix username on server doesn’t match Cloudflare identity email prefix, can’t automatically login with short-lived certificates, instead prompted for password or key.

Cause: This is a known design limitation of current browser-rendered terminals. Their authentication flow is fixed, always using email prefix as target username.

Solutions:

  1. Align Usernames (Recommended): If possible, the simplest solution is adjusting Unix usernames on server to match users’ email prefixes.
  2. Use Other Methods: If usernames can’t be aligned, for these specific users, avoid browser-rendered terminals and guide them to use local CLI method with configured ProxyCommand, since CLI method can properly handle different usernames.
  3. Follow Community: There are multiple discussion threads about this issue in the Cloudflare community. Follow these threads for official latest developments or solutions.

Problem: After logging into Cloudflare Access, browser terminal page shows errors or won’t load.

Causes:

  • Unsupported Policies: Browser rendering doesn’t support Bypass or Service Auth type Access policies. Check your application policies, ensure only Allow or Block are used.
  • Tunnel or Server Issues: Ensure backend cloudflared tunnel is in Healthy status and SSH server itself is running normally.
  • Network Issues: Though rare, client network issues or browser plugins might interfere with WebSocket connections, causing rendering failure. Try accessing in browser’s incognito mode.

By adopting Cloudflare Zero Trust platform to protect SSH access, organizations can fundamentally improve their infrastructure security posture. This approach transforms traditional passive security models based on perimeter defense into proactive, identity-centric zero trust architectures.

Core advantages manifest in several areas:

Complete Attack Surface Elimination: Through Cloudflare Tunnel, SSH servers no longer need exposure to the public internet, completely eliminating external network direct scanning and attack risks. This is a fundamental leap from “hardening the gate” to “making the castle invisible.”

Dynamic and Granular Access Control: Cloudflare Access places every SSH connection under strict policy review. Access decisions no longer rely on static IP addresses or shared keys, but on users’ real-time identity, device security status, and rich contextual information like multi-factor authentication, truly achieving the spiritual core of least privilege principles.

Revolutionary Authentication Model Upgrade: Replacing static, hard-to-manage SSH keys with dynamically generated, extremely short-lived SSH certificates is this solution’s most transformative feature. This not only greatly reduces security risks from key leaks but fundamentally solves operational pain points of key rotation and lifecycle management.

During implementation, choosing the right architecture model is crucial. The WARP-to-Tunnel model provides the most comprehensive, seamless security protection for enterprise environments; browser-rendered terminals bring great convenience for temporary access scenarios but need attention to current username handling limitations; while client cloudflared proxy preserves native terminal flexibility and powerful features for technical users.

Although deployment involves coordinated configuration of servers, clients, and cloud platforms and might encounter specific technical challenges, by strictly following the steps and troubleshooting guides detailed in this article, any organization can successfully upgrade their SSH access system to modern zero trust security standards, laying solid security foundations for enterprise digital transformation.

Related Content