prole/docs/oidc-setup.md
chrisfu 3728889e25 Phase 1: OIDC provider integration and GKE auth deployment
- 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>
2026-04-28 12:22:45 -07:00

12 KiB

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:

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:

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:

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):

./deploy.sh -S -c conf/gke.cfg   # or the scoped milestone for GitLab OIDC only

Or by hand for a targeted refresh:

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 with a replacements file:

# 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:

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)

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)

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:

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/knoegit.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.