Cloudflare Zero trust - which is planned be rebrand to Cloudflare One is pretty awesome platform that can accommodate small engineering teams when it comes to strickling security.
Unfortunately the Cloudflare docs can be quite confusing and sometimes even contradicting - it seems the product evolved quite rapidly and the documentation or blog posts were lagging behind and the old one - were never updated.
Let’s go over common use cases we could use Zero Trust. I will assume that you’re familiar with Terraform and skip irrelevant code bits.
Locking domain behind github auth
- Add new github auth per official docs
- I will assume cloudflare account ID to be stored in
cloudflare_account_idvariable - I will assume
your_zonezone and someyour_domainA record being configured
Start with identity provider.
resource "cloudflare_access_identity_provider" "github_oauth" {
account_id = var.cloudflare_account_id
name = "GitHub"
type = "github"
config {
client_id = "<your GH app client id>"
client_secret = "<your GH app secret>"
}
}
Then grant access to your GH organization.
resource "cloudflare_access_group" "github_org" {
account_id = var.cloudflare_account_id
name = "Github Organization Group"
include {
github {
identity_provider_id = cloudflare_access_identity_provider.github_oauth.id
name = "<name of your github org>"
}
}
}
And glue it together by protecting your domain within the zone.
resource "cloudflare_access_application" "example" {
zone_id = cloudflare_zone.your_zone.id
name = cloudflare_record.your_domain.name
domain = cloudflare_record.your_domain.name
type = "self_hosted"
session_duration = "24h"
auto_redirect_to_identity = true
allowed_idps = [
cloudflare_access_identity_provider.github_oauth.id
]
policies = [
cloudflare_access_policy.example.id,
]
}
resource "cloudflare_access_policy" "example" {
account_id = var.cloudflare_account_id
name = "github auth"
session_duration = "24h"
decision = "allow"
include {
group = [
cloudflare_access_group.github_org.id
]
}
}
Locking specific path
It’s exactly the same as the above, but you customize the domain bit.
resource "cloudflare_access_application" "example" {
zone_id = cloudflare_zone.your_zone.id
name = cloudflare_record.your_domain.name
domain = "${cloudflare_record.your_domain.name}/some-path"
type = "self_hosted"
session_duration = "24h"
auto_redirect_to_identity = true
allowed_idps = [
cloudflare_access_identity_provider.github_oauth.id
]
policies = [
cloudflare_access_policy.example.id,
]
}
Using WARP client to access internal network
One cool thing you can do is install cloudflared daemon on one of your host in the internal network and create a secure tunnel between that network and grant access to it using WARP client. There are tons and tons options there, but I will provide most basic example.
I’m not gonna lie that it’s been ages since I set this one up, so my knowledge is a little bit rusty here. Example below allows traffic 10.0.0.0/16 to be routed by the tunnel and accessed when signed into Zero Trust account via WARP client using Github auth (from the example above).
Cloudflared itself can be installed on the host e.g via debian/rpm package. Once installed configure tunnel via cloudflared service install <your tunnel secret> command.
resource "cloudflare_device_settings_policy" "warp_policy" {
account_id = var.cloudflare_account_id
name = "WARP settings policy"
description = "WARP settings policy"
default = true
enabled = true
allow_mode_switch = true
allow_updates = true
allowed_to_leave = true
auto_connect = 0
disable_auto_fallback = true
}
resource "cloudflare_split_tunnel" "internal_network" {
account_id = var.cloudflare_account_id
policy_id = cloudflare_device_settings_policy.warp_policy.id
mode = "include"
tunnels {
address = "10.0.0.0/16"
description = "internal network"
}
}
resource "cloudflare_device_posture_rule" "device_rules" {
account_id = var.cloudflare_account_id
name = "Devices posture rule"
type = "warp"
}
data "cloudflare_access_application" "warp" {
account_id = var.cloudflare_account_id
domain = "<cloudflare org name>.cloudflareaccess.com/warp"
}
resource "cloudflare_access_policy" "warp" {
account_id = var.cloudflare_account_id
application_id = data.cloudflare_access_application.warp.id
name = "warp enrollment policy"
precedence = "2"
session_duration = "24h"
decision = "allow"
include {
group = [cloudflare_access_group.github_org.id]
}
}
resource "cloudflare_tunnel" "example" {
account_id = var.cloudflare_account_id
name = "<your-server-name>"
secret = base64encode("<your tunnel secret>")
}
resource "cloudflare_tunnel_config" "example_config" {
account_id = var.cloudflare_account_id
tunnel_id = cloudflare_tunnel.example.id
config {
warp_routing {
enabled = true
}
ingress_rule {
service = "http://127.0.0.1"
}
}
}
resource "cloudflare_tunnel_route" "tunnel_route" {
account_id = var.cloudflare_account_id
tunnel_id = cloudflare_tunnel.example.id
network = "10.0.0.0/16"
}
Once connected you can just do ssh 10.0.X.Y from your computer and things should just work (assuming there is a working node in your internal network with that IP that is).