Clients
This commit is contained in:
@@ -22,10 +22,49 @@ Ansible Vault-encrypted vars file:
|
||||
- `openldap_readonly_password`: existing LDAP search-account password.
|
||||
- `matrix_dex_oidc_client_id` and `matrix_dex_oidc_client_secret`: existing MAS client.
|
||||
- `postgresql_admin_password`: needed only if deliberately enabling DB management.
|
||||
- Optional `www_dex_client_secret`: enables the website client and its separate
|
||||
`www-ldap`/`entryUUID` connector, without changing legacy identities. It must
|
||||
match the website's `DEX_CLIENT_SECRET`. Leave absent to preserve Matrix-only
|
||||
behavior. Review and declare any other deployed clients before rollout.
|
||||
- `www_dex_client_secret`: matches the website's `DEX_CLIENT_SECRET`.
|
||||
- `gitea_dex_client_secret`, `discourse_dex_client_secret`,
|
||||
`peertube_dex_client_secret`, `mastodon_dex_client_secret`, and
|
||||
`nextcloud_dex_client_secret`: one distinct confidential-client secret per app.
|
||||
|
||||
The site playbook now registers all seven clients explicitly in
|
||||
`dex_static_clients` and disables the Matrix convenience client to avoid a
|
||||
duplicate. None of these secrets is optional unless you deliberately remove its
|
||||
client from your inventory/playbook. Existing secrets must be preserved, not
|
||||
regenerated on each deploy. No real secrets are included in source control.
|
||||
|
||||
### Application configuration required after client registration
|
||||
|
||||
All applications use issuer **https://dex.eom.dev/** and discovery document
|
||||
**https://dex.eom.dev/.well-known/openid-configuration**, with `openid profile
|
||||
email` scopes (and `groups` only when used). Configure the matching ID/secret in
|
||||
each service. Client creation in Dex **does not enable SSO in the application**.
|
||||
|
||||
| Application | Client ID | Exact callback / prerequisite |
|
||||
| --- | --- | --- |
|
||||
| Matrix Auth Service | Existing `matrix_dex_oidc_client_id` | Original `https://mas.eom.dev/upstream/callback/01K96AQEZKKABW34PY3R6BVNJ4` retained |
|
||||
| www | `www-membership` | `https://www.eom.dev/members/oidc/callback/` |
|
||||
| Gitea | `gitea` | `https://gitea.eom.dev/user/oauth2/dex/callback`; add OpenID Connect authentication source named **dex** |
|
||||
| Discourse | `discourse` | `https://discourse.eom.dev/auth/oidc/callback`; enable discourse-openid-connect and confirm callback for your installed plugin version |
|
||||
| PeerTube | `peertube` | `https://peertube.eom.dev/plugins/auth-openid-connect/router/code-cb`; install/configure official auth-openid-connect plugin |
|
||||
| Mastodon | `mastodon` | `https://mastodon.eom.dev/auth/auth/openid_connect/callback`; retained from its configured OIDC_REDIRECT_URI; verify installed OIDC implementation supports that route |
|
||||
| Nextcloud | `nextcloud` | `https://nextcloud.eom.dev/index.php/apps/user_oidc/code`; install **user_oidc**, not the OIDC provider app or oidc_login |
|
||||
|
||||
Callback paths are not interchangeable. Gitea's source name affects its URL;
|
||||
Nextcloud's admin screen supplies the exact callback, which can omit index.php
|
||||
when URL rewriting is enabled. If using **oidc_login** instead, explicitly replace
|
||||
the callback with its `/apps/oidc_login/oidc` route rather than enabling both by
|
||||
guesswork. The existing Mastodon deployment points to Google; changing it to Dex
|
||||
is a separate app-side migration, not another set of automatically active OIDC
|
||||
environment variables. Keep a tested administrator fallback and avoid automatic
|
||||
email-only account linking when migrating existing users.
|
||||
|
||||
The website's `www-ldap` connector uses entryUUID while the legacy `ldap`
|
||||
connector uses uid. Those produce different subjects for the same directory
|
||||
entry: do not switch existing accounts between connectors without an explicit
|
||||
linking/migration plan. The legacy connector still filters for Dex Users; merely
|
||||
registering an application does not bypass this restriction or grant paid room
|
||||
access. Each relying application must implement its own authorization policy.
|
||||
|
||||
Run the playbook on the controller with its kubeconfig and this role available
|
||||
in `ANSIBLE_ROLES_PATH`. Load your encrypted variables with Ansible's `--extra-vars`
|
||||
@@ -70,8 +109,8 @@ The site playbook maps legacy inventory variables explicitly:
|
||||
| `openldap_readonly_password` | `dex_ldap_bind_password` |
|
||||
| `matrix_dex_oidc_client_id` / `matrix_dex_oidc_client_secret` | Existing Matrix Auth Service client |
|
||||
|
||||
The site playbook enables the existing Matrix client. Its original
|
||||
redirect URI is explicit in `dex_matrix_redirect_uris`; override to match your
|
||||
The site playbook explicitly includes the existing Matrix client. Its original
|
||||
redirect URI is explicit in `dex_static_clients`; override to match your
|
||||
actual MAS configuration. Other clients previously added directly to Helm must
|
||||
be declared in `dex_static_clients` before running this role. Helm values are
|
||||
reset to this role's complete values: undeclared manual Helm customizations are
|
||||
|
||||
@@ -46,14 +46,54 @@
|
||||
dex_ldap_group_user_attribute: cn
|
||||
dex_ldap_group_filter: "(objectClass=groupOfUniqueNames)"
|
||||
|
||||
dex_matrix_client_enabled: true
|
||||
dex_matrix_redirect_uris:
|
||||
- https://mas.eom.dev/upstream/callback/01K96AQEZKKABW34PY3R6BVNJ4
|
||||
|
||||
# Optional website integration. Set www_dex_client_secret in Vault to enable;
|
||||
# it must equal the membership application's DEX_CLIENT_SECRET.
|
||||
dex_static_clients: "{{ [{'id': 'www-membership', 'name': 'eom.dev Membership', 'secret': www_dex_client_secret, 'redirectURIs': ['https://www.eom.dev/members/oidc/callback/']}] if (www_dex_client_secret | default('') | length > 0) else [] }}"
|
||||
dex_additional_connectors: "{{ [_dex_eom_www_connector] if (www_dex_client_secret | default('') | length > 0) else [] }}"
|
||||
# All clients are declared once below; don't also emit the convenience client.
|
||||
dex_matrix_client_enabled: false
|
||||
# Credentials are separate Vault/inventory variables, shared only with the
|
||||
# corresponding application. No secret is generated or rotated by this play.
|
||||
dex_static_clients:
|
||||
- id: "{{ matrix_dex_oidc_client_id }}"
|
||||
name: Matrix Auth Service
|
||||
secret: "{{ matrix_dex_oidc_client_secret }}"
|
||||
redirectURIs:
|
||||
- https://mas.eom.dev/upstream/callback/01K96AQEZKKABW34PY3R6BVNJ4
|
||||
- id: www-membership
|
||||
name: eom.dev Membership
|
||||
secret: "{{ www_dex_client_secret }}"
|
||||
redirectURIs:
|
||||
- https://www.eom.dev/members/oidc/callback/
|
||||
- id: gitea
|
||||
name: Gitea
|
||||
secret: "{{ gitea_dex_client_secret }}"
|
||||
# Authentication source in Gitea must be named exactly "dex".
|
||||
redirectURIs:
|
||||
- https://gitea.eom.dev/user/oauth2/dex/callback
|
||||
- id: discourse
|
||||
name: Discourse
|
||||
secret: "{{ discourse_dex_client_secret }}"
|
||||
# discourse-openid-connect strategy name is oidc.
|
||||
redirectURIs:
|
||||
- https://discourse.eom.dev/auth/oidc/callback
|
||||
- id: peertube
|
||||
name: PeerTube
|
||||
secret: "{{ peertube_dex_client_secret }}"
|
||||
# Requires peertube-plugin-auth-openid-connect.
|
||||
redirectURIs:
|
||||
- https://peertube.eom.dev/plugins/auth-openid-connect/router/code-cb
|
||||
- id: mastodon
|
||||
name: Mastodon
|
||||
secret: "{{ mastodon_dex_client_secret }}"
|
||||
# Matches OIDC_REDIRECT_URI in the existing Mastodon deployment.
|
||||
redirectURIs:
|
||||
- https://mastodon.eom.dev/auth/auth/openid_connect/callback
|
||||
- id: nextcloud
|
||||
name: Nextcloud
|
||||
secret: "{{ nextcloud_dex_client_secret }}"
|
||||
# This chooses the user_oidc app, not oidc_login or the OIDC provider app.
|
||||
# Override from its admin screen if your installation rewrites index.php.
|
||||
redirectURIs:
|
||||
- https://nextcloud.eom.dev/index.php/apps/user_oidc/code
|
||||
dex_additional_connectors:
|
||||
- "{{ _dex_eom_www_connector }}"
|
||||
_dex_eom_www_connector:
|
||||
type: ldap
|
||||
id: www-ldap
|
||||
|
||||
@@ -13,6 +13,23 @@
|
||||
fail_msg: Configure database/LDAP credentials, client secrets and explicit database chart version if managing PostgreSQL.
|
||||
no_log: true
|
||||
|
||||
- name: Validate explicit OIDC clients
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- item.id | default('') | length > 0
|
||||
- item.name | default('') | length > 0
|
||||
- item.redirectURIs | default([]) | length > 0
|
||||
- item.public | default(false) or ((item.secret | default('') | length > 0) != (item.secretEnv | default('') | length > 0))
|
||||
fail_msg: Every confidential client needs an ID, name, exact callback URI and either a secret or secretEnv, but not both.
|
||||
loop: "{{ dex_static_clients }}"
|
||||
no_log: true
|
||||
|
||||
- name: Reject duplicate explicit client IDs
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- dex_static_clients | map(attribute='id') | unique | length == dex_static_clients | length
|
||||
no_log: true
|
||||
|
||||
- name: Ensure Dex namespace
|
||||
kubernetes.core.k8s:
|
||||
state: present
|
||||
|
||||
+20
-10
@@ -8,31 +8,41 @@ from kubernetes_validate import validate
|
||||
from ansible.parsing.dataloader import DataLoader
|
||||
from ansible.template import Templar
|
||||
|
||||
# Resolve the site's actual workflow variables with fixture credentials only;
|
||||
# verify both Matrix-only migration and opt-in website integration.
|
||||
# Resolve the site's actual workflow with fixture credentials only.
|
||||
defaults = yaml.safe_load(Path('defaults/main.yml').read_text())
|
||||
site = yaml.safe_load(Path('playbooks/deploy-eom.yml').read_text())[0]['vars']
|
||||
for website_enabled in (False, True):
|
||||
for fixture_run in (1,):
|
||||
variables = {
|
||||
**defaults, **site,
|
||||
'dex_admin_password': 'fixture-db',
|
||||
'openldap_readonly_password': 'fixture-ldap',
|
||||
'matrix_dex_oidc_client_id': 'matrix-fixture',
|
||||
'matrix_dex_oidc_client_secret': 'fixture-matrix',
|
||||
'www_dex_client_secret': 'fixture-www',
|
||||
'gitea_dex_client_secret': 'fixture-gitea',
|
||||
'discourse_dex_client_secret': 'fixture-discourse',
|
||||
'peertube_dex_client_secret': 'fixture-peertube',
|
||||
'mastodon_dex_client_secret': 'fixture-mastodon',
|
||||
'nextcloud_dex_client_secret': 'fixture-nextcloud',
|
||||
}
|
||||
if website_enabled:
|
||||
variables['www_dex_client_secret'] = 'fixture-www'
|
||||
resolved = Templar(loader=DataLoader(), variables=variables).template(site)
|
||||
assert resolved['dex_issuer'] == 'https://dex.eom.dev/'
|
||||
assert resolved['dex_postgres_password'] == 'fixture-db'
|
||||
assert resolved['dex_ldap_group_user_attribute'] == 'cn'
|
||||
assert resolved['dex_theme_enabled'] is True
|
||||
assert resolved['dex_postgres_manage'] is False
|
||||
assert bool(resolved['dex_static_clients']) == website_enabled
|
||||
assert bool(resolved['dex_additional_connectors']) == website_enabled
|
||||
if website_enabled:
|
||||
assert resolved['dex_static_clients'][0]['secret'] == 'fixture-www'
|
||||
assert resolved['dex_additional_connectors'][0]['config']['userSearch']['idAttr'] == 'entryUUID'
|
||||
clients = {client['id']: client for client in resolved['dex_static_clients']}
|
||||
assert len(clients) == len(resolved['dex_static_clients']) == 7
|
||||
assert resolved['dex_matrix_client_enabled'] is False
|
||||
assert clients['matrix-fixture']['redirectURIs'] == ['https://mas.eom.dev/upstream/callback/01K96AQEZKKABW34PY3R6BVNJ4']
|
||||
assert clients['www-membership']['secret'] == 'fixture-www'
|
||||
assert clients['gitea']['redirectURIs'] == ['https://gitea.eom.dev/user/oauth2/dex/callback']
|
||||
assert clients['discourse']['redirectURIs'] == ['https://discourse.eom.dev/auth/oidc/callback']
|
||||
assert clients['peertube']['redirectURIs'] == ['https://peertube.eom.dev/plugins/auth-openid-connect/router/code-cb']
|
||||
assert clients['mastodon']['redirectURIs'] == ['https://mastodon.eom.dev/auth/auth/openid_connect/callback']
|
||||
assert clients['nextcloud']['redirectURIs'] == ['https://nextcloud.eom.dev/index.php/apps/user_oidc/code']
|
||||
assert all(client['secret'] and len(client['redirectURIs']) == 1 for client in clients.values())
|
||||
assert resolved['dex_additional_connectors'][0]['config']['userSearch']['idAttr'] == 'entryUUID'
|
||||
|
||||
values = yaml.safe_load(Path('/tmp/dex-values.yml').read_text())
|
||||
config = values['config']
|
||||
|
||||
Reference in New Issue
Block a user