mirror of
https://github.com/dredx/prole.git
synced 2026-09-23 12:03:59 +00:00
- Implement Google OIDC support in Authority module via GoogleOAuthService - Update AuthProperties and application.yml with OIDC configuration - Add oidc-setup.md documentation for GKE/Google Cloud setup - Update etc/init_knoe_auth.sh to handle OIDC secrets and path-B configuration - Configure knoe-auth-deployment.yaml and gke.cfg for production auth Co-authored-by: Junie <junie@jetbrains.com>
290 lines
12 KiB
Markdown
290 lines
12 KiB
Markdown
# Google Workspace OIDC setup for knoe on GKE
|
|
|
|
End-to-end wiring for a Google Workspace user (e.g. `chrisfu@knoey.com`) to
|
|
sign into `git.knoe.dev` and have GitLab JIT-create their user account.
|
|
|
|
## Status and path decision
|
|
|
|
Investigation (April 2026) showed that `knoe-auth` — the Spring app behind
|
|
`api.knoe.dev/auth` — does not currently implement an OIDC Provider. It only
|
|
serves Kerberos-based `/auth/login`, `/auth/spnego`, `/auth/form`,
|
|
`/auth/verify`. There is no `/.well-known/openid-configuration`, no authorize
|
|
endpoint, no token endpoint, and the Google OAuth env vars wired to the pod
|
|
(`GOOGLE_CLIENT_ID`, `OIDC_ISSUER_URL`, …) are unread by the Java code.
|
|
|
|
Two paths exist:
|
|
|
|
| Path | Description | Status |
|
|
|---|---|---|
|
|
| **A** | GitLab talks OIDC directly to Google Workspace. Issuer = `https://accounts.google.com`. knoe-auth is out of the loop. | Deprecated — moved to Path B |
|
|
| **B** | GitLab → knoe-auth (OIDC OP) → Google. Issuer = `https://api.knoe.dev/auth`. Aligns with the Kerberos/unified-SSO long-term plan. | **Active — see docs/oidc-path-b.md** |
|
|
|
|
When Path B is ready (implemented April 2026), `GITLAB_OIDC_ISSUER` is set to `https://api.knoe.dev/auth`.
|
|
|
|
---
|
|
|
|
## 1. Path A architecture
|
|
|
|
```
|
|
┌────────────┐ 1. browse ┌──────────────────────┐
|
|
│ Browser │ ──────────────────────► │ git.knoe.dev │ GKE ingress, namespace gitlab
|
|
│ chrisfu@.. │ │ gitlab-frontdoor │ (GCE LB, gitlab-managed-cert)
|
|
└──────┬─────┘ └────────┬─────────────┘
|
|
│ │ 2. unauth → redirect to Google
|
|
│ ▼
|
|
│ ┌─────────────────────┐
|
|
└────── 3. Google login ─────► │ accounts.google. │ Google Workspace
|
|
│ com │ (knoey.com domain)
|
|
└────────┬────────────┘
|
|
│ 4. id_token → redirect to GitLab
|
|
▼
|
|
git.knoe.dev/users/auth/openid_connect/callback
|
|
│ 5. id_token { email: chrisfu@knoey.com }
|
|
▼
|
|
GitLab JIT creates user "chrisfu"
|
|
```
|
|
|
|
---
|
|
|
|
## 2. Secrets — the indirection pattern
|
|
|
|
`conf/gke.cfg` does **not** hold plaintext OAuth client credentials. Instead:
|
|
|
|
```ini
|
|
GITLAB_OIDC_CLIENT_ID = secretref://google-oidc-client-id
|
|
GITLAB_OIDC_CLIENT_SECRET = secretref://google-oidc-client-secret
|
|
GITLAB_OIDC_ISSUER = https://accounts.google.com
|
|
```
|
|
|
|
The `secretref://<name>` URI is resolved at installer-run time by
|
|
`knoe/core/actions.py:_resolve_secretref_value`. Resolution order:
|
|
|
|
1. **Environment variable** (checked first). For these two refs the loader
|
|
explicitly walks: `GITLAB_OIDC_CLIENT_ID`, `OIDC_CLIENT_ID`,
|
|
`GOOGLE_OIDC_CLIENT_ID`, `GOOGLE_CLIENT_ID` (and the `_SECRET` variants).
|
|
2. **File at `etc/secrets/<name>`** (preferred for local dev). The
|
|
`etc/secrets/` directory is gitignored (`.gitignore:46`), so values here
|
|
never enter version control.
|
|
3. **File at `secrets/<name>`** or `${KNOE_SERVICE}/secrets/<name>`.
|
|
|
|
For a partial public fork of this repo, the sensitive values are absent from
|
|
git and are only populated at deploy time on a trusted machine.
|
|
|
|
Only one k8s secret is actually applied: `gitlab-google-oidc` in the `gitlab`
|
|
namespace, rendered by `etc/init_gitlab.sh` from
|
|
`deploy/gcp/gke/gitlab-google-oidc-secret.example.yaml` via `envsubst`. The
|
|
`knoe-auth-google-oidc` secret template exists for Path B and can stay empty
|
|
or unapplied until that path ships.
|
|
|
|
---
|
|
|
|
## 3. Google Cloud Console — OAuth 2.0 client setup
|
|
|
|
You've already created the OAuth client (`knoe.dev GitLab`, April 18 2026).
|
|
Confirm it has these settings in **GCP Console → APIs & Services →
|
|
Credentials**:
|
|
|
|
- Application type: **Web application**
|
|
- Authorized JavaScript origins:
|
|
- `https://git.knoe.dev`
|
|
- `https://api.knoe.dev` *(optional — only needed when Path B ships)*
|
|
- Authorized redirect URIs:
|
|
- `https://git.knoe.dev/users/auth/openid_connect/callback` *(primary)*
|
|
- `https://api.knoe.dev/auth/callback/google` *(pre-registered for Path B)*
|
|
|
|
For Path A only the first redirect URI is consulted. The second is harmless.
|
|
|
|
OAuth consent screen configuration (separate page):
|
|
|
|
- User Type: **Internal** (restricts to the `knoey.com` Workspace).
|
|
- Scopes: `openid`, `email`, `profile`.
|
|
|
|
---
|
|
|
|
## 4. Populate the client credentials locally (do NOT commit)
|
|
|
|
After rotating the client secret (see §6), put the values into local files:
|
|
|
|
```bash
|
|
mkdir -p etc/secrets && chmod 0700 etc/secrets
|
|
printf '%s' '<CLIENT_ID>' > etc/secrets/google-oidc-client-id
|
|
printf '%s' '<CLIENT_SECRET>' > etc/secrets/google-oidc-client-secret
|
|
chmod 0600 etc/secrets/google-oidc-client-*
|
|
```
|
|
|
|
Verify `etc/secrets/.keep` is the only file from that directory that `git status`
|
|
will ever show (`.keep` is allowlisted by `.gitignore`).
|
|
|
|
Alternative: export as env vars before running `./install.sh` or `./deploy.sh`:
|
|
|
|
```bash
|
|
export GITLAB_OIDC_CLIENT_ID='200699...apps.googleusercontent.com'
|
|
export GITLAB_OIDC_CLIENT_SECRET='<new secret from GCP console>'
|
|
```
|
|
|
|
---
|
|
|
|
## 5. Apply / re-apply the `gitlab-google-oidc` secret
|
|
|
|
Either via the installer (picks up the new issuer from `conf/gke.cfg`):
|
|
|
|
```bash
|
|
./deploy.sh -S -c conf/gke.cfg # or the scoped milestone for GitLab OIDC only
|
|
```
|
|
|
|
Or by hand for a targeted refresh:
|
|
|
|
```bash
|
|
APP_CTX=gke_plenary-truck-485623-p7_us-west3_knoe-dev-0
|
|
|
|
GITLAB_OIDC_PROVIDER_NAME=openid_connect \
|
|
GITLAB_OIDC_ISSUER=https://accounts.google.com \
|
|
GITLAB_OIDC_CLIENT_ID="$(cat etc/secrets/google-oidc-client-id)" \
|
|
GITLAB_OIDC_CLIENT_SECRET="$(cat etc/secrets/google-oidc-client-secret)" \
|
|
GITLAB_OIDC_REDIRECT_URI=https://git.knoe.dev/users/auth/openid_connect/callback \
|
|
envsubst < deploy/gcp/gke/gitlab-google-oidc-secret.example.yaml \
|
|
| kubectl --context=$APP_CTX apply -n gitlab -f -
|
|
|
|
kubectl --context=$APP_CTX -n gitlab rollout restart deploy/gitlab-webservice-default
|
|
```
|
|
|
|
---
|
|
|
|
## 6. Leaked-secret remediation (required before any push)
|
|
|
|
The value `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` lived in
|
|
`conf/gke.cfg` as plaintext and is present in the git history. Even with a
|
|
private upstream, portions of this repo will be forked publicly, so full
|
|
remediation is required.
|
|
|
|
### 6a. Rotate the secret in GCP (user action)
|
|
|
|
1. GCP Console → APIs & Services → Credentials.
|
|
2. Click the **`knoe.dev GitLab`** OAuth 2.0 client.
|
|
3. Click **Reset secret** (or **Rotate client secret**). Copy the new value.
|
|
4. Save the new value into `etc/secrets/google-oidc-client-secret` per §4.
|
|
5. Revoke the old client secret when prompted (or confirm the rotation
|
|
invalidates it).
|
|
|
|
Review Google Workspace Admin → Security → Investigation → OAuth grants /
|
|
Token usage logs for the old client ID between the commit timestamp and the
|
|
rotation timestamp — if any unfamiliar issuance, the secret was actively
|
|
misused.
|
|
|
|
### 6b. Scrub it from git history
|
|
|
|
The working tree is already clean (see commit that introduced the
|
|
`secretref://` change). History still contains it. Use
|
|
[`git filter-repo`](https://github.com/newren/git-filter-repo) with a
|
|
replacements file:
|
|
|
|
```bash
|
|
# Install if needed:
|
|
brew install git-filter-repo # macOS
|
|
# Or: pip install --user git-filter-repo
|
|
|
|
cat > /tmp/knoe-secret-replacements.txt <<'EOF'
|
|
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==>REDACTED-CLIENT-SECRET
|
|
EOF
|
|
|
|
# Run from the repo root. filter-repo rewrites the entire history.
|
|
git filter-repo --replace-text /tmp/knoe-secret-replacements.txt
|
|
|
|
# Verify the string is gone:
|
|
git log --all -S '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' --oneline
|
|
# Expect: no output.
|
|
```
|
|
|
|
Coordinate with any teammate who has clones — they'll need to re-clone or
|
|
rebase onto the rewritten history. Force-push to all remotes:
|
|
|
|
```bash
|
|
git push --force-with-lease origin --all
|
|
git push --force-with-lease origin --tags
|
|
```
|
|
|
|
### 6c. Pre-commit hedge
|
|
|
|
Add a pre-commit hook (or `gitleaks` in CI) to reject any commit that
|
|
reintroduces a `GOCSPX-…` or `AIza…` or `-----BEGIN PRIVATE KEY-----`
|
|
literal. Low-friction way: `pre-commit` framework with the `gitleaks` hook.
|
|
|
|
---
|
|
|
|
## 7. Pre-DNS verification (can run now, Path A)
|
|
|
|
```bash
|
|
APP_CTX=gke_plenary-truck-485623-p7_us-west3_knoe-dev-0
|
|
|
|
# a) Is the gitlab-google-oidc secret wired to the new issuer?
|
|
kubectl --context=$APP_CTX -n gitlab get secret gitlab-google-oidc \
|
|
-o jsonpath='{.data.provider}' | base64 -d | head -20
|
|
# expect: issuer: "https://accounts.google.com" and uid_field: email
|
|
# If it still shows https://api.knoe.dev/auth, re-run §5 to re-apply.
|
|
|
|
# b) Does Google's OIDC discovery look sane? (independent of our cluster)
|
|
curl -sS https://accounts.google.com/.well-known/openid-configuration | jq '.issuer, .authorization_endpoint, .token_endpoint'
|
|
# expect: "https://accounts.google.com", /o/oauth2/v2/auth, /token endpoints.
|
|
|
|
# c) Does the GitLab CR reference the secret for JIT signin?
|
|
kubectl --context=$APP_CTX -n gitlab get gitlab gitlab -o yaml \
|
|
| grep -A4 omniauth
|
|
# expect: allowSingleSignOn: [openid_connect], blockAutoCreatedUsers: false,
|
|
# providers: [{ secret: gitlab-google-oidc, key: provider }]
|
|
```
|
|
|
|
---
|
|
|
|
## 8. Post-DNS verification (once git.knoe.dev resolves)
|
|
|
|
```bash
|
|
curl -sI http://git.knoe.dev | head -3 # expect: 301 → https://
|
|
curl -sI https://git.knoe.dev | head -3 # expect: 302 → /users/sign_in
|
|
curl -sL https://git.knoe.dev/users/sign_in | grep -oE 'openid_connect[^"]*' | head
|
|
# expect an OmniAuth link pointing at /users/auth/openid_connect
|
|
```
|
|
|
|
Then in a real browser, click **Sign in with Google Workspace**. Flow:
|
|
|
|
```
|
|
git.knoe.dev/users/sign_in
|
|
→ GET /users/auth/openid_connect
|
|
→ 302 https://accounts.google.com/o/oauth2/v2/auth?client_id=...
|
|
→ (sign in as chrisfu@knoey.com)
|
|
→ 302 https://git.knoe.dev/users/auth/openid_connect/callback?code=...
|
|
→ GitLab exchanges code, receives id_token { email: chrisfu@knoey.com }
|
|
→ GitLab JIT creates user "chrisfu"
|
|
→ lands on /
|
|
```
|
|
|
|
If GitLab 500s on the callback, check:
|
|
|
|
```bash
|
|
kubectl --context=$APP_CTX -n gitlab logs -l app=webservice --tail=200 \
|
|
| grep -i 'openid\|oidc\|omniauth'
|
|
```
|
|
|
|
Common causes:
|
|
- Clock skew between cluster and Google — check node NTP.
|
|
- `uid_field` mismatch with claims — the template uses `uid_field: email`
|
|
which maps to the Google `email` claim. If Google returns
|
|
`email_verified: false`, GitLab may reject the account; verified for
|
|
Workspace users by default.
|
|
- GitLab refuses to auto-create with message "Sign-in using Google
|
|
Workspace auth is not allowed for your username" — the `allowSingleSignOn`
|
|
list must include `openid_connect` and `blockAutoCreatedUsers` must be
|
|
false (checked in §7c).
|
|
|
|
---
|
|
|
|
## 9. Open items
|
|
|
|
- **Task #6** — Fork `github:dredx/knoe` → `git.knoe.dev/chrisfu/knoe.dev`.
|
|
After first sign-in, create the group, import the mirror.
|
|
- **Task #7** — Kerberos backing (Path B). Design doc TBD. When ready, swap
|
|
`GITLAB_OIDC_ISSUER` back to `https://api.knoe.dev/auth` and implement the
|
|
OIDC OP surface inside `knoe-auth` (or adopt Keycloak/Dex).
|
|
- **Task #10** — Edge-auth strategy. The nginx `auth-url` annotations on the
|
|
frontdoor ingress are no-ops on GCE. If edge-enforced auth is desired,
|
|
move to IAP + BackendConfig or an oauth2-proxy sidecar.
|