From 9a935ac8b56e84783f0f37e9b8b7bd28ef473818 Mon Sep 17 00:00:00 2001 From: Botond Gal Date: Fri, 26 Sep 2025 12:45:11 +0200 Subject: [PATCH 1/7] add basic logto role --- control-plane/kind.yaml | 6 +++ .../group_vars/control-plane/logto.yaml | 3 ++ roles/logto/README.md | 38 +++++++++++++++++++ roles/logto/defaults/main.yml | 2 + roles/logto/tasks/main.yml | 32 ++++++++++++++++ 5 files changed, 81 insertions(+) create mode 100644 inventories/group_vars/control-plane/logto.yaml create mode 100644 roles/logto/README.md create mode 100644 roles/logto/defaults/main.yml create mode 100644 roles/logto/tasks/main.yml diff --git a/control-plane/kind.yaml b/control-plane/kind.yaml index 949e46d5..cfe16d75 100644 --- a/control-plane/kind.yaml +++ b/control-plane/kind.yaml @@ -21,6 +21,12 @@ nodes: - containerPort: 50051 hostPort: 50051 listenAddress: 0.0.0.0 + - containerPort: 3001 + hostPort: 3001 + listenAddress: 0.0.0.0 + - containerPort: 3002 + hostPort: 3002 + listenAddress: 0.0.0.0 # if you want to run gardener operator + metal-stack, you need more pods kubeadmConfigPatches: - | diff --git a/inventories/group_vars/control-plane/logto.yaml b/inventories/group_vars/control-plane/logto.yaml new file mode 100644 index 00000000..dc17e0f9 --- /dev/null +++ b/inventories/group_vars/control-plane/logto.yaml @@ -0,0 +1,3 @@ +--- +auth_logto_ingress_dns: "logto.{{ metal_control_plane_ingress_dns }}" +auth_logto_issuer_url: http://logto.{{ metal_control_plane_ingress_dns }} \ No newline at end of file diff --git a/roles/logto/README.md b/roles/logto/README.md new file mode 100644 index 00000000..648786ef --- /dev/null +++ b/roles/logto/README.md @@ -0,0 +1,38 @@ +Role Name +========= + +A brief description of the role goes here. + +Requirements +------------ + +Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. + +Role Variables +-------------- + +A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. + +Dependencies +------------ + +A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. + +Example Playbook +---------------- + +Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: + + - hosts: servers + roles: + - { role: username.rolename, x: 42 } + +License +------- + +MIT + +Author Information +------------------ + +An optional section for the role authors to include contact information, or a website (HTML is not allowed). diff --git a/roles/logto/defaults/main.yml b/roles/logto/defaults/main.yml new file mode 100644 index 00000000..7cd671b8 --- /dev/null +++ b/roles/logto/defaults/main.yml @@ -0,0 +1,2 @@ +--- +logto_namespace: "metal-control-plane" \ No newline at end of file diff --git a/roles/logto/tasks/main.yml b/roles/logto/tasks/main.yml new file mode 100644 index 00000000..ea24142c --- /dev/null +++ b/roles/logto/tasks/main.yml @@ -0,0 +1,32 @@ +--- +- name: Git clone logto repo + ansible.builtin.git: + repo: "https://github.com/appthrust/logto-helm.git" + dest: /tmp/helm/logto + +- name: Setup logto at {{ auth_logto_ingress_dns }} + kubernetes.core.helm: + name: logto + chart_ref: /tmp/helm/logto/charts/logto + release_namespace: "{{ logto_namespace }}" + values: + replicaCount: 1 + logto: + endpoint: "http://{{ auth_logto_ingress_dns }}/api" + adminEndpoint: "http://{{ auth_logto_ingress_dns }}/admin" + postgresql: + enabled: true + ingress: + enabled: true + className: nginx + annotations: + kubernetes.io/ingress.class: nginx + nginx.ingress.kubernetes.io/rewrite-target: / + hosts: + - host: "{{ auth_logto_ingress_dns }}" + paths: + - path: /api + pathType: ImplementationSpecific + - path: /admin + pathType: ImplementationSpecific + From 7ca7562a06545ccf3b960ca44a7add6ad6f55a9b Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Mon, 27 Oct 2025 12:57:56 +0100 Subject: [PATCH 2/7] Adoptions --- deploy_control_plane.yaml | 2 ++ roles/logto/tasks/main.yml | 16 ++++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/deploy_control_plane.yaml b/deploy_control_plane.yaml index 2b0312cc..9aad70d7 100644 --- a/deploy_control_plane.yaml +++ b/deploy_control_plane.yaml @@ -27,6 +27,8 @@ tags: valkey - name: auth-dex tags: auth + - name: logto + tags: auth - name: metal-roles/control-plane/roles/metal tags: metal diff --git a/roles/logto/tasks/main.yml b/roles/logto/tasks/main.yml index ea24142c..704a97d1 100644 --- a/roles/logto/tasks/main.yml +++ b/roles/logto/tasks/main.yml @@ -1,8 +1,10 @@ --- - name: Git clone logto repo ansible.builtin.git: - repo: "https://github.com/appthrust/logto-helm.git" + repo: "https://github.com/majst01/logto-helm.git" dest: /tmp/helm/logto + single_branch: yes + version: use-official-kubectl-image - name: Setup logto at {{ auth_logto_ingress_dns }} kubernetes.core.helm: @@ -10,12 +12,17 @@ chart_ref: /tmp/helm/logto/charts/logto release_namespace: "{{ logto_namespace }}" values: + image: + repository: ghcr.io/logto-io/logto + tag: edge replicaCount: 1 logto: endpoint: "http://{{ auth_logto_ingress_dns }}/api" adminEndpoint: "http://{{ auth_logto_ingress_dns }}/admin" postgresql: enabled: true + image: + tag: 17-alpine ingress: enabled: true className: nginx @@ -29,4 +36,9 @@ pathType: ImplementationSpecific - path: /admin pathType: ImplementationSpecific - + secretExtractor: + enabled: true + image: + repository: registry.k8s.io/kubectl + tag: v1.32.0 + From 959c67bc5849e05414e65e3cb858c03eb0c06aa1 Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Wed, 29 Oct 2025 09:24:31 +0100 Subject: [PATCH 3/7] Adoptions --- control-plane/kind.yaml | 6 ------ roles/logto/README.md | 21 +++++++++++++++++++++ roles/logto/tasks/main.yml | 5 ++--- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/control-plane/kind.yaml b/control-plane/kind.yaml index cfe16d75..949e46d5 100644 --- a/control-plane/kind.yaml +++ b/control-plane/kind.yaml @@ -21,12 +21,6 @@ nodes: - containerPort: 50051 hostPort: 50051 listenAddress: 0.0.0.0 - - containerPort: 3001 - hostPort: 3001 - listenAddress: 0.0.0.0 - - containerPort: 3002 - hostPort: 3002 - listenAddress: 0.0.0.0 # if you want to run gardener operator + metal-stack, you need more pods kubeadmConfigPatches: - | diff --git a/roles/logto/README.md b/roles/logto/README.md index 648786ef..1a101a64 100644 --- a/roles/logto/README.md +++ b/roles/logto/README.md @@ -3,6 +3,27 @@ Role Name A brief description of the role goes here. +## Notes + +Well known config for the apiserver +# http://localhost:3001/oidc/.well-known/openid-configuration + + +Machine2Machine Account +https://docs.logto.io/integrate-logto/interact-with-management-api + +```bash +curl --location \ + --request POST 'http://logto.172.17.0.1.nip.io:8080' \ + --header 'Authorization: Basic a3FxNm5tWmpRdVZkQzJPOHpWOUozR2dqRnF2Y09aWUEK' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'grant_type=client_credentials' \ + --data-urlencode 'resource=https://default.logto.app/api' \ + --data-urlencode 'scope=all' +``` + +Does not work yet + Requirements ------------ diff --git a/roles/logto/tasks/main.yml b/roles/logto/tasks/main.yml index 704a97d1..624ce1df 100644 --- a/roles/logto/tasks/main.yml +++ b/roles/logto/tasks/main.yml @@ -17,8 +17,8 @@ tag: edge replicaCount: 1 logto: - endpoint: "http://{{ auth_logto_ingress_dns }}/api" - adminEndpoint: "http://{{ auth_logto_ingress_dns }}/admin" + endpoint: "http://{{ auth_logto_ingress_dns }}:8080/api" + adminEndpoint: "http://{{ auth_logto_ingress_dns }}:8080/admin" postgresql: enabled: true image: @@ -41,4 +41,3 @@ image: repository: registry.k8s.io/kubectl tag: v1.32.0 - From 1f2c4f08449e9f8deabb137b0da95640c763d6a7 Mon Sep 17 00:00:00 2001 From: ostempel Date: Wed, 29 Oct 2025 17:19:46 +0100 Subject: [PATCH 4/7] checkpoint logto --- Untitled-1.json | 18 ++ deploy_control_plane.yaml | 52 +++--- files/certs/logto-admin/server.json | 24 +++ .../group_vars/control-plane/logto.yaml | 8 +- logto-admin.sh | 93 ++++++++++ logto-user.sh | 161 ++++++++++++++++++ logto.md | 73 ++++++++ roles/logto/tasks/main.yml | 49 +++++- roles/logto/templates/logto-admin-tls.yaml | 10 ++ scripts/roll_certs.sh | 1 + 10 files changed, 457 insertions(+), 32 deletions(-) create mode 100644 Untitled-1.json create mode 100644 files/certs/logto-admin/server.json create mode 100644 logto-admin.sh create mode 100644 logto-user.sh create mode 100644 logto.md create mode 100644 roles/logto/templates/logto-admin-tls.yaml diff --git a/Untitled-1.json b/Untitled-1.json new file mode 100644 index 00000000..5c3d0c5a --- /dev/null +++ b/Untitled-1.json @@ -0,0 +1,18 @@ +{ + "name": "mini-lab", + "description": "mini-lab IdP", + "type": "Traditional", + "oidcClientMetadata": { + "redirectUris": [ + { + "postLogoutRedirectUris": [ + "http://v2.api.172.17.0.1.nip.io:8080/auth/oidc/callback" + ] + } + ], + "postLogoutRedirectUris": [ + "http://v2.api.172.17.0.1.nip.io:8080/auth/oidc/callback" + ] + }, + "isThirdParty": true +} diff --git a/deploy_control_plane.yaml b/deploy_control_plane.yaml index 9aad70d7..68f0f947 100644 --- a/deploy_control_plane.yaml +++ b/deploy_control_plane.yaml @@ -6,32 +6,32 @@ roles: - name: ansible-common tags: always - - name: ingress-controller - tags: ingress-controller - - name: metal-roles/control-plane/roles/prepare - tags: prepare - - name: metal-roles/control-plane/roles/nsq - tags: nsq - - name: metal-roles/control-plane/roles/metal-db - tags: metal-db - - name: metal-roles/control-plane/roles/ipam-db - tags: ipam-db - - name: metal-roles/control-plane/roles/headscale - tags: headscale - - name: metal-roles/control-plane/roles/masterdata-db - tags: masterdata-db - - name: metal-roles/control-plane/roles/auditing-timescaledb - when: metal_auditing_timescaledb_enabled - tags: auditing - - name: metal-roles/control-plane/roles/valkey - tags: valkey - - name: auth-dex - tags: auth + # - name: ingress-controller + # tags: ingress-controller + # - name: metal-roles/control-plane/roles/prepare + # tags: prepare + # - name: metal-roles/control-plane/roles/nsq + # tags: nsq + # - name: metal-roles/control-plane/roles/metal-db + # tags: metal-db + # - name: metal-roles/control-plane/roles/ipam-db + # tags: ipam-db + # - name: metal-roles/control-plane/roles/headscale + # tags: headscale + # - name: metal-roles/control-plane/roles/masterdata-db + # tags: masterdata-db + # - name: metal-roles/control-plane/roles/auditing-timescaledb + # when: metal_auditing_timescaledb_enabled + # tags: auditing + # - name: metal-roles/control-plane/roles/valkey + # tags: valkey + # - name: auth-dex + # tags: auth - name: logto tags: auth - - name: metal-roles/control-plane/roles/metal - tags: metal + # - name: metal-roles/control-plane/roles/metal + # tags: metal -- name: deploy gardener - import_playbook: deploy_gardener.yaml - when: gardener_enabled +# - name: deploy gardener +# import_playbook: deploy_gardener.yaml +# when: gardener_enabled diff --git a/files/certs/logto-admin/server.json b/files/certs/logto-admin/server.json new file mode 100644 index 00000000..236fc9aa --- /dev/null +++ b/files/certs/logto-admin/server.json @@ -0,0 +1,24 @@ +{ + "CN": "logto", + "hosts": [ + "localhost", + "logto", + "logto.metal-control-plane.svc", + "logto.metal-control-plane.svc.cluster.local", + "logto-admin.172.17.0.1.nip.io", + "logto.172.17.0.1.nip.io" + ], + "key": { + "algo": "rsa", + "size": 4096 + }, + "names": [ + { + "C": "DE", + "L": "Muenchen", + "O": "metal-stack", + "OU": "DevOps", + "ST": "Bayern" + } + ] +} diff --git a/inventories/group_vars/control-plane/logto.yaml b/inventories/group_vars/control-plane/logto.yaml index dc17e0f9..89957f40 100644 --- a/inventories/group_vars/control-plane/logto.yaml +++ b/inventories/group_vars/control-plane/logto.yaml @@ -1,3 +1,9 @@ --- +auth_logto_admin_ingress_dns: "logto-admin.{{ metal_control_plane_ingress_dns }}" auth_logto_ingress_dns: "logto.{{ metal_control_plane_ingress_dns }}" -auth_logto_issuer_url: http://logto.{{ metal_control_plane_ingress_dns }} \ No newline at end of file +auth_logto_issuer_url: http://logto.{{ metal_control_plane_ingress_dns }} + + +logto_admin_certs_server_key: "{{ lookup('file', 'certs/logto-admin/server-key.pem') }}" +logto_admin_certs_server_cert: "{{ lookup('file', 'certs/logto-admin/server.pem') }}" +logto_admin_certs_ca: "{{ lookup('file', 'certs/ca.pem') }}" diff --git a/logto-admin.sh b/logto-admin.sh new file mode 100644 index 00000000..902506a5 --- /dev/null +++ b/logto-admin.sh @@ -0,0 +1,93 @@ +#!/bin/bash +set -euo pipefail + +# =============================== +# Konfiguration +# =============================== +LOGTO_DB_CONTAINER="logto-postgres-1" +LOGTO_DB_USER="postgres" +LOGTO_DB_NAME="logto" +LOGTO_API_URL="http://localhost:3002" +CLIENT_ID="m-admin" +RESOURCE="https://admin.logto.app/api" +SCOPE="all" + +APP_NAME="mini-lab" +APP_DESCRIPTION="mini-lab IdP" +REDIRECT_URI="http://v2.api.172.17.0.1.nip.io:8080/auth/oidc/callback" + +# =============================== +# 1. Hole m-admin secret aus der Datenbank +# =============================== +echo "🔑 Hole Client Secret für ${CLIENT_ID}..." +CLIENT_SECRET=$(docker exec -it "$LOGTO_DB_CONTAINER" sh -c \ + "psql -U $LOGTO_DB_USER -d $LOGTO_DB_NAME -t -A -c \"SELECT secret FROM applications WHERE id = '$CLIENT_ID';\"" \ + | tr -d '\r') + +if [[ -z "$CLIENT_SECRET" ]]; then + echo "❌ Konnte Client Secret nicht finden. Bitte prüfe, ob die Datenbank läuft und m-admin existiert." + exit 1 +fi + +echo "✅ Secret gefunden: ${CLIENT_SECRET}" + +# =============================== +# 2. Hole Access Token +# =============================== +echo "🔐 Fordere Access Token an..." +ACCESS_TOKEN=$(curl -s --location \ + --request POST "$LOGTO_API_URL/oidc/token" \ + --header "Content-Type: application/x-www-form-urlencoded" \ + --data-urlencode "grant_type=client_credentials" \ + --data-urlencode "client_id=$CLIENT_ID" \ + --data-urlencode "client_secret=$CLIENT_SECRET" \ + --data-urlencode "resource=$RESOURCE" \ + --data-urlencode "scope=$SCOPE" \ + | jq -r '.access_token') + +if [[ "$ACCESS_TOKEN" == "null" || -z "$ACCESS_TOKEN" ]]; then + echo "❌ Fehler beim Abrufen des Access Tokens." + exit 1 +fi + +echo "✅ Access Token erfolgreich erhalten." + +# =============================== +# 3. (Optional) Liste bestehende Third-Party-Apps +# =============================== +echo "📜 Bestehende Third-Party-Anwendungen:" +curl -s --location \ + --request GET "$LOGTO_API_URL/api/applications?isThirdParty=true" \ + --header "Authorization: Bearer $ACCESS_TOKEN" \ + | jq '.[] | {id, name, description}' + +# =============================== +# 4. Erstelle mini-lab Anwendung +# =============================== +echo "🚀 Erstelle neue Anwendung: $APP_NAME ..." +CREATE_RESPONSE=$(curl -s -w "\n%{http_code}" --location \ + --request POST "$LOGTO_API_URL/api/applications" \ + --header "Authorization: Bearer $ACCESS_TOKEN" \ + --header "Content-Type: application/json" \ + --data "{ + \"name\": \"$APP_NAME\", + \"description\": \"$APP_DESCRIPTION\", + \"type\": \"Traditional\", + \"oidcClientMetadata\": { + \"redirectUris\": [\"$REDIRECT_URI\"], + \"postLogoutRedirectUris\": [\"$REDIRECT_URI\"] + }, + \"isThirdParty\": true + }") + +HTTP_CODE=$(echo "$CREATE_RESPONSE" | tail -n1) +BODY=$(echo "$CREATE_RESPONSE" | sed '$d') + +if [[ "$HTTP_CODE" != "200" && "$HTTP_CODE" != "201" ]]; then + echo "❌ Fehler beim Erstellen der Anwendung (HTTP $HTTP_CODE):" + echo "$BODY" | jq . + exit 1 +fi + +echo "✅ Anwendung erfolgreich erstellt:" +echo "$BODY" | jq . diff --git a/logto-user.sh b/logto-user.sh new file mode 100644 index 00000000..ccc4babc --- /dev/null +++ b/logto-user.sh @@ -0,0 +1,161 @@ +#!/bin/bash +set -euo pipefail + +# =============================== +# Konfiguration +# =============================== +LOGTO_DB_CONTAINER="logto-postgres-1" +LOGTO_DB_USER="postgres" +LOGTO_DB_NAME="logto" +LOGTO_API_URL="http://localhost:3002" +CLIENT_ID="m-admin" +RESOURCE="https://admin.logto.app/api" +SCOPE="all" + +APP_NAME="mini-lab" +APP_DESCRIPTION="mini-lab IdP" +REDIRECT_URI="http://v2.api.172.17.0.1.nip.io:8080/auth/oidc/callback" + +ADMIN_NAME="admin" +ADMIN_PW="password1234" + +# =============================== +# 1. Hole m-admin secret aus der Datenbank +# =============================== +echo "🔑 Hole Client Secret für ${CLIENT_ID}..." +CLIENT_SECRET=$(docker exec -it "$LOGTO_DB_CONTAINER" sh -c \ + "psql -U $LOGTO_DB_USER -d $LOGTO_DB_NAME -t -A -c \"SELECT secret FROM applications WHERE id = '$CLIENT_ID';\"" \ + | tr -d '\r') +if [[ -z "$CLIENT_SECRET" ]]; then + echo "❌ Konnte Client Secret nicht finden. Bitte prüfe, ob die Datenbank läuft und m-admin existiert." + exit 1 +fi +echo "✅ Secret gefunden: ${CLIENT_SECRET}" + +# =============================== +# 2. Hole Access Token +# =============================== +echo "🔐 Fordere Access Token an..." +ACCESS_TOKEN=$(curl -s --location \ + --request POST "$LOGTO_API_URL/oidc/token" \ + --header "Content-Type: application/x-www-form-urlencoded" \ + --data-urlencode "grant_type=client_credentials" \ + --data-urlencode "client_id=$CLIENT_ID" \ + --data-urlencode "client_secret=$CLIENT_SECRET" \ + --data-urlencode "resource=$RESOURCE" \ + --data-urlencode "scope=$SCOPE" \ + | jq -r '.access_token') +if [[ "$ACCESS_TOKEN" == "null" || -z "$ACCESS_TOKEN" ]]; then + echo "❌ Fehler beim Abrufen des Access Tokens." + exit 1 +fi +echo "✅ Access Token erfolgreich erhalten." + +# Create admin-user +echo "👤 Erstelle Admin-Benutzer..." +CREATE_RESPONSE=$(curl -s -w "\n%{http_code}" --location \ + --request POST "$LOGTO_API_URL/api/users" \ + --header "Authorization: Bearer $ACCESS_TOKEN" \ + --header "Content-Type: application/json" \ + --data "{ + \"username\": \"$ADMIN_NAME\", + \"password\": \"$ADMIN_PW\" + }") +HTTP_CODE=$(echo "$CREATE_RESPONSE" | tail -n1) +BODY=$(echo "$CREATE_RESPONSE" | sed '$d') +if [[ "$HTTP_CODE" != "200" && "$HTTP_CODE" != "201" ]]; then + echo "❌ Fehler beim Erstellen des Adminusers (HTTP $HTTP_CODE):" + echo "$BODY" | jq . + exit 1 +fi +echo "✅ Adminuser erfolgreich erstellt:" +echo "$BODY" | jq . +USERID=$(echo "$BODY" | jq -r '.id') + +# Create admin-user +echo "Add user to organisation" +CREATE_RESPONSE=$(curl -s -w "\n%{http_code}" --location \ + --request POST "$LOGTO_API_URL/api/organizations/t-default/users" \ + --header "Authorization: Bearer $ACCESS_TOKEN" \ + --header "Content-Type: application/json" \ + --data "{ + \"userIds\": [\"$USERID\"] + }") +HTTP_CODE=$(echo "$CREATE_RESPONSE" | tail -n1) +BODY=$(echo "$CREATE_RESPONSE" | sed '$d') +if [[ "$HTTP_CODE" != "200" && "$HTTP_CODE" != "201" ]]; then + echo "❌ Fehler beim Hinzufügen des Adminusers zur Organisation (HTTP $HTTP_CODE):" + echo "$BODY" | jq . + exit 1 +fi +echo "✅ Adminuser erfolgreich hinzugefügt:" + + +echo "Adminrechte der Organisation zugeweisen" +CREATE_RESPONSE=$(curl -s -w "\n%{http_code}" --location \ + --request POST "$LOGTO_API_URL/api/organizations/t-default/users/roles" \ + --header "Authorization: Bearer $ACCESS_TOKEN" \ + --header "Content-Type: application/json" \ + --data "{ + \"userIds\": [\"$USERID\"], + \"organizationRoleIds\": [\"admin\"] + }") +HTTP_CODE=$(echo "$CREATE_RESPONSE" | tail -n1) +BODY=$(echo "$CREATE_RESPONSE" | sed '$d') +if [[ "$HTTP_CODE" != "200" && "$HTTP_CODE" != "201" ]]; then + echo "❌ Fehler beim Hinzufügen der Adminrechte zur Organisation (HTTP $HTTP_CODE):" + echo "$BODY" | jq . + exit 1 +fi +echo "✅ Adminrechte erfolgreich hinzugefügt:" + +echo "Rollen laden" +CREATE_RESPONSE=$(curl -s -w "\n%{http_code}" --location \ + --request GET "$LOGTO_API_URL/api/roles?type=User" \ + --header "Authorization: Bearer $ACCESS_TOKEN") +HTTP_CODE=$(echo "$CREATE_RESPONSE" | tail -n1) +BODY=$(echo "$CREATE_RESPONSE" | sed '$d') +if [[ "$HTTP_CODE" != "200" && "$HTTP_CODE" != "201" ]]; then + echo "❌ Fehler beim Laden der Rollen (HTTP $HTTP_CODE):" + echo "$BODY" | jq . + exit 1 +fi +echo "✅ Rollen erfolgreich geladen:" +echo "$BODY" | jq . +ROLE_IDS=$(echo "$BODY" | jq -r '.[].id' | jq -R . | paste -sd, -) +echo "Gefundene Rollen IDs: $ROLE_IDS" + +echo "Rollen zu Adminuser zuweisen" +CREATE_RESPONSE=$(curl -s -w "\n%{http_code}" --location \ + --request POST "$LOGTO_API_URL/api/users/$USERID/roles" \ + --header "Authorization: Bearer $ACCESS_TOKEN" \ + --header "Content-Type: application/json" \ + --data "{ + \"roleIds\": [$(echo "$ROLE_IDS" | paste -sd, -)] + }") +HTTP_CODE=$(echo "$CREATE_RESPONSE" | tail -n1) +BODY=$(echo "$CREATE_RESPONSE" | sed '$d') +if [[ "$HTTP_CODE" != "200" && "$HTTP_CODE" != "201" ]]; then + echo "❌ Fehler beim Zuweisen der Rollen (HTTP $HTTP_CODE):" + echo "$BODY" | jq . + exit 1 +fi +echo "✅ Rollen erfolgreich zugewiesen:" + +echo "Login anpassen" +CREATE_RESPONSE=$(curl -s -w "\n%{http_code}" --location \ + --request PATCH "$LOGTO_API_URL/api/sign-in-exp" \ + --header "Authorization: Bearer $ACCESS_TOKEN" \ + --header "Content-Type: application/json" \ + --data "{ + \"tenantId\": \"admin\", + \"signInMode\": \"SignIn\" + }") +HTTP_CODE=$(echo "$CREATE_RESPONSE" | tail -n1) +BODY=$(echo "$CREATE_RESPONSE" | sed '$d') +if [[ "$HTTP_CODE" != "200" && "$HTTP_CODE" != "201" ]]; then + echo "❌ Fehler beim Anpassen des Logins (HTTP $HTTP_CODE):" + echo "$BODY" | jq . + exit 1 +fi +echo "✅ Login erfolgreich angepasst:" \ No newline at end of file diff --git a/logto.md b/logto.md new file mode 100644 index 00000000..a89986bf --- /dev/null +++ b/logto.md @@ -0,0 +1,73 @@ +curl --location \ + --request POST 'http://localhost:3001/oidc/token' \ + --header 'Authorization: Basic MHN4ZTd3NWV1eGdqcDFrZnJid3g3OlVueVp3d0RCY2gzUjA1NTRzcUJRR0VuSWVjU0hyMXk5' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'grant_type=client_credentials' \ + --data-urlencode 'resource=https://default.logto.app/api' \ + --data-urlencode 'scope=all' + +------- + +RFtlQNmRxH4HLDMZVra6Zad0VeWNsT8a + +curl --location \ + --request POST 'http://localhost:3002/oidc/token' \ + --header 'Authorization: Basic bS1hZG1pbjpSRnRsUU5tUnhINEhMRE1aVnJhNlphZDBWZVdOc1Q4YQ' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'grant_type=client_credentials' \ + --data-urlencode 'resource=https://default.logto.app/api' \ + --data-urlencode 'scope=all' + +curl \ + --request POST 'http://localhost:3001/api/applications' \ + --header "Authorization: Bearer RFtlQNmRxH4HLDMZVra6Zad0VeWNsT8a" \ + --header "Content-Type: application/json" \ + --data '{"name":"mini-lab","description":"Mini-Lab","type":"MachineToMachine"}' + + +---- + +./logto-create-admin --baseUrl=http://localhost:3002 --appSecret=RFtlQNmRxH4HLDMZVra6Zad0VeWNsT8a --username=admin --password=password123 + +---- + +Solution: + +1. Get m-admin token +docker exec -it logto-postgres-1 sh -c 'psql -U postgres -d logto -t -A -c "SELECT secret FROM applications WHERE id = '\''m-admin'\'';"' + +2. Use the token to get access token for m-admin +curl --location \ + --request POST 'http://localhost:3002/oidc/token' \ + --header 'Content-Type: application/x-www-form-urlencoded' \ + --data-urlencode 'grant_type=client_credentials' \ + --data-urlencode 'client_id=m-admin' \ + --data-urlencode 'client_secret=RFtlQNmRxH4HLDMZVra6Zad0VeWNsT8a' \ + --data-urlencode 'resource=https://admin.logto.app/api' \ + --data-urlencode 'scope=all' \ +| jq -r '.access_token' + +3. Use the access token to manage entities +curl --location \ + --request GET 'http://localhost:3002/api/applications?isThirdParty=true' \ + --header 'Authorization: Bearer eyJhbGciOiJFUzM4NCIsInR5cCI6ImF0K2p3dCIsImtpZCI6IjlobWw4NDl5NUZYQk5mUE93bnA1Q1g3ZUVkdERTejl5ejd5SllOZ0RnajAifQ.eyJqdGkiOiI5aFZDZWlaV202Q1p4Z0VDRTJWVDIiLCJzdWIiOiJtLWFkbWluIiwiaWF0IjoxNzYxNzQ0NjA1LCJleHAiOjE3NjE3NDgyMDUsInNjb3BlIjoiYWxsIiwiY2xpZW50X2lkIjoibS1hZG1pbiIsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6MzAwMi9vaWRjIiwiYXVkIjoiaHR0cHM6Ly9hZG1pbi5sb2d0by5hcHAvYXBpIn0.u7GEcRma56PDiFSPF4_281xtodMUD1ZlpQu_NNAWKhpAj5RAg_zZKFk7sR3euXk3mgPqjko2oPBBTbDh9i0hiwjRDY-Iv_pYDlD9L18xUbjjIyoPI6X3hqTGNXpK-u0t' + +4. Create mini-lab oidc app +curl --location \ + --request POST 'http://localhost:3002/api/applications' \ + --header 'Authorization: Bearer eyJhbGciOiJFUzM4NCIsInR5cCI6ImF0K2p3dCIsImtpZCI6IjlobWw4NDl5NUZYQk5mUE93bnA1Q1g3ZUVkdERTejl5ejd5SllOZ0RnajAifQ.eyJqdGkiOiI5aFZDZWlaV202Q1p4Z0VDRTJWVDIiLCJzdWIiOiJtLWFkbWluIiwiaWF0IjoxNzYxNzQ0NjA1LCJleHAiOjE3NjE3NDgyMDUsInNjb3BlIjoiYWxsIiwiY2xpZW50X2lkIjoibS1hZG1pbiIsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6MzAwMi9vaWRjIiwiYXVkIjoiaHR0cHM6Ly9hZG1pbi5sb2d0by5hcHAvYXBpIn0.u7GEcRma56PDiFSPF4_281xtodMUD1ZlpQu_NNAWKhpAj5RAg_zZKFk7sR3euXk3mgPqjko2oPBBTbDh9i0hiwjRDY-Iv_pYDlD9L18xUbjjIyoPI6X3hqTGNXpK-u0t' \ + --header 'Content-Type: application/json' \ + --data '{ + "name": "mini-lab", + "description": "mini-lab IdP", + "type": "Traditional", + "oidcClientMetadata": { + "redirectUris": [ + "http://v2.api.172.17.0.1.nip.io:8080/auth/oidc/callback" + ], + "postLogoutRedirectUris": [ + "http://v2.api.172.17.0.1.nip.io:8080/auth/oidc/callback" + ] + }, + "isThirdParty": true + }' diff --git a/roles/logto/tasks/main.yml b/roles/logto/tasks/main.yml index 624ce1df..83b1e895 100644 --- a/roles/logto/tasks/main.yml +++ b/roles/logto/tasks/main.yml @@ -6,6 +6,12 @@ single_branch: yes version: use-official-kubectl-image +- name: Deploy tls secret for logto admin ingress + k8s: + definition: "{{ lookup('template', 'logto-admin-tls.yaml') }}" + namespace: "{{ logto_namespace }}" + apply: true + - name: Setup logto at {{ auth_logto_ingress_dns }} kubernetes.core.helm: name: logto @@ -17,27 +23,60 @@ tag: edge replicaCount: 1 logto: - endpoint: "http://{{ auth_logto_ingress_dns }}:8080/api" - adminEndpoint: "http://{{ auth_logto_ingress_dns }}:8080/admin" + endpoint: "https://{{ auth_logto_ingress_dns }}:4443" + adminEndpoint: "https://{{ auth_logto_admin_ingress_dns }}:4443" postgresql: enabled: true image: tag: 17-alpine ingress: + tls: + - hosts: + - "{{ auth_logto_admin_ingress_dns }}" + - "{{ auth_logto_ingress_dns }}" + secretName: logto-admin-tls enabled: true className: nginx annotations: kubernetes.io/ingress.class: nginx - nginx.ingress.kubernetes.io/rewrite-target: / hosts: - host: "{{ auth_logto_ingress_dns }}" + backend: + service: + name: logto + port: + name: http-main paths: - - path: /api + - path: / pathType: ImplementationSpecific - - path: /admin + - host: "{{ auth_logto_admin_ingress_dns }}" + backend: + service: + name: logto + port: + name: http-admin + paths: + paths: + - path: / pathType: ImplementationSpecific secretExtractor: enabled: true image: repository: registry.k8s.io/kubectl tag: v1.32.0 + +- name: Get logto secret + kubernetes.core.k8s_info: + api_version: v1 + kind: Secret + name: logto-application-secrets + namespace: metal-control-plane + register: logto_secret + +- name: Decode m-admin-secret from base64 + set_fact: + logto_m_admin_secret: "{{ logto_secret.resources[0].data['m-admin-secret'] | b64decode | trim }}" + +- name: Show access token + debug: + msg: "Access Token: {{ logto_m_admin_secret }}" \ No newline at end of file diff --git a/roles/logto/templates/logto-admin-tls.yaml b/roles/logto/templates/logto-admin-tls.yaml new file mode 100644 index 00000000..ae30967c --- /dev/null +++ b/roles/logto/templates/logto-admin-tls.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: v1 +kind: Secret +metadata: + name: logto-admin-tls +type: kubernetes.io/tls +data: + tls.key: {{ logto_admin_certs_server_key | b64encode }} + tls.crt: {{ logto_admin_certs_server_cert | b64encode }} + ca.crt: {{ logto_admin_certs_ca | b64encode }} \ No newline at end of file diff --git a/scripts/roll_certs.sh b/scripts/roll_certs.sh index 7fc34acd..51b30dec 100755 --- a/scripts/roll_certs.sh +++ b/scripts/roll_certs.sh @@ -13,6 +13,7 @@ rm *.csr for component in \ grpc \ + logto-admin \ masterdata-api; do pushd $component From 0fc628f17e189c9620d3c057c67d969a402e6794 Mon Sep 17 00:00:00 2001 From: ostempel Date: Thu, 30 Oct 2025 12:06:23 +0100 Subject: [PATCH 5/7] draft logto manifests --- deploy_control_plane.yaml | 52 ++++---- roles/logto/tasks/main.yml | 80 ++++-------- roles/logto/templates/logto.yaml | 125 ++++++++++++++++++ roles/logto/templates/postgres.yaml | 97 ++++++++++++++ roles/logto/templates/secret-extractor.yaml | 134 ++++++++++++++++++++ 5 files changed, 410 insertions(+), 78 deletions(-) create mode 100644 roles/logto/templates/logto.yaml create mode 100644 roles/logto/templates/postgres.yaml create mode 100644 roles/logto/templates/secret-extractor.yaml diff --git a/deploy_control_plane.yaml b/deploy_control_plane.yaml index 68f0f947..9aad70d7 100644 --- a/deploy_control_plane.yaml +++ b/deploy_control_plane.yaml @@ -6,32 +6,32 @@ roles: - name: ansible-common tags: always - # - name: ingress-controller - # tags: ingress-controller - # - name: metal-roles/control-plane/roles/prepare - # tags: prepare - # - name: metal-roles/control-plane/roles/nsq - # tags: nsq - # - name: metal-roles/control-plane/roles/metal-db - # tags: metal-db - # - name: metal-roles/control-plane/roles/ipam-db - # tags: ipam-db - # - name: metal-roles/control-plane/roles/headscale - # tags: headscale - # - name: metal-roles/control-plane/roles/masterdata-db - # tags: masterdata-db - # - name: metal-roles/control-plane/roles/auditing-timescaledb - # when: metal_auditing_timescaledb_enabled - # tags: auditing - # - name: metal-roles/control-plane/roles/valkey - # tags: valkey - # - name: auth-dex - # tags: auth + - name: ingress-controller + tags: ingress-controller + - name: metal-roles/control-plane/roles/prepare + tags: prepare + - name: metal-roles/control-plane/roles/nsq + tags: nsq + - name: metal-roles/control-plane/roles/metal-db + tags: metal-db + - name: metal-roles/control-plane/roles/ipam-db + tags: ipam-db + - name: metal-roles/control-plane/roles/headscale + tags: headscale + - name: metal-roles/control-plane/roles/masterdata-db + tags: masterdata-db + - name: metal-roles/control-plane/roles/auditing-timescaledb + when: metal_auditing_timescaledb_enabled + tags: auditing + - name: metal-roles/control-plane/roles/valkey + tags: valkey + - name: auth-dex + tags: auth - name: logto tags: auth - # - name: metal-roles/control-plane/roles/metal - # tags: metal + - name: metal-roles/control-plane/roles/metal + tags: metal -# - name: deploy gardener -# import_playbook: deploy_gardener.yaml -# when: gardener_enabled +- name: deploy gardener + import_playbook: deploy_gardener.yaml + when: gardener_enabled diff --git a/roles/logto/tasks/main.yml b/roles/logto/tasks/main.yml index 83b1e895..5341ac76 100644 --- a/roles/logto/tasks/main.yml +++ b/roles/logto/tasks/main.yml @@ -12,58 +12,34 @@ namespace: "{{ logto_namespace }}" apply: true -- name: Setup logto at {{ auth_logto_ingress_dns }} - kubernetes.core.helm: - name: logto - chart_ref: /tmp/helm/logto/charts/logto - release_namespace: "{{ logto_namespace }}" - values: - image: - repository: ghcr.io/logto-io/logto - tag: edge - replicaCount: 1 - logto: - endpoint: "https://{{ auth_logto_ingress_dns }}:4443" - adminEndpoint: "https://{{ auth_logto_admin_ingress_dns }}:4443" - postgresql: - enabled: true - image: - tag: 17-alpine - ingress: - tls: - - hosts: - - "{{ auth_logto_admin_ingress_dns }}" - - "{{ auth_logto_ingress_dns }}" - secretName: logto-admin-tls - enabled: true - className: nginx - annotations: - kubernetes.io/ingress.class: nginx - hosts: - - host: "{{ auth_logto_ingress_dns }}" - backend: - service: - name: logto - port: - name: http-main - paths: - - path: / - pathType: ImplementationSpecific - - host: "{{ auth_logto_admin_ingress_dns }}" - backend: - service: - name: logto - port: - name: http-admin - paths: - paths: - - path: / - pathType: ImplementationSpecific - secretExtractor: - enabled: true - image: - repository: registry.k8s.io/kubectl - tag: v1.32.0 +- name: Deploy postgres + k8s: + definition: "{{ lookup('template', 'postgres.yaml') }}" + namespace: "{{ logto_namespace }}" + apply: true + +- name: Deploy logto + k8s: + definition: "{{ lookup('template', 'logto.yaml') }}" + namespace: "{{ logto_namespace }}" + apply: true + +- name: Deploy secret-extractor + k8s: + definition: "{{ lookup('template', 'secret-extractor.yaml') }}" + namespace: "{{ logto_namespace }}" + apply: true + +- name: Wait for logto secret-extractor job to complete + kubernetes.core.k8s_info: + api_version: batch/v1 + kind: Job + name: logto-secret-extractor + namespace: "{{ logto_namespace }}" + register: logto_job_info + until: logto_job_info.resources[0].status.succeeded | default(0) > 0 + retries: 30 + delay: 10 - name: Get logto secret kubernetes.core.k8s_info: diff --git a/roles/logto/templates/logto.yaml b/roles/logto/templates/logto.yaml new file mode 100644 index 00000000..fae495b9 --- /dev/null +++ b/roles/logto/templates/logto.yaml @@ -0,0 +1,125 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: logto + labels: + app.kubernetes.io/name: logto +--- +apiVersion: v1 +kind: Service +metadata: + name: logto + labels: + app.kubernetes.io/name: logto +spec: + type: ClusterIP + ports: + - port: 3001 + targetPort: 3001 + protocol: TCP + name: http-main + - port: 3002 + targetPort: 3002 + protocol: TCP + name: http-admin + selector: + app.kubernetes.io/name: logto +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: logto + labels: + app.kubernetes.io/name: logto +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: logto + template: + metadata: + labels: + app.kubernetes.io/name: logto + spec: + serviceAccountName: logto + initContainers: + - name: wait-for-db + image: postgres:17-alpine + command: ['sh', '-c', 'until pg_isready -h logto-postgresql -p 5432; do echo waiting for postgresql; sleep 2; done;'] + containers: + - name: logto + image: svhd/logto:latest + imagePullPolicy: IfNotPresent + command: ["sh", "-c", "npm run cli db seed -- --swe && npm start"] + ports: + - name: http-main + containerPort: 3001 + protocol: TCP + - name: http-admin + containerPort: 3002 + protocol: TCP + env: + - name: TRUST_PROXY_HEADER + value: "true" + - name: DB_URL + value: postgres://postgres:postgres@logto-postgresql:5432/logto + - name: ENDPOINT + value: http://logto.172.17.0.1.nip.io:8080 + - name: ADMIN_ENDPOINT + value: http://logto-admin.172.17.0.1.nip.io:8080 + # Changed health check path to /api/health which is more common + livenessProbe: + httpGet: + path: /api/status + port: 3001 + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 6 + readinessProbe: + httpGet: + path: /api/status + port: 3001 + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + resources: + limits: + cpu: 1000m + memory: 1024Mi + requests: + cpu: 100m + memory: 128Mi +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: logto + labels: + app.kubernetes.io/name: logto +spec: + ingressClassName: nginx + # tls: + rules: + - host: logto.172.17.0.1.nip.io + http: + paths: + - backend: + service: + name: logto + port: + name: http-main + path: / + pathType: ImplementationSpecific + - host: logto-admin.172.17.0.1.nip.io + http: + paths: + - backend: + service: + name: logto + port: + name: http-admin + path: / + pathType: ImplementationSpecific \ No newline at end of file diff --git a/roles/logto/templates/postgres.yaml b/roles/logto/templates/postgres.yaml new file mode 100644 index 00000000..a0786a11 --- /dev/null +++ b/roles/logto/templates/postgres.yaml @@ -0,0 +1,97 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: logto-postgresql + labels: + app.kubernetes.io/component: database +spec: + type: ClusterIP + ports: + - port: 5432 + targetPort: postgresql + protocol: TCP + name: postgresql + selector: + app.kubernetes.io/component: database +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: logto-postgresql + labels: + app.kubernetes.io/component: database +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 8Gi +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: logto-postgresql + labels: + app.kubernetes.io/name: logto + app.kubernetes.io/component: database +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: logto + app.kubernetes.io/component: database + template: + metadata: + labels: + app.kubernetes.io/name: logto + app.kubernetes.io/component: database + spec: + containers: + - name: postgresql + image: postgres:17-alpine + imagePullPolicy: IfNotPresent + ports: + - name: postgresql + containerPort: 5432 + protocol: TCP + env: + - name: POSTGRES_USER + value: postgres + - name: POSTGRES_PASSWORD + value: postgres + - name: POSTGRES_DB + value: logto + livenessProbe: + exec: + command: + - pg_isready + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 3 + readinessProbe: + exec: + command: + - pg_isready + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 3 + resources: + limits: + cpu: 1000m + memory: 1024Mi + requests: + cpu: 100m + memory: 128Mi + volumeMounts: + - name: data + mountPath: /var/lib/postgresql/data + volumes: + - name: data + persistentVolumeClaim: + claimName: logto-postgresql +--- \ No newline at end of file diff --git a/roles/logto/templates/secret-extractor.yaml b/roles/logto/templates/secret-extractor.yaml new file mode 100644 index 00000000..068df1fc --- /dev/null +++ b/roles/logto/templates/secret-extractor.yaml @@ -0,0 +1,134 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: logto-secret-extractor + labels: + app.kubernetes.io/component: secret-extractor +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: logto-secret-extractor + labels: + app.kubernetes.io/component: secret-extractor +rules: + - apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "create", "update", "patch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: logto-secret-extractor + labels: + app.kubernetes.io/component: secret-extractor +subjects: + - kind: ServiceAccount + name: logto-secret-extractor + namespace: metal-control-plane +roleRef: + kind: Role + name: logto-secret-extractor + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: logto-secret-extractor +spec: + ttlSecondsAfterFinished: 100 + template: + metadata: + labels: + app.kubernetes.io/name: logto + app.kubernetes.io/component: secret-extractor + spec: + serviceAccountName: logto-secret-extractor + restartPolicy: OnFailure + volumes: + - name: shared-data + emptyDir: {} + containers: + - name: secret-extractor + image: postgres:17-alpine + env: + - name: POSTGRES_HOST + value: logto-postgresql + - name: POSTGRES_USER + value: postgres + - name: POSTGRES_PASSWORD + value: postgres + - name: POSTGRES_DB + value: logto + volumeMounts: + - name: shared-data + mountPath: /shared + command: + - /bin/sh + - -c + - | + # Wait for PostgreSQL to be ready + until PGPASSWORD=$POSTGRES_PASSWORD psql -h $POSTGRES_HOST -U $POSTGRES_USER -d $POSTGRES_DB -c "SELECT 1;" > /dev/null 2>&1; do + echo "Waiting for PostgreSQL to be ready..." + sleep 2 + done + + # Wait for both applications to exist and extract their secrets + while true; do + # Check if both applications exist and get their secrets + SECRETS=$(PGPASSWORD=$POSTGRES_PASSWORD psql -h $POSTGRES_HOST -U $POSTGRES_USER -d $POSTGRES_DB -t -A -F"," -c \ + "SELECT id, secret FROM applications WHERE id IN ('m-default', 'm-admin');") + + COUNT=$(echo "$SECRETS" | wc -l) + if [ "$COUNT" -eq 2 ]; then + echo "Found both applications, extracting secrets..." + break + fi + + echo "Waiting for applications to be created..." + sleep 5 + done + + # Extract and base64 encode secrets + M_DEFAULT_SECRET=$(echo "$SECRETS" | grep "^m-default," | cut -d',' -f2 | base64) + M_ADMIN_SECRET=$(echo "$SECRETS" | grep "^m-admin," | cut -d',' -f2 | base64) + + # Create Kubernetes Secret manifest + cat < /shared/secret.yaml + apiVersion: v1 + kind: Secret + metadata: + name: logto-application-secrets + type: Opaque + data: + m-default-secret: $M_DEFAULT_SECRET + m-admin-secret: $M_ADMIN_SECRET + EOF + + # Signal that the secret file is ready + touch /shared/secret-ready + + # Wait for the secret to be applied + while [ -f /shared/secret-ready ]; do + sleep 1 + done + - name: kubectl + image: "bitnami/kubectl:latest" + volumeMounts: + - name: shared-data + mountPath: /shared + command: + - /bin/sh + - -c + - | + # Wait for the secret file to be ready + while [ ! -f /shared/secret-ready ]; do + sleep 1 + done + + # Apply the secret + kubectl apply -f /shared/secret.yaml + + # Signal completion + rm -f /shared/secret-ready \ No newline at end of file From 6a2c3ed4361fea4cbd961a7376cdbf3418a449e8 Mon Sep 17 00:00:00 2001 From: ostempel Date: Thu, 30 Oct 2025 13:15:29 +0100 Subject: [PATCH 6/7] test tls --- roles/logto/templates/logto.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/roles/logto/templates/logto.yaml b/roles/logto/templates/logto.yaml index fae495b9..9a85d35a 100644 --- a/roles/logto/templates/logto.yaml +++ b/roles/logto/templates/logto.yaml @@ -101,7 +101,11 @@ metadata: app.kubernetes.io/name: logto spec: ingressClassName: nginx - # tls: + tls: + - hosts: + - logto.172.17.0.1.nip.io + - logto-admin.172.17.0.1.nip.io + secretName: logto-admin-tls rules: - host: logto.172.17.0.1.nip.io http: From a4de9721db3b046e72ef5e14f5b14eab47bc8a4a Mon Sep 17 00:00:00 2001 From: ostempel Date: Fri, 31 Oct 2025 09:26:29 +0100 Subject: [PATCH 7/7] add tls --- roles/logto/templates/logto.yaml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/roles/logto/templates/logto.yaml b/roles/logto/templates/logto.yaml index 9a85d35a..2748b083 100644 --- a/roles/logto/templates/logto.yaml +++ b/roles/logto/templates/logto.yaml @@ -59,15 +59,22 @@ spec: - name: http-admin containerPort: 3002 protocol: TCP + volumeMounts: + - name: logto-admin-ca + mountPath: /etc/ssl/certs/ca.crt + subPath: ca.crt + readOnly: true env: + - name: NODE_TLS_REJECT_UNAUTHORIZED + value: "0" - name: TRUST_PROXY_HEADER value: "true" - name: DB_URL value: postgres://postgres:postgres@logto-postgresql:5432/logto - name: ENDPOINT - value: http://logto.172.17.0.1.nip.io:8080 + value: https://logto.172.17.0.1.nip.io:4443 - name: ADMIN_ENDPOINT - value: http://logto-admin.172.17.0.1.nip.io:8080 + value: https://logto-admin.172.17.0.1.nip.io:4443 # Changed health check path to /api/health which is more common livenessProbe: httpGet: