Skip to content

Commit 25b4939

Browse files
committed
Add external console integration (SSO handoff) guide
Guide for CSPs/ISVs to embed the KubeDB Platform console into their own console via a mirrored user + session-cookie handoff. Covers admin-token user provisioning, the server-side login flow, cookie delivery to the browser on a shared subdomain, logout, and a security checklist. Includes two rendered sequence diagrams. Signed-off-by: Tamal Saha <tamal@appscode.com>
1 parent 6611704 commit 25b4939

3 files changed

Lines changed: 249 additions & 0 deletions

File tree

Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
---
2+
layout: docs
3+
menu:
4+
docsplatform_{{.version}}:
5+
identifier: external-console-integration
6+
name: External Console Integration
7+
parent: integrations
8+
weight: 60
9+
menu_name: docsplatform_{{.version}}
10+
section_menu_id: guides
11+
---
12+
13+
# Integrating an External Console with the KubeDB Platform
14+
15+
This guide is for **Cloud Service Providers (CSPs)** and ISVs who already operate their
16+
own web console and want to embed the KubeDB Platform console for their end users.
17+
18+
## 1. Goal
19+
20+
A CSP already has a console where its customers sign in. The CSP wants to offer KubeDB
21+
(managed databases) as a feature. The KubeDB Platform console is hosted on a **subdomain of
22+
the CSP's console**, for example:
23+
24+
| Role | Host |
25+
|------|------|
26+
| CSP console (the CSP's existing product; identity provider) | `https://console.acme.com` |
27+
| KubeDB Platform console **and** API server (per-CSP deployment) | `https://db.acme.com` |
28+
29+
The requirement: **when a user logs into the CSP console, the CSP backend should
30+
seamlessly log that same user into the KubeDB console** — no second username/password
31+
prompt. The user's identity of record lives in the CSP console; the KubeDB Platform holds a
32+
*mirror* of that identity that the CSP backend controls.
33+
34+
This is achieved with two flows:
35+
36+
1. **Provisioning (once per user)** — the CSP backend creates a mirrored KubeDB user
37+
using an **admin bearer token**. The CSP generates and stores that user's KubeDB
38+
password; the end user never sees or types it.
39+
2. **Session handoff (every CSP login)** — the CSP backend performs a server-side login
40+
to the KubeDB Platform on the user's behalf, captures the resulting session cookies, and
41+
hands them to the user's browser scoped to the KubeDB subdomain.
42+
43+
Because both consoles share the registrable domain `acme.com`, the browser treats
44+
`console.acme.com``db.acme.com` as **same-site**, so the handoff works cleanly.
45+
46+
---
47+
48+
## 2. Prerequisites
49+
50+
- A per-CSP KubeDB Platform deployment reachable at the subdomain (`https://db.acme.com`),
51+
serving both the web console and the `/api/v1` REST API.
52+
- An **admin personal access token** (bearer token) issued to the CSP, held **only** by
53+
the CSP backend — never shipped to a browser. Used for `/api/v1/admin/*` calls.
54+
- TLS on both hosts. All calls below assume `https://`.
55+
- The mirrored KubeDB users must **not** have 2FA enabled — the password login endpoint
56+
rejects 2FA-enrolled users (HTTP 405). Since the CSP console is the identity provider,
57+
leave 2FA off on the mirror and enforce MFA in the CSP console instead.
58+
59+
Throughout, replace:
60+
61+
- `db.acme.com` → your KubeDB Platform subdomain
62+
- `2ed08ee9a855b8ff614ef1505b33c75a8836d55d` → your admin bearer token
63+
64+
---
65+
66+
## 3. Phase 1 — Provision the mirrored user (once, at CSP signup)
67+
68+
When a customer signs up (or is first granted database access) on the CSP console, the
69+
CSP backend creates the corresponding user in the KubeDB Platform. Do **not** use the public
70+
signup API — user creation is an admin operation.
71+
72+
The CSP backend generates a strong random password for the KubeDB identity and **stores
73+
it** (encrypted) alongside the CSP user record. This password is an internal credential
74+
used only for the server-side handoff in Phase 2; the end user never learns it.
75+
76+
**Create user**`POST /api/v1/admin/users`:
77+
78+
```bash
79+
curl -X POST 'https://db.acme.com/api/v1/admin/users' \
80+
-H 'Authorization: Bearer 2ed08ee9a855b8ff614ef1505b33c75a8836d55d' \
81+
-H 'Content-Type: application/json' \
82+
--data-raw '{
83+
"username": "acme-user-42",
84+
"full_name": "Jane Doe",
85+
"email": "jane@customer.example.com",
86+
"password": "<STRONG_RANDOM_PASSWORD_GENERATED_AND_STORED_BY_CSP>",
87+
"must_change_password": false,
88+
"send_notify": false
89+
}'
90+
```
91+
92+
Notes:
93+
94+
- Set `must_change_password: false` — a forced password change would break the automated
95+
login handoff.
96+
- Set `send_notify: false` — the KubeDB Platform should not email the user; the CSP owns all
97+
user communication.
98+
- Pick a stable, collision-free `username` (e.g. prefix with your tenant slug). Persist the
99+
mapping `CSP user ↔ KubeDB username` in the CSP database.
100+
101+
**Keep profile in sync (optional)** — when the user edits their name/email in the CSP
102+
console, mirror it with `POST /api/v1/admin/users/{username}/update`:
103+
104+
```bash
105+
curl -X POST 'https://db.acme.com/api/v1/admin/users/acme-user-42/update' \
106+
-H 'Authorization: Bearer 2ed08ee9a855b8ff614ef1505b33c75a8836d55d' \
107+
-H 'Content-Type: application/json' \
108+
--data-raw '{
109+
"name": "acme-user-42",
110+
"full_name": "Jane A. Doe",
111+
"email": "jane@customer.example.com",
112+
"keep_email_private": false,
113+
"language": "en",
114+
"description": "Mirrored from CSP console"
115+
}'
116+
```
117+
118+
**Rotate the password (optional)** — if the CSP rotates the stored KubeDB credential,
119+
push the new value with `POST /api/v1/admin/users/{username}/change-password`:
120+
121+
```bash
122+
curl -X POST 'https://db.acme.com/api/v1/admin/users/acme-user-42/change-password' \
123+
-H 'Authorization: Bearer 2ed08ee9a855b8ff614ef1505b33c75a8836d55d' \
124+
-H 'Content-Type: application/json' \
125+
--data-raw '{ "password": "<NEW_STRONG_RANDOM_PASSWORD>" }'
126+
```
127+
128+
![Provisioning the mirrored user](../images/csp-provisioning.svg)
129+
130+
---
131+
132+
## 4. Phase 2 — Session handoff (every time the user opens the KubeDB console)
133+
134+
The KubeDB Platform's login endpoint sets a **session cookie** plus a `_csrf` cookie. The
135+
trick is that these cookies are obtained by the CSP backend server-to-server, then delivered
136+
to the user's browser so it holds a valid `db.acme.com` session.
137+
138+
### 4.1 The login call
139+
140+
```bash
141+
curl -X POST 'https://db.acme.com/accounts/user/login' \
142+
-H 'content-type: application/x-www-form-urlencoded' \
143+
--data-raw 'user_name=acme-user-42&password=<STORED_KUBEDB_PASSWORD>&remember=on' \
144+
-c cookie.txt -D headers.txt
145+
```
146+
147+
The response's `Set-Cookie` headers (captured above in `headers.txt`, cookies jarred in
148+
`cookie.txt`) contain the session cookie and the `_csrf` cookie. Any **subsequent
149+
server-side API call** made with these cookies must also send the `_csrf` value in the
150+
`X-Csrf-Token` header:
151+
152+
```bash
153+
curl -X GET 'https://db.acme.com/api/v1/user/settings/profile' \
154+
-H 'Content-Type: application/json' \
155+
-H 'X-Csrf-Token: <VALUE_OF__csrf_COOKIE>' \
156+
-b cookie.txt
157+
```
158+
159+
### 4.2 Delivering the cookies to the browser
160+
161+
The CSP backend can log in, but a backend cannot set cookies in the browser for a domain
162+
other than the one that served the response. So the piece that **re-emits** the captured
163+
cookies must run on the KubeDB host itself. Host a small **launch endpoint on the KubeDB
164+
subdomain**, e.g. `https://db.acme.com/csp-sso/launch`, in one of two ways:
165+
166+
- **Reverse proxy** a path prefix (`db.acme.com/csp-sso/*`) on the KubeDB ingress to the CSP
167+
backend, or
168+
- run a **tiny CSP-owned handler co-located on the subdomain**.
169+
170+
Either way the launch endpoint is same-origin with the KubeDB console, so the `Set-Cookie`
171+
headers it returns are accepted by the browser for `db.acme.com`.
172+
173+
The end-to-end handoff:
174+
175+
1. User is already authenticated on `console.acme.com` and clicks **"Open Databases"**.
176+
2. The CSP console backend mints a **short-lived, single-use handoff token** (signed, ~30 s
177+
TTL) identifying the CSP user, and redirects the browser to
178+
`https://db.acme.com/csp-sso/launch?ticket=<handoff-token>`.
179+
3. The launch endpoint validates the ticket, looks up the mapped KubeDB username +
180+
stored password, and performs the **server-side login** (§4.1).
181+
4. The launch endpoint copies the login response's `Set-Cookie` headers onto its **own
182+
redirect response** to the browser, then `302`s to `https://db.acme.com/`.
183+
5. The browser now holds a valid KubeDB session cookie for `db.acme.com` and loads the
184+
KubeDB console fully authenticated — no login prompt.
185+
186+
![Session handoff / login process](../images/csp-session-handoff.svg)
187+
188+
### 4.3 Optional: shared-domain single sign-on
189+
190+
If your KubeDB Platform deployment is configured to set its session cookie with
191+
`Domain=.acme.com` (the shared parent domain) instead of the default host-only cookie, the
192+
same session is valid on **both** `console.acme.com` and `db.acme.com`. In that case the
193+
launch endpoint can set the cookie once and the user moves between the two consoles without
194+
re-handoff. This requires the KubeDB Platform cookie-domain setting; confirm with your
195+
deployment before relying on it. The per-launch flow in §4.2 works regardless and is the
196+
safe default.
197+
198+
---
199+
200+
## 5. Logout
201+
202+
When the user logs out of the CSP console, also terminate the KubeDB session so a shared
203+
browser can't keep the console open. Call the logout route with the user's cookies and CSRF
204+
token:
205+
206+
```bash
207+
curl -X GET 'https://db.acme.com/accounts/user/logout' \
208+
-H 'Content-Type: application/json' \
209+
-H 'X-Csrf-Token: <VALUE_OF__csrf_COOKIE>' \
210+
-b cookie.txt
211+
```
212+
213+
If you use shared-domain SSO (§4.3), clear the `.acme.com` cookie on logout as well.
214+
215+
---
216+
217+
## 6. API summary
218+
219+
| Step | When | Method & path | Auth |
220+
|------|------|---------------|------|
221+
| Create mirrored user | CSP signup (once) | `POST /api/v1/admin/users` | Admin bearer token |
222+
| Sync profile | On CSP profile edit | `POST /api/v1/admin/users/{username}/update` | Admin bearer token |
223+
| Rotate password | On credential rotation | `POST /api/v1/admin/users/{username}/change-password` | Admin bearer token |
224+
| Server-side login | Each console open | `POST /accounts/user/login` (form-encoded) | Mirror user password → sets cookies |
225+
| Authenticated API call | As needed | any `/api/v1/...` | Session cookie + `X-Csrf-Token: <_csrf>` |
226+
| Logout | On CSP logout | `GET /accounts/user/logout` | Session cookie + `X-Csrf-Token: <_csrf>` |
227+
228+
---
229+
230+
## 7. Security checklist
231+
232+
- **Admin bearer token** stays server-side, in a secret manager. Rotate periodically. Its
233+
compromise means full control of every mirrored user.
234+
- **Stored KubeDB passwords** are internal credentials: generate them randomly (high
235+
entropy), encrypt at rest, and never expose them to the browser or the end user.
236+
- **Handoff ticket** must be short-lived (seconds), single-use, signed/encrypted, and bound
237+
to the authenticated CSP session — it is the only thing standing between a URL and a KubeDB
238+
session. Never put the KubeDB password in the URL.
239+
- **Cookie flags**: ensure the session cookies delivered to the browser are `Secure`,
240+
`HttpOnly`, and `SameSite=Lax` (Lax suffices because `console.acme.com``db.acme.com`
241+
is same-site and the handoff is a top-level navigation).
242+
- **TLS everywhere**.
243+
- **No 2FA on mirrors** (see §2); enforce MFA in the CSP console instead.
244+
- **Logout propagation** (§5) so a KubeDB session never outlives the CSP session on a shared
245+
device.
246+
- **Deprovisioning**: when a CSP user is disabled/deleted, disable or delete the mirrored
247+
KubeDB user via the admin API so access is revoked in both places.

0 commit comments

Comments
 (0)