A Traefik middleware plugin for Backend.AI AppProxy worker that provides authentication, session tracking, and lifecycle management for Backend.AI applications. This plugin is available in two implementations: Rust WASM and Go native.
This project provides two complementary Traefik plugins that serve different purposes in the Backend.AI AppProxy ecosystem:
The WASM plugin handles authentication and authorization for Backend.AI applications:
- Interactive Session Authentication: Validates HMAC-based cookies for user-initiated interactive sessions (Jupyter notebooks, RStudio, etc.)
- Inference Endpoint Authentication: Validates JWT tokens for programmatic API access to inference endpoints
- Multi-Protocol Support: Supports HTTP, gRPC, HTTP/2, TCP, and preopen protocols
- Flexible Frontend Modes: Works with both wildcard domain and port-based routing
- WebSocket Support: Handles WebSocket connection lifecycle with active/inactive state tracking
The Go plugin focuses on session tracking and monitoring:
- Route Access Tracking: Records last-accessed timestamps for each Traefik route
- Circuit Lifecycle Management: Tracks when circuits become active or inactive
- Session Monitoring: Monitors session usage patterns for resource management
- Unix Socket Communication: Communicates with Backend.AI AppProxy via Unix domain sockets for efficient data exchange
Together, these plugins ensure proper authentication for Backend.AI applications while maintaining comprehensive session activity tracking for resource management, billing, and automatic cleanup of idle resources.
Important: This plugin is designed to work in conjunction with Backend.AI AppProxy. The AppProxy component automatically manages the plugin configuration, circuit information, and authentication secrets. The plugin cannot function independently without the AppProxy system.
This is a Cargo workspace containing:
├── proxy/ # Main WASM plugin binary (appproxy-traefik-proxy)
├── lib/ # Shared library (appproxy_traefik_lib)
├── traefik_wasm_api/ # Traefik WASM HTTP handler bindings
├── go/ # Go native plugin implementation
├── pkg/ # Build output directory
└── target/ # Rust build artifacts
- Main Handler (
proxy/src/main.rs): Exportshandle_requestandhandle_responsefunctions for Traefik WASM runtime - Configuration: Lazy-loaded plugin configuration from Traefik with circuit information, JWT secrets, and cookie settings
- Authentication Logic:
- Interactive Sessions: Validates HMAC-based cookies for user sessions accessing Jupyter, RStudio, and other interactive applications
- Inference Endpoints: Validates JWT tokens for programmatic API access to model inference endpoints
- Public Access: Allows unauthenticated access when circuits are marked as public
- JWT Module (
lib/src/jwt.rs): JWT token decoding and validation - Cookie Module (
lib/src/cookie.rs): Cookie parsing and HMAC validation - DTO Module (
lib/src/dto.rs): Data structures for circuits, routes, and configuration - Utils Module (
lib/src/utils.rs): Common utility functions
- Standard Middleware (
go/plugin.go): Implements Go'shttp.Handlerinterface - Route Tracking Logic: Records last-accessed timestamps for each Traefik route that passes through the middleware
- Circuit State Management: Tracks active/inactive state of circuits, particularly for WebSocket connections
- Unix Socket Communication: Communicates with Backend.AI AppProxy via Unix domain sockets to report usage statistics
- Lightweight Design: Focuses purely on tracking without authentication logic for optimal performance
- Custom Rust bindings for Traefik's WASM HTTP handler interface
- Provides functions for header manipulation, body reading/writing, logging, and configuration access
-
Request Processing:
- Plugin receives HTTP request through Traefik
- Determines authentication method based on circuit configuration:
- Interactive sessions (
user_idpresent): Validates HMAC cookie - Inference endpoints (
endpoint_idpresent): Validates JWT token - Public circuits: Allows access without authentication
- Interactive sessions (
- Detects WebSocket upgrade requests for connection tracking
- Returns execution control to Traefik (continue or stop with 401 if auth fails)
-
Response Processing:
- Handles WebSocket connection cleanup
- Marks circuits as inactive when WebSocket connections close
-
Request Processing:
- Records timestamp when route is accessed
- Identifies WebSocket connections for state tracking
- Communicates with AppProxy via Unix socket to report usage
-
Response Processing:
- Updates circuit state (active/inactive) based on connection type
- Reports final usage statistics to AppProxy
-
Configuration Structure:
{ "circuit": "{ JSON circuit configuration }", "jwt_secret": "base64-encoded-secret", "permit_hash_secret": "hmac-secret", "permit_cookie_name": "cookie-name" }
- Backend.AI AppProxy: This plugin requires Backend.AI AppProxy to be installed and configured
- Rust Toolchain: 1.70+ with
wasm32-wasip1target - Go: 1.19+ (for Go implementation)
- Traefik: v3.0+ with WASM plugin support
- Docker & Docker Compose (for testing)
# Clone the repository
git clone https://github.com/lablup/backend.ai-appproxy-worker-traefik.git
cd backend.ai-appproxy-worker-traefik
# Install Rust WASM target
make setup
# Equivalent to: rustup target add wasm32-wasip1# Development build
make build
# Production build (optimized for size)
make release
# Clean build artifacts
make cleanThe Go plugin is built automatically when using the provided Docker Compose setup. Note that the Go plugin is typically deployed separately from the WASM plugin, as they serve different purposes - the WASM plugin for authentication and the Go plugin for usage tracking.
-
Build the plugin:
make release
-
Configure Traefik with local plugin:
# traefik.yml experimental: localPlugins: traefik-appproxy: modulename: github.com/lablup/backend.ai-appproxy-worker-traefik entryPoints: web: address: ":80"
-
Mount plugin files:
# WASM Plugin cp pkg/backend.ai/appproxy-traefik-plugin/plugin.wasm /path/to/plugins/ cp .traefik.yml /path/to/plugins/ # Go Plugin cp -r pkg/backend.ai/appproxy-traefik-plugin-go/ /path/to/plugins/
# Start test environment
make docker
# Test the plugin
make httpNote: In production environments, plugin configuration is automatically managed by Backend.AI AppProxy. The AppProxy component dynamically generates and updates the configuration based on circuit information, user sessions, and security settings.
For development and testing purposes, you can manually configure the middleware:
# Dynamic configuration
http:
middlewares:
appproxy-auth:
plugin:
traefik-appproxy:
circuit: '{"id":"circuit-123","app":"jupyter","protocol":"http","worker":"worker-1","app_mode":"interactive","frontend_mode":"wildcard","envs":{},"open_to_public":false,"session_ids":["session-456"],"route_info":[{"session_id":"session-456","kernel_host":"127.0.0.1","kernel_port":8888,"protocol":"http","traffic_ratio":1.0}],"created_at":"2024-01-01T00:00:00Z","updated_at":"2024-01-01T00:00:00Z"}'
jwt_secret: "your-jwt-secret-base64"
permit_hash_secret: "your-hmac-secret"
permit_cookie_name: "backend_ai_permit"
routers:
app-router:
rule: "Host(`app.example.com`)"
service: app-service
middlewares:
- appproxy-authThe circuit configuration is automatically generated by Backend.AI AppProxy based on session and application information:
id: Unique circuit identifierapp: Application type (jupyter, rstudio, etc.)protocol: Communication protocol (http, grpc, http2, tcp, preopen)app_mode: Application mode (interactive, inference)frontend_mode: Routing mode (wildcard, port)open_to_public: Whether authentication is requireduser_id: User ID for cookie-based authenticationendpoint_id: Endpoint ID for JWT-based authenticationsession_ids: List of associated session IDsroute_info: Backend routing information
# Test Rust code
cargo test
# Test with specific target
cargo test --target wasm32-wasip1# Start test environment
make docker
# Test HTTP requests
make http
# Manual testing
curl -v http://localhost/foo \
-H "Authorization: Bearer your-jwt-token"# Build and inspect WASM
make debug
# View detailed logs
docker-compose logs -f traefik# Format code
cargo fmt
# Check code quality
cargo clippy
# Check without building
cargo check --target wasm32-wasip1 --no-default-features- Make changes to source code
- Run tests:
cargo test - Build plugin:
make build - Test with Docker:
make docker - Verify functionality:
make http
- Authentication Methods: Extend authentication logic in
proxy/src/main.rsandlib/src/ - Protocol Support: Add new protocol variants to
lib/src/dto.rs - Session Tracking: Modify session tracking logic for new requirements
The plugin exports two main functions for Traefik WASM runtime:
handle_request(): Called for each incoming requesthandle_response(req_ctx: i32, is_error: i32): Called after request processing
-
Plugin Not Loading:
- Verify WASM file path in Traefik configuration
- Check Traefik logs for plugin loading errors
- Ensure
.traefik.ymlis correctly configured
-
Authentication Failures:
- Validate JWT secret configuration
- Check cookie name matches configuration
- Verify HMAC secret for cookie validation
-
Session Tracking Issues:
- Confirm session marker file permissions (Rust version)
- Verify Unix socket accessibility (Go version)
- Check session ID format in circuit configuration
-
AppProxy Integration Issues:
- Ensure Backend.AI AppProxy is running and properly configured
- Verify network connectivity between AppProxy and Traefik
- Check AppProxy logs for configuration generation errors
Enable debug logging in Traefik:
log:
level: DEBUGThe plugin outputs detailed logs for:
- Configuration loading
- Authentication attempts
- Session tracking operations
- WebSocket connection lifecycle
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Run the test suite
- Submit a pull request
This project is licensed under the terms specified in the repository license file.
- Backend.AI: AI/ML workload orchestration platform
- Backend.AI AppProxy: Application proxy component that manages this plugin
- Traefik: Modern reverse proxy and load balancer
- Traefik WASM Plugin System: Traefik's plugin architecture