Access Private Cloud Resources Securely with Cloudflare Zero Trust

Ted O'ConnorTed O'Connor
7 min read

Built from experience, not autocomplete.

Let's talk about the elephant in the room, traditional bastion hosts are security nightmares. You're opening SSH ports to the internet, managing keys, and praying your firewall rules are tight enough. But you still need to access your private cloud resources, right? Enter Cloudflare Zero Trust Tunnel - the VPN killer that actually works.

In this post, I'll walk through practical, battle-tested approaches to ditch your traditional bastion and access private AWS resources securely using Cloudflare Tunnel. No more open SSH ports, no more key management headaches, no more "can you try disconnecting and reconnecting?" support calls. Just clean, auditable zero-trust access.

And here's the kicker, this approach aligns with NIST's latest guidance on Zero Trust Architecture (SP 1800-35), which recommends exactly this kind of policy-based access control. Plus these features are available on Cloudflare's free plan.


๐Ÿ” 1. Replace Traditional Bastion Access with Cloudflare Tunnel

The problem: Traditional bastion hosts require opening SSH ports to the internet, managing SSH keys, and hoping your security groups are configured correctly. One misconfiguration and you've got a direct path into your private network.

The fix: Run cloudflared on a bastion instance in your private subnet with zero open ingress ports. The bastion reaches out to Cloudflare, not the other way around.

Why this works: Your bastion sits in a private subnet with no public IP and no inbound rules. It establishes outbound HTTPS connections to Cloudflare, and you access it through Cloudflare's edge network with proper authentication. Even if someone compromises your bastion, they can't reach it from the internet.

Example:
Here's a bash script sample to install and configure a secure tunnel:

curl -L --output cloudflared.deb https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
dpkg -i cloudflared.deb

mkdir -p /etc/cloudflared

cat > /etc/cloudflared/cert.json << EOF
{
    "AccountTag"   : "${account_id}",
    "TunnelID"     : "${tunnel_id}",
    "TunnelName"   : "${tunnel_name}",
    "TunnelSecret" : "${tunnel_secret}"
}
EOF

cat > /etc/cloudflared/config.yml << EOF
tunnel: ${tunnel_id}
credentials-file: /etc/cloudflared/cert.json
writeLogfile: /var/writeLog/cloudflared.writeLog
writeLoglevel: info

ingress:
  - hostname: ${tunnel_name}
    service: ssh://localhost:22
  - hostname: "*"
    service: hello-world
EOF

cloudflared service install
systemctl start cloudflared

Caveat: You'll need to run the cloudflared daemon on your bastion, but it's lightweight and stable. Much better than managing a VPN and firewall rules.

AI might suggest using AWS Systems Manager Session Manager instead. That's great for direct server access, but what about your internal web apps and APIs? Cloudflare Tunnel handles those too, and you can still SSH through the tunnel. The Cloudflare approach is also hosting provider agnostic. So you can use this same solution anywhere.


๐Ÿ›ก๏ธ 2. Layer Zero Trust Policies on Top

The problem: Once you have a tunnel, you need to control who can access what. Traditional bastions give you "all or nothing" access - not exactly granular.

The fix: Use Cloudflare Zero Trust policies to enforce access controls based on identity, device posture, and network context. This aligns with NIST's Enhanced Identity Governance (EIG) approach to Zero Trust Architecture.

Why this works: You can require MFA, check device compliance, and even block access from certain countries or IP ranges. All without touching your application code or infrastructure. Plus, you get detailed logs of every access attempt. According to NIST's guidance, this policy-based approach is the foundation of modern Zero Trust Architecture.

Example:
Here's a Terraform sample for a Zero Trust tunnel that only allows access from a specific email domain and IP:

# Generates a 35-character secret for the tunnel.
resource "random_id" "tunnel_secret" {
  byte_length = 35
}

data "cloudflare_zone" "zone" {
  zone_id = var.cloudflare_tunnel_zone_id
}

locals {
  tunnel_domain = "${var.cloudflare_tunnel_subdomain}.${data.cloudflare_zone.zone.name}"
  tunnel_secret = random_id.tunnel_secret.b64_std
}

# Creates a new locally-managed tunnel for the bastion
resource "cloudflare_zero_trust_tunnel_cloudflared" "tunnel" {
  account_id = var.cloudflare_tunnel_account_id
  name       = local.tunnel_domain
  secret     = local.tunnel_secret
}

# Creates the CNAME record that routes domain to the tunnel
resource "cloudflare_record" "dns" {
  zone_id = var.cloudflare_tunnel_zone_id
  name    = var.cloudflare_tunnel_subdomain
  content = "${cloudflare_zero_trust_tunnel_cloudflared.tunnel.id}.cfargotunnel.com"
  type    = "CNAME"
  proxied = true
}

# Creates an Access application to control who can connect
resource "cloudflare_zero_trust_access_application" "app" {
  zone_id          = var.cloudflare_tunnel_zone_id
  name             = local.tunnel_domain
  domain           = local.tunnel_domain
  session_duration = "1h"
}

# Creates an Access group for the application
resource "cloudflare_zero_trust_access_group" "group" {
  zone_id = var.cloudflare_tunnel_zone_id
  name    = local.tunnel_domain

  include {
    email_domain = [var.email_domain]
  }
}

# Creates an Access policy for the application
resource "cloudflare_zero_trust_access_policy" "policy" {
  application_id = cloudflare_zero_trust_access_application.app.id
  zone_id        = var.cloudflare_tunnel_zone_id
  name           = local.tunnel_domain
  decision       = "allow"
  precedence     = "1"

  include {
    group = [cloudflare_zero_trust_access_group.group.id]
  }

  require {
    ip = [var.office_ip]
  }
}

Caveat: The free Cloudflare plan only retains 24 hours of access logs. Paid plans increase this to 30 days or 6 months.

AI might recommend AWS IAM roles and temporary credentials. That's great for programmatic access, but what about your developers who need to access internal tools. It also requires different solutions per provider when not locked into AWS. Zero Trust handles both use cases.


๐Ÿ” 3. Add Audit Logging That Actually Matters

The problem: Traditional bastion logs are notoriously useless. "User connected from IP X" doesn't tell you what they accessed or when they disconnected.

The fix: Cloudflare Zero Trust provides detailed audit logs showing exactly who accessed what, when, and from where. This centralized access auditing is something you simply don't get with traditional SSH.

Why this works: You get visibility into access patterns, failed authentication attempts, and can quickly identify suspicious activity. Perfect for compliance requirements and security investigations. NIST's guidance emphasizes the importance of continuous monitoring and logging as key components of Zero Trust Architecture.

Example:
Here's a simple script to query Cloudflare audit logs for access events:

# Query Cloudflare audit logs for the last 24 hours
curl -X GET "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/audit_logs" \
  -H "Authorization: Bearer $API_TOKEN" \
  -H "Content-Type: application/json" \
  --data-urlencode "since=$(date -u -d '24 hours ago' +%Y-%m-%dT%H:%M:%SZ)" \
  --data-urlencode "until=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
  | jq '.result[] | select(.action == "access_granted") | {user: .actor.email, resource: .resource.name, timestamp: .timestamp}'

Caveat: The audit logs API has rate limits, so don't go crazy with queries. But for normal security monitoring, it's more than sufficient.

AI might suggest using AWS CloudTrail for audit logging. That's great for AWS API calls, but what about access to your internal applications? Zero Trust logs cover the full picture.


๐Ÿ”‘ 4. SSO Support That Traditional SSH Can't Match

The problem: Traditional SSH requires managing individual SSH keys for each user. When someone leaves the company, you have to hunt down and remove their keys from every server.

The fix: Cloudflare Zero Trust integrates with your existing SSO provider (Okta, Google Workspace, Azure AD, etc.) for seamless authentication.

Why this works: Users authenticate through your existing SSO system, and access is automatically revoked when they're removed from your identity provider. No more SSH key management, no more forgotten access. This single sign-on approach is exactly what NIST recommends for modern Zero Trust implementations.

Caveat: You'll need to configure your SSO provider on Cloudflare, but once it's set up, user management becomes trivial.

AI might suggest using SSH certificates instead of keys. That's better than raw keys, but you still need to manage the certificate authority and user enrollment process.


๐Ÿ“ฆ Bonus: Ditch Some Traditional Security Tools

Sometimes the best security improvement is removing complexity:

  • VPN infrastructure? There is no need for dedicated VPN servers or heavy client apps.

  • VPN concentrators? Cloudflare handles the scaling and redundancy.

  • Certificate management? Cloudflare manages SSL/TLS termination automatically.

The key isn't to abandon security. It's to use the right tool at the right scale and know when you're being charged complexity tax.


๐Ÿ‘€ Final Thoughts

Zero Trust isn't just a buzzword โ€” it's a practical approach to security that actually works. And here's the rub: AI will rarely suggest it. Most LLMs default to recommending traditional VPN or bastion solutions because that's what's in the documentation. They don't understand the operational pain of managing SSH keys and firewall rules or the security risks of open ingress ports.

The NIST guidance on Zero Trust Architecture validates this approach, recommending policy-based access control and continuous monitoring - exactly what Cloudflare Zero Trust provides. Plus, most of these enterprise-grade features are available on Cloudflare's free plan, making it accessible for teams of any size.


Want more human-powered DevOps hacks like this? Follow along. I promise not to recommend Kubernetes for every problem.

โœ๏ธ About the author
I'm Ted, a cloud infrastructure and blockchain engineer focused on practical DevOps and cost optimization strategies.

๐Ÿ“ฌ Want more like this? Subscribe to my newsletter or follow me on Hashnode / Medium.

โ˜• Found this helpful? Buy me a coffee

0
Subscribe to my newsletter

Read articles from Ted O'Connor directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Ted O'Connor
Ted O'Connor