In this article, we'll see how to leverage Cloudflare's argo tunnels without publicly exposing our services. In this setup we'll use EC2 as an example, but this is works with Fargate as well.
What is an Argo Tunnel?
Argo Tunnel provides a secure way to connect your origin to Cloudflare without a publicly routable IP address. With Argo Tunnel, you do not expose an external IP from your infrastructure to the Internet. Instead, a lightweight daemon runs in your infrastructure and creates outbound-only connections to Cloudflare’s edge.
There are tons of use cases like using exposing internal applications, replacing VPN setup with Cloudflare Access possibilities are endless!
Currently, I use this setup for developing remotely on EC2's securely.
What is Cloudflare Access?
If we want to only expose this to your team internally, we can configure a zero trust access with Cloudflare access
We'll use Terraform to define our cloud resources
Let's define the providers aws
and cloudflare
which we'll be using:
terraform { required_providers { aws = { source = "hashicorp/aws" version = "~> 2.7.0" } cloudflare = { source = "cloudflare/cloudflare" version = "~> 2.26.0" } } required_version = ">= 0.13" } provider "cloudflare" { api_token = var.cloudflare_api_token }
We can define our api keys and secrets as variables in variables.tf
variable "region" { type = string default = "us-west-2" } variable "cloudflare_api_token" { type = string description = "Cloudflare api token" default = "<YOUR_API_TOKEN>" } variable "cloudflare_account_id" { type = string description = "Cloudflare account id" default = "<YOUR_ACCOUNT_ID>" } variable "cloudflare_zone_id" { type = string description = "Cloudflare zone id" default = "<YOUR_ZONE_ID>" } variable "subdomain" { type = string description = "your subdomain" default = "pretty-cool" }
In our main.tf
file, we'll define resources. We'll first create an argo tunnel and add a cloudflare proxied record CNAME
for it so that we can use in our user_data
init script.
resource "random_id" "argo_secret" { byte_length = 35 } resource "cloudflare_argo_tunnel" "argo_tunnel" { account_id = var.cloudflare_account_id name = "${var.subdomain}-tunnel" secret = random_id.argo_secret.b64_std } resource "cloudflare_record" "http_app" { zone_id = var.cloudflare_zone_id name = var.subdomain value = "${cloudflare_argo_tunnel.argo_tunnel.id}.cfargotunnel.com" type = "CNAME" proxied = true }
data "template_file" "init" { template = file("my-project/init.tpl") vars = { subdomain = var.subdomain domain = var.cloudflare_zone, account = var.cloudflare_account_id, tunnel_id = cloudflare_argo_tunnel.argo_tunnel.id, tunnel_name = cloudflare_argo_tunnel.argo_tunnel.name, secret = random_id.argo_secret.b64_std } } resource "aws_instance" "api" { ami = "ami-03d5c68bab01f3496" instance_type = "t3.large" user_data = data.template_file.init.rendered }
In the init.tpl
we'll simply install cloudflared
and create a config.yml
and then run it in background as our EC2 starts.
#!/bin/bash # Logs are availabe at /var/logs/cloud-init-output.log # Install cloudflared wget https://bin.equinox.io/c/VdrWdbjqyF/cloudflared-stable-linux-amd64.deb sudo dpkg -i cloudflared-stable-linux-amd64.deb # Create required dirs mkdir ~/.cloudflared touch ~/.cloudflared/cert.json touch ~/.cloudflared/config.yml # Create cert.json cat > ~/.cloudflared/cert.json << "EOF" { "AccountTag" : "${account}", "TunnelID" : "${tunnel_id}", "TunnelName" : "${tunnel_name}", "TunnelSecret" : "${secret}" } EOF # Add a config file cat > ~/.cloudflared/config.yml << "EOF" tunnel: ${tunnel_id} credentials-file: /etc/cloudflared/cert.json logfile: /var/log/cloudflared.log loglevel: info ingress: - hostname: ${subdomain}.${domain} service: http://localhost:80 - service: http_status:404 EOF # Start Cloudflared service sudo cloudflared service install sudo cp -via ~/.cloudflared/cert.json /etc/cloudflared/ sudo service cloudflared start
Once our EC2 starts, we'll be able to access it via https://pretty-cool.your-cloudflare-domain.com
and all without allowing any ingress in the security group!
Hope this was helpful!
Top comments (0)