Pulse/docs/PROXY_AUTH.md
rcourtman c91b7874ac docs: comprehensive v4.24.0 documentation audit and updates
Complete documentation overhaul for Pulse v4.24.0 release covering all new
features and operational procedures.

Documentation Updates (19 files):

P0 Release-Critical:
- Operations: Rewrote ADAPTIVE_POLLING_ROLLOUT.md as GA operations runbook
- Operations: Updated ADAPTIVE_POLLING_MANAGEMENT_ENDPOINTS.md with DEFERRED status
- Operations: Enhanced audit-log-rotation.md with scheduler health checks
- Security: Updated proxy hardening docs with rate limit defaults
- Docker: Added runtime logging and rollback procedures

P1 Deployment & Integration:
- KUBERNETES.md: Runtime logging config, adaptive polling, post-upgrade verification
- PORT_CONFIGURATION.md: Service naming, change tracking via update history
- REVERSE_PROXY.md: Rate limit headers, error pass-through, v4.24.0 verification
- PROXY_AUTH.md, OIDC.md, WEBHOOKS.md: Runtime logging integration
- TROUBLESHOOTING.md, VM_DISK_MONITORING.md, zfs-monitoring.md: Updated workflows

Features Documented:
- X-RateLimit-* headers for all API responses
- Updates rollback workflow (UI & CLI)
- Scheduler health API with rich metadata
- Runtime logging configuration (no restart required)
- Adaptive polling (GA, enabled by default)
- Enhanced audit logging
- Circuit breakers and dead-letter queue

Supporting Changes:
- Discovery service enhancements
- Config handlers updates
- Sensor proxy installer improvements

Total Changes: 1,626 insertions(+), 622 deletions(-)
Files Modified: 24 (19 docs, 5 code)

All documentation is production-ready for v4.24.0 release.
2025-10-20 17:20:13 +00:00

8.1 KiB

Proxy Authentication

Pulse supports proxy-based authentication for integration with SSO providers like Authentik, Authelia, Caddy, and others. This allows you to authenticate users via your existing reverse proxy authentication system while maintaining security.

When to use this: If you already have an authentication proxy (Authentik, Authelia, etc.) protecting your services and want Pulse to trust that authentication instead of requiring its own login.

Quick Start

  1. Set PROXY_AUTH_SECRET to a random secret string
  2. Configure your proxy to send this secret in the X-Proxy-Secret header
  3. Set PROXY_AUTH_USER_HEADER to match your proxy's username header
  4. (Optional) Configure role-based access control with PROXY_AUTH_ROLE_HEADER

Configuration

Set the following environment variables to enable proxy authentication:

Required Settings

# Shared secret between proxy and Pulse (required)
PROXY_AUTH_SECRET=your-secure-secret-here

# Header containing the authenticated username (optional but recommended)
PROXY_AUTH_USER_HEADER=X-Authentik-Username

Optional Settings

# Header containing user roles/groups
PROXY_AUTH_ROLE_HEADER=X-Authentik-Groups

# Separator for multiple roles (default: |)
PROXY_AUTH_ROLE_SEPARATOR=|

# Role name that grants admin access (default: admin)
PROXY_AUTH_ADMIN_ROLE=admin

# URL to redirect users to for logout
PROXY_AUTH_LOGOUT_URL=/outpost.goauthentik.io/sign_out

How It Works

  1. User visits Pulse → Your proxy intercepts the request
  2. Proxy authenticates user → Via its own login page/SSO
  3. Proxy adds headers to the request:
    • X-Proxy-Secret: Shared secret (prevents spoofing)
    • Username header (e.g., X-Authentik-Username)
    • Roles header (e.g., X-Authentik-Groups)
  4. Pulse validates the secret and trusts the user identity
  5. No Pulse login required → User sees the dashboard immediately

Example Configurations

Authentik with Traefik

# docker-compose.yml environment variables
environment:
  - PROXY_AUTH_SECRET=your-secure-secret-here
  - PROXY_AUTH_USER_HEADER=X-Authentik-Username
  - PROXY_AUTH_ROLE_HEADER=X-Authentik-Groups
  - PROXY_AUTH_ROLE_SEPARATOR=|
  - PROXY_AUTH_ADMIN_ROLE=admin
  - PROXY_AUTH_LOGOUT_URL=/outpost.goauthentik.io/sign_out

Traefik middleware configuration:

http:
  middlewares:
    proxy-header-secret:
      headers:
        customRequestHeaders:
          X-Proxy-Secret: "your-secure-secret-here"
    
    authentik-auth:
      forwardAuth:
        address: http://authentik:9000/outpost.goauthentik.io/auth/traefik
        trustForwardHeader: true
        authResponseHeaders:
          - X-Authentik-Username
          - X-Authentik-Groups
          - X-Authentik-Email

  routers:
    pulse:
      rule: Host(`pulse.example.com`)
      entryPoints:
        - websecure
      middlewares:
        - authentik-auth
        - proxy-header-secret
      service: pulse-service
    
    pulse-auth:
      rule: Host(`pulse.example.com`) && PathPrefix(`/outpost.goauthentik.io/`)
      entryPoints:
        - websecure
      service: authentik-outpost

Authelia Example

# docker-compose.yml environment variables
environment:
  - PROXY_AUTH_SECRET=your-secure-secret-here
  - PROXY_AUTH_USER_HEADER=Remote-User
  - PROXY_AUTH_ROLE_HEADER=Remote-Groups
  - PROXY_AUTH_ROLE_SEPARATOR=,
  - PROXY_AUTH_ADMIN_ROLE=admins
  - PROXY_AUTH_LOGOUT_URL=/logout

Nginx configuration:

location / {
    # Authelia authorization
    auth_request /authelia;
    auth_request_set $user $upstream_http_remote_user;
    auth_request_set $groups $upstream_http_remote_groups;
    
    # Pass headers to Pulse
    proxy_set_header X-Proxy-Secret "your-secure-secret-here";
    proxy_set_header Remote-User $user;
    proxy_set_header Remote-Groups $groups;
    proxy_pass_header X-RateLimit-Limit;
    proxy_pass_header X-RateLimit-Remaining;
    proxy_pass_header X-RateLimit-Reset;
    proxy_pass_header Retry-After;

    proxy_pass http://pulse:7655;
}

Caddy with Forward Auth

pulse.example.com {
    forward_auth authelia:9091 {
        uri /api/verify?rd=https://auth.example.com
        copy_headers Remote-User Remote-Groups
    }
    
    header_downstream X-Proxy-Secret "your-secure-secret-here"
    
    reverse_proxy pulse:7655
}

Nginx Proxy Manager

In NPM's Advanced tab for your Pulse proxy host:

# Custom Nginx Configuration
proxy_set_header X-Proxy-Secret "your-secure-secret-here";
proxy_set_header X-Authentik-Username $http_x_authentik_username;
proxy_set_header X-Authentik-Groups $http_x_authentik_groups;

Security Considerations

  1. Use a strong secret: Generate a secure random string for PROXY_AUTH_SECRET
  2. HTTPS only: Always use HTTPS between the proxy and Pulse in production
  3. Network isolation: Ensure Pulse is not directly accessible, only through the proxy
  4. Header validation: Pulse validates all headers and the proxy secret on every request
  5. Preserve rate-limit headers: Do not strip X-RateLimit-* or Retry-After. Clients rely on them when Pulse throttles requests.

Combining with Other Auth Methods

Proxy authentication can work alongside other authentication methods:

  • If PROXY_AUTH_SECRET is set, proxy auth takes precedence
  • API tokens (API_TOKENS or legacy API_TOKEN) still work for programmatic access
  • Basic auth (PULSE_AUTH_USER/PULSE_AUTH_PASS) can be used as fallback

Troubleshooting

Users can't access Pulse (401 Unauthorized)

  1. Check the secret header:

    # Test with curl
    curl -H "X-Proxy-Secret: your-secret" \
         -H "X-Authentik-Username: testuser" \
         http://pulse:7655/api/state
    
  2. Verify headers are being sent:

    • Temporarily raise logging to debug via Settings → System → Logging (or set LOG_LEVEL=debug and restart). Remember to return to info when finished.
    • Check Pulse logs: docker logs pulse or journalctl -u pulse
    • Look for "Invalid proxy secret" or "Proxy auth user header not found"
  3. Common issues:

    • Typo in PROXY_AUTH_SECRET
    • Header names are case-sensitive in configuration
    • Proxy not forwarding headers correctly

Admin features not available

Check if user is recognized as admin:

curl -H "X-Proxy-Secret: your-secret" \
     -H "X-Authentik-Username: admin" \
     -H "X-Authentik-Groups: users|admin" \
     http://pulse:7655/api/security/status | jq '.proxyAuthIsAdmin'
  • Ensure the roles header contains the admin role
  • Verify PROXY_AUTH_ADMIN_ROLE matches your configuration
  • Check the role separator matches your proxy's format (default: |)

Logout doesn't work

  • Verify PROXY_AUTH_LOGOUT_URL points to your proxy's logout endpoint
  • Ensure the logout URL is accessible from the user's browser
  • For Authentik: /outpost.goauthentik.io/sign_out
  • For Authelia: /logout or custom path

Testing your configuration

Test proxy auth without a reverse proxy:

# Should return 401
curl http://localhost:7655/api/state

# Should return 200 with state data
curl -H "X-Proxy-Secret: your-secret-here" \
     -H "X-Your-User-Header: testuser" \
     http://localhost:7655/api/state

FAQ

Q: Do I still need to set up Pulse authentication?
A: No, when proxy auth is configured, Pulse trusts your proxy's authentication. Users won't see Pulse's login page.

Q: Can I use this with Cloudflare Access or Tailscale?
A: Yes, any service that can add custom headers after authentication will work.

Q: What happens if someone bypasses my proxy?
A: They can't authenticate. Without the correct X-Proxy-Secret header, all requests are rejected with 401.

Q: Can I have some users with read-only access?
A: Currently, Pulse has admin and non-admin roles. Non-admin users have read-only access to monitoring data.

Q: Is the username displayed in Pulse?
A: Yes, the authenticated username appears in the top-right corner of the UI.

Q: Can I use both proxy auth and API tokens?
A: Yes! API tokens still work for automation/scripts. Proxy auth is for human users via the web UI.