Skip to content

Commit a723adb

Browse files
committed
Refactor group and role sync documentation
- Split group and role sync details into a dedicated `group-sync.md`. - Update links to reflect new file structure. - Simplify OIDC configuration guidance for easier navigation.
1 parent fe6e89a commit a723adb

File tree

5 files changed

+297
-294
lines changed

5 files changed

+297
-294
lines changed

docs/admin/users/README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,22 @@ By default, Coder is accessible via password authentication. For production depl
44

55
## Configuring SSO
66

7-
- [OpenID Connect](./auth.md#openid-connect) (e.g. Okta, KeyCloak, PingFederate, Azure AD)
8-
- [GitHub](./auth.md#github) (or GitHub Enterprise)
7+
- [OpenID Connect](./oidc-auth.md) (e.g. Okta, KeyCloak, PingFederate, Azure AD)
8+
- [GitHub](./github-auth.md) (or GitHub Enterprise)
99

1010
## Groups
1111

1212
Multiple users can be organized into logical groups to control which templates they can use. While groups can be manually created in Coder, we recommend syncing them from your identity provider.
1313

14-
- [Learn more about Groups](./groups.md)
15-
- [Group & Role Sync](./group-role-sync.md)
14+
- [Learn more about Groups](./groups-roles.md)
15+
- [Group & Role Sync](./group-sync.md)
1616

1717
## Roles
1818

1919
Roles determine which actions users can take within the platform. Typically, most developers in your organization have the `Member` role, allowing them to create workspaces. Other roles have administrative capabilities such as auditing, managing users, and managing templates.
2020

21-
- [Learn more about Roles](./roles.md)
22-
- [Group & Role Sync](./group-role-sync.md)
21+
- [Learn more about Roles](./groups-roles.md)
22+
- [Group & Role Sync](./group-sync.md)
2323

2424
## User status
2525

docs/admin/users/group-sync.md

Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
# Group Sync (enterprise) (premium)
2+
3+
If your OpenID Connect provider supports group claims, you can configure Coder
4+
to synchronize groups in your auth provider to groups within Coder.
5+
6+
To enable group sync, ensure that the `groups` claim is set by adding the
7+
correct scope to request. If group sync is enabled, the user's groups will be
8+
controlled by the OIDC provider. This means manual group additions/removals will
9+
be overwritten on the next login.
10+
11+
```env
12+
# as an environment variable
13+
CODER_OIDC_SCOPES=openid,profile,email,groups
14+
```
15+
16+
```shell
17+
# as a flag
18+
--oidc-scopes openid,profile,email,groups
19+
```
20+
21+
With the `groups` scope requested, we also need to map the `groups` claim name.
22+
Coder recommends using `groups` for the claim name. This step is necessary if
23+
your **scope's name** is something other than `groups`.
24+
25+
```env
26+
# as an environment variable
27+
CODER_OIDC_GROUP_FIELD=groups
28+
```
29+
30+
```shell
31+
# as a flag
32+
--oidc-group-field groups
33+
```
34+
35+
On login, users will automatically be assigned to groups that have matching
36+
names in Coder and removed from groups that the user no longer belongs to.
37+
38+
For cases when an OIDC provider only returns group IDs ([Azure AD][azure-gids])
39+
or you want to have different group names in Coder than in your OIDC provider,
40+
you can configure mapping between the two.
41+
42+
```env
43+
# as an environment variable
44+
CODER_OIDC_GROUP_MAPPING='{"myOIDCGroupID": "myCoderGroupName"}'
45+
```
46+
47+
```shell
48+
# as a flag
49+
--oidc-group-mapping '{"myOIDCGroupID": "myCoderGroupName"}'
50+
```
51+
52+
Below is an example mapping in the Coder Helm chart:
53+
54+
```yaml
55+
coder:
56+
env:
57+
- name: CODER_OIDC_GROUP_MAPPING
58+
value: >
59+
{"myOIDCGroupID": "myCoderGroupName"}
60+
```
61+
62+
From the example above, users that belong to the `myOIDCGroupID` group in your
63+
OIDC provider will be added to the `myCoderGroupName` group in Coder.
64+
65+
> **Note:** Groups are only updated on login.
66+
67+
[azure-gids]:
68+
https://github.com/MicrosoftDocs/azure-docs/issues/59766#issuecomment-664387195
69+
70+
### Group allowlist
71+
72+
You can limit which groups from your identity provider can log in to Coder with
73+
[CODER_OIDC_ALLOWED_GROUPS](https://coder.com/docs/reference/cli/server#--oidc-allowed-groups).
74+
Users who are not in a matching group will see the following error:
75+
76+
![Unauthorized group error](../../images/admin/group-allowlist.png)
77+
78+
## Role sync
79+
80+
If your OpenID Connect provider supports roles claims, you can configure Coder
81+
to synchronize roles in your auth provider to deployment-wide roles within
82+
Coder.
83+
84+
Set the following in your Coder server [configuration](./configure.md).
85+
86+
```env
87+
# Depending on your identity provider configuration, you may need to explicitly request a "roles" scope
88+
CODER_OIDC_SCOPES=openid,profile,email,roles
89+
90+
# The following fields are required for role sync:
91+
CODER_OIDC_USER_ROLE_FIELD=roles
92+
CODER_OIDC_USER_ROLE_MAPPING='{"TemplateAuthor":["template-admin","user-admin"]}'
93+
```
94+
95+
> One role from your identity provider can be mapped to many roles in Coder
96+
> (e.g. the example above maps to 2 roles in Coder.)
97+
98+
## Troubleshooting group/role sync
99+
100+
Some common issues when enabling group/role sync.
101+
102+
### General guidelines
103+
104+
If you are running into issues with group/role sync, is best to view your Coder
105+
server logs and enable
106+
[verbose mode](https://coder.com/docs/v2/v2.5.1/cli#-v---verbose). To reduce
107+
noise, you can filter for only logs related to group/role sync:
108+
109+
```sh
110+
CODER_VERBOSE=true
111+
CODER_LOG_FILTER=".*userauth.*|.*groups returned.*"
112+
```
113+
114+
Be sure to restart the server after changing these configuration values. Then,
115+
attempt to log in, preferably with a user who has the `Owner` role.
116+
117+
The logs for a successful group sync look like this (human-readable):
118+
119+
```sh
120+
[debu] coderd.userauth: got oidc claims request_id=49e86507-6842-4b0b-94d4-f245e62e49f3 source=id_token claim_fields="[aio aud email exp groups iat idp iss name nbf oid preferred_username rh sub tid uti ver]" blank=[]
121+
122+
[debu] coderd.userauth: got oidc claims request_id=49e86507-6842-4b0b-94d4-f245e62e49f3 source=userinfo claim_fields="[email family_name given_name name picture sub]" blank=[]
123+
124+
[debu] coderd.userauth: got oidc claims request_id=49e86507-6842-4b0b-94d4-f245e62e49f3 source=merged claim_fields="[aio aud email exp family_name given_name groups iat idp iss name nbf oid picture preferred_username rh sub tid uti ver]" blank=[]
125+
126+
[debu] coderd: groups returned in oidc claims request_id=49e86507-6842-4b0b-94d4-f245e62e49f3 email=ben@coder.com username=ben len=3 groups="[c8048e91-f5c3-47e5-9693-834de84034ad 66ad2cc3-a42f-4574-a281-40d1922e5b65 70b48175-107b-4ad8-b405-4d888a1c466f]"
127+
```
128+
129+
To view the full claim, the Owner role can visit this endpoint on their Coder
130+
deployment after logging in:
131+
132+
```sh
133+
https://[coder.example.com]/api/v2/debug/[username]/debug-link
134+
```
135+
136+
### User not being assigned / Group does not exist
137+
138+
If you want Coder to create groups that do not exist, you can set the following
139+
environment variable. If you enable this, your OIDC provider might be sending
140+
over many unnecessary groups. Use filtering options on the OIDC provider to
141+
limit the groups sent over to prevent creating excess groups.
142+
143+
```env
144+
# as an environment variable
145+
CODER_OIDC_GROUP_AUTO_CREATE=true
146+
```
147+
148+
```shell
149+
# as a flag
150+
--oidc-group-auto-create=true
151+
```
152+
153+
A basic regex filtering option on the Coder side is available. This is applied
154+
**after** the group mapping (`CODER_OIDC_GROUP_MAPPING`), meaning if the group
155+
is remapped, the remapped value is tested in the regex. This is useful if you
156+
want to filter out groups that do not match a certain pattern. For example, if
157+
you want to only allow groups that start with `my-group-` to be created, you can
158+
set the following environment variable.
159+
160+
```env
161+
# as an environment variable
162+
CODER_OIDC_GROUP_REGEX_FILTER="^my-group-.*$"
163+
```
164+
165+
```shell
166+
# as a flag
167+
--oidc-group-regex-filter="^my-group-.*$"
168+
```
169+
170+
### Invalid Scope
171+
172+
If you see an error like the following, you may have an invalid scope.
173+
174+
```console
175+
The application '<oidc_application>' asked for scope 'groups' that doesn't exist on the resource...
176+
```
177+
178+
This can happen because the identity provider has a different name for the
179+
scope. For example, Azure AD uses `GroupMember.Read.All` instead of `groups`.
180+
You can find the correct scope name in the IDP's documentation. Some IDP's allow
181+
configuring the name of this scope.
182+
183+
The solution is to update the value of `CODER_OIDC_SCOPES` to the correct value
184+
for the identity provider.
185+
186+
### No `group` claim in the `got oidc claims` log
187+
188+
Steps to troubleshoot.
189+
190+
1. Ensure the user is a part of a group in the IDP. If the user has 0 groups, no
191+
`groups` claim will be sent.
192+
2. Check if another claim appears to be the correct claim with a different name.
193+
A common name is `memberOf` instead of `groups`. If this is present, update
194+
`CODER_OIDC_GROUP_FIELD=memberOf`.
195+
3. Make sure the number of groups being sent is under the limit of the IDP. Some
196+
IDPs will return an error, while others will just omit the `groups` claim. A
197+
common solution is to create a filter on the identity provider that returns
198+
less than the limit for your IDP.
199+
- [Azure AD limit is 200, and omits groups if exceeded.](https://learn.microsoft.com/en-us/azure/active-directory/hybrid/connect/how-to-connect-fed-group-claims#options-for-applications-to-consume-group-information)
200+
- [Okta limit is 100, and returns an error if exceeded.](https://developer.okta.com/docs/reference/api/oidc/#scope-dependent-claims-not-always-returned)
201+
202+
## Provider-Specific Guides
203+
204+
Below are some details specific to individual OIDC providers.
205+
206+
### Active Directory Federation Services (ADFS)
207+
208+
> **Note:** Tested on ADFS 4.0, Windows Server 2019
209+
210+
1. In your Federation Server, create a new application group for Coder. Follow
211+
the steps as described
212+
[here.](https://learn.microsoft.com/en-us/windows-server/identity/ad-fs/development/msal/adfs-msal-web-app-web-api#app-registration-in-ad-fs)
213+
- **Server Application**: Note the Client ID.
214+
- **Configure Application Credentials**: Note the Client Secret.
215+
- **Configure Web API**: Set the Client ID as the relying party identifier.
216+
- **Application Permissions**: Allow access to the claims `openid`, `email`,
217+
`profile`, and `allatclaims`.
218+
1. Visit your ADFS server's `/.well-known/openid-configuration` URL and note the
219+
value for `issuer`.
220+
> **Note:** This is usually of the form
221+
> `https://adfs.corp/adfs/.well-known/openid-configuration`
222+
1. In Coder's configuration file (or Helm values as appropriate), set the
223+
following environment variables or their corresponding CLI arguments:
224+
225+
- `CODER_OIDC_ISSUER_URL`: the `issuer` value from the previous step.
226+
- `CODER_OIDC_CLIENT_ID`: the Client ID from step 1.
227+
- `CODER_OIDC_CLIENT_SECRET`: the Client Secret from step 1.
228+
- `CODER_OIDC_AUTH_URL_PARAMS`: set to
229+
230+
```console
231+
{"resource":"$CLIENT_ID"}
232+
```
233+
234+
where `$CLIENT_ID` is the Client ID from step 1
235+
([see here](https://learn.microsoft.com/en-us/windows-server/identity/ad-fs/overview/ad-fs-openid-connect-oauth-flows-scenarios#:~:text=scope%E2%80%AFopenid.-,resource,-optional)).
236+
This is required for the upstream OIDC provider to return the requested
237+
claims.
238+
239+
- `CODER_OIDC_IGNORE_USERINFO`: Set to `true`.
240+
241+
1. Configure
242+
[Issuance Transform Rules](https://learn.microsoft.com/en-us/windows-server/identity/ad-fs/operations/create-a-rule-to-send-ldap-attributes-as-claims)
243+
on your federation server to send the following claims:
244+
245+
- `preferred_username`: You can use e.g. "Display Name" as required.
246+
- `email`: You can use e.g. the LDAP attribute "E-Mail-Addresses" as
247+
required.
248+
- `email_verified`: Create a custom claim rule:
249+
250+
```console
251+
=> issue(Type = "email_verified", Value = "true")
252+
```
253+
254+
- (Optional) If using Group Sync, send the required groups in the configured
255+
groups claim field. See [here](https://stackoverflow.com/a/55570286) for an
256+
example.
257+
258+
### Keycloak
259+
260+
The access_type parameter has two possible values: "online" and "offline." By
261+
default, the value is set to "offline". This means that when a user
262+
authenticates using OIDC, the application requests offline access to the user's
263+
resources, including the ability to refresh access tokens without requiring the
264+
user to reauthenticate.
265+
266+
To enable the `offline_access` scope, which allows for the refresh token
267+
functionality, you need to add it to the list of requested scopes during the
268+
authentication flow. Including the `offline_access` scope in the requested
269+
scopes ensures that the user is granted the necessary permissions to obtain
270+
refresh tokens.
271+
272+
By combining the `{"access_type":"offline"}` parameter in the OIDC Auth URL with
273+
the `offline_access` scope, you can achieve the desired behavior of obtaining
274+
refresh tokens for offline access to the user's resources.

docs/admin/users/groups-roles.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Groups and roles can be manually assigned in Coder. For production deployments,
44
these can also be
5-
[managed and synced by the identity provider](./oidc.md#group-sync).
5+
[managed and synced by the identity provider](./group-sync.md).
66

77
## Groups
88

@@ -17,17 +17,17 @@ which templates developers can use. For example:
1717

1818
Roles determine which actions users can take within the platform.
1919

20-
| | Auditor | User Admin | Template Admin | Owner |
21-
| ----------------------------------------------------- | ------- | ---------- | -------------- | ----- |
22-
| Add and remove Users | || ||
23-
| Manage groups (enterprise) | || ||
24-
| Change User roles | | | ||
25-
| Manage **ALL** Templates | | |||
26-
| View **ALL** Workspaces | | |||
27-
| Update and delete **ALL** Workspaces | | | ||
28-
| Run [external provisioners](./provisioners.md) | | |||
29-
| Execute and use **ALL** Workspaces | | | ||
30-
| View all user operation [Audit Logs](./audit-logs.md) || | ||
20+
| | Auditor | User Admin | Template Admin | Owner |
21+
| --------------------------------------------------------------- | ------- | ---------- | -------------- | ----- |
22+
| Add and remove Users | || ||
23+
| Manage groups (enterprise) | || ||
24+
| Change User roles | | | ||
25+
| Manage **ALL** Templates | | |||
26+
| View **ALL** Workspaces | | |||
27+
| Update and delete **ALL** Workspaces | | | ||
28+
| Run [external provisioners](../provisioners.md) | | |||
29+
| Execute and use **ALL** Workspaces | | | ||
30+
| View all user operation [Audit Logs](../security/audit-logs.md) || | ||
3131

3232
A user may have one or more roles. All users have an implicit Member role that
3333
may use personal workspaces.

0 commit comments

Comments
 (0)