|
| 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 | + |
| 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. |
0 commit comments