Compare commits

..

2 commits

Author SHA1 Message Date
Daniel Noulet
8942383ff9 chore: testing build
Some checks failed
Build, test, publish, deploy / build-test (push) Has been cancelled
Build, test, publish, deploy / integration-test (push) Has been cancelled
Build, test, publish, deploy / publish (push) Has been cancelled
Build, test, publish, deploy / deploy-prd (push) Has been cancelled
2026-10-10 18:58:32 +02:00
Daniel Noulet
d3ee64282d ci: add Forgejo build and deployment workflows 2026-10-08 10:36:33 +02:00
14 changed files with 523 additions and 188 deletions

View file

@ -0,0 +1,122 @@
#!/usr/bin/env bash
set -Eeuo pipefail
NAMESPACE=go-insane-prd
REGISTRY=nexus.urpi.be
CERT_MANAGER_VERSION=v1.19.1
LOCAL_PATH_VERSION=v0.0.37
LOCK_NAME=forgejo-prd-deploy-lock
if [[ $# -lt 4 ]]; then echo "Usage: $0 <chart> <release> <image-name> <image-tag> [helm args...]" >&2; exit 2; fi
CHART=$1; RELEASE=$2; IMAGE_NAME=$3; IMAGE_TAG=$4; shift 4
: "${KUBECONFIG_PRD:?Set the Forgejo secret KUBECONFIG_PRD to the PRD kubeconfig contents}"
: "${NEXUS_USERNAME:?Set the Forgejo secret NEXUS_USERNAME}"
: "${NEXUS_PASSWORD:?Set the Forgejo secret NEXUS_PASSWORD}"
KUBECONFIG="${RUNNER_TEMP:-/tmp}/kubeconfig-prd-${GITHUB_RUN_ID:-$$}"
umask 077; printf '%s\n' "$KUBECONFIG_PRD" > "$KUBECONFIG"; export KUBECONFIG
LOCK_ACQUIRED=false
cleanup() { if [[ "$LOCK_ACQUIRED" == true ]]; then kubectl -n "$NAMESPACE" delete configmap "$LOCK_NAME" --ignore-not-found --wait=false >/dev/null 2>&1 || true; fi; rm -f "$KUBECONFIG"; }
trap cleanup EXIT
secret_value() {
local name=$1 key=$2 encoded
encoded="$(kubectl -n "$NAMESPACE" get secret "$name" -o go-template="{{index .data \"${key}\"}}" 2>/dev/null || true)"
[[ -z "$encoded" || "$encoded" == "<no value>" ]] && return 0
printf '%s' "$encoded" | base64 -d 2>/dev/null || true
}
kubectl get --raw=/readyz >/dev/null
if [[ "$RELEASE" == go-loose ]] && ! kubectl -n "$NAMESPACE" get secret go-loose-wildcard-tls >/dev/null 2>&1; then
echo "Required go-loose-wildcard-tls Secret is missing; provision the tenant wildcard certificate before bootstrap/deploy." >&2
exit 1
fi
kubectl create namespace "$NAMESPACE" --dry-run=client -o yaml | kubectl apply -f -
for attempt in {1..360}; do if kubectl -n "$NAMESPACE" create configmap "$LOCK_NAME" --from-literal=owner="${GITHUB_REPOSITORY:-local}:${GITHUB_RUN_ID:-$$}" >/dev/null 2>&1; then LOCK_ACQUIRED=true; break; fi; sleep 5; done
if [[ "$LOCK_ACQUIRED" != true ]]; then echo "Timed out waiting for another go-insane-prd deploy to release its lock." >&2; exit 1; fi
kubectl -n "$NAMESPACE" create secret docker-registry nexus-registry --docker-server="$REGISTRY" --docker-username="$NEXUS_USERNAME" --docker-password="$NEXUS_PASSWORD" --dry-run=client -o yaml | kubectl apply -f -
DEFAULT_STORAGE_CLASS="$(kubectl get storageclass -o=jsonpath='{range .items[*]}{.metadata.name}{" "}{.metadata.annotations.storageclass\.kubernetes\.io/is-default-class}{"\n"}{end}' | awk '$2 == "true" { print $1; exit }')"
if [[ -z "$DEFAULT_STORAGE_CLASS" ]]; then
if ! kubectl get storageclass local-path >/dev/null 2>&1 || ! kubectl -n local-path-storage get deployment local-path-provisioner >/dev/null 2>&1; then kubectl apply -f "https://raw.githubusercontent.com/rancher/local-path-provisioner/${LOCAL_PATH_VERSION}/deploy/local-path-storage.yaml"; kubectl -n local-path-storage rollout status deployment/local-path-provisioner --timeout=5m; fi
kubectl annotate storageclass local-path storageclass.kubernetes.io/is-default-class=true --overwrite
fi
if ! kubectl get ingressclass nginx >/dev/null 2>&1; then
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx --force-update
helm repo update ingress-nginx
helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx --namespace ingress-nginx --create-namespace --set controller.service.type=NodePort --set controller.hostPort.enabled=true --set controller.kind=DaemonSet --set controller.admissionWebhooks.enabled=false --wait --timeout 10m
fi
if ! kubectl get crd clusterissuers.cert-manager.io >/dev/null 2>&1 || ! kubectl -n cert-manager get deployment cert-manager >/dev/null 2>&1; then
kubectl apply --validate=false -f "https://github.com/cert-manager/cert-manager/releases/download/${CERT_MANAGER_VERSION}/cert-manager.yaml"
kubectl -n cert-manager rollout status deployment/cert-manager --timeout=5m
kubectl -n cert-manager rollout status deployment/cert-manager-cainjector --timeout=5m
kubectl -n cert-manager rollout status deployment/cert-manager-webhook --timeout=5m
fi
if ! kubectl get clusterissuer letsencrypt-prod >/dev/null 2>&1; then
kubectl apply -f - <<'ISSUER'
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: admin@urpi.be
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
class: nginx
ISSUER
fi
kubectl wait --for=condition=Ready clusterissuer/letsencrypt-prod --timeout=2m
[[ -d "$CHART" ]] || { echo "Helm chart not found: $CHART" >&2; exit 1; }
if [[ -f "$CHART/Chart.lock" ]]; then helm dependency build "$CHART"; fi
HELM_ARGS=(--namespace "$NAMESPACE" --create-namespace)
if [[ "$RELEASE" != go-guess ]]; then HELM_ARGS+=(--set-string "image.repository=${REGISTRY}/docker-hosted/${IMAGE_NAME}" --set-string "image.tag=${IMAGE_TAG}"); fi
[[ ! -f "$CHART/values-prd.yaml" ]] || HELM_ARGS+=(--values "$CHART/values-prd.yaml")
case "$RELEASE" in
go-loose)
db_password="$(secret_value go-loose-runtime postgresql-password)"
[[ -n "$db_password" ]] || db_password="$(secret_value go-loose-postgresql postgres-password)"
[[ -n "$db_password" ]] || db_password="$(secret_value go-loose-postgresql password)"
if [[ -z "$db_password" ]] && kubectl -n "$NAMESPACE" get pvc -o name | grep -Eq 'go-loose.*postgresql|data-go-loose'; then
echo "Existing go-loose database storage has no recoverable password secret; refusing to rotate its credentials." >&2
exit 1
fi
[[ -n "$db_password" ]] || db_password="$(openssl rand -hex 24)"
session_secret="$(secret_value go-loose-runtime session-secret)"
[[ -n "$session_secret" ]] || session_secret="$(secret_value go-loose-env GO_LOOSE_SESSION_SECRET)"
[[ -n "$session_secret" ]] || session_secret="$(openssl rand -hex 32)"
database_url="postgres://goloose:${db_password}@go-loose-postgresql:5432/goloose?sslmode=disable"
kubectl -n "$NAMESPACE" create secret generic go-loose-runtime \
--from-literal=postgresql-password="$db_password" \
--from-literal=postgres-password="$db_password" \
--from-literal=database-url="$database_url" \
--from-literal=session-secret="$session_secret" \
--dry-run=client -o yaml | kubectl apply -f -
;;
go-mad)
if ! kubectl -n "$NAMESPACE" get secret go-mad-runtime >/dev/null 2>&1; then
db_password="$(secret_value go-mad-postgresql password)"; [[ -n "$db_password" ]] || db_password="$(secret_value go-mad-postgresql postgres-password)"
if [[ -z "$db_password" ]] && kubectl -n "$NAMESPACE" get pvc -o name | grep -Eq 'go-mad.*postgresql|data-go-mad'; then echo "Existing go-mad database storage has no recoverable password secret; refusing to rotate its credentials." >&2; exit 1; fi
[[ -n "$db_password" ]] || db_password="$(openssl rand -hex 24)"
kubectl -n "$NAMESPACE" create secret generic go-mad-runtime --from-literal=postgresql-password="$db_password" --from-literal=jwt-secret="$(openssl rand -hex 32)"
fi
db_password="$(secret_value go-mad-runtime postgresql-password)"; jwt_secret="$(secret_value go-mad-runtime jwt-secret)"
HELM_ARGS+=(--set-string "postgresql.auth.password=${db_password}" --set-string "go-mad.jwtSecret=${jwt_secret}")
;;
go-first)
if ! kubectl -n "$NAMESPACE" get secret go-first-runtime >/dev/null 2>&1; then
kubectl -n "$NAMESPACE" create secret generic go-first-runtime --from-literal=jwt-secret="$(openssl rand -hex 32)"
fi
;;
go-places)
: "${GO_LOOSE_JWT_SECRET:?Set Forgejo secret GO_LOOSE_JWT_SECRET to the same signing key used by go-loose}"
kubectl -n "$NAMESPACE" create secret generic go-loose-jwt --from-literal=secret="$GO_LOOSE_JWT_SECRET" --dry-run=client -o yaml | kubectl apply -f -
;;
go-bananas)
: "${GO_BANANAS_OIDC_CLIENT_SECRET:?Set Forgejo secret GO_BANANAS_OIDC_CLIENT_SECRET}"
session_secret="$(secret_value go-bananas-auth session-secret)"
if [[ -z "$session_secret" ]]; then session_secret="$(openssl rand -hex 32)"; fi
kubectl -n "$NAMESPACE" create secret generic go-bananas-auth --from-literal=session-secret="$session_secret" --from-literal=oidc-client-secret="$GO_BANANAS_OIDC_CLIENT_SECRET" --dry-run=client -o yaml | kubectl apply -f -
;;
esac
helm upgrade --install "$RELEASE" "$CHART" "${HELM_ARGS[@]}" "$@" --wait --timeout 15m
kubectl -n "$NAMESPACE" get deployments,statefulsets,pods,services,ingresses

View file

@ -1,58 +1,41 @@
name: CI/CD name: Build, test, publish, deploy
on: on:
push: push:
branches: [main, develop]
tags: ['v*']
pull_request: pull_request:
branches: [main, develop] workflow_dispatch:
env: env:
REGISTRY: nexus-registry.urpi.be GO_VERSION: "1.27.1"
REGISTRY: nexus.urpi.be
IMAGE_NAME: docker-hosted/go-loose IMAGE_NAME: docker-hosted/go-loose
GO_VERSION: '1.27.1'
jobs: jobs:
build-and-test: build-test:
name: Build and Test
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: read
steps: steps:
- name: Checkout repository - uses: actions/checkout@v4
uses: actions/checkout@v4 - uses: actions/setup-go@v5
- name: Set up Go
uses: actions/setup-go@v5
with: with:
go-version: ${{ env.GO_VERSION }} go-version-file: go.mod
cache: true cache: true
- name: Build and test Go service
- name: Download dependencies
run: go mod download
- name: Build
run: go build ./...
- name: Run unit tests
run: go test -race ./... -count=1
- name: Run vet
run: go vet ./...
- name: Check formatting
run: | run: |
if [ "$(gofmt -l . | grep -v vendor | grep -v dist | wc -l)" -gt 0 ]; then go mod download
echo "Code is not formatted:" go vet ./...
gofmt -l . | grep -v vendor | grep -v dist go test -race ./... -count=1
exit 1 go build ./...
fi - uses: azure/setup-helm@v4
with:
version: v3.18.6
- name: Validate production chart
run: |
helm dependency build deploy/helm/go-loose
helm lint deploy/helm/go-loose -f deploy/helm/go-loose/values-prd.yaml
integration-test: integration-test:
name: Integration Tests
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: build-and-test needs: build-test
services: services:
postgres: postgres:
image: postgres:17-alpine image: postgres:17-alpine
@ -60,151 +43,70 @@ jobs:
POSTGRES_DB: goloose POSTGRES_DB: goloose
POSTGRES_USER: goloose POSTGRES_USER: goloose
POSTGRES_PASSWORD: goloose POSTGRES_PASSWORD: goloose
ports: ['5432:5432'] ports: [5432:5432]
options: >- options: >-
--health-cmd="pg_isready -U goloose -d goloose" --health-cmd="pg_isready -U goloose -d goloose"
--health-interval=5s --health-interval=5s
--health-timeout=3s --health-timeout=3s
--health-retries=10 --health-retries=10
steps: steps:
- name: Checkout repository - uses: actions/checkout@v4
uses: actions/checkout@v4 - uses: actions/setup-go@v5
- name: Set up Go
uses: actions/setup-go@v5
with: with:
go-version: ${{ env.GO_VERSION }} go-version-file: go.mod
cache: true cache: true
- name: Run database-backed tests
- name: Download dependencies env:
run: go mod download PGPASSWORD: goloose
GO_LOOSE_TEST_DATABASE_URL: postgres://goloose:goloose@localhost:5432/goloose_test?sslmode=disable
- name: Create test databases GO_LOOSE_TEST_SERVER_DATABASE_URL: postgres://goloose:goloose@localhost:5432/goloose_server_test?sslmode=disable
GO_LOOSE_BEHAVIOUR_DATABASE_URL: postgres://goloose:goloose@localhost:5432/goloose_behaviour_test?sslmode=disable
run: | run: |
sleep 5 sleep 5
createdb -h localhost -U goloose goloose_test || true createdb -h localhost -U goloose goloose_test || true
createdb -h localhost -U goloose goloose_server_test || true createdb -h localhost -U goloose goloose_server_test || true
createdb -h localhost -U goloose goloose_behaviour_test || true createdb -h localhost -U goloose goloose_behaviour_test || true
- name: Run integration tests
env:
GO_LOOSE_TEST_DATABASE_URL: postgres://goloose:goloose@localhost:5432/goloose_test?sslmode=disable
GO_LOOSE_TEST_SERVER_DATABASE_URL: postgres://goloose:goloose@localhost:5432/goloose_server_test?sslmode=disable
GO_LOOSE_BEHAVIOUR_DATABASE_URL: postgres://goloose:goloose@localhost:5432/goloose_behaviour_test?sslmode=disable
run: |
go test -race ./internal/store/ ./internal/server/ -count=1 go test -race ./internal/store/ ./internal/server/ -count=1
GO_LOOSE_BEHAVIOUR=1 go test ./internal/behaviour/ -count=1 -v GO_LOOSE_BEHAVIOUR=1 go test ./internal/behaviour/ -count=1 -v
docker: publish:
name: Build and Push Docker Image if: (github.event_name == 'push' && github.ref == 'refs/heads/main') || (github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main')
needs: [build-test, integration-test]
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [build-and-test, integration-test]
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
permissions:
contents: read
packages: write
steps: steps:
- name: Checkout repository - uses: actions/checkout@v4
uses: actions/checkout@v4 - uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Nexus Registry
uses: docker/login-action@v3
with: with:
registry: ${{ env.REGISTRY }} registry: ${{ env.REGISTRY }}
username: ${{ secrets.NEXUS_USERNAME }} username: ${{ secrets.NEXUS_USERNAME }}
password: ${{ secrets.NEXUS_PASSWORD }} password: ${{ secrets.NEXUS_PASSWORD }}
- uses: docker/build-push-action@v6
- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha
- name: Build and push Docker image
uses: docker/build-push-action@v5
with: with:
context: . context: .
file: Dockerfile
push: true push: true
tags: ${{ steps.meta.outputs.tags }} tags: |
labels: ${{ steps.meta.outputs.labels }} ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
cache-from: type=gha ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
cache-to: type=gha,mode=max
# deploy-tst:
# name: Deploy to TST
# runs-on: ubuntu-latest
# needs: docker
# if: github.event_name == 'push' && github.ref == 'refs/heads/develop'
# permissions:
# contents: read
# id-token: write
# environment: tst
#
# steps:
# - name: Checkout repository
# uses: actions/checkout@v4
#
# - name: Set up Helm
# uses: azure/setup-helm@v4
# with:
# version: 'v3.14.0'
#
# - name: Set up kubectl
# uses: azure/k8s-set-context@v4
# with:
# kubeconfig: ${{ secrets.KUBECONFIG_TST }}
#
# - name: Deploy to TST with Helm
# run: |
# helm upgrade --install go-loose ./deploy/helm/go-loose \
# --namespace go-loose \
# --create-namespace \
# --set image.repository=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} \
# --set image.tag=${{ github.sha }} \
# --set image.pullSecrets[0].name=nexus-registry \
# --wait --timeout 5m
deploy-prd: deploy-prd:
name: Deploy to PRD if: (github.event_name == 'push' && github.ref == 'refs/heads/main') || (github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main')
needs: publish
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: docker
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
permissions:
contents: read
id-token: write
environment: prd
steps: steps:
- name: Checkout repository - uses: actions/checkout@v4
uses: actions/checkout@v4 - uses: azure/setup-helm@v4
- name: Set up Helm
uses: azure/setup-helm@v4
with: with:
version: 'v3.14.0' version: v3.18.6
- uses: azure/setup-kubectl@v4
- name: Set up kubectl
uses: azure/k8s-set-context@v4
with: with:
kubeconfig: ${{ secrets.KUBECONFIG_PRD }} version: v1.32.2
- name: Bootstrap resources and deploy go-loose
- name: Deploy to PRD with Helm env:
KUBECONFIG_PRD: ${{ secrets.KUBECONFIG_PRD }}
NEXUS_USERNAME: ${{ secrets.NEXUS_USERNAME }}
NEXUS_PASSWORD: ${{ secrets.NEXUS_PASSWORD }}
run: | run: |
helm upgrade --install go-loose ./deploy/helm/go-loose \ set -Eeuo pipefail
--namespace go-loose \ bash .forgejo/scripts/deploy-prd.sh deploy/helm/go-loose go-loose go-loose "${{ github.sha }}"
--create-namespace \
--values ./deploy/helm/go-loose/values-prd.yaml \
--set image.repository=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} \
--set image.tag=${{ github.ref_name }} \
--wait --timeout 5m

View file

@ -0,0 +1,6 @@
dependencies:
- name: postgresql
repository: https://charts.bitnami.com/bitnami
version: 16.7.27
digest: sha256:e8b999a3aaad6328a13d0c666207650897b69c61367c947d363b2acbe0ea1b42
generated: "2026-10-04T19:38:06.343578353+02:00"

View file

@ -2,9 +2,14 @@ apiVersion: v2
name: go-loose name: go-loose
description: Authentication and authorization service for urpi platform. Provides OIDC, session management, and tenant isolation. description: Authentication and authorization service for urpi platform. Provides OIDC, session management, and tenant isolation.
type: application type: application
version: 1.0.0 version: 1.1.0
appVersion: "1.0.0" appVersion: "1.0.0"
kubeVersion: ">=1.28.0-0" kubeVersion: ">=1.28.0-0"
dependencies:
- name: postgresql
version: "16.x.x"
repository: "https://charts.bitnami.com/bitnami"
condition: postgresql.enabled
keywords: keywords:
- authentication - authentication
- authorization - authorization
@ -20,4 +25,4 @@ maintainers:
url: https://github.com/urpi url: https://github.com/urpi
annotations: annotations:
category: Security category: Security
licenses: MIT licenses: MIT

View file

@ -0,0 +1,81 @@
# Go Loose Helm chart
This is the canonical Go Loose chart. The central deploy script and the Go Loose
CI workflow both use this directory.
## Environment profiles
Use one profile file per environment:
| Environment | Namespace | Profile | Ingress class | TLS issuer |
|---|---|---|---|---|
| `dev` | `go-insane-dev` | `values-dev.yaml` | nginx | `letsencrypt-staging` |
| `tst` | `go-insane-tst` | `values-tst.yaml` | nginx | `letsencrypt-staging` |
| `prd` | `go-insane-prd` | `values-prd.yaml` | nginx | `letsencrypt-prod` |
| `lcl` | `go-insane-lcl` | `values-lcl.yaml` | Traefik | local TLS |
The namespace is supplied by Helm's release namespace; it is not hard-coded in
the chart templates.
## Runtime Secret contract
Before a release, the target namespace must contain `go-loose-runtime` with:
| Key | Used for |
|---|---|
| `postgresql-password` | PostgreSQL application user's password |
| `postgres-password` | PostgreSQL administrator password |
| `database-url` | `GO_LOOSE_DATABASE_URL` |
| `session-secret` | `GO_LOOSE_SESSION_SECRET` |
The chart reads these values using Kubernetes `secretKeyRef` and the PostgreSQL
subchart's `existingSecret` support. Runtime credentials are not stored in chart
values or Helm release configuration.
To provision/update the secret from protected files without printing its values:
```bash
/home/dnoulet/go/ops/scripts/apply-go-loose-secret.sh \
<dev|tst|prd|lcl> \
/secure/path/postgresql-password \
/secure/path/database-url \
/secure/path/session-secret \
[kubeconfig]
```
The input files should contain only the required value (no trailing newline).
The helper creates the environment namespace if it is not present, then applies
the Secret. It does not print secret values.
The PRD CI deployment script maintains the same secret contract automatically.
Do not commit the input files or put their contents in a Helm values file.
## Tenant wildcard ingress
Go Guess signs in through tenant-specific hosts such as
`nmbs.auth.dev-urpi.be` and `nmbs.auth.urpi.be`. The chart therefore
creates a second ingress for `*.auth-<env>...` and requires a separate TLS Secret
named `go-loose-wildcard-tls` in the same namespace. The central deploy script
and PRD CI check for this Secret before installing the release.
Provision it from a trusted wildcard certificate and private key:
```bash
kubectl --kubeconfig <kubeconfig> --namespace go-insane-<env> create secret tls \
go-loose-wildcard-tls --cert=/secure/path/wildcard.crt \
--key=/secure/path/wildcard.key
```
The PRD `letsencrypt-prod` issuer documented for the apex ingress uses HTTP-01;
HTTP-01 cannot issue wildcard certificates. Obtain this certificate through
DNS-01 or the approved certificate authority, then provision the Secret. Do not
put the private key in the chart, repository, or Helm release values.
## Validation
```bash
helm lint . -f values-dev.yaml
helm lint . -f values-tst.yaml
helm lint . -f values-prd.yaml
helm lint . -f values-lcl.yaml
```

View file

@ -40,14 +40,20 @@ spec:
containerPort: {{ .Values.service.targetPort }} containerPort: {{ .Values.service.targetPort }}
protocol: TCP protocol: TCP
env: env:
- name: GO_LOOSE_DATABASE_URL
valueFrom:
secretKeyRef:
name: {{ .Values.runtimeSecret.name }}
key: {{ .Values.runtimeSecret.keys.databaseURL }}
- name: GO_LOOSE_SESSION_SECRET
valueFrom:
secretKeyRef:
name: {{ .Values.runtimeSecret.name }}
key: {{ .Values.runtimeSecret.keys.sessionSecret }}
{{- range $key, $value := .Values.env }} {{- range $key, $value := .Values.env }}
- name: {{ $key }} - name: {{ $key }}
value: {{ $value | quote }} value: {{ $value | quote }}
{{- end }} {{- end }}
{{- range $key, $value := .Values.envSecrets }}
- name: {{ $key }}
value: {{ $value | quote }}
{{- end }}
livenessProbe: livenessProbe:
{{- toYaml .Values.livenessProbe | nindent 12 }} {{- toYaml .Values.livenessProbe | nindent 12 }}
readinessProbe: readinessProbe:
@ -65,4 +71,4 @@ spec:
{{- with .Values.tolerations }} {{- with .Values.tolerations }}
tolerations: tolerations:
{{- toYaml . | nindent 8 }} {{- toYaml . | nindent 8 }}
{{- end }} {{- end }}

View file

@ -1,12 +0,0 @@
apiVersion: v1
kind: Secret
metadata:
name: {{ include "go-loose.fullname" . }}-env
namespace: {{ .Release.Namespace }}
labels:
{{- include "go-loose.labels" . | nindent 4 }}
type: Opaque
stringData:
{{- range $key, $value := .Values.envSecrets }}
{{ $key }}: {{ $value | quote }}
{{- end }}

View file

@ -0,0 +1,30 @@
{{- if .Values.wildcardIngress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "go-loose.fullname" . }}-wildcard
namespace: {{ .Release.Namespace }}
labels:
{{- include "go-loose.labels" . | nindent 4 }}
{{- with .Values.wildcardIngress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
ingressClassName: {{ .Values.wildcardIngress.className }}
tls:
- secretName: {{ .Values.wildcardIngress.tlsSecretName }}
hosts:
- {{ .Values.wildcardIngress.host | quote }}
rules:
- host: {{ .Values.wildcardIngress.host | quote }}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: {{ include "go-loose.fullname" . }}
port:
number: {{ .Values.service.port }}
{{- end }}

View file

@ -0,0 +1,46 @@
replicaCount: 1
image:
repository: nexus.urpi.be/docker-hosted/go-loose
tag: latest
pullPolicy: Always
imagePullSecrets:
- name: nexus-registry
ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-staging
nginx.ingress.kubernetes.io/ssl-redirect: "true"
hosts:
- host: auth.dev-urpi.be
paths:
- path: /
pathType: Prefix
tls:
- secretName: go-loose-dev-tls
hosts:
- auth.dev-urpi.be
wildcardIngress:
enabled: true
className: nginx
host: "*.auth.dev-urpi.be"
tlsSecretName: go-loose-wildcard-tls
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
postgresql:
primary:
persistence:
enabled: true
size: 5Gi
env:
GO_LOOSE_BASE_URL: https://auth.dev-urpi.be
GO_LOOSE_AUTH_DOMAIN: auth.dev-urpi.be
GO_LOOSE_OIDC_REDIRECT_URL: https://auth.dev-urpi.be/auth/callback
GO_LOOSE_DEV_LOGIN: "true"
GO_LOOSE_LOCAL_LOGIN: "true"

View file

@ -0,0 +1,65 @@
replicaCount: 1
imagePullSecrets: []
ingress:
enabled: true
className: traefik
annotations:
cert-manager.io/cluster-issuer: urpi-private-ca
hosts:
# Apex only. The tenant hosts are served by wildcardIngress below, so that
# each host family keeps its own certificate: go-loose-lcl-tls covers the
# apex, go-loose-wildcard-tls covers *.auth.lcl-urpi.be.
- host: auth.lcl-urpi.be
paths:
- path: /
pathType: Prefix
tls:
- secretName: go-loose-lcl-tls
hosts:
- auth.lcl-urpi.be
# Serves every <tenant>.auth.lcl-urpi.be. Adding a tenant is then a row in the
# database only: no Helm upgrade, no new certificate, no per-host rule.
wildcardIngress:
enabled: true
className: traefik
host: "*.auth.lcl-urpi.be"
tlsSecretName: go-loose-wildcard-tls
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
certManager:
enabled: true
issuerRef:
name: urpi-private-ca
kind: ClusterIssuer
postgresql:
enabled: true
image:
# Bitnami removed its versioned tags from Docker Hub; only :latest remains
# for bitnami/postgresql. The tag pinned in values.yaml (16.4.0) now 404s
# and leaves the StatefulSet in ImagePullBackOff.
tag: "latest"
auth:
database: goloose
username: goloose
password: "goloose"
existingSecret: go-loose-runtime
secretKeys:
adminPasswordKey: postgres-password
userPasswordKey: postgresql-password
primary:
persistence:
enabled: false
size: 5Gi
env:
GO_LOOSE_ADDR: ":8080"
GO_LOOSE_BASE_URL: "https://lcl-urpi.be"
GO_LOOSE_AUTH_DOMAIN: "auth.lcl-urpi.be"
GO_LOOSE_OIDC_REDIRECT_URL: "https://lcl-urpi.be/auth/callback"
GO_LOOSE_DEV_LOGIN: "true"
GO_LOOSE_LOCAL_LOGIN: "true"
GO_LOOSE_ALLOW_PRIVATE_CONTRACT_URLS: "true"

View file

@ -5,7 +5,7 @@ imagePullSecrets:
- name: nexus-registry - name: nexus-registry
image: image:
repository: nexus-registry.urpi.be/docker-hosted/go-loose repository: nexus.urpi.be/docker-hosted/go-loose
tag: "0.0.1" tag: "0.0.1"
pullPolicy: Always pullPolicy: Always
@ -16,9 +16,10 @@ service:
ingress: ingress:
enabled: true enabled: true
className: traefik className: nginx
annotations: annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/ssl-redirect: "true"
# nginx.ingress.kubernetes.io/ssl-redirect: "true" # nginx.ingress.kubernetes.io/ssl-redirect: "true"
# nginx.ingress.kubernetes.io/proxy-body-size: "10m" # nginx.ingress.kubernetes.io/proxy-body-size: "10m"
hosts: hosts:
@ -31,6 +32,14 @@ ingress:
hosts: hosts:
- auth.urpi.be - auth.urpi.be
wildcardIngress:
enabled: true
className: nginx
host: "*.auth.urpi.be"
tlsSecretName: go-loose-wildcard-tls
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
certManager: certManager:
enabled: true enabled: true
issuerRef: issuerRef:
@ -69,13 +78,9 @@ env:
GO_LOOSE_AUTH_DOMAIN: "auth.urpi.be" GO_LOOSE_AUTH_DOMAIN: "auth.urpi.be"
GO_LOOSE_OIDC_REDIRECT_URL: "https://auth.urpi.be/auth/callback" GO_LOOSE_OIDC_REDIRECT_URL: "https://auth.urpi.be/auth/callback"
GO_LOOSE_DEV_LOGIN: "false" GO_LOOSE_DEV_LOGIN: "false"
GO_LOOSE_LOCAL_LOGIN: "true" GO_LOOSE_LOCAL_LOGIN: "false"
GO_LOOSE_ALLOW_PRIVATE_CONTRACT_URLS: "true" GO_LOOSE_ALLOW_PRIVATE_CONTRACT_URLS: "true"
envSecrets:
GO_LOOSE_DATABASE_URL: "postgres://goloose:changeme@go-loose-postgresql:5432/goloose?sslmode=disable"
GO_LOOSE_SESSION_SECRET: "changeme-generate-secure-random"
livenessProbe: livenessProbe:
httpGet: httpGet:
path: /healthz path: /healthz
@ -92,4 +97,4 @@ readinessProbe:
initialDelaySeconds: 10 initialDelaySeconds: 10
periodSeconds: 10 periodSeconds: 10
timeoutSeconds: 3 timeoutSeconds: 3
failureThreshold: 3 failureThreshold: 3

View file

@ -0,0 +1,46 @@
replicaCount: 1
image:
repository: nexus.urpi.be/docker-hosted/go-loose
tag: latest
pullPolicy: Always
imagePullSecrets:
- name: nexus-registry
ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-staging
nginx.ingress.kubernetes.io/ssl-redirect: "true"
hosts:
- host: auth.tst-urpi.be
paths:
- path: /
pathType: Prefix
tls:
- secretName: go-loose-tst-tls
hosts:
- auth.tst-urpi.be
wildcardIngress:
enabled: true
className: nginx
host: "*.auth.tst-urpi.be"
tlsSecretName: go-loose-wildcard-tls
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
postgresql:
primary:
persistence:
enabled: true
size: 5Gi
env:
GO_LOOSE_BASE_URL: https://auth.tst-urpi.be
GO_LOOSE_AUTH_DOMAIN: auth.tst-urpi.be
GO_LOOSE_OIDC_REDIRECT_URL: https://auth.tst-urpi.be/auth/callback
GO_LOOSE_DEV_LOGIN: "false"
GO_LOOSE_LOCAL_LOGIN: "false"

View file

@ -54,6 +54,13 @@ ingress:
hosts: hosts:
- auth.urpi.be - auth.urpi.be
wildcardIngress:
enabled: false
className: nginx
host: "*.auth.urpi.be"
tlsSecretName: go-loose-wildcard-tls
annotations: {}
certManager: certManager:
enabled: true enabled: true
issuerRef: issuerRef:
@ -74,12 +81,24 @@ autoscaling:
maxReplicas: 3 maxReplicas: 3
targetCPUUtilizationPercentage: 80 targetCPUUtilizationPercentage: 80
runtimeSecret:
name: go-loose-runtime
keys:
databaseURL: database-url
sessionSecret: session-secret
postgresql: postgresql:
enabled: true enabled: true
image:
tag: "16.4.0"
auth: auth:
database: goloose database: goloose
username: goloose username: goloose
password: changeme password: "goloose"
existingSecret: go-loose-runtime
secretKeys:
adminPasswordKey: postgres-password
userPasswordKey: postgresql-password
primary: primary:
persistence: persistence:
enabled: true enabled: true
@ -98,13 +117,9 @@ env:
GO_LOOSE_AUTH_DOMAIN: "auth.urpi.be" GO_LOOSE_AUTH_DOMAIN: "auth.urpi.be"
GO_LOOSE_OIDC_REDIRECT_URL: "https://auth.urpi.be/auth/callback" GO_LOOSE_OIDC_REDIRECT_URL: "https://auth.urpi.be/auth/callback"
GO_LOOSE_DEV_LOGIN: "false" GO_LOOSE_DEV_LOGIN: "false"
GO_LOOSE_LOCAL_LOGIN: "true" GO_LOOSE_LOCAL_LOGIN: "false"
GO_LOOSE_ALLOW_PRIVATE_CONTRACT_URLS: "true" GO_LOOSE_ALLOW_PRIVATE_CONTRACT_URLS: "true"
envSecrets:
GO_LOOSE_DATABASE_URL: ""
GO_LOOSE_SESSION_SECRET: ""
livenessProbe: livenessProbe:
httpGet: httpGet:
path: /healthz path: /healthz
@ -125,4 +140,4 @@ readinessProbe:
nodeSelector: {} nodeSelector: {}
tolerations: [] tolerations: []
affinity: {} affinity: {}

18
docs/commands Normal file
View file

@ -0,0 +1,18 @@
# Delete the incomplete secret
kubectl delete secret go-loose-runtime --kubeconfig=/home/dnoulet/.kube/config_lcl --insecure-skip-tls-verify -n go-insane-lcl --ignore-not-found
# Recreate it with all required properties mapped correctly
kubectl create secret generic go-loose-runtime \
--from-literal=postgres-password="goloose" \
--from-literal=postgresql-password="goloose" \
--from-literal=session-secret="localdevsecret123" \
--from-literal=database-url="postgres://goloose:goloose@go-loose-postgresql:5432/goloose?sslmode=disable" \
--kubeconfig=/home/dnoulet/.kube/config_lcl \
--insecure-skip-tls-verify \
-n go-insane-lcl
KUBECONFIG=~/.kube/config_lcl kubectl config set-cluster local --insecure-skip-tls-verify=true
openssl s_client -showcerts -connect rancher.intern-urpi.be:443 </dev/null 2>/dev/null | sed -n '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ~/.kube/rancher-ca.crt
KUBECONFIG=~/.kube/config_lcl kubectl config set-cluster local --certificate-authority=/home/dnoulet/.kube/rancher-ca.crt
KUBECONFIG=~/.kube/config_lcl kubectl config set-cluster local --insecure-skip-tls-verify=false