diff --git a/ansible/playbooks/indri.yml b/ansible/playbooks/indri.yml index c2bb67a..51d2db7 100644 --- a/ansible/playbooks/indri.yml +++ b/ansible/playbooks/indri.yml @@ -161,6 +161,23 @@ no_log: true tags: [caddy] + # Jellyfin SSO client secret + - name: Fetch Jellyfin OIDC client secret + ansible.builtin.command: + cmd: op read "op://vg6xf6vvfmoh5hqjjhlhbeoaie/oor7os5kapczgpbwv7obkca4y4/jellyfin-client-secret" + delegate_to: localhost + register: _jellyfin_oidc_secret + changed_when: false + no_log: true + check_mode: false + tags: [jellyfin] + + - name: Set Jellyfin OIDC client secret fact + ansible.builtin.set_fact: + jellyfin_sso_client_secret: "{{ _jellyfin_oidc_secret.stdout }}" + no_log: true + tags: [jellyfin] + # Jellyfin API key for metrics collection - name: Fetch Jellyfin API key ansible.builtin.command: diff --git a/ansible/roles/jellyfin/defaults/main.yml b/ansible/roles/jellyfin/defaults/main.yml index 6c96d34..380e625 100644 --- a/ansible/roles/jellyfin/defaults/main.yml +++ b/ansible/roles/jellyfin/defaults/main.yml @@ -21,3 +21,10 @@ jellyfin_webdir: "{{ jellyfin_cask_app_path }}/Contents/Resources/jellyfin-web" # Log directory jellyfin_log_dir: "{{ ansible_env.HOME }}/Library/Logs" + +# SSO plugin configuration +jellyfin_sso_plugin_version: "4.0.0.3" +jellyfin_sso_client_id: jellyfin +jellyfin_sso_client_secret: "" +jellyfin_sso_provider_name: authentik +jellyfin_plugins_dir: "{{ jellyfin_data_dir }}/plugins" diff --git a/ansible/roles/jellyfin/tasks/main.yml b/ansible/roles/jellyfin/tasks/main.yml index 6a92aa4..bf213ee 100644 --- a/ansible/roles/jellyfin/tasks/main.yml +++ b/ansible/roles/jellyfin/tasks/main.yml @@ -28,3 +28,36 @@ when: jellyfin_launchctl_check.rc != 0 changed_when: true failed_when: false + +# SSO plugin installation +- name: Ensure SSO-Auth plugin directory exists + ansible.builtin.file: + path: "{{ jellyfin_plugins_dir }}/SSO-Auth_{{ jellyfin_sso_plugin_version }}" + state: directory + mode: '0755' + +- name: Download SSO-Auth plugin archive + ansible.builtin.get_url: + url: "https://github.com/9p4/jellyfin-plugin-sso/releases/download/v{{ jellyfin_sso_plugin_version }}/sso-authentication_{{ jellyfin_sso_plugin_version }}.zip" + dest: "/tmp/sso-authentication_{{ jellyfin_sso_plugin_version }}.zip" + mode: '0644' + +- name: Extract SSO-Auth plugin + ansible.builtin.unarchive: + src: "/tmp/sso-authentication_{{ jellyfin_sso_plugin_version }}.zip" + dest: "{{ jellyfin_plugins_dir }}/SSO-Auth_{{ jellyfin_sso_plugin_version }}" + remote_src: true + notify: Reload jellyfin + +- name: Ensure plugin configurations directory exists + ansible.builtin.file: + path: "{{ jellyfin_plugins_dir }}/configurations" + state: directory + mode: '0755' + +- name: Deploy SSO-Auth plugin configuration + ansible.builtin.template: + src: sso-auth.xml.j2 + dest: "{{ jellyfin_plugins_dir }}/configurations/SSO-Auth.xml" + mode: '0644' + notify: Reload jellyfin diff --git a/ansible/roles/jellyfin/templates/sso-auth.xml.j2 b/ansible/roles/jellyfin/templates/sso-auth.xml.j2 new file mode 100644 index 0000000..8e8bd76 --- /dev/null +++ b/ansible/roles/jellyfin/templates/sso-auth.xml.j2 @@ -0,0 +1,33 @@ + + + + + + + {{ jellyfin_sso_provider_name }} + + + https://authentik.ops.eblu.me/application/o/jellyfin + {{ jellyfin_sso_client_id }} + {{ jellyfin_sso_client_secret }} + true + true + true + + admins + + false + + groups + + openid + email + profile + + https + + + + + + diff --git a/argocd/manifests/authentik/configmap-blueprint.yaml b/argocd/manifests/authentik/configmap-blueprint.yaml index 5501811..f5b4784 100644 --- a/argocd/manifests/authentik/configmap-blueprint.yaml +++ b/argocd/manifests/authentik/configmap-blueprint.yaml @@ -245,3 +245,45 @@ data: enabled: true negate: false timeout: 30 + + jellyfin.yaml: | + version: 1 + metadata: + name: BlumeOps Jellyfin SSO + labels: + blueprints.goauthentik.io/description: "Jellyfin OIDC provider and application" + entries: + # OAuth2 provider for Jellyfin + - model: authentik_providers_oauth2.oauth2provider + id: jellyfin-provider + identifiers: + name: Jellyfin + attrs: + name: Jellyfin + authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]] + invalidation_flow: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]] + client_type: confidential + client_id: jellyfin + client_secret: !Env AUTHENTIK_JELLYFIN_CLIENT_SECRET + redirect_uris: + - matching_mode: strict + url: https://jellyfin.ops.eblu.me/sso/OID/redirect/authentik + signing_key: !Find [authentik_crypto.certificatekeypair, [name, authentik Self-signed Certificate]] + property_mappings: + - !Find [authentik_providers_oauth2.scopemapping, [scope_name, openid]] + - !Find [authentik_providers_oauth2.scopemapping, [scope_name, email]] + - !Find [authentik_providers_oauth2.scopemapping, [scope_name, profile]] + sub_mode: hashed_user_id + include_claims_in_id_token: true + + # Jellyfin application — all authenticated users allowed (no policy binding) + - model: authentik_core.application + id: jellyfin-app + identifiers: + slug: jellyfin + attrs: + name: Jellyfin + slug: jellyfin + provider: !KeyOf jellyfin-provider + meta_launch_url: https://jellyfin.ops.eblu.me + policy_engine_mode: all diff --git a/argocd/manifests/authentik/deployment-worker.yaml b/argocd/manifests/authentik/deployment-worker.yaml index bbc421f..9bcc9fd 100644 --- a/argocd/manifests/authentik/deployment-worker.yaml +++ b/argocd/manifests/authentik/deployment-worker.yaml @@ -68,6 +68,11 @@ spec: secretKeyRef: name: authentik-config key: zot-client-secret + - name: AUTHENTIK_JELLYFIN_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: authentik-config + key: jellyfin-client-secret volumeMounts: - name: blueprints mountPath: /blueprints/custom diff --git a/argocd/manifests/authentik/external-secret.yaml b/argocd/manifests/authentik/external-secret.yaml index 0f4b639..f0218b9 100644 --- a/argocd/manifests/authentik/external-secret.yaml +++ b/argocd/manifests/authentik/external-secret.yaml @@ -49,3 +49,7 @@ spec: remoteRef: key: "Authentik (blumeops)" property: zot-client-secret + - secretKey: jellyfin-client-secret + remoteRef: + key: "Authentik (blumeops)" + property: jellyfin-client-secret diff --git a/docs/changelog.d/feature-jellyfin-authentik-sso.feature.md b/docs/changelog.d/feature-jellyfin-authentik-sso.feature.md new file mode 100644 index 0000000..67de207 --- /dev/null +++ b/docs/changelog.d/feature-jellyfin-authentik-sso.feature.md @@ -0,0 +1 @@ +Add Authentik SSO to Jellyfin with admin group mapping