# πŸ” Passkey Auth for Kubernetes Nginx Ingress A WebAuthn-based passkey authentication provider that integrates seamlessly with Kubernetes nginx ingress controllers. This service provides secure, passwordless authentication using passkeys (FIDO2/WebAuthn) and acts as an auth backend for nginx ingress. ## ✨ Features - **Pa2. **"User not found" during login**: - Ensure user is registered and approved (if required) - Check that email address matches exactly 3. **WebAuthn errors**:dless Authentication**: Uses WebAuthn/FIDO2 passkeys for secure authentication - **Email-Based Access Control**: Users are identified by email addresses with configurable allowlists - **Nginx Ingress Integration**: Works as an auth backend using nginx `auth_request` directive - **User Management**: Admin interface for managing users and their approval status - **Access Control**: Configure allowed email addresses and approval requirements - **Kubernetes Native**: Designed specifically for Kubernetes deployment - **Persistent Storage**: Uses SQLite with persistent volumes for data storage - **Modern UI**: Clean, responsive web interface for user registration and management ## πŸ—οΈ Architecture ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ User Browser β”‚ β”‚ Nginx Ingress β”‚ β”‚ Your App β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ 1. Request │───▢│ 2. Auth Check │───▢│ 4. Serve App β”‚ β”‚ 4. Redirect │◀───│ 3. 401/302 β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ auth_request β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Passkey Auth β”‚ β”‚ β”‚ β”‚ - WebAuthn β”‚ β”‚ - User Mgmt β”‚ β”‚ - Session Mgmt β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ## πŸš€ Quick Start ### Prerequisites - Kubernetes cluster with nginx ingress controller - Docker - kubectl configured to access your cluster ### 1. Clone and Build ```bash git clone cd passkey-auth # Build the Docker image ./scripts/build.sh ``` ### 2. Configure Edit `k8s/deployment.yaml` to update: ```yaml # Update these values in the ConfigMap webauthn: rp_id: "your-domain.com" # Your domain rp_origins: - "https://your-domain.com" # Your domain with protocol cors: allowed_origins: - "https://your-domain.com" # Your domain with protocol # Wildcard domains are supported for subdomains: - "*.your-domain.com" # Matches api.your-domain.com, app.your-domain.com, etc. auth: session_secret: "your-secure-secret-key" # Generate a secure random string ``` ### 3. Deploy to Kubernetes ```bash # Deploy the passkey auth service ./scripts/deploy.sh # Verify deployment kubectl get pods -n passkey-auth kubectl logs -f deployment/passkey-auth -n passkey-auth ``` ### 4. Configure Your App's Ingress Update your application's ingress to use passkey auth: ```yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: your-app-ingress annotations: # Auth backend - points to passkey auth service nginx.ingress.kubernetes.io/auth-url: "http://passkey-auth-service.passkey-auth.svc.cluster.local/auth" # Redirect unauthorized users to login page nginx.ingress.kubernetes.io/auth-signin: "https://your-domain.com/auth" # Pass user info to your app nginx.ingress.kubernetes.io/auth-response-headers: "X-Auth-User,X-Auth-User-ID" spec: rules: - host: your-app.com http: paths: - path: / pathType: Prefix backend: service: name: your-app-service port: number: 80 ``` ### 5. Create Ingress for Passkey Auth ```yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: passkey-auth-ingress namespace: passkey-auth spec: rules: - host: your-domain.com http: paths: - path: /auth pathType: Prefix backend: service: name: passkey-auth-service port: number: 80 ``` Apply the ingress: ```bash kubectl apply -f k8s/ingress-example.yaml ``` ## πŸ‘₯ User Management ### Access the Admin Interface 1. Navigate to `https://your-domain.com/auth` in your browser 2. You'll see the admin dashboard with three tabs: - **Register User**: Register new users with passkeys - **Test Login**: Test authentication - **Manage Users**: View and manage all users ### User Registration Flow 1. **Register**: Admin enters email address and display name 2. **Email Validation**: System checks if email is in the allowlist (if configured) 3. **Passkey Creation**: Browser prompts for passkey creation (TouchID, Windows Hello, etc.) 4. **Approval**: If `require_approval` is enabled, admin must approve users manually 5. **Authentication**: Users can now authenticate with their passkeys ### User Approval Process When `require_approval` is enabled in the configuration: 1. **New users register** but cannot authenticate until approved 2. **Admin reviews pending users** in the "Manage Users" tab 3. **Admin clicks "Approve"** next to pending users 4. **Users can now authenticate** with their passkeys **To approve a user:** 1. Navigate to the admin interface at `https://your-domain.com/auth` 2. Click the "Manage Users" tab 3. Find users with "Pending" status 4. Click the "Approve" button next to the user 5. Confirm the approval in the dialog **User Status Indicators:** - 🟒 **Approved**: User can authenticate - 🟑 **Pending**: User registered but needs approval ### Configuration Options In `config.yaml` or environment variables: ```yaml auth: require_approval: true # Require admin approval for new users session_secret: "secret" # Session encryption key allowed_emails: # Email allowlist (empty = allow all) - "admin@company.com" - "user@company.com" ``` Environment variable overrides: - `WEBAUTHN_RP_ID`: WebAuthn Relying Party ID (your domain) - `SESSION_SECRET`: Session encryption secret - `DATABASE_PATH`: SQLite database file path - `PORT`: Server port (default: 8080) - `ALLOWED_EMAILS`: Comma-separated list of allowed emails ## πŸ”§ Development ### Local Development 1. **Install Go dependencies**: ```bash go mod download ``` 2. **Run locally**: ```bash # Update config.yaml for local development go run main.go ``` 3. **Access the interface**: ``` http://localhost:8080 ``` ### Project Structure ``` passkey-auth/ β”œβ”€β”€ main.go # Application entry point β”œβ”€β”€ internal/ β”‚ β”œβ”€β”€ auth/ # WebAuthn implementation β”‚ β”œβ”€β”€ config/ # Configuration management β”‚ β”œβ”€β”€ database/ # SQLite database layer β”‚ └── handlers/ # HTTP handlers β”œβ”€β”€ web/ # Static web files β”œβ”€β”€ k8s/ # Kubernetes manifests β”œβ”€β”€ scripts/ # Deployment scripts └── config.yaml # Configuration file ``` ### API Endpoints | Endpoint | Method | Description | |----------|--------|-------------| | `/api/register/begin` | POST | Start passkey registration | | `/api/register/finish` | POST | Complete passkey registration | | `/api/login/begin` | POST | Start passkey authentication | | `/api/login/finish` | POST | Complete passkey authentication | | `/api/logout` | POST | Logout user | | `/auth` | GET | Nginx auth check endpoint | | `/api/users` | GET | List all users (admin) | | `/api/users` | POST | Create new user (admin) | | `/api/users/{id}` | PUT | Update user (approve/admin) | | `/api/users/{id}` | DELETE | Delete user (admin) | | `/health` | GET | Health check | ## πŸ”’ Security Considerations ### Production Deployment 1. **HTTPS Only**: Always use HTTPS in production 2. **Secure Session Secret**: Use a strong, random session secret 3. **Domain Configuration**: Ensure `rp_id` matches your domain exactly 4. **Network Security**: Use Kubernetes network policies to restrict access 5. **Regular Backups**: Backup the SQLite database regularly ### Session Configuration ```yaml # Secure session configuration for production auth: session_secret: "your-256-bit-random-key" # Use a proper secret manager ``` ### Database Security The SQLite database contains: - User information (email addresses, display names) - WebAuthn credentials (public keys, metadata) - No passwords or private keys are stored ## πŸ” Email Access Control ### Allowlist Configuration You can control who can register by configuring an email allowlist: ```yaml # config.yaml auth: allowed_emails: - "admin@yourcompany.com" - "engineering@yourcompany.com" - "support@yourcompany.com" ``` Or via environment variable: ```bash export ALLOWED_EMAILS="admin@company.com,user1@company.com,user2@company.com" ``` ### Access Control Options 1. **Open Registration** (allowed_emails is empty or not set): - Any email address can register - Suitable for internal/trusted environments 2. **Allowlist Mode** (allowed_emails configured): - Only specified email addresses can register - Recommended for production environments 3. **Combined with Approval**: - Users must be in allowlist AND get admin approval - Maximum security for sensitive applications ## πŸ“Š Monitoring ### Health Checks The service exposes a health endpoint at `/health`: ```bash curl http://passkey-auth-service.passkey-auth.svc.cluster.local/health ``` ### Logs View application logs: ```bash kubectl logs -f deployment/passkey-auth -n passkey-auth ``` ### Metrics For production, consider adding metrics collection: - Authentication success/failure rates - User registration rates - Session duration statistics ## πŸ› Troubleshooting ### Common Issues 1. **Docker build failures with SQLite CGO errors**: - The Dockerfile uses Debian-based images (golang:1.21-bullseye) instead of Alpine - This resolves musl vs glibc compatibility issues with go-sqlite3 - If you encounter `pread64` or `pwrite64` errors, ensure you're using a glibc-based image 2. **WebAuthn encoding errors** (challenge not ArrayBuffer): - The web interface includes base64url conversion functions - Ensure you're using the included HTML file, not a custom frontend - Binary WebAuthn data must be converted between base64url and ArrayBuffer 3. **"User not found" during login**: - Ensure user is registered and approved (if required) - Check that username matches exactly 4. **WebAuthn errors**: - Verify `rp_id` matches your domain - Ensure HTTPS is used (required for WebAuthn) - Check browser support for WebAuthn 5. **Auth backend not working**: - Verify ingress annotations are correct - Check that the auth service is accessible from nginx - Review nginx ingress controller logs 6. **Session issues**: - Ensure session secret is consistent - Check cookie settings (secure flag for HTTPS) - Verify session storage is persistent ### Debug Commands ```bash # Check pod status kubectl get pods -n passkey-auth # View logs kubectl logs deployment/passkey-auth -n passkey-auth # Check service kubectl get svc -n passkey-auth # Test auth endpoint kubectl exec -it deployment/passkey-auth -n passkey-auth -- wget -O- http://localhost:8080/health # Port forward for local testing kubectl port-forward svc/passkey-auth-service 8080:80 -n passkey-auth ``` ## 🀝 Contributing 1. Fork the repository 2. Create a feature branch 3. Make your changes 4. Add tests if applicable 5. Submit a pull request ## πŸ“„ License Apache License 2.0 ## πŸ™ Acknowledgments - [go-webauthn](https://github.com/go-webauthn/webauthn) - WebAuthn library for Go - [Gorilla](https://github.com/gorilla) - HTTP utilities for Go - WebAuthn/FIDO2 specifications - Kubernetes and nginx ingress controller teams --- For support or questions, please create an issue in the repository.