Files
homelab/services/tinyauth
Jordan Ramos c4962194e3 feat(auth): integrate TinyAuth SSO for NetBox authentication
Deploy TinyAuth v4 as CT 115 (192.168.2.10) to provide centralized
SSO authentication for NetBox via Nginx Proxy Manager.

**New Infrastructure:**
- CT 115: TinyAuth authentication layer
- Domain: tinyauth.apophisnetworking.net
- Integration: NPM auth_request → TinyAuth → NetBox

**Configuration:**
- Docker Compose with bcrypt-hashed credentials
- NPM advanced config for auth_request integration
- HTTPS enforcement via SSL termination

**Issues Resolved:**
- 500 Internal Server Error (Nginx config syntax)
- "IP addresses not allowed" (APP_URL domain requirement)
- Port mapping (8000:3000 for internal port 3000)
- Invalid password (bcrypt hash requirement for v4)

**Documentation:**
- Complete TinyAuth README at services/tinyauth/README.md
- Updated CLAUDE_STATUS.md with CT 115 infrastructure
- Added bug report for scribe agent tool permissions

**Note:** Container restart required on CT 115 to apply bcrypt hash

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-18 08:15:05 -07:00
..

TinyAuth - SSO Authentication Layer

Overview

TinyAuth is a lightweight, self-hosted authentication service providing Single Sign-On (SSO) capabilities for homelab services. Deployed as a Docker container within LXC CT 115, it acts as a centralized authentication gateway that integrates with Nginx Proxy Manager to protect services like NetBox.

Key Benefits:

  • Centralized credential management
  • Nginx auth_request integration
  • Bcrypt-hashed password storage
  • Simple, dependency-free deployment
  • Foundation for extending SSO to multiple services

Infrastructure Details

Property Value
Container CT 115 (LXC with Docker support)
IP Address 192.168.2.10
Port 8000 (internal), 443 (via NPM)
Domain tinyauth.apophisnetworking.net
Docker Image ghcr.io/steveiliop56/tinyauth:v4
Technology Go-based authentication service
Configuration Environment variable-based
Deployment Date 2025-12-18

Integration Architecture

                              ┌─────────────────────────────────────┐
                              │            INTERNET                 │
                              └──────────────────┬──────────────────┘
                                                 │
                                                 │ HTTPS
                                                 ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│  CT 102 - Nginx Proxy Manager (192.168.2.101)                              │
│  ┌───────────────────────────────────────────────────────────────────────┐  │
│  │  SSL Termination, Reverse Proxy, auth_request Handler                │  │
│  └───────────────────────────────┬───────────────────────────────────────┘  │
└──────────────────────────────────┼──────────────────────────────────────────┘
                                   │
                    ┌──────────────┴───────────────┐
                    │                              │
                    ▼                              ▼
    ┌───────────────────────────┐  ┌───────────────────────────────┐
    │  CT 115 - TinyAuth        │  │  CT 103 - NetBox              │
    │  (192.168.2.10:8000)      │  │  (192.168.2.104:8000)         │
    │                           │  │                               │
    │  ┌─────────────────────┐  │  │  ┌─────────────────────────┐  │
    │  │  /api/auth/nginx    │  │  │  │  NetBox Application     │  │
    │  │  Authentication     │◄─┼──┼──│  (Protected Resource)   │  │
    │  │  Endpoint           │  │  │  │                         │  │
    │  └─────────────────────┘  │  │  └─────────────────────────┘  │
    └───────────────────────────┘  └───────────────────────────────┘

Authentication Flow

  1. User accesses protected service: Browser requests https://netbox.apophisnetworking.net
  2. Nginx intercepts: NPM receives request, triggers auth_request /tinyauth
  3. TinyAuth validation: NPM forwards credentials to TinyAuth's /api/auth/nginx endpoint
  4. Authentication decision:
    • Valid credentials: TinyAuth returns HTTP 200 → NPM proxies to NetBox
    • Invalid credentials: TinyAuth returns HTTP 401 → NPM redirects to login page
  5. Login redirect: User sent to https://tinyauth.apophisnetworking.net/login?redirect_uri=...
  6. Post-login: After successful authentication, user redirected back to original URL

Configuration

Docker Compose

File: /home/jramos/homelab/services/tinyauth/docker-compose.yml

services:
  tinyauth:
    container_name: tinyauth
    image: ghcr.io/steveiliop56/tinyauth:v4
    restart: unless-stopped
    ports:
      - "8000:3000"  # External:Internal (TinyAuth runs on port 3000 internally)
    environment:
      - APP_URL=https://tinyauth.apophisnetworking.net
      - USERS='jramos:$2b$05$...'  # Bcrypt-hashed password (MUST be single-quoted)

Critical Configuration Notes:

  • APP_URL: MUST use the domain name, not an IP address (IP addresses trigger validation errors)
  • Port Mapping: TinyAuth listens on port 3000 internally, exposed as 8000 externally
  • USERS Format: 'username:bcrypt_hash' - Single quotes prevent shell interpretation of special characters
  • Bcrypt Hash: Generate with htpasswd -nbB username password, then extract hash portion

Nginx Proxy Manager Configuration

Proxy Host: netbox.apophisnetworking.net

  • Scheme: http
  • Forward Hostname/IP: 192.168.2.104
  • Forward Port: 8000
  • Force SSL: Enabled
  • HTTP/2 Support: Enabled

Advanced Configuration:

# Main location block - protect the entire service
location / {
    proxy_pass $forward_scheme://$server:$port;

    # Trigger authentication subrequest
    auth_request /tinyauth;

    # On authentication failure, redirect to login
    error_page 401 = @tinyauth_login;
}

# Internal authentication endpoint
location /tinyauth {
    internal;  # Only accessible to nginx (not external requests)
    proxy_pass http://192.168.2.10:8000/api/auth/nginx;
    proxy_pass_request_body off;  # Don't forward request body to auth endpoint
    proxy_set_header Content-Length "";

    # Forward original request context to TinyAuth
    proxy_set_header X-Original-URI $request_uri;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Host $http_host;
    proxy_set_header X-Forwarded-Uri $request_uri;
}

# Login redirect handler
location @tinyauth_login {
    return 302 https://tinyauth.apophisnetworking.net/login?redirect_uri=$scheme://$http_host$request_uri;
}

NPM Proxy Host for TinyAuth Itself:

Issues Encountered & Solutions

Issue #1: 500 Internal Server Error (Initial Deployment)

Symptoms:

  • Accessing netbox.apophisnetworking.net returned HTTP 500
  • NPM logs showed Nginx configuration errors

Root Causes:

  1. Syntax errors in NPM advanced configuration
  2. Incorrect proxy_pass format for auth_request subrequest
  3. Missing internal; directive for /tinyauth location

Solution:

  • Corrected Nginx syntax in NPM advanced config
  • Added internal; directive to prevent external access to auth endpoint
  • Verified proxy_pass URL format matches TinyAuth API expectations

Validation:

# Check Nginx config syntax
docker exec -it nginx-proxy-manager nginx -t

# Monitor NPM logs during request
docker logs -f nginx-proxy-manager

Issue #2: "IP addresses not allowed" Error

Symptoms:

  • TinyAuth returned: {"error": "IP addresses not allowed"}
  • Login page appeared but validation failed immediately

Root Cause:

  • APP_URL was set to http://192.168.2.10:8000 (IP address)
  • TinyAuth v4 validates that APP_URL uses a domain name for security

Solution: Changed docker-compose.yml:

-  - APP_URL=http://192.168.2.10:8000
+  - APP_URL=https://tinyauth.apophisnetworking.net

Why This Matters:

  • Security: Prevents session fixation and CSRF attacks
  • SSL: Ensures proper cookie domain scoping
  • Production Practice: Domain-based deployments are standard in production

Issue #3: Port Mapping Confusion

Symptoms:

  • Container started successfully but authentication requests timed out
  • Direct connection to http://192.168.2.10:8000 failed

Root Cause:

  • TinyAuth runs on port 3000 internally
  • Initial port mapping was 8000:8000, but container wasn't listening on 8000
  • Docker port mapping syntax: host_port:container_port

Solution:

-    - "8000:8000"
+    - "8000:3000"

Validation:

# Verify TinyAuth is accessible
curl http://192.168.2.10:8000/api/auth/nginx

# Check container port binding
docker ps | grep tinyauth
# Should show: 0.0.0.0:8000->3000/tcp

Issue #4: Invalid Password / Authentication Failure

Symptoms:

  • Login page loaded correctly
  • Entering correct credentials returned "Invalid password"
  • After 5 failed attempts, account locked for 5 minutes

Root Cause:

  • TinyAuth v4 requires bcrypt-hashed passwords, not plaintext
  • Initial configuration used USERS=jramos:Nbkx4md007 (plaintext)
  • TinyAuth compares bcrypt hash of input against stored hash - plaintext storage fails

Solution:

  1. Generate bcrypt hash:
htpasswd -nbB jramos Nbkx4md007
# Output: jramos:$2b$05$AbCdEfGhIjKlMnOpQrStUvWxYz0123456789...
  1. Update docker-compose.yml with single-quoted hash:
- USERS='jramos:$2b$05$AbCdEfGhIjKlMnOpQrStUvWxYz0123456789...'
  1. Restart container:
cd /home/jramos/homelab/services/tinyauth
docker-compose down
docker-compose up -d

Why Single Quotes Matter:

  • $ has special meaning in shell/YAML double-quoted strings
  • Single quotes prevent variable expansion and preserve the literal bcrypt hash
  • Without quotes, the hash will be corrupted during environment variable parsing

Validation:

# Check environment variable is set correctly
docker exec tinyauth env | grep USERS
# Should show: USERS='jramos:$2b$05$...'

# Test authentication
curl -u jramos:Nbkx4md007 http://192.168.2.10:8000/api/auth/nginx
# Should return HTTP 200 on success

Access & Credentials

Login URL

Credential Management

Adding New Users:

  1. Generate bcrypt hash:
    htpasswd -nbB newuser password123
    
  2. Update docker-compose.yml USERS variable (comma-separated for multiple users):
    - USERS='jramos:$2b$05$...,alice:$2b$05$...,bob:$2b$05$...'
    
  3. Restart container:
    docker-compose down && docker-compose up -d
    

Changing Passwords:

  1. Generate new bcrypt hash with new password
  2. Replace the hash in docker-compose.yml
  3. Restart container

Security Note: Credentials are stored in docker-compose.yml. For production use, consider:

  • Environment variable injection from secrets management
  • Integration with LDAP/Active Directory
  • Migration to more robust SSO (Authelia, Keycloak)

Maintenance

Logs

# Container logs
docker logs -f tinyauth

# Last 100 lines
docker logs --tail 100 tinyauth

# Authentication attempts
docker logs tinyauth | grep "authentication"

Health Check

# Container status
docker ps | grep tinyauth

# Authentication endpoint test
curl -I http://192.168.2.10:8000/api/auth/nginx
# Expected: HTTP 401 (not authenticated) or HTTP 200 (if providing valid creds)

Restart

cd /home/jramos/homelab/services/tinyauth
docker-compose restart

Backup

# Backup docker-compose.yml (contains credentials)
cp docker-compose.yml docker-compose.yml.backup-$(date +%Y%m%d)

Updates

# Pull latest TinyAuth image
docker pull ghcr.io/steveiliop56/tinyauth:v4

# Recreate container with new image
docker-compose down
docker-compose pull
docker-compose up -d

Troubleshooting

Symptoms: Login page doesn't load

Check:

  1. NPM proxy host for tinyauth.apophisnetworking.net exists and is enabled
  2. SSL certificate is valid
  3. TinyAuth container is running: docker ps | grep tinyauth

Commands:

docker logs nginx-proxy-manager | grep tinyauth
curl -I https://tinyauth.apophisnetworking.net

Symptoms: "Invalid password" error

Check:

  1. USERS environment variable uses bcrypt hash: docker exec tinyauth env | grep USERS
  2. Hash is single-quoted in docker-compose.yml
  3. Password hasn't changed since hash generation
  4. Account isn't locked (wait 5 minutes after 5 failed attempts)

Commands:

# Verify hash format
docker exec tinyauth env | grep USERS

# Test authentication directly
curl -u jramos:Nbkx4md007 http://192.168.2.10:8000/api/auth/nginx

Symptoms: "IP addresses not allowed"

Fix: Update APP_URL to use domain instead of IP:

- APP_URL=https://tinyauth.apophisnetworking.net  # NOT http://192.168.2.10:8000

Symptoms: Connection timeout to TinyAuth

Check:

  1. Port mapping is correct (8000:3000): docker ps | grep tinyauth
  2. Container is listening: docker exec tinyauth netstat -tlnp
  3. Firewall rules allow port 8000

Symptoms: Authentication works but redirect fails

Check:

  1. redirect_uri parameter in login URL matches original request
  2. NPM advanced config includes X-Original-URI header
  3. No extra path manipulation in NPM config

Performance & Scaling

Resource Usage

  • Memory: ~50-100 MB
  • CPU: <1% idle, ~2-5% during authentication bursts
  • Disk: ~20 MB (Docker image)
  • Network: Minimal (authentication requests are small)

Capacity

  • Concurrent Users: Designed for small-scale homelab use (~10-50 users)
  • Authentication Latency: <50ms for local network requests
  • Session Management: Cookie-based, no server-side session storage

Limitations

  • No Multi-Factor Authentication (MFA): Consider Authelia for MFA support
  • No LDAP/OAuth Integration: Users managed in environment variables only
  • No Audit Logging: Authentication events logged to container stdout only
  • No Rate Limiting: Beyond the 5-attempt lockout (5 minutes)

Security Considerations

Strengths

Bcrypt password hashing (computationally expensive, resists brute force) HTTPS enforcement via NPM Account lockout after 5 failed attempts Minimal attack surface (single authentication endpoint) No database dependencies (reduces vulnerability vectors)

Weaknesses & Mitigations

⚠️ Credentials in docker-compose.yml: Ensure file permissions restrict read access

  • Mitigation: chmod 600 docker-compose.yml
  • Future: Migrate to secrets management (Docker Secrets, Vault)

⚠️ No MFA: Single-factor authentication only

  • Mitigation: Use strong, unique passwords
  • Future: Consider Authelia or Keycloak for MFA

⚠️ Session fixation risk: Sessions not explicitly invalidated

  • Mitigation: Use short session timeouts
  • Future: Investigate TinyAuth session configuration options

⚠️ Limited audit logging: Authentication events not persisted

  • Mitigation: Forward logs to centralized logging (Loki, via rsyslog)
  • Future: Integrate with SIEM for security monitoring
  1. File Permissions:

    chmod 600 /home/jramos/homelab/services/tinyauth/docker-compose.yml
    
  2. Network Isolation:

    • TinyAuth should only be accessible via NPM, not directly exposed
    • Consider firewall rules restricting port 8000 to NPM's IP
  3. Regular Updates:

  4. Log Monitoring:

    • Configure alerts for repeated authentication failures
    • Forward logs to Loki (CT 101 - monitoring stack)

Future Enhancements

Short-Term

  • Add additional users for team access
  • Integrate TinyAuth with Grafana for monitoring dashboard authentication
  • Configure log forwarding to Loki for centralized authentication auditing
  • Document session timeout configuration

Medium-Term

  • Extend authentication to Proxmox web UI (if supported by TinyAuth)
  • Implement automated backup of docker-compose.yml to PBS
  • Explore TinyAuth API for programmatic user management

Long-Term

  • Evaluate migration to Authelia for MFA support and LDAP integration
  • Implement SSO across all homelab services (Gitea, n8n, Proxmox, Grafana)
  • Integrate with external identity provider (Google, GitHub OAuth)

References


Maintained by: Homelab Infrastructure Team Last Updated: 2025-12-18 Status: Operational - Protecting NetBox with SSO authentication