{"id":31585063,"url":"https://github.com/hezzitlda/cftl","last_synced_at":"2026-04-02T11:58:19.071Z","repository":{"id":314534950,"uuid":"1055895766","full_name":"hezzitlda/cftl","owner":"hezzitlda","description":"Adds application-level security to Cloudflare Zero Trust with AUD validation and email access control.","archived":false,"fork":false,"pushed_at":"2026-03-20T19:44:37.000Z","size":187,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-21T10:44:54.075Z","etag":null,"topics":["authentication","cloudflare","cloudflare-access","docker","failover","nginx","reverse-proxy","zero-trust"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hezzitlda.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-13T01:59:41.000Z","updated_at":"2025-09-29T08:26:00.000Z","dependencies_parsed_at":null,"dependency_job_id":"d341ae64-47a7-4568-ac8d-51a17d3495a6","html_url":"https://github.com/hezzitlda/cftl","commit_stats":null,"previous_names":["hezzitlda/cftl"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/hezzitlda/cftl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hezzitlda%2Fcftl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hezzitlda%2Fcftl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hezzitlda%2Fcftl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hezzitlda%2Fcftl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hezzitlda","download_url":"https://codeload.github.com/hezzitlda/cftl/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hezzitlda%2Fcftl/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31305969,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T09:48:21.550Z","status":"ssl_error","status_checked_at":"2026-04-02T09:48:19.196Z","response_time":89,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authentication","cloudflare","cloudflare-access","docker","failover","nginx","reverse-proxy","zero-trust"],"created_at":"2025-10-06T01:26:49.564Z","updated_at":"2026-04-02T11:58:19.054Z","avatar_url":"https://github.com/hezzitlda.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://raw.githubusercontent.com/hezzitlda/cftl/main/logo.png\"\n        height=\"100\"\u003e\n\u003c/p\u003e\n\n# 🛡️ CF Zero Trust Third Layer (CFTL)\n\n**Additional Security Layer for Cloudflare Access Applications**\n\nCFTL provides an extra validation layer on top of Cloudflare Zero Trust, adding application-level security with AUD validation and email-based access control.\n\n[![Docker](https://img.shields.io/badge/docker-%230db7ed.svg?style=for-the-badge\u0026logo=docker\u0026logoColor=white)](https://hub.docker.com/r/hezzit/cftl)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=for-the-badge)](https://opensource.org/licenses/MIT)\n\n## 🔐 Three Layers of Security\n\n| Layer | Component              | Purpose                                        |\n| ----- | ---------------------- | ---------------------------------------------- |\n| **1** | **Cloudflare Access**  | Identity validation (SSO, MFA, policies)       |\n| **2** | **Cloudflare Tunnel**  | Secure network connection + JWT validation     |\n| **3** | **CFTL (This System)** | Additional AUD validation + email restrictions |\n\n## 🚀 Quick Start\n\n### Using Docker Image\n\n```yaml\nservices:\n  cftl:\n    image: hezzit/cftl:latest\n    container_name: cftl\n    restart: always\n    environment:\n      - TUNNEL_TOKEN=your_tunnel_token_here #     v aud     v comma-separated list of emails\n      - CONFIGS=your-app.example.com:my-app:3000:your_aud:your@email.com\n        #\t\t\t^ hostname\t\t  ^ service:port\t\t\t\t\n    networks:\n      - app-network\n    depends_on:\n      - app\n\n  # Your application\n  my-app:\n    image: your-app:latest\n    container_name: my-app\n    networks:\n      - app-network\n    # No external ports - access only through CFTL\n\nnetworks:\n  app-network:\n    external: false\n```\n\n## 🎯 Configuration System\n\nCFTL uses a flexible alias-based configuration system that allows you to define reusable components and organize your services in multiple ways.\n\n### Basic Structure\n\n```bash\n# Define reusable components with aliases\nAUDS=aud_alias:aud_value\nEMAILS=email_alias:email1@domain.com,email2@domain.com\nHOSTNAMES=hostname_alias:hostname.example.com\nSERVICES=service_alias:service_name\n\n# Configure services using aliases\nCONFIGS=hostname_alias:service_alias:port:aud_alias:email_alias\n```\n\n### Configuration Examples\n\n#### Simple Configuration (Single Service)\n\n```bash\n# Define components\nAUDS=prod:abc123def456789\nEMAILS=team:admin@company.com,user@company.com\nHOSTNAMES=app:myapp.example.com\nSERVICES=backend:my-backend-service\n\n# Configure the service\nCONFIGS=app:backend:3000:prod:team\n```\n\n#### Multiple Services\n\n```bash\n# Define shared components\nAUDS=prod:abc123def456789\nEMAILS=admin:admin@company.com|dev:dev@company.com\nHOSTNAMES=api:api.example.com|web:web.example.com\nSERVICES=backend:backend-api|frontend:nginx\n\n# Configure each service\nCONFIGS_API=api:backend:3000:prod:admin\nCONFIGS_WEB=web:frontend:80:prod:dev\n```\n\n#### Advanced Organization Patterns\n\n##### Pattern 1: Environment-Based\n\n```bash\n# Development environment\nAUDS_DEV=dev:dev_aud_123\nEMAILS_DEV=devteam:dev1@company.com,dev2@company.com\nHOSTNAMES_DEV=ide:ide.dev.example.com|debug:debug.dev.example.com\nSERVICES_DEV=vscode:code-server\nCONFIGS_DEV_IDE=ide:vscode:8080:dev:devteam\nCONFIGS_DEV_DEBUG=debug:vscode:8081:dev:devteam\n\n# Production environment\nAUDS_PROD=prod:prod_aud_456\nEMAILS_PROD=ops:ops@company.com\nHOSTNAMES_PROD=app:app.example.com|api:api.example.com\nSERVICES_PROD=web:nginx|api:backend\nCONFIGS_PROD_APP=app:web:80:prod:ops\nCONFIGS_PROD_API=api:api:3000:prod:ops\n```\n\n##### Pattern 2: Team-Based\n\n```bash\n# Frontend team resources\nAUDS_FRONTEND=fe:frontend_aud\nEMAILS_FRONTEND=fe_team:frontend@company.com\nHOSTNAMES_FRONTEND=app:app.example.com|preview:preview.example.com\n\n# Backend team resources\nAUDS_BACKEND=be:backend_aud\nEMAILS_BACKEND=be_team:backend@company.com\nHOSTNAMES_BACKEND=api:api.example.com|admin:admin.example.com\n\n# Shared services\nSERVICES=nginx:nginx|node:nodejs|python:python-app\n\n# Service configurations\nCONFIGS_FE_APP=app:nginx:80:fe:fe_team\nCONFIGS_FE_PREVIEW=preview:node:3000:fe:fe_team\nCONFIGS_BE_API=api:python:8000:be:be_team\nCONFIGS_BE_ADMIN=admin:node:4000:be:be_team\n```\n\n##### Pattern 3: Simplified (Using Defaults)\n\n```bash\n# When you don't need aliases, values without ':' use '0' as default alias\nAUDS=abc123def456789\nEMAILS=admin@company.com,user@company.com\nHOSTNAMES=app.example.com\nSERVICES=backend\n\n# Reference using '0' alias\nCONFIGS=0:0:3000:0:0\n```\n\n### Special Cases\n\n#### Service Without Authentication\n\n```bash\n# Empty AUD and emails fields = no third layer protection\nCONFIGS_PUBLIC=public:nginx:80::\n```\n\n#### Only AUD Validation (No Email Restriction)\n\n```bash\nCONFIGS_API=api:backend:3000:prod:\n#                                   ^ no email restriction\n```\n\n#### Mixed Configuration Styles\n\n```bash\n# You can mix all patterns in one deployment\nAUDS=prod:prod_aud|staging:staging_aud\nEMAILS=admin@company.com  # Uses '0' as default alias\nHOSTNAMES_PROD=app:app.example.com\nHOSTNAMES_DEV=dev:dev.example.com\nSERVICES=backend:my-backend|frontend:nginx\n\n# Multiple CONFIGS variations\nCONFIGS=app:backend:3000:prod:0|dev:frontend:80:staging:0  # Using default email alias\nCONFIGS_PUBLIC=public.example.com:nginx:80::  # Direct values without aliases\n```\n\n## 📋 Complete Setup Guide\n\n### Step 1: Configure Authentication Method\n\nFirst, set up your identity provider integration:\n\n📖 **Guide**: [Identity Provider Integration](https://developers.cloudflare.com/cloudflare-one/identity/idp-integration/)\n\n**Popular options:**\n- GitHub OAuth\n- Google\n- Azure AD\n- Generic OIDC\n\n### Step 2: Create Access Policies\n\nDefine who can access your applications:\n\n📖 **Guide**: [Access Policies](https://developers.cloudflare.com/cloudflare-one/policies/access/)\n\n**Example policy:**\n- **Policy Name**: \"Admin Access\"\n- **Rule**: Email contains `admin@yourcompany.com`\n- **Action**: Allow\n\n### Step 3: Create Access Application\n\nSet up your application in Cloudflare Access:\n\n📖 **Guide**: [Self-Hosted Applications](https://developers.cloudflare.com/cloudflare-one/applications/configure-apps/self-hosted-public-app/)\n\n**Configuration:**\n1. **Application Name**: Your App Name\n2. **Application Domain**: `your-app.example.com`\n3. **Authentication Method**: Select your configured method (GitHub, Google, etc.)\n4. **Policies**: Select your access policy\n5. **Save and copy the Application AUD** (you'll need this later)\n\n### Step 4: Create Cloudflare Tunnel\n\nSet up secure connection to your application:\n\n📖 **Guide**: [Create Remote Tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/get-started/create-remote-tunnel/)\n\n**Configuration:**\n1. **Tunnel Name**: Your tunnel name\n2. **Public Hostname**: `your-app.example.com` (same as Access app)\n3. **Service**: `http://localhost:8080` (CFTL proxy port)\n\n**⚠️ IMPORTANT - Additional Settings:**\n- Navigate to **Access** tab in tunnel configuration\n- **Enable \"Validate JWT\"**\n- **Select your Access Application** (created in Step 3)\n\n4. **Save and copy the Tunnel Token**\n\n### Step 5: Configure CFTL\n\nChoose your configuration style:\n\n#### Option A: Simple Configuration\n```bash\nCONFIGS=your-app.example.com:your-service:3000:your_aud_from_step_3:authorized@email.com\n```\n\n#### Option B: Multi-Service Configuration\n```bash\nTUNNEL_TOKEN=your_tunnel_token\n\n# Define all your AUDs\nAUDS=prod:aud_123|staging:aud_456\n\n# Define email groups\nEMAILS=admin:admin@company.com|dev:dev@company.com,dev2@company.com\n\n# Define all hostnames\nHOSTNAMES=app:app.example.com|api:api.example.com|admin:admin.example.com\n\n# Define service types\nSERVICES=web:nginx|backend:nodejs-api\n\n# Configure each service\nCONFIGS_APP=app:web:80:prod:admin\nCONFIGS_API=api:backend:3000:prod:dev\nCONFIGS_ADMIN=admin:backend:4000:staging:admin\n```\n\n### Step 6: Deploy\n\n```bash\ndocker-compose up -d\n```\n\n## 🔧 Environment Variables\n\n### Core Variables\n\n| Variable       | Description             | Required | Example                               |\n| -------------- | ----------------------- | -------- | ------------------------------------- |\n| `TUNNEL_TOKEN` | Cloudflare Tunnel token | ✅       | `eyJhbGci...`                         |\n| `PORT`   | CFTL listening port    | ❌       | `8080` (default)                      |\n| `VERBOSE`      | Enable verbose logging  | ❌       | `false` (default)                     |\n\n### Configuration Variables\n\n| Variable Pattern | Description | Example |\n|-----------------|-------------|---------|\n| `AUDS*` | AUD definitions | `AUDS=prod:abc123` or `AUDS_DEV=dev:xyz789` |\n| `EMAILS*` | Email group definitions | `EMAILS=admin:admin@company.com` |\n| `HOSTNAMES*` | Hostname definitions | `HOSTNAMES=app:app.example.com` |\n| `SERVICES*` | Service type definitions | `SERVICES=backend:my-backend` |\n| `CONFIGS*` | Service configurations | `CONFIGS_APP=app:backend:3000:prod:admin` |\n\n*Note: All patterns support multiple definitions (AUDS, AUDS_1, AUDS_PROD, etc.)*\n\n## 🔍 How It Works\n\n1. **User visits** `your-app.example.com`\n2. **Cloudflare Access** validates identity (Layer 1)\n3. **Cloudflare Tunnel** validates JWT and forwards to CFTL (Layer 2)\n4. **CFTL** validates AUD and email authorization (Layer 3)\n5. **If all layers pass**, request is forwarded to your application\n\n### User Headers Passed to Application\n\nWhen authentication is successful, your application receives these HTTP headers:\n\n| Header | Description | Example |\n|--------|-------------|---------|\n| `X-Auth-User-Email` | User's email address | `user@company.com` |\n| `X-Auth-User-ID` | Unique user ID (CF Access sub) | `7335d417-61da-459d-899c-0a01c76a2f94` |\n| `X-Auth-User-Country` | User's authentication country | `US` |\n| `X-Auth-Method` | Authentication method used | `cf-access-third-layer` |\n| `X-Auth-Service` | Service name (internal) | `app_example_com` |\n| `X-Auth-AUD` | Validated CF Access AUD | `abc123def456...` |\n| `X-Auth-Issuer` | CF Access issuer URL | `https://yourteam.cloudflareaccess.com` |\n| `X-Auth-Token-Type` | Token type | `app` |\n| `X-Auth-Identity-Nonce` | CF identity cache key | `6ei69kawdKzMIAPF` |\n\n### Using Headers in Your Application\n\n**Flask (Python):**\n```python\n@app.route('/')\ndef index():\n    user_email = request.headers.get('X-Auth-User-Email')\n    user_country = request.headers.get('X-Auth-User-Country')\n    return f\"Welcome {user_email} from {user_country}\"\n```\n\n**Express.js (Node.js):**\n```javascript\napp.get('/', (req, res) =\u003e {\n    const userEmail = req.headers['x-auth-user-email'];\n    const userCountry = req.headers['x-auth-user-country'];\n    res.send(`Welcome ${userEmail} from ${userCountry}`);\n});\n```\n\n**Note:** Only services **with third layer protection** receive user headers. Services without third layer (bypass mode) are direct proxied without authentication headers.\n\n## 🛠️ Troubleshooting\n\n### Check System Status\n\n```bash\ndocker-compose logs cftl\n```\n\n### Common Issues\n\n| Issue | Possible Cause | Solution |\n|-------|---------------|----------|\n| `DENIED: No CF Access token` | Domain mismatch between Access App and CFTL | Ensure Access Application domain matches CFTL hostname exactly |\n| `DENIED: AUD mismatch` | Wrong AUD in configuration | Copy correct AUD from Access Application |\n| `DENIED: Unauthorized email` | Email not in authorized list | Add email to EMAILS configuration |\n| Nginx error page (white/plain) | Issue between CFTL and your app | Check app connectivity and port configuration |\n| Browser error (empty response/connection reset) | Issue between Tunnel and Access App | Ensure tunnel hostname matches Access Application domain exactly |\n| Tunnel not connecting | Invalid tunnel token | Generate new token from tunnel settings |\n\n### Test Individual Layers\n\n```bash\n# Test if tunnel is working\ncurl -I https://your-app.example.com\n\n# Check CFTL logs for third layer validation\ndocker-compose logs -f cftl\n```\n\n## 📄 License\n\nThis project is licensed under the MIT License - see the [LICENSE](https://raw.githubusercontent.com/hezzitlda/cftl/main/LICENSE) file for details.\n\n---\n\nBuilt with ❤️ by Hezzit. Contributions are welcome!\n\n**⭐ If this project helped you, please give it a star!**\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhezzitlda%2Fcftl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhezzitlda%2Fcftl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhezzitlda%2Fcftl/lists"}