ci: enable oidc for jenkins/gitops/gitea

This commit is contained in:
Brad Stein 2025-12-14 20:58:57 -03:00
parent 04602a2914
commit a46226bb0a
7 changed files with 136 additions and 34 deletions

View File

@ -55,6 +55,12 @@ spec:
value: "master"
- name: ROOT_URL
value: "https://scm.bstein.dev"
- name: GITEA__service__ENABLE_OPENID_SIGNIN
value: "true"
- name: GITEA__service__ALLOW_ONLY_EXTERNAL_REGISTRATION
value: "true"
- name: GITEA__service__DISABLE_REGISTRATION
value: "false"
- name: DB_TYPE
value: "postgres"
- name: DB_HOST

View File

@ -7,3 +7,4 @@ resources:
- service.yaml
- pvc.yaml
- ingress.yaml
- oidc-job.yaml

View File

@ -0,0 +1,85 @@
# services/gitea/oidc-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: gitea-oidc-bootstrap
namespace: gitea
spec:
ttlSecondsAfterFinished: 1800
backoffLimit: 1
template:
metadata:
labels:
app: gitea
job: gitea-oidc-bootstrap
spec:
securityContext:
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: gitea
topologyKey: kubernetes.io/hostname
restartPolicy: OnFailure
volumes:
- name: gitea-data
persistentVolumeClaim:
claimName: gitea-data
containers:
- name: gitea-oidc-bootstrap
image: gitea/gitea:1.23
imagePullPolicy: IfNotPresent
volumeMounts:
- name: gitea-data
mountPath: /data
env:
- name: CLIENT_ID
valueFrom:
secretKeyRef:
name: gitea-oidc
key: client_id
- name: CLIENT_SECRET
valueFrom:
secretKeyRef:
name: gitea-oidc
key: client_secret
- name: DISCOVERY_URL
valueFrom:
secretKeyRef:
name: gitea-oidc
key: openid_auto_discovery_url
command:
- /bin/bash
- -c
- |
set -euo pipefail
APPINI=/data/gitea/conf/app.ini
BIN=/usr/local/bin/gitea
list="$($BIN -c "$APPINI" admin auth list)"
id=$(echo "$list" | awk '$2=="keycloak"{print $1}')
if [ -n "$id" ]; then
echo "Updating existing auth source id=$id"
$BIN -c "$APPINI" admin auth update-oauth \
--id "$id" \
--name keycloak \
--provider openidConnect \
--key "$CLIENT_ID" \
--secret "$CLIENT_SECRET" \
--auto-discover-url "$DISCOVERY_URL" \
--scopes "openid profile email" \
--group-claim-name groups
else
echo "Creating keycloak auth source"
$BIN -c "$APPINI" admin auth add-oauth \
--name keycloak \
--provider openidConnect \
--key "$CLIENT_ID" \
--secret "$CLIENT_SECRET" \
--auto-discover-url "$DISCOVERY_URL" \
--scopes "openid profile email" \
--group-claim-name groups
fi

View File

@ -23,13 +23,10 @@ spec:
remediateLastFailure: true
cleanupOnFail: true
values:
additionalArgs:
- --auth-methods=oidc
adminUser:
create: true
createClusterRole: true
createSecret: true
username: admin
# bcrypt hash for temporary password "G1tOps!2025" (rotate after login)
passwordHash: "$2y$12$wDEOzR1Gc2dbvNSJ3ZXNdOBVFEjC6YASIxnZmHIbO.W1m0fie/QVi"
create: false
ingress:
enabled: true
className: traefik
@ -45,5 +42,7 @@ spec:
- secretName: gitops-ui-tls
hosts:
- cd.bstein.dev
oidcSecret:
create: false
metrics:
enabled: true

View File

@ -7,3 +7,4 @@ resources:
- helmrelease.yaml
- certificate.yaml
- networkpolicy-acme.yaml
- rbac.yaml

View File

@ -0,0 +1,15 @@
# services/gitops-ui/rbac.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: gitops-admins
labels:
app.kubernetes.io/name: weave-gitops
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: Group
name: admin
apiGroup: rbac.authorization.k8s.io

View File

@ -44,7 +44,7 @@ spec:
- oic-auth
containerEnv:
- name: ENABLE_OIDC
value: "false"
value: "true"
- name: OIDC_ISSUER
value: "https://sso.bstein.dev/realms/atlas"
- name: OIDC_CLIENT_ID
@ -85,50 +85,45 @@ spec:
optional: true
initScripts:
oidc.groovy: |
import hudson.util.Secret
import jenkins.model.IdStrategy
import jenkins.model.Jenkins
import org.jenkinsci.plugins.oic.OicSecurityRealm
import org.jenkinsci.plugins.oic.OicServerWellKnownConfiguration
def env = System.getenv()
def enable = (env['ENABLE_OIDC'] ?: 'false').toBoolean()
if (!enable) {
if (!(env['ENABLE_OIDC'] ?: 'false').toBoolean()) {
println("OIDC disabled (ENABLE_OIDC=false); keeping default security realm")
return
}
def required = ['OIDC_CLIENT_ID','OIDC_CLIENT_SECRET','OIDC_AUTH_URL','OIDC_TOKEN_URL','OIDC_USERINFO_URL']
def required = ['OIDC_CLIENT_ID','OIDC_CLIENT_SECRET','OIDC_ISSUER']
if (!required.every { env[it] }) {
println("OIDC enabled but missing vars: ${required.findAll { !env[it] }}")
return
}
try {
def wellKnown = "${env['OIDC_ISSUER']}/.well-known/openid-configuration"
def serverCfg = new OicServerWellKnownConfiguration(wellKnown)
serverCfg.setScopesOverride('openid profile email')
def realm = new OicSecurityRealm(
env['OIDC_CLIENT_ID'],
env['OIDC_CLIENT_SECRET'],
env['OIDC_TOKEN_URL'],
env['OIDC_AUTH_URL'],
env['OIDC_USERINFO_URL'],
true, // logout from provider
env['OIDC_LOGOUT_URL'] ?: "",
"", // postLogoutRedirectUrl
"openid email profile",
"", // prompt
"preferred_username",
"name",
"email",
false, // disableSslVerification
true, // escapeHatchEnabled
"admin",
"", // escapeHatchSecret
"", // escapeHatchGroup
true, // loadUserInfo
true, // validateScopes
false, // allowUnsignedIdTokens
false, // enforceValidIssuers
env['OIDC_ISSUER'] ?: "",
false // disableUserInfoFetch
Secret.fromString(env['OIDC_CLIENT_SECRET']),
serverCfg,
false,
IdStrategy.CASE_INSENSITIVE,
IdStrategy.CASE_INSENSITIVE
)
realm.setLogoutFromOpenidProvider(true)
realm.setPostLogoutRedirectUrl('https://ci.bstein.dev')
realm.setUserNameField('preferred_username')
realm.setFullNameFieldName('name')
realm.setEmailFieldName('email')
realm.setGroupsFieldName('groups')
realm.setRootURLFromRequest(true)
realm.setSendScopesInTokenRequest(true)
def j = Jenkins.get()
j.setSecurityRealm(realm)
j.save()
println("Configured OIDC realm from init script")
println("Configured OIDC realm from init script (well-known)")
} catch (Exception e) {
println("Failed to configure OIDC realm: ${e}")
}