Securing Jellyfin Exposures in Production

Review network policies, TLS configuration, and authentication mechanisms to ensure secure Jellyfin exposure in production.

JR

2 minute read

Review network policies, TLS configuration, and authentication mechanisms to ensure secure Jellyfin exposure in production.

1. Audit Network Exposure

Start by identifying how Jellyfin is exposed to the network. Overexposure is the most common failure point.

Steps:

  • Run kubectl get services -n <jellyfin-namespace> to check service types. Avoid type: LoadBalancer without TLS termination.
  • If using Ingress, verify TLS configuration with kubectl get ingress -n <namespace> -o yaml | grep tls.
  • Check for unnecessary port mappings in Helm values or deployment manifests.

Common Mistake: Exposing the Jellyfin UI on a public IP without authentication.

2. Enforce Authentication

Jellyfin supports basic auth and OAuth2. Enable one of these unconditionally.

Policy Example (OpenShift):

apiVersion: v1
kind: ConfigMap
metadata:
  name: jellyfin-auth
  namespace: media
data:
  htpasswd: |
    # Example htpasswd file generated via `htpasswd -n -kbB user password`
    user:$$m5hash$$...
---
apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: jellyfin
  namespace: media
spec:
  tls:
    termination: edge
    edgeTerminationPolicy: Redirect
  wildcardPolicy:
    exposed: true
  port:
    targetPort: 8096
  auth:
    type: HttpAuthentication
    httpAuthentication:
      passthrough: false
      identityProviders:
      - challenge: true
        name: jellyfin-basic-auth

Tradeoff: Basic auth requires HTTPS to avoid credential leaks. If TLS isn’t already enforced, this adds complexity.

3. Restrict Network Traffic

Use NetworkPolicy to limit ingress to Jellyfin pods.

Example:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: jellyfin-traffic
  namespace: media
spec:
  podSelector:
    matchLabels:
      app: jellyfin
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          network: allowed
    ports:
    - protocol: TCP
      port: 8096

Caveat: NetworkPolicy support depends on your CNI plugin (e.g., Calico, Cilium). If unsupported, traffic flows unfiltered.

4. Tooling for Validation

  • TLS Check: Use openssl s_client -connect <jellyfin-url>:443 to validate certificates.
  • Network Policy Test: Deploy a test pod in the same namespace and attempt curl to Jellyfin ports.
  • Security Scan: Run kube-hunter --hunt to detect exposed services.

5. Troubleshooting Common Failures

  • 403 Forbidden: Misconfigured auth (e.g., htpasswd file permissions, OAuth2 misalignment).
  • Connection Timeout: NetworkPolicy blocking traffic. Check kubectl get networkpolicy -n <namespace>.
  • TLS Handshake Errors: Certificates not properly mounted or expired. Verify with kubectl describe secret <tls-secret>.

Prevention Workflow

  1. Restrict service exposure to TLS-terminated routes only.
  2. Apply NetworkPolicy to allow only known sources (e.g., internal networks, auth proxies).
  3. Rotate credentials and certificates quarterly.

Final Check: If you can access Jellyfin without HTTPS or credentials, you’re already compromised.

Source thread: Is my setup for exposing Jellyfin secure?

comments powered by Disqus