- 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>
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:
- 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_SECRETvariants). - File at
etc/secrets/<name>(preferred for local dev). Theetc/secrets/directory is gitignored (.gitignore:46), so values here never enter version control. - 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.devhttps://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.comWorkspace). - 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)
- GCP Console → APIs & Services → Credentials.
- Click the
knoe.dev GitLabOAuth 2.0 client. - Click Reset secret (or Rotate client secret). Copy the new value.
- Save the new value into
etc/secrets/google-oidc-client-secretper §4. - 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_fieldmismatch with claims — the template usesuid_field: emailwhich maps to the Googleemailclaim. If Google returnsemail_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
allowSingleSignOnlist must includeopenid_connectandblockAutoCreatedUsersmust 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_ISSUERback tohttps://api.knoe.dev/authand implement the OIDC OP surface insideknoe-auth(or adopt Keycloak/Dex). - Task #10 — Edge-auth strategy. The nginx
auth-urlannotations on the frontdoor ingress are no-ops on GCE. If edge-enforced auth is desired, move to IAP + BackendConfig or an oauth2-proxy sidecar.