Compare commits

...

26 commits

Author SHA1 Message Date
2148ba8925 [Skip-CI] Add initial integration notes 2024-08-30 17:13:37 +02:00
e7bd7fc964 Fix keycloak weird logins 2024-08-30 16:56:59 +02:00
81cc7510c1 Revert to single service/ingress and no management interface 2024-08-29 16:56:08 +02:00
4ac839e015 added ingress and service for management-interface 2024-08-29 12:14:19 +02:00
9206d9f8ad Update configmap and test 2024-08-29 12:08:11 +02:00
30a93b11f7 Merge branch 'kc-upgrade-and-integration' of ssh://repo.prod.meissa.de:2222/meissa/c4k-keycloak into kc-upgrade-and-integration 2024-08-29 11:40:38 +02:00
b8d0e9bc3f Update image version 2024-08-29 11:38:02 +02:00
95f618a3be fix service-port to 80 2024-08-29 11:16:01 +02:00
b9c99db1b2 rename burst-rate to max-concurrent-requests 2024-08-29 10:45:52 +02:00
2e40b2fc48 Fix test 2024-08-28 17:12:08 +02:00
89f0101442 Update port name 2024-08-28 16:59:42 +02:00
f3bd608ed1 Update port no 2024-08-28 16:59:28 +02:00
d0ca62856e Update secret name 2024-08-28 16:44:54 +02:00
552ca1b6c4 Add keys to spec and to ingress generation 2024-08-28 16:35:02 +02:00
efad4b46a9 Add defaults for ratelimit 2024-08-28 16:34:21 +02:00
60049acd07 Fix number 2024-08-28 15:50:14 +02:00
ddcc43ddd9 Fix cert issue 2024-08-28 15:42:27 +02:00
8d7c010733 Update keyword order 2024-08-28 15:07:26 +02:00
9d518ba4be Implement and test configmap generation 2024-08-28 15:07:26 +02:00
7037d8a92a Update secret generation and tests 2024-08-28 14:48:54 +02:00
aa9bfc482d Update and test deployment generation 2024-08-28 14:24:23 +02:00
ce9d51e1cd [Skip-CI] Use ratelimit ingress 2024-08-27 16:31:52 +02:00
1d22c20da9 Add recommended key 2024-08-27 16:26:55 +02:00
861b43b4bf Add more todos 2024-08-27 16:26:42 +02:00
f98d4ab9b5 Get env from configmap and secret 2024-08-27 15:40:16 +02:00
59208e8829 [Skip-CI] Remove opt and issuer 2024-08-23 10:37:18 +02:00
7 changed files with 135 additions and 134 deletions

28
doc/IntegrationNotes.md Normal file
View file

@ -0,0 +1,28 @@
- ## Outline - Keycloak&Forgejo integration
- ### Forgejo-Seite
- Forgejo Test mit v8.0 hochziehen
- ### Config
- https://s3lph.me/ldap-to-oidc-migration-1-forgejo.html
- OpenID Connect Auto Discovery URL finden
- https://keycloak.discourse.group/t/changes-in-oidc-token-endpoints/18024/3
- `https://<full server dns name>/realms/<realm_name>`
- macht aber eine Zertifikatsprüfung -> tut nur mit prod zert
- key von keycloak eintragen
- forgejo-test user anlegen
- oidc auth source festlegen
- ## Keycloak-Seite
- Keycloak mit c4k/keycloak kc-upgrade-and-integration Branch hochziehen
- Admin login über keycloak.test.meissa.de/realms/master/account/
- [Getting started with kubernetes](https://www.keycloak.org/getting-started/getting-started-kube)
- Achtung URL für Userlogin ist <hostname>/realms/<realmname>/account
- Achtung: Pro realm angelegte user können sich auch nur pro realm einloggen
- Im master realm: https://keycloak.test.meissa.de/realms/master/account:
- Meissa realm anlegen
- "Forgejotest" user anlegen
- Forgejo-client anlegen
- Root url ist schema + hostname
- Client secret anlegen
- Schalter bei Client Authentication umlegen
- Capability config
- https://stackoverflow.com/questions/44752273/do-keycloak-clients-have-a-client-secret/69726692#69726692
- Keys anlegen und public key bei forgejo eintragen

View file

@ -19,7 +19,9 @@
:postgres-size :2gb :postgres-size :2gb
:db-name "keycloak" :db-name "keycloak"
:pv-storage-size-gb 30 :pv-storage-size-gb 30
:pvc-storage-class-name default-storage-class}) :pvc-storage-class-name default-storage-class
:max-rate 100
:max-concurrent-requests 50})
(def config? (s/keys :req-un [::kc/fqdn] (def config? (s/keys :req-un [::kc/fqdn]
:opt-un [::kc/issuer :opt-un [::kc/issuer
@ -38,9 +40,10 @@
(cm/concat-vec (cm/concat-vec
(ns/generate config) (ns/generate config)
(postgres/generate-config config) (postgres/generate-config config)
[(kc/generate-service config) [(kc/generate-configmap config)
(kc/generate-service config)
(kc/generate-deployment config)] (kc/generate-deployment config)]
(kc/generate-ingress config) (kc/generate-ratelimit-ingress config)
(when (contains? config :mon-cfg) (when (contains? config :mon-cfg)
(mon/generate-config)))))) (mon/generate-config))))))

View file

@ -1,53 +1,70 @@
(ns dda.c4k-keycloak.keycloak (ns dda.c4k-keycloak.keycloak
(:require (:require
[clojure.spec.alpha :as s] [clojure.spec.alpha :as s]
#?(:cljs [dda.c4k-common.macros :refer-macros [inline-resources]]) #?(:cljs [dda.c4k-common.macros :refer-macros [inline-resources]])
#?(:clj [orchestra.core :refer [defn-spec]] #?(:clj [orchestra.core :refer [defn-spec]]
:cljs [orchestra.core :refer-macros [defn-spec]]) :cljs [orchestra.core :refer-macros [defn-spec]])
[dda.c4k-common.yaml :as yaml] [dda.c4k-common.yaml :as yaml]
[dda.c4k-common.common :as cm] [dda.c4k-common.common :as cm]
[dda.c4k-common.base64 :as b64] [dda.c4k-common.base64 :as b64]
[dda.c4k-common.ingress :as ing] [dda.c4k-common.ingress :as ing]
[dda.c4k-common.predicate :as cp])) [dda.c4k-common.predicate :as cp]))
(s/def ::fqdn cp/fqdn-string?) (s/def ::fqdn cp/fqdn-string?)
(s/def ::namespace string?)
(s/def ::issuer cp/letsencrypt-issuer?) (s/def ::issuer cp/letsencrypt-issuer?)
(s/def ::namespace string?)
(s/def ::max-rate int?)
(s/def ::max-concurrent-requests int?)
(s/def ::keycloak-admin-user cp/bash-env-string?) (s/def ::keycloak-admin-user cp/bash-env-string?)
(s/def ::keycloak-admin-password cp/bash-env-string?) (s/def ::keycloak-admin-password cp/bash-env-string?)
(def config? (s/keys :req-un [::fqdn] (def config? (s/keys :req-un [::fqdn]
:opt-un [::issuer :opt-un [::issuer
::namespace])) ::namespace
::max-rate
::max-concurrent-requests]))
(def auth? (s/keys :req-un [::keycloak-admin-user (def auth? (s/keys :req-un [::keycloak-admin-user
::keycloak-admin-password])) ::keycloak-admin-password]))
#?(:cljs #?(:cljs
(defmethod yaml/load-resource :keycloak [resource-name] (defmethod yaml/load-resource :keycloak [resource-name]
(get (inline-resources "keycloak") resource-name))) (get (inline-resources "keycloak") resource-name)))
(defn-spec generate-ingress cp/map-or-seq? (defn-spec generate-ratelimit-ingress seq?
[config config?] [config config?]
(ing/generate-ingress-and-cert (let [{:keys [fqdn max-rate max-concurrent-requests namespace]} config]
(merge (ing/generate-simple-ingress (merge
{:service-name "keycloak" {:service-name "keycloak"
:service-port 80 :service-port 80
:fqdns [(:fqdn config)]} :fqdns [fqdn]
config))) :average-rate max-rate
:burst-rate max-concurrent-requests
:namespace namespace}
config))))
(defn-spec generate-secret cp/map-or-seq? (defn-spec generate-secret cp/map-or-seq?
[config config? [config config?
auth auth?] auth auth?]
(let [{:keys [namespace]} config (let [{:keys [namespace]} config
{:keys [keycloak-admin-user keycloak-admin-password]} auth] {:keys [keycloak-admin-user keycloak-admin-password postgres-db-user postgres-db-password]} auth]
(-> (->
(yaml/load-as-edn "keycloak/secret.yaml") (yaml/load-as-edn "keycloak/secret.yaml")
(cm/replace-all-matching "NAMESPACE" namespace) (cm/replace-all-matching "NAMESPACE" namespace)
(cm/replace-key-value :keycloak-user (b64/encode keycloak-admin-user)) (cm/replace-all-matching "DBUSER" (b64/encode postgres-db-user))
(cm/replace-key-value :keycloak-password (b64/encode keycloak-admin-password))))) (cm/replace-all-matching "DBPW" (b64/encode postgres-db-password))
(cm/replace-all-matching "ADMIN_USER" (b64/encode keycloak-admin-user))
(cm/replace-all-matching "ADMIN_PASS" (b64/encode keycloak-admin-password)))))
(defn-spec generate-service cp/map-or-seq? (defn-spec generate-configmap cp/map-or-seq?
[config config?]
(let [{:keys [namespace fqdn]} config]
(->
(yaml/load-as-edn "keycloak/configmap.yaml")
(cm/replace-all-matching "NAMESPACE" namespace)
(cm/replace-all-matching "FQDN" fqdn))))
(defn-spec generate-service cp/map-or-seq?
[config config?] [config config?]
(let [{:keys [namespace]} config] (let [{:keys [namespace]} config]
(-> (->
@ -57,8 +74,7 @@
(defn-spec generate-deployment cp/map-or-seq? (defn-spec generate-deployment cp/map-or-seq?
[config config?] [config config?]
(let [{:keys [fqdn namespace]} config] (let [{:keys [fqdn namespace]} config]
(-> (->
(yaml/load-as-edn "keycloak/deployment.yaml") (yaml/load-as-edn "keycloak/deployment.yaml")
(cm/replace-all-matching "NAMESPACE" namespace) (cm/replace-all-matching "NAMESPACE" namespace))))
(cm/replace-all-matching "FQDN" fqdn))))

View file

@ -0,0 +1,22 @@
# Hostname config:
# https://www.keycloak.org/server/hostname#_exposing_the_administration_console_on_a_separate_hostname
apiVersion: v1
kind: ConfigMap
metadata:
name: keycloak-env
namespace: NAMESPACE
data:
KC_HTTPS_CERTIFICATE_FILE: /etc/certs/tls.crt
KC_HTTPS_CERTIFICATE_KEY_FILE: /etc/certs/tls.key
# We trust our traefik to properly set headers
# see: https://www.keycloak.org/server/reverseproxy & https://www.keycloak.org/server/hostname
# and: https://doc.traefik.io/traefik/getting-started/faq/#what-are-the-forwarded-headers-when-proxying-http-requests
KC_HOSTNAME: FQDN
KC_PROXY_HEADERS: xforwarded
KC_DB: postgres
KC_DB_URL_HOST: postgresql-service
KC_DB_URL_PORT: "5432"
# We need to enable http, as we are behind an ingress
KC_HTTP_ENABLED: "true"
# TODO Maybe also enable load shedding
# KC_HTTP_MAX_QUEUED_REQUESTS: 2000

View file

@ -15,9 +15,10 @@ spec:
labels: labels:
app: keycloak app: keycloak
spec: spec:
# TODO: Add Resource allocations
containers: containers:
- name: keycloak - name: keycloak
image: quay.io/keycloak/keycloak:20.0.3 image: quay.io/keycloak/keycloak:25.0.4
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
args: args:
- start - start
@ -25,48 +26,13 @@ spec:
- name: keycloak-cert - name: keycloak-cert
mountPath: /etc/certs mountPath: /etc/certs
readOnly: true readOnly: true
env: envFrom:
- name: KC_HTTPS_CERTIFICATE_FILE - configMapRef:
value: /etc/certs/tls.crt name: keycloak-env
- name: KC_HTTPS_CERTIFICATE_KEY_FILE - secretRef:
value: /etc/certs/tls.key
- name: KC_HOSTNAME
value: FQDN
- name: KC_PROXY
value: edge
- name: DB_VENDOR
value: POSTGRES
- name: DB_ADDR
value: postgresql-service
- name: DB_SCHEMA
value: public
- name: DB_DATABASE
valueFrom:
configMapKeyRef:
name: postgres-config
key: postgres-db
- name: DB_USER
valueFrom:
secretKeyRef:
name: postgres-secret
key: postgres-user
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secret
key: postgres-password
- name: KEYCLOAK_ADMIN
valueFrom:
secretKeyRef:
name: keycloak-secret name: keycloak-secret
key: keycloak-user
- name: KEYCLOAK_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: keycloak-secret
key: keycloak-password
ports: ports:
- name: http - name: keycloak
containerPort: 8080 containerPort: 8080
volumes: volumes:
- name: keycloak-cert - name: keycloak-cert

View file

@ -5,5 +5,7 @@ metadata:
namespace: NAMESPACE namespace: NAMESPACE
type: Opaque type: Opaque
data: data:
keycloak-user: admin KC_DB_USERNAME: DBUSER
keycloak-password: admin KC_DB_PASSWORD: DBPW
KEYCLOAK_ADMIN: ADMIN_USER
KEYCLOAK_ADMIN_PASSWORD: ADMIN_PASS

View file

@ -13,66 +13,30 @@
:metadata {:name "keycloak-secret", :namespace "keycloak"} :metadata {:name "keycloak-secret", :namespace "keycloak"}
:type "Opaque" :type "Opaque"
:data :data
{:keycloak-user "dXNlcg==" {:KC_DB_USERNAME "a2V5Y2xvYWs="
:keycloak-password "cGFzc3dvcmQ="}} :KC_DB_PASSWORD "ZGItcGFzc3dvcmQ="
(cut/generate-secret {:namespace "keycloak" :fqdn "test.de"} {:keycloak-admin-user "user" :keycloak-admin-password "password"})))) :KEYCLOAK_ADMIN "dXNlcg=="
:KEYCLOAK_ADMIN_PASSWORD "cGFzc3dvcmQ="}}
(cut/generate-secret {:namespace "keycloak" :fqdn "test.de"}
{:keycloak-admin-user "user" :keycloak-admin-password "password"
:postgres-db-user "keycloak"
:postgres-db-password "db-password"}))))
(deftest should-generate-configmap
(is (= {:apiVersion "v1",
:kind "ConfigMap",
:metadata {:name "keycloak-env", :namespace "keycloak"},
:data
{:KC_HTTPS_CERTIFICATE_FILE "/etc/certs/tls.crt",
:KC_HTTPS_CERTIFICATE_KEY_FILE "/etc/certs/tls.key",
:KC_HOSTNAME "test.de" ,
:KC_PROXY_HEADERS "xforwarded" ,
:KC_DB "postgres",
:KC_DB_URL_HOST "postgresql-service",
:KC_DB_URL_PORT "5432",
:KC_HTTP_ENABLED "true"}}
(cut/generate-configmap {:namespace "keycloak" :fqdn "test.de"}))))
(deftest should-generate-deployment (deftest should-generate-deployment
(is (= {:apiVersion "apps/v1", (is (= {:name "keycloak", :namespace "keycloak", :labels {:app "keycloak"}}
:kind "Deployment", (:metadata (cut/generate-deployment {:fqdn "example.com" :namespace "keycloak"})))))
:metadata
{:name "keycloak", :namespace "keycloak", :labels {:app "keycloak"}},
:spec
{:replicas 1,
:selector {:matchLabels {:app "keycloak"}},
:template
{:metadata {:labels {:app "keycloak"}},
:spec
{:containers
[{:name "keycloak",
:image "quay.io/keycloak/keycloak:20.0.3",
:imagePullPolicy "IfNotPresent",
:args ["start"],
:volumeMounts
[{:name "keycloak-cert",
:mountPath "/etc/certs",
:readOnly true}],
:env
[{:name "KC_HTTPS_CERTIFICATE_FILE",
:value "/etc/certs/tls.crt"}
{:name "KC_HTTPS_CERTIFICATE_KEY_FILE",
:value "/etc/certs/tls.key"}
{:name "KC_HOSTNAME", :value "test.de"}
{:name "KC_PROXY", :value "edge"}
{:name "DB_VENDOR", :value "POSTGRES"}
{:name "DB_ADDR", :value "postgresql-service"}
{:name "DB_SCHEMA", :value "public"}
{:name "DB_DATABASE",
:valueFrom
{:configMapKeyRef
{:name "postgres-config", :key "postgres-db"}}}
{:name "DB_USER",
:valueFrom
{:secretKeyRef
{:name "postgres-secret", :key "postgres-user"}}}
{:name "DB_PASSWORD",
:valueFrom
{:secretKeyRef
{:name "postgres-secret", :key "postgres-password"}}}
{:name "KEYCLOAK_ADMIN",
:valueFrom
{:secretKeyRef
{:name "keycloak-secret", :key "keycloak-user"}}}
{:name "KEYCLOAK_ADMIN_PASSWORD",
:valueFrom
{:secretKeyRef
{:name "keycloak-secret", :key "keycloak-password"}}}],
:ports [{:name "http", :containerPort 8080}]}],
:volumes
[{:name "keycloak-cert",
:secret
{:secretName "keycloak",
:items
[{:key "tls.crt", :path "tls.crt"}
{:key "tls.key", :path "tls.key"}]}}]}}}}
(cut/generate-deployment {:fqdn "test.de" :namespace "keycloak"}))))