Skip to content

docs: rework "admin/authentication" page + PKI authentication docs #9236

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
fix it up
  • Loading branch information
bpmct committed Aug 22, 2023
commit fbf96a5af6332e098f97e111e4ec058f353f7d1a
42 changes: 42 additions & 0 deletions docs/admin/auth/adfs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Active Directory Federation Services OIDC with Coder (ADFS)

> **Note:** Tested on ADFS 4.0, Windows Server 2019
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
> **Note:** Tested on ADFS 4.0, Windows Server 2019
> ![NOTE]
> Tested on ADFS 4.0, Windows Server 2019


1. In your Federation Server, create a new application group for Coder. Follow the
steps as described [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)
- **Server Application**: Note the Client ID.
- **Configure Application Credentials**: Note the Client Secret.
- **Configure Web API**: Set the Client ID as the relying party identifier.
- **Application Permissions**: Allow access to the claims `openid`, `email`, `profile`, and `allatclaims`.
1. Visit your ADFS server's `/.well-known/openid-configuration` URL and note
the value for `issuer`.
> **Note:** This is usually of the form `https://adfs.corp/adfs/.well-known/openid-configuration`
1. In Coder's configuration file (or Helm values as appropriate), set the following
environment variables or their corresponding CLI arguments:

- `CODER_OIDC_ISSUER_URL`: the `issuer` value from the previous step.
- `CODER_OIDC_CLIENT_ID`: the Client ID from step 1.
- `CODER_OIDC_CLIENT_SECRET`: the Client Secret from step 1.
- `CODER_OIDC_AUTH_URL_PARAMS`: set to

```console
{"resource":"$CLIENT_ID"}
```

where `$CLIENT_ID` is the Client ID from step 1 ([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)).
This is required for the upstream OIDC provider to return the requested claims.

- `CODER_OIDC_IGNORE_USERINFO`: Set to `true`.

1. Configure [Issuance Transform Rules](https://learn.microsoft.com/en-us/windows-server/identity/ad-fs/operations/create-a-rule-to-send-ldap-attributes-as-claims)
on your federation server to send the following claims:

- `preferred_username`: You can use e.g. "Display Name" as required.
- `email`: You can use e.g. the LDAP attribute "E-Mail-Addresses" as required.
- `email_verified`: Create a custom claim rule:

```console
=> issue(Type = "email_verified", Value = "true")
```

- (Optional) If using Group Sync, send the required groups in the configured groups claim field. See [here](https://stackoverflow.com/a/55570286) for an example.
137 changes: 137 additions & 0 deletions docs/admin/auth/group-role-sync.md
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, this section should not be under auth directory as it is not an auth method but a feature on top of OIDC/SAML. May be we should have a subdirectory OIDC under auth directory and move this along with setting up OIDC.

These are my thoughts, and they are not very important. If you feel the current flow and organization are right. Please ignore this comment.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, that makes sense to me too. Like "Identity Providers" can be a subsection under OIDC and have each one listed.

Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# Group & Role Sync (Enterprise)

You can use groups and roles from your identity provider as the definitive source for Coder's user roles and groups.

## How it Works

1. **Configure OIDC**: Adjust your OIDC identity provider settings to transmit claims via the OIDC token or userinfo endpoint. These claims, usually labeled `groups` and `roles`, aren't sent by default in most OIDC clients.

1. **Configure Coder Server**: Coder can either:
- A) Create new groups in Coder, or
- B) Map claims to existing Coder groups/roles.

1. **Roles Sync on Login**: Upon user authentication, their associated groups and roles synchronize with Coder, using the identity provider as the reference.

## Group Sync (enterprise)

If your OpenID Connect provider supports group claims, you can configure Coder
to synchronize groups in your auth provider to groups within Coder.

To enable group sync, ensure that a groups claim is being sent. This is often `groups` or `memberOf`. Technically, a `roles` claim could be mapped to syncronize groups as Coder just expects an array of strings (e.g. `["Admin", "DevOps-Admin"`)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
To enable group sync, ensure that a groups claim is being sent. This is often `groups` or `memberOf`. Technically, a `roles` claim could be mapped to syncronize groups as Coder just expects an array of strings (e.g. `["Admin", "DevOps-Admin"`)
To enable group sync, ensure that a group's claim is being sent. This is often `groups` or `memberOf`. Technically, a `roles` claim could be mapped to synchronize groups as Coder just expects an array of strings (e.g., `["Admin", "DevOps-Admin"`)


To check, [configure](../configure.md) the Coder server with the following environment variable to send verbose logs:

```sh
CODER_VERBOSE=true
```

Be sure to restart the server. When a user logs in with OIDC, you should see the following logs from the server.


```sh
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
```sh
```shell

shell is more general

[debu] coderd.userauth: got oidc claims trace=0x1b09780 span=0x1b09820 request_id=833f136a-2e6b-4df5-8ecb-1316c71a425a source=id_token claim_fields="[aio aud email exp groups iat idp iss name nbf oid preferred_username rh sub tid uti ver]" blank=[]

[debu] coderd.userauth: got oidc claims trace=0x1b09780 span=0x1b09820 request_id=833f136a-2e6b-4df5-8ecb-1316c71a425a source=userinfo claim_fields="[email family_name given_name name picture sub]" blank=[]

[debu] coderd.userauth: got oidc claims trace=0x1b09780 span=0x1b09820 request_id=833f136a-2e6b-4df5-8ecb-1316c71a425a 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=[]
```

> ℹ️ In this example, Coder is successfully getting the `groups` OIDC claim from the token and merging the claims from userinfo endpoint. See below for troubleshooting instructions.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not related to this PR. But I wonder if we should have different types of Notes e.g.,

Note

A note

Important

An important information

Warning

Be careful here

https://github.com/orgs/community/discussions/16925 for details

Copy link
Member

@matifali matifali Aug 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@BrunoQuaresma, can these be rendered on coder.com/v2/docs
With some research, I found https://www.npmjs.com/package/remark-github-beta-blockquote-admonitions

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
> ℹ️ In this example, Coder is successfully getting the `groups` OIDC claim from the token and merging the claims from userinfo endpoint. See below for troubleshooting instructions.
> [!NOTE]
> In this example, Coder successfully gets the `groups` OIDC claim from the token and merges the claims from the userinfo endpoint. Please take a look at the troubleshooting instructions below.

as per https://github.com/orgs/community/discussions/16925


### Enabling Group Sync

To enable group sync, you must tell Coder which claim to be used:

```sh
CODER_OIDC_GROUP_FIELD=groups
```

By default, Coder will only sync groups that match an existing group in Coder. However, there are two other options.

#### Automatically Create New Groups

To automatically create groups in Coder if they don't exist, set the following server value:

```console
CODER_OIDC_GROUP_AUTO_CREATE=true
```

#### Configuring Group Mapping

For cases when an OIDC provider only returns group IDs ([Azure AD][azure-gids])
or you want to have different group names in Coder than in your OIDC provider,
you can configure mapping between the two.

```console
CODER_OIDC_GROUP_MAPPING='{"myOIDCGroupID": "myCoderGroupName"}'
```

Below is an example mapping in the Coder Helm chart:

```yaml
coder:
env:
- name: CODER_OIDC_GROUP_MAPPING
value: >
{"myOIDCGroupID": "myCoderGroupName"}
```

### Filtering Group Sync

A basic regex filtering option on the Coder side is available. This is applied **after** the group mapping (`CODER_OIDC_GROUP_MAPPING`), meaning if the group is remapped, the remapped value is tested in the regex. This is useful if you want to filter out groups that do not match a certain pattern. For example, if you want to only allow groups that start with `my-group-` to be created, you can set the following environment variable.

```console
CODER_OIDC_GROUP_REGEX_FILTER="^my-group-.*$"
```

## Role Sync (enterprise)

If your OpenID Connect provider supports roles claims, you can configure Coder
to synchronize roles in your auth provider to deployment-wide roles within Coder.

Set the following in your Coder server [configuration](./configure.md).

```console
# Depending on your identity provider configuration, you may need to explicitly request a "roles" scope
CODER_OIDC_SCOPES=openid,profile,email,roles

# The following fields are required for role sync:
CODER_OIDC_USER_ROLE_FIELD=roles
CODER_OIDC_USER_ROLE_MAPPING='{"TemplateAuthor":["template-admin","user-admin"]}'
```

> One role from your identity provider can be mapped to many roles in Coder (e.g. the example above maps to 2 roles in Coder.)

[azure-gids]: https://github.com/MicrosoftDocs/azure-docs/issues/59766#issuecomment-664387195

### Troubleshooting

Some common issues when enabling group and role sync.

#### No `groups` claim in the `got oidc claims` log

If you are not recieving the `groups` claim, refer to your identify provider documentation. In some cases, you will need to add the claim to your identity provider and request it via a scope in the OIDC config:

```sh
CODER_OIDC_SCOPES=openid,profile,email,groups
```

Here are some general steps:

1. Ensure the user is a part of a group in the IDP. If the user has 0 groups, no `groups` claim will be sent.
2. Check if another claim appears to be the correct claim with a different name. A common name is `memberOf` instead of `groups`. If this is present, update `CODER_OIDC_GROUP_FIELD=memberOf`.
3. Make sure the number of groups being sent is under the limit of the IDP. Some IDPs will return an error, while others will just omit the `groups` claim. A common solution is to create a filter on the identity provider that returns less than the limit for your IDP.
- [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)
- [Okta limit is 100, and returns an error if exceeded.](https://developer.okta.com/docs/reference/api/oidc/#scope-dependent-claims-not-always-returned)

#### Invalid Scope

If you see an error like the following, you may have an invalid scope.

```console
The application '<oidc_application>' asked for scope 'groups' that doesn't exist on the resource...
```

This can happen because the identity provider has a different name for the scope. For example, Azure AD uses `GroupMember.Read.All` instead of `groups`. You can find the correct scope name in the IDP's documentation. Some IDP's allow configuring the name of this scope.

The solution is to update the value of `CODER_OIDC_SCOPES` to the correct value for the identity provider.
7 changes: 7 additions & 0 deletions docs/admin/auth/keycloak.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Keycloak Authentication with Coder

The access_type parameter has two possible values: "online" and "offline." By default, the value is set to "offline". This means that when a user authenticates using OIDC, the application requests offline access to the user's resources, including the ability to refresh access tokens without requiring the user to reauthenticate.

To enable the `offline_access` scope, which allows for the refresh token functionality, you need to add it to the list of requested scopes during the authentication flow. Including the `offline_access` scope in the requested scopes ensures that the user is granted the necessary permissions to obtain refresh tokens.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we provide the example?

CODER_OIDC_SCOPES=openid,profile,email,offline_access

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better if we also include an example


By combining the `{"access_type":"offline"}` parameter in the OIDC Auth URL with the `offline_access` scope, you can achieve the desired behavior of obtaining refresh tokens for offline access to the user's resources.
13 changes: 12 additions & 1 deletion docs/admin/auth/oidc.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ Restart your Coder server to apply this configuration. An OIDC authentication bu

![Log in with OIDC button](https://user-images.githubusercontent.com/22407953/261882891-7aa2e922-5572-490f-992a-07126bad0161.png)

## Provider Specific Notes

Any OIDC provider should work with Coder. With that being said, we have some special notes for specific providers.

- [Keycloak](./keycloak.md)
- [Active Directory Federation Services (ADFS)](./adfs.md)

## Group and Role Sync (enterprise)

Learn how to do [group and role sync](group-role-sync.md) with COder.

## How Coder Reads OIDC claims

When a user logs in for the first time via OIDC, Coder will merge both
Expand Down Expand Up @@ -146,7 +157,7 @@ Restart your Coder server to apply this configuration.
If you wish to manually onboard users, or use a [script](../automation.md) to add users to Coder, set:

```console
UTH2=false
CODER_OIDC_ALLOW_SIGNUPS=false
```

This will prevent new users from logging in via GitHub. An admin can manually add GitHub users from the "Users" page.
19 changes: 19 additions & 0 deletions docs/admin/auth/passwordless.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Passwordless Authentication

You can create passwordless users in users for machine accounts. This can come in handy if you plan on [automating Coder](../automation.md) in CI/CD pipelines, for example.

In the Users page `https://coder.example.com/users`, create a new user with `Login Type: none`:

![Create new user](https://user-images.githubusercontent.com/22407953/262183871-9a9070fa-ca35-4816-9990-465b16b94fe4.png)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replace image path with realative


From there, you can create a long-lived token on behalf of the passwordless user using the [Create token API key](../../api/users.md#create-token-api-key):

```sh
# Replace API_KEY with a token from https://coder.example.com/cli-auth
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Replace API_KEY with a token from https://coder.example.com/cli-auth
# Replace API_KEY with a token from https://coder.example.com/cli-auth
# The logged in user needs to have the requisite permissions to create an API
# key on behalf of another user.

curl -X POST http://coder-server:8080/api/v2/users/coder-bot/keys/tokens \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
curl -X POST http://coder-server:8080/api/v2/users/coder-bot/keys/tokens \
curl -X POST http://coder-server:8080/api/v2/users/<machine_username>/keys/tokens \

-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Coder-Session-Token: API_KEY'
```

Then, follow our documentation in [automating Coder](../automation.md) to perform actions on behalf of this user using their API token.
20 changes: 19 additions & 1 deletion docs/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,25 @@
{
"title": "OIDC",
"description": "Configure OIDC authentication with Coder",
"path": "./admin/auth/oidc.md"
"path": "./admin/auth/oidc.md",
"children": [
{
"title": "Keycloak",
"description": "Authenticate to Coder with Keyclock",
"path": "./admin/auth/keycloak.md"
},
{
"title": "Active Directory Federation Services (ADFS)",
"description": "Authenticate to Coder with ADFS",
"path": "./admin/auth/adfs.md"
},
{
"title": "Group and Role Sync",
"description": "Sync groups and roles from your identity provider into Coder",
"path": "./admin/auth/group-role-sync.md",
"state": "enterprise"
}
]
},
{
"title": "Passwordless",
Expand Down