diff --git a/README.md b/README.md index e5f0cbcf8..6b0b3c5a9 100644 --- a/README.md +++ b/README.md @@ -138,7 +138,7 @@ $ TAILSCALE_USE_WIP_CODE=1 TS_AUTHKEY={YOUR_TAILSCALE_AUTHKEY} TSNET_FORCE_LOGIN The `tsidp-server` is configured by several command-line flags: | Flag | Description | Default | -| ----------------------- | -------------------------------------------------------------------------------------------------- | -------- | +|-------------------------|----------------------------------------------------------------------------------------------------|----------| | `-dir ` | Directory path to save tsnet and tsidp state. Recommend to be set. | `""` | | `-hostname ` | hostname on tailnet. Will become `.your-tailnet.ts.net` | `idp` | | `-port ` | Port to listen on | `443` | @@ -172,7 +172,7 @@ The Docker image exposes the CLI flags through environment variables. If omitted > [!NOTE] > `TS_STATE_DIR` and `TS_HOSTNAME` are legacy names. These will be replaced by `TSIDP_STATE_DIR` and `TSIDP_HOSTNAME` in the future. | Environment Variable | CLI flag | -| ---------------------------------------- | -------------------------- | +|------------------------------------------|----------------------------| | `TS_STATE_DIR=` _\*note prefix_ | `-dir ` | | `TS_HOSTNAME=` _\*note prefix_ | `-hostname ` | | `TSIDP_PORT=` | `-port ` | @@ -191,6 +191,7 @@ tsidp can be used as IdP server for any application that supports custom OIDC pr > Note: If you'd like to use tsidp to login to a SaaS application outside of your tailnet rather than a self-hosted app inside of your tailnet, you'll need to run tsidp with `--funnel` enabled. - [Proxmox](docs/proxmox/README.md) +- [Portainer](docs/portainer/README.md) ### TODOs diff --git a/docs/portainer/README.md b/docs/portainer/README.md new file mode 100644 index 000000000..2e91de1d6 --- /dev/null +++ b/docs/portainer/README.md @@ -0,0 +1,99 @@ +# Portainer setup with tsidp + +This doc will cover the OAuth configuration for Portainer using tsidp. If you want a guide on how to setup tsidp, you can check the [Proxmox](../proxmox/README.md) guide. + +## Configure Portainer to use tsidp + +This example assumes: +- Portainer server: https://portainer.yourtailnet.ts.net:9443 +- tsidp instance: https://idp.yourtailnet.ts.net + +> NOTE: This guide will use Portainer Business Edition, but the steps can be applied to the Community Edition as well. + + +### Add a new claim to the Tailscale Access Control +1. **Visit** `https://login.tailscale.com/admin/acls/file` +2. On the Policy JSON, inside the `tsidp` app, add the following `extraClaims` property: +```json +"extraClaims": { + "groups": [ + "group_1", + "group_2", + ... + ] +} +``` +It is reccomended to map the group names (`group_1`, `group_2`, ...) to groups inside Portainer to ease the setup process +These groups can be created following the policies you already have configured on Tailscale. If you do not have any policies in place, you can create a single group called `admin` and link all the users to this group. +![Tailscale Access Control](tailscale-access-control.png) + +### Register Portainer as a Client in tsidp + +1. **Visit** `https://idp.yourtailnet.ts.net` and click "Add New Client" + + ![Add New Client](add-oidc-client.png) + +2. **Configure the client**: + - Add redirect URIs for each way you access Proxmox + - Save the generated Client ID and Client Secret; you'll use these next + + ![Configure the client](tsidp-multiple-uri-redirects.png) + + +### Configure the Groups to allow resource access +1. Navigate to User-related → Teams +2. Create a new team. You can call it whatever you want, but, to ease the configuration process, we will call it with the same name we configured on the [Add a new claim to the Tailscale Access Control](#add-a-new-claim-to-the-tailscale-access-control) step. + + ![Portainer groups view](group-view.png) + +3. Go to **Environment-related** -> **Groups** -> on the `Unassigned` group, click on **Manage access** +4. On the **Create access** section, select the group you just created and the role you want to associate to it. +5. Click on **+ Create access** + + ![Environment group access](environment-group-access.png) + + +### Configure OpenID Connect in Portainer + +1. **Navigate to** Settings → Authentication → **OAuth** + + ![Configure OAuth](oauth-screen.png) + +2. **Set the following options:** + - **Use SSO**: Enabled + - **Hide internal authentication prompt**: Enabled if you want to force SSO, otherwise, disabled. + - **Automatic user provisioning**: Enabled + - **Automatic team membership**: Enabled + - **Claim name**: `groups` - the same we configured on [Add a new claim to the Tailscale Access Control](#add-a-new-claim-to-the-tailscale-access-control) + - **Statically assigned teams**: click on the `add team mapping` button + - **Claim value regex**: `admin` maps to `admin` team + > This step should be repeated for all the groups created on the [Add a new claim to the Tailscale Access Control](#add-a-new-claim-to-the-tailscale-access-control). + - **Default team**: No team + - **Assign admin rights to group(s)**: Enabled + - **claim value regex**: `admin` + +3. **Configure the Custom OAuth provider** with these settings: + - **Client ID**: (from tsidp) + - **Client Secret**: (from tsidp) + - **Authorization URL**: `https://idp.yourtailnet.ts.net/authorize` + - **Access token URL**: `https://idp.yourtailnet.ts.net/token` + - **Resource URL**: `https://idp.yourtailnet.ts.net/userinfo` + - **Redirect URL**: `https://portainer.yourtailnet.ts.net:9443` + - **Logout URL**: Blank + - **User identifier**: `username` + - **Scopes**: `openid email profile` + - **Auth style**: `Auto Detect` + + ![Configured Authenticatin Settings](authentication-settings-finalized.png) + + +### Test the Authentication + +1. **Open an incognito browser window** and navigate to `https://portainer.yourtailnet.ts.net:9443` + +2. **Log in with OAuth** + - Authentication should work immediately + - Portainer will auto-create a user account (due to "Automatic user provisioning: enabled") + - You should be able to see all environments configured on your Portainer installation. + + ![Login with OAuth](login-with-oauth.png) diff --git a/docs/portainer/add-oidc-client.png b/docs/portainer/add-oidc-client.png new file mode 100644 index 000000000..5a641aff3 Binary files /dev/null and b/docs/portainer/add-oidc-client.png differ diff --git a/docs/portainer/authentication-settings-finalized.png b/docs/portainer/authentication-settings-finalized.png new file mode 100644 index 000000000..8dbd2bac2 Binary files /dev/null and b/docs/portainer/authentication-settings-finalized.png differ diff --git a/docs/portainer/environment-group-access.png b/docs/portainer/environment-group-access.png new file mode 100644 index 000000000..bb61f0b64 Binary files /dev/null and b/docs/portainer/environment-group-access.png differ diff --git a/docs/portainer/group-view.png b/docs/portainer/group-view.png new file mode 100644 index 000000000..0824ef0fd Binary files /dev/null and b/docs/portainer/group-view.png differ diff --git a/docs/portainer/login-with-oauth.png b/docs/portainer/login-with-oauth.png new file mode 100644 index 000000000..d8f96948c Binary files /dev/null and b/docs/portainer/login-with-oauth.png differ diff --git a/docs/portainer/oauth-screen.png b/docs/portainer/oauth-screen.png new file mode 100644 index 000000000..19582dce0 Binary files /dev/null and b/docs/portainer/oauth-screen.png differ diff --git a/docs/portainer/tailscale-access-control.png b/docs/portainer/tailscale-access-control.png new file mode 100644 index 000000000..77542a916 Binary files /dev/null and b/docs/portainer/tailscale-access-control.png differ diff --git a/docs/portainer/tsidp-multiple-uri-redirects.png b/docs/portainer/tsidp-multiple-uri-redirects.png new file mode 100644 index 000000000..5ad4b0452 Binary files /dev/null and b/docs/portainer/tsidp-multiple-uri-redirects.png differ