Sign inSign up

hezzit/cftl

By hezzit

•Updated 7 months ago

Application-level security to Cloudflare Zero Trust with AUD validation and email access control.

Image
Networking
Security
Web servers
0

1.1K

hezzit/cftl repository overview

ā šŸ›”ļø CF Zero Trust Third Layer (CFTL)

Additional Security Layer for Cloudflare Access Applications

CFTL provides an extra validation layer on top of Cloudflare Zero Trust, adding application-level security with AUD validation and email-based access control.

Docker License: MIT

ā šŸ” Three Layers of Security

LayerComponentPurpose
1Cloudflare AccessIdentity validation (SSO, MFA, policies)
2Cloudflare TunnelSecure network connection + JWT validation
3CFTL (This System)Additional AUD validation + email restrictions

ā šŸš€ Quick Start

⁠Using Docker Image
services:
  cftl:
    image: hezzit/cftl:latest
    container_name: cftl
    restart: always
    environment:
      - TUNNEL_TOKEN=your_tunnel_token_here #     v aud     v comma-separated list of emails
      - CONFIGS=your-app.example.com:my-app:3000:your_aud:[email protected]
        #			^ hostname		  ^ service:port				
    networks:
      - app-network
    depends_on:
      - app

  # Your application
  my-app:
    image: your-app:latest
    container_name: my-app
    networks:
      - app-network
    # No external ports - access only through CFTL

networks:
  app-network:
    external: false

ā šŸŽÆ Configuration System

CFTL uses a flexible alias-based configuration system that allows you to define reusable components and organize your services in multiple ways.

⁠Basic Structure
# Define reusable components with aliases
AUDS=aud_alias:aud_value
EMAILS=email_alias:[email protected],[email protected]
HOSTNAMES=hostname_alias:hostname.example.com
SERVICES=service_alias:service_name

# Configure services using aliases
CONFIGS=hostname_alias:service_alias:port:aud_alias:email_alias
⁠Configuration Examples
⁠Simple Configuration (Single Service)
# Define components
AUDS=prod:abc123def456789
EMAILS=team:[email protected],[email protected]
HOSTNAMES=app:myapp.example.com
SERVICES=backend:my-backend-service

# Configure the service
CONFIGS=app:backend:3000:prod:team
⁠Multiple Services
# Define shared components
AUDS=prod:abc123def456789
EMAILS=admin:[email protected]|dev:[email protected]
HOSTNAMES=api:api.example.com|web:web.example.com
SERVICES=backend:backend-api|frontend:nginx

# Configure each service
CONFIGS_API=api:backend:3000:prod:admin
CONFIGS_WEB=web:frontend:80:prod:dev
⁠Advanced Organization Patterns
⁠Pattern 1: Environment-Based
# Development environment
AUDS_DEV=dev:dev_aud_123
EMAILS_DEV=devteam:[email protected],[email protected]
HOSTNAMES_DEV=ide:ide.dev.example.com|debug:debug.dev.example.com
SERVICES_DEV=vscode:code-server
CONFIGS_DEV_IDE=ide:vscode:8080:dev:devteam
CONFIGS_DEV_DEBUG=debug:vscode:8081:dev:devteam

# Production environment
AUDS_PROD=prod:prod_aud_456
EMAILS_PROD=ops:[email protected]
HOSTNAMES_PROD=app:app.example.com|api:api.example.com
SERVICES_PROD=web:nginx|api:backend
CONFIGS_PROD_APP=app:web:80:prod:ops
CONFIGS_PROD_API=api:api:3000:prod:ops
⁠Pattern 2: Team-Based
# Frontend team resources
AUDS_FRONTEND=fe:frontend_aud
EMAILS_FRONTEND=fe_team:[email protected]
HOSTNAMES_FRONTEND=app:app.example.com|preview:preview.example.com

# Backend team resources
AUDS_BACKEND=be:backend_aud
EMAILS_BACKEND=be_team:[email protected]
HOSTNAMES_BACKEND=api:api.example.com|admin:admin.example.com

# Shared services
SERVICES=nginx:nginx|node:nodejs|python:python-app

# Service configurations
CONFIGS_FE_APP=app:nginx:80:fe:fe_team
CONFIGS_FE_PREVIEW=preview:node:3000:fe:fe_team
CONFIGS_BE_API=api:python:8000:be:be_team
CONFIGS_BE_ADMIN=admin:node:4000:be:be_team
⁠Pattern 3: Simplified (Using Defaults)
# When you don't need aliases, values without ':' use '0' as default alias
AUDS=abc123def456789
[email protected],[email protected]
HOSTNAMES=app.example.com
SERVICES=backend

# Reference using '0' alias
CONFIGS=0:0:3000:0:0
⁠Special Cases
⁠Service Without Authentication
# Empty AUD and emails fields = no third layer protection
CONFIGS_PUBLIC=public:nginx:80::
⁠Only AUD Validation (No Email Restriction)
CONFIGS_API=api:backend:3000:prod:
#                                   ^ no email restriction
⁠Mixed Configuration Styles
# You can mix all patterns in one deployment
AUDS=prod:prod_aud|staging:staging_aud
[email protected]  # Uses '0' as default alias
HOSTNAMES_PROD=app:app.example.com
HOSTNAMES_DEV=dev:dev.example.com
SERVICES=backend:my-backend|frontend:nginx

# Multiple CONFIGS variations
CONFIGS=app:backend:3000:prod:0|dev:frontend:80:staging:0  # Using default email alias
CONFIGS_PUBLIC=public.example.com:nginx:80::  # Direct values without aliases

ā šŸ“‹ Complete Setup Guide

⁠Step 1: Configure Authentication Method

First, set up your identity provider integration:

šŸ“– Guide: Identity Provider Integration⁠

Popular options:

  • GitHub OAuth
  • Google
  • Azure AD
  • Generic OIDC
⁠Step 2: Create Access Policies

Define who can access your applications:

šŸ“– Guide: Access Policies⁠

Example policy:

⁠Step 3: Create Access Application

Set up your application in Cloudflare Access:

šŸ“– Guide: Self-Hosted Applications⁠

Configuration:

  1. Application Name: Your App Name
  2. Application Domain: your-app.example.com
  3. Authentication Method: Select your configured method (GitHub, Google, etc.)
  4. Policies: Select your access policy
  5. Save and copy the Application AUD (you'll need this later)
⁠Step 4: Create Cloudflare Tunnel

Set up secure connection to your application:

šŸ“– Guide: Create Remote Tunnel⁠

Configuration:

  1. Tunnel Name: Your tunnel name
  2. Public Hostname: your-app.example.com (same as Access app)
  3. Service: http://localhost:8080 (CFTL proxy port)

āš ļø IMPORTANT - Additional Settings:

  • Navigate to Access tab in tunnel configuration
  • Enable "Validate JWT"
  • Select your Access Application (created in Step 3)
  1. Save and copy the Tunnel Token
⁠Step 5: Configure CFTL

Choose your configuration style:

⁠Option A: Simple Configuration
CONFIGS=your-app.example.com:your-service:3000:your_aud_from_step_3:[email protected]
⁠Option B: Multi-Service Configuration
TUNNEL_TOKEN=your_tunnel_token

# Define all your AUDs
AUDS=prod:aud_123|staging:aud_456

# Define email groups
EMAILS=admin:[email protected]|dev:[email protected],[email protected]

# Define all hostnames
HOSTNAMES=app:app.example.com|api:api.example.com|admin:admin.example.com

# Define service types
SERVICES=web:nginx|backend:nodejs-api

# Configure each service
CONFIGS_APP=app:web:80:prod:admin
CONFIGS_API=api:backend:3000:prod:dev
CONFIGS_ADMIN=admin:backend:4000:staging:admin
⁠Step 6: Deploy
docker-compose up -d

ā šŸ”§ Environment Variables

⁠Core Variables
VariableDescriptionRequiredExample
TUNNEL_TOKENCloudflare Tunnel tokenāœ…eyJhbGci...
PORTCFTL listening portāŒ8080 (default)
VERBOSEEnable verbose loggingāŒfalse (default)
⁠Configuration Variables
Variable PatternDescriptionExample
AUDS*AUD definitionsAUDS=prod:abc123 or AUDS_DEV=dev:xyz789
EMAILS*Email group definitionsEMAILS=admin:[email protected]
HOSTNAMES*Hostname definitionsHOSTNAMES=app:app.example.com
SERVICES*Service type definitionsSERVICES=backend:my-backend
CONFIGS*Service configurationsCONFIGS_APP=app:backend:3000:prod:admin

Note: All patterns support multiple definitions (AUDS, AUDS_1, AUDS_PROD, etc.)

ā šŸ” How It Works

  1. User visits your-app.example.com
  2. Cloudflare Access validates identity (Layer 1)
  3. Cloudflare Tunnel validates JWT and forwards to CFTL (Layer 2)
  4. CFTL validates AUD and email authorization (Layer 3)
  5. If all layers pass, request is forwarded to your application
⁠User Headers Passed to Application

When authentication is successful, your application receives these HTTP headers:

HeaderDescriptionExample
X-Auth-User-EmailUser's email address[email protected]
X-Auth-User-IDUnique user ID (CF Access sub)7335d417-61da-459d-899c-0a01c76a2f94
X-Auth-User-CountryUser's authentication countryUS
X-Auth-MethodAuthentication method usedcf-access-third-layer
X-Auth-ServiceService name (internal)app_example_com
X-Auth-AUDValidated CF Access AUDabc123def456...
X-Auth-IssuerCF Access issuer URLhttps://yourteam.cloudflareaccess.com
X-Auth-Token-TypeToken typeapp
X-Auth-Identity-NonceCF identity cache key6ei69kawdKzMIAPF
⁠Using Headers in Your Application

Flask (Python):

@app.route('/')
def index():
    user_email = request.headers.get('X-Auth-User-Email')
    user_country = request.headers.get('X-Auth-User-Country')
    return f"Welcome {user_email} from {user_country}"

Express.js (Node.js):

app.get('/', (req, res) => {
    const userEmail = req.headers['x-auth-user-email'];
    const userCountry = req.headers['x-auth-user-country'];
    res.send(`Welcome ${userEmail} from ${userCountry}`);
});

Note: Only services with third layer protection receive user headers. Services without third layer (bypass mode) are direct proxied without authentication headers.

ā šŸ› ļø Troubleshooting

⁠Check System Status
docker-compose logs cftl
⁠Common Issues
IssuePossible CauseSolution
DENIED: No CF Access tokenDomain mismatch between Access App and CFTLEnsure Access Application domain matches CFTL hostname exactly
DENIED: AUD mismatchWrong AUD in configurationCopy correct AUD from Access Application
DENIED: Unauthorized emailEmail not in authorized listAdd email to EMAILS configuration
Nginx error page (white/plain)Issue between CFTL and your appCheck app connectivity and port configuration
Browser error (empty response/connection reset)Issue between Tunnel and Access AppEnsure tunnel hostname matches Access Application domain exactly
Tunnel not connectingInvalid tunnel tokenGenerate new token from tunnel settings
⁠Test Individual Layers
# Test if tunnel is working
curl -I https://your-app.example.com

# Check CFTL logs for third layer validation
docker-compose logs -f cftl

ā šŸ“„ License

This project is licensed under the MIT License - see the LICENSE⁠ file for details.


Built with ā¤ļø by Hezzit. Contributions are welcome!

⭐ If this project helped you, please give it a star!

Tag summary

Content type

Image

Digest

sha256:f392bdfea…

Size

57.3 MB

Last updated

7 months ago

docker pull hezzit/cftl