diff --git a/.buildkite/hooks/pre-artifact b/.buildkite/hooks/pre-artifact index 362dbe840..6b9ab6bfb 100755 --- a/.buildkite/hooks/pre-artifact +++ b/.buildkite/hooks/pre-artifact @@ -3,7 +3,7 @@ set +u declare -A BUILDS=(["linux"]="amd64 arm arm64 amd64-musl arm-musl arm64-musl" ["freebsd"]="amd64") -DOCKER_IMAGE=authelia/authelia +DOCKER_IMAGE=authelia:dist if [[ "${BUILDKITE_LABEL}" == ":hammer_and_wrench: Unit Test" ]]; then if [[ ! "${BUILDKITE_BRANCH}" =~ ^renovate/ ]]; then @@ -35,4 +35,4 @@ if [[ "${BUILDKITE_LABEL}" =~ ":debian: Build Package" ]]; then for f in *.deb; do mv "$f" "$(echo "$f" | sed s/${VERSION}-1_//)"; done fi sha256sum "authelia_${PACKAGE}.deb" > "authelia_${PACKAGE}.deb.sha256" -fi \ No newline at end of file +fi diff --git a/.buildkite/hooks/pre-command b/.buildkite/hooks/pre-command index a7e2411a6..134f01d9f 100755 --- a/.buildkite/hooks/pre-command +++ b/.buildkite/hooks/pre-command @@ -30,10 +30,13 @@ fi if [[ "${BUILDKITE_LABEL}" =~ ":selenium:" ]]; then DEFAULT_ARCH=coverage - echo "--- :docker: Extract, load and tag build container" + echo "--- :docker: Extract and load build container" buildkite-agent artifact download "authelia-image-${DEFAULT_ARCH}*" . - zstdcat "authelia-image-${DEFAULT_ARCH}.tar.zst" | docker load - docker tag authelia/authelia authelia:dist + if [[ "${SUITE}" == "Kubernetes" ]]; then + zstd -d authelia-image-coverage.tar.zst --stdout > ./internal/suites/example/kube/authelia-image-${DEFAULT_ARCH}.tar + else + zstdcat "authelia-image-${DEFAULT_ARCH}.tar.zst" | docker load + fi if [[ "${BUILD_DUO}" == "true" ]] && [[ "${SUITE}" == "DuoPush" ]]; then CONTAINER="integration-duo" diff --git a/.editorconfig b/.editorconfig index 0466ef21c..cc3c38a0c 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,7 +7,11 @@ trim_trailing_whitespace = true end_of_line = lf insert_final_newline = true -[{.buildkite/hooks/**,*.sh,*.yml,*.yaml}] +[*.{sh,yml,yaml}] +indent_style = space +indent_size = 2 + +[.buildkite/hooks/**] indent_style = space indent_size = 2 diff --git a/.gitignore b/.gitignore index aab30be7a..7bb4c5401 100644 --- a/.gitignore +++ b/.gitignore @@ -1,50 +1,27 @@ +# IDE user configuration +.idea/ +.vscode/ -# NodeJs modules +# Nodejs modules +.pnpm-store/ node_modules/ -# npm debug logs -npm-debug.log* - # Coverage reports coverage/ +.nyc_output/ coverage.txt -.vscode/ - -*.swp -*~ - -# Directory used by example -/notifications/ - -# VSCode user configuration -.vscode/ - # Generated by TypeScript compiler dist/ -.nyc_output/ - -*.tgz - # Specific files /configuration.yml /config.yml /config.test.yml -internal/suites/example/ldap/private.ldif - -Configuration.schema.json - .suite .kube -.idea +authelia-image-dev.tar -.authelia-interrupt - -qemu-*-static - -public_html.gen.go - -authelia +/authelia __debug_bin diff --git a/.renovaterc b/.renovaterc index 9ddef69e8..9ca3f6696 100644 --- a/.renovaterc +++ b/.renovaterc @@ -14,12 +14,17 @@ "workarounds:all" ], "enabledManagers": [ - "bundler", "docker-compose", "dockerfile", "gomod", + "kubernetes", "npm" ], + { + "kubernetes": { + "fileMatch": ["kube/.+\\.yml$"] + } + } "labels": [ "dependencies" ], @@ -47,6 +52,14 @@ "go" ] }, + { + "datasources": [ + "kubernetes" + ], + "addLabels": [ + "kubernetes" + ] + }, { "datasources": [ "npm" diff --git a/cmd/authelia-scripts/cmd/bootstrap.go b/cmd/authelia-scripts/cmd/bootstrap.go index eb511639f..0e43531d6 100644 --- a/cmd/authelia-scripts/cmd/bootstrap.go +++ b/cmd/authelia-scripts/cmd/bootstrap.go @@ -87,12 +87,19 @@ var hostEntries = []HostEntry{ {Domain: "mail.example.com", IP: "192.168.240.100"}, {Domain: "duo.example.com", IP: "192.168.240.100"}, - // For Traefik suite. - {Domain: "traefik.example.com", IP: "192.168.240.100"}, - // For HAProxy suite. {Domain: "haproxy.example.com", IP: "192.168.240.100"}, + // Kubernetes dashboard. + {Domain: "kubernetes.example.com", IP: "192.168.240.100"}, + + // OIDC tester app. + {Domain: "oidc.example.com", IP: "192.168.240.100"}, + {Domain: "oidc-public.example.com", IP: "192.168.240.100"}, + + // For Traefik suite. + {Domain: "traefik.example.com", IP: "192.168.240.100"}, + // For testing network ACLs. {Domain: "proxy-client1.example.com", IP: "192.168.240.201"}, {Domain: "proxy-client2.example.com", IP: "192.168.240.202"}, @@ -107,12 +114,6 @@ var hostEntries = []HostEntry{ {Domain: "redis-sentinel-0.example.com", IP: "192.168.240.120"}, {Domain: "redis-sentinel-1.example.com", IP: "192.168.240.121"}, {Domain: "redis-sentinel-2.example.com", IP: "192.168.240.122"}, - - // Kubernetes dashboard. - {Domain: "kubernetes.example.com", IP: "192.168.240.110"}, - // OIDC tester app. - {Domain: "oidc.example.com", IP: "192.168.240.100"}, - {Domain: "oidc-public.example.com", IP: "192.168.240.100"}, } func runCommand(cmd string, args ...string) { diff --git a/internal/suites/const.go b/internal/suites/const.go index 4d2d9258c..8a8f11cda 100644 --- a/internal/suites/const.go +++ b/internal/suites/const.go @@ -58,6 +58,12 @@ const ( testPassword = "password" ) +const ( + namespaceAuthelia = "authelia" + namespaceDashboard = "kubernetes-dashboard" + namespaceKube = "kube-system" +) + var ( storageLocalTmpConfig = schema.Configuration{ TOTP: schema.TOTPConfiguration{ diff --git a/internal/suites/environment.go b/internal/suites/environment.go index bbdbd5909..9cf51979b 100644 --- a/internal/suites/environment.go +++ b/internal/suites/environment.go @@ -58,6 +58,15 @@ func waitUntilAutheliaFrontendIsReady(dockerEnvironment *DockerEnvironment) erro []string{"dev server running at", "ready in"}) } +func waitUntilK3DIsReady(dockerEnvironment *DockerEnvironment) error { + return waitUntilServiceLogDetected( + 5*time.Second, + 90*time.Second, + dockerEnvironment, + "k3d", + []string{"API listen on [::]:2376"}) +} + func waitUntilSambaIsReady(dockerEnvironment *DockerEnvironment) error { return waitUntilServiceLogDetected( 5*time.Second, diff --git a/internal/suites/example/compose/k3d/docker-compose.yml b/internal/suites/example/compose/k3d/docker-compose.yml new file mode 100644 index 000000000..0f463249b --- /dev/null +++ b/internal/suites/example/compose/k3d/docker-compose.yml @@ -0,0 +1,26 @@ +--- +version: '3' +services: + k3d: + image: ghcr.io/k3d-io/k3d:5.4.6-dind + volumes: + - './example/kube:/authelia' + - './example/kube/authelia/configs/configuration.yml:/configmaps/authelia/configuration.yml' + - './common/ssl:/configmaps/authelia/ssl' + - './example/compose/ldap/ldif:/configmaps/ldap' + - './example/compose/nginx/backend:/configmaps/nginx-backend' + privileged: true + networks: + authelianet: + aliases: + - public.example.com + - secure.example.com + - login.example.com + - admin.example.com + - dev.example.com + - mail.example.com + - kubernetes.example.com + - traefik.example.com + # Set the IP to be able to query on port 443 + ipv4_address: 192.168.240.100 +... diff --git a/internal/suites/example/compose/kind/Dockerfile b/internal/suites/example/compose/kind/Dockerfile deleted file mode 100644 index 5051892d2..000000000 --- a/internal/suites/example/compose/kind/Dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -FROM alpine:3.17.0 - -WORKDIR /kind - -RUN apk add --no-cache bash curl docker && \ - curl -Lo kind https://github.com/kubernetes-sigs/kind/releases/download/v0.10.0/kind-linux-amd64 && chmod +x kind && \ - curl -Lo kubectl https://storage.googleapis.com/kubernetes-release/release/v1.20.2/bin/linux/amd64/kubectl && chmod +x kubectl - -ADD entrypoint.sh entrypoint.sh -ADD patch-kubeconfig.sh patch-kubeconfig.sh - -ENV HOME=/kind/config -ENV KUBECONFIG=/kind/config/.kube/kind-config-kind - -VOLUME /kind/config - -ENTRYPOINT ["./entrypoint.sh"] \ No newline at end of file diff --git a/internal/suites/example/compose/kind/config.yml b/internal/suites/example/compose/kind/config.yml deleted file mode 100644 index a6a8b70f3..000000000 --- a/internal/suites/example/compose/kind/config.yml +++ /dev/null @@ -1,9 +0,0 @@ ---- -kind: Cluster -apiVersion: kind.x-k8s.io/v1alpha4 -containerdConfigPatches: - # yamllint disable-line rule:indentation - - |- - [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"] - endpoint = ["http://registrycache.internal:5000"] -... diff --git a/internal/suites/example/compose/kind/docker-compose.yml b/internal/suites/example/compose/kind/docker-compose.yml deleted file mode 100644 index d8d599880..000000000 --- a/internal/suites/example/compose/kind/docker-compose.yml +++ /dev/null @@ -1,44 +0,0 @@ ---- -version: '3' -services: - authelia-kind-proxy: - build: - context: ./example/compose/kind - volumes: - - 'kind-volume:/kind/config' - - '/var/run/docker.sock:/var/run/docker.sock' - - './example/kube:/authelia' - - './example/compose/kind/config.yml:/etc/kind/config.yml' - command: 'kubectl port-forward --address 0.0.0.0 -n authelia service/nginx-ingress-controller-service 8080:443' - environment: - - KIND_EXPERIMENTAL_DOCKER_NETWORK=authelia_authelianet - networks: - authelianet: - aliases: - - public.example.com - - secure.example.com - - login.example.com - - admin.example.com - - dev.example.com - - mail.example.com - # Set the IP to be able to query on port 443 - ipv4_address: 192.168.240.100 - - kube-dashboard: - build: - context: ./example/compose/kind - volumes: - - 'kind-volume:/kind/config' - - './example/compose/kind/entrypoint-dashboard.sh:/entrypoint-dashboard.sh' - command: '/entrypoint-dashboard.sh' - environment: - - KIND_EXPERIMENTAL_DOCKER_NETWORK=authelia_authelianet - networks: - authelianet: - aliases: - - kubernetes.example.com - ipv4_address: 192.168.240.110 - -volumes: - kind-volume: # yamllint disable-line rule:empty-values -... diff --git a/internal/suites/example/compose/kind/entrypoint-dashboard.sh b/internal/suites/example/compose/kind/entrypoint-dashboard.sh deleted file mode 100755 index e94c5e0ec..000000000 --- a/internal/suites/example/compose/kind/entrypoint-dashboard.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash - -# Retries a command on failure. -# $1 - the max number of attempts -# $2... - the command to run - -retry() { - local -r -i max_attempts="$1"; shift - local -r cmd="$@" - local -i attempt_num=1 - until $cmd - do - if ((attempt_num==max_attempts)) - then - echo "Attempt $attempt_num failed and there are no more attempts left!" - return 1 - else - echo "Attempt $attempt_num failed! Trying again in 10 seconds..." - sleep 10 - fi - done -} - -kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep admin-user | awk '{print $1}') -retry 10 kubectl port-forward --address 0.0.0.0 -n kubernetes-dashboard service/kubernetes-dashboard 443:443 \ No newline at end of file diff --git a/internal/suites/example/compose/kind/entrypoint.sh b/internal/suites/example/compose/kind/entrypoint.sh deleted file mode 100755 index c93edc815..000000000 --- a/internal/suites/example/compose/kind/entrypoint.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -export PATH=/kind:$PATH - -exec "$@" \ No newline at end of file diff --git a/internal/suites/example/compose/kind/patch-kubeconfig.sh b/internal/suites/example/compose/kind/patch-kubeconfig.sh deleted file mode 100755 index e103a5b7c..000000000 --- a/internal/suites/example/compose/kind/patch-kubeconfig.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh - -# This script patches the kubeconfig generated by Kind in order to access the cluster container via this container - -echo "Patching Kubeconfig to target Kube container without link" -sed -i "s/127.0.0.1:.*/$(docker inspect -f '{{(index .NetworkSettings.Networks "authelia_authelianet").IPAddress}}' kind-control-plane):6443/" ${KUBECONFIG} \ No newline at end of file diff --git a/internal/suites/example/kube/README.md b/internal/suites/example/kube/README.md deleted file mode 100644 index 395fa1960..000000000 --- a/internal/suites/example/kube/README.md +++ /dev/null @@ -1,62 +0,0 @@ -# Authelia on Kubernetes - -Authelia is now available on Kube in order to protect your most critical -applications using 2-factor authentication and Single Sign-On. - -This example leverages [ingress-nginx](https://github.com/kubernetes/ingress-nginx) -to delegate authentication and authorization to Authelia within the cluster. - -## Getting started - -You can either try to install **Authelia** on your running instance of Kubernetes -or deploy the dedicated [suite](/docs/suites.md) called *kubernetes*. - -### Set up a Kube cluster - -The simplest way to start a Kubernetes cluster is to deploy the *kubernetes* suite with - - authelia-scripts suites setup kubernetes - -This will take a few seconds (or minutes) to deploy the cluster. - -## How does it work? - -### Authentication via Authelia - -In a Kube clusters, the routing logic of requests is handled by ingress -controllers following rules provided by ingress configurations. - -In this example, [ingress-nginx](https://github.com/kubernetes/ingress-nginx) -controller has been installed to handle the incoming requests. Some of them -(specified in the ingress configuration) are forwarded to Authelia so that -it can verify whether they are allowed and should reach the protected endpoint. - -The authentication is provided at the ingress level by an annotation called -`nginx.ingress.kubernetes.io/auth-url` that is filled with the URL of -Authelia's verification endpoint. -The ingress controller also requires the URL to the -authentication portal so that the user can be redirected if he is not -yet authenticated. This annotation is as follows: -`nginx.ingress.kubernetes.io/auth-signin: "https://login.example.com:8080/"` - -Those annotations can be seen in `apps/apps.yml` configuration. - -### Production grade infrastructure - -What is great with using [ingress-nginx](https://github.com/kubernetes/ingress-nginx) -is that it is compatible with [kube-lego](https://github.com/jetstack/kube-lego) -which removes the usual pain of manually renewing SSL certificates. It uses -letsencrypt to issue and renew certificates every three month without any -manual intervention. - -## What do I need to know to deploy it in my cluster? - -Given your cluster already runs a LDAP server, a Redis, a SQL database, -a SMTP server and a nginx ingress-controller, you can deploy **Authelia** -and update your ingress configurations. An example is provided -[here](authelia). - -## Questions - -If you have questions about the implementation, please post them on -[![Gitter](https://img.shields.io/gitter/room/badges/shields.svg)](https://gitter.im/authelia/general?utm_source=share-link&utm_medium=link&utm_campaign=share-link) diff --git a/internal/suites/example/kube/apps/apps.yml b/internal/suites/example/kube/apps/apps.yml deleted file mode 100644 index 498292ffb..000000000 --- a/internal/suites/example/kube/apps/apps.yml +++ /dev/null @@ -1,154 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: test-app - namespace: authelia - labels: - app: test-app -spec: - replicas: 1 - selector: - matchLabels: - app: test-app - template: - metadata: - labels: - app: test-app - spec: - containers: - - name: test-app - image: nginx:alpine - command: ["/entrypoint.sh"] - ports: - - containerPort: 80 - volumeMounts: - - name: config-volume - mountPath: /entrypoint.sh - subPath: entrypoint.sh - - name: config-volume - mountPath: /etc/nginx/nginx.conf - subPath: nginx.conf - - name: config-volume - mountPath: /tmp/html.tar.gz - subPath: html.tar.gz - volumes: - - name: config-volume - configMap: - name: nginx-config - items: - - key: entrypoint.sh - path: entrypoint.sh - mode: 0755 # yamllint disable-line rule:octal-values - - key: nginx.conf - path: nginx.conf - - key: html.tar.gz - path: html.tar.gz -... ---- -apiVersion: v1 -kind: Service -metadata: - name: test-app-service - namespace: authelia - labels: - app: test-app -spec: - selector: - app: test-app - ports: - - port: 80 - name: http - - port: 443 - name: https -... ---- -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: insecure-ingress - namespace: authelia - annotations: - kubernetes.io/ingress.class: "nginx" - kubernetes.io/ingress.allow-http: "false" - nginx.ingress.kubernetes.io/force-ssl-redirect: "true" -spec: - tls: - - secretName: test-app-tls - hosts: - - home.example.com - rules: - - host: home.example.com - http: - paths: - - path: / - backend: - serviceName: test-app-service - servicePort: 80 -... ---- -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: secure-ingress - namespace: authelia - annotations: - kubernetes.io/ingress.class: "nginx" - kubernetes.io/ingress.allow-http: "false" - nginx.ingress.kubernetes.io/force-ssl-redirect: "true" - nginx.ingress.kubernetes.io/auth-url: "https://authelia-service.authelia.svc.cluster.local/api/verify" - nginx.ingress.kubernetes.io/auth-signin: "https://login.example.com:8080/" -spec: - tls: - - secretName: test-app-tls - hosts: - - public.example.com - - admin.example.com - - dev.example.com - - mx1.mail.example.com - - mx2.mail.example.com - - singlefactor.example.com - rules: - - host: public.example.com - http: - paths: - - path: / - backend: - serviceName: test-app-service - servicePort: 80 - - host: admin.example.com - http: - paths: - - path: / - backend: - serviceName: test-app-service - servicePort: 80 - - host: dev.example.com - http: - paths: - - path: / - backend: - serviceName: test-app-service - servicePort: 80 - - host: mx1.mail.example.com - http: - paths: - - path: / - backend: - serviceName: test-app-service - servicePort: 80 - - host: mx2.mail.example.com - http: - paths: - - path: / - backend: - serviceName: test-app-service - servicePort: 80 - - host: singlefactor.example.com - http: - paths: - - path: / - backend: - serviceName: test-app-service - servicePort: 80 -... diff --git a/internal/suites/example/kube/apps/configs/entrypoint.sh b/internal/suites/example/kube/apps/configs/entrypoint.sh deleted file mode 100644 index 971912ff2..000000000 --- a/internal/suites/example/kube/apps/configs/entrypoint.sh +++ /dev/null @@ -1,5 +0,0 @@ -#! /bin/sh - -rm -rf /usr/share/nginx/html && \ -tar xfz /tmp/html.tar.gz -C /usr/share/nginx/ && \ -nginx "-g daemon off;" \ No newline at end of file diff --git a/internal/suites/example/kube/apps/configs/html.tar.gz b/internal/suites/example/kube/apps/configs/html.tar.gz deleted file mode 100644 index c0f308e48..000000000 Binary files a/internal/suites/example/kube/apps/configs/html.tar.gz and /dev/null differ diff --git a/internal/suites/example/kube/apps/configs/nginx.conf b/internal/suites/example/kube/apps/configs/nginx.conf deleted file mode 100644 index 37d20fdae..000000000 --- a/internal/suites/example/kube/apps/configs/nginx.conf +++ /dev/null @@ -1,51 +0,0 @@ -worker_processes 1; - -events { - worker_connections 1024; -} - - -http { - server { - listen 80; - root /usr/share/nginx/html/home; - server_name home.example.com; - } - - server { - listen 80; - root /usr/share/nginx/html/public; - server_name public.example.com; - } - - server { - listen 80; - root /usr/share/nginx/html/secure; - server_name secure.example.com; - } - - server { - listen 80; - root /usr/share/nginx/html/admin; - server_name admin.example.com; - } - - server { - listen 80; - root /usr/share/nginx/html/dev; - server_name dev.example.com; - } - - server { - listen 80; - root /usr/share/nginx/html/mail; - server_name mx1.mail.example.com mx2.mail.example.com; - } - - server { - listen 80; - root /usr/share/nginx/html/singlefactor; - server_name singlefactor.example.com; - } -} - diff --git a/internal/suites/example/kube/apps/nginx.yml b/internal/suites/example/kube/apps/nginx.yml new file mode 100644 index 000000000..a604ade1f --- /dev/null +++ b/internal/suites/example/kube/apps/nginx.yml @@ -0,0 +1,138 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-backend + namespace: authelia + labels: + app: nginx-backend +spec: + replicas: 1 + selector: + matchLabels: + app: nginx-backend + template: + metadata: + labels: + app: nginx-backend + spec: + containers: + - name: nginx-backend + image: nginx:alpine + ports: + - containerPort: 80 + volumeMounts: + - name: nginx-config + mountPath: /etc/nginx/nginx.conf + - name: nginx-html + mountPath: /usr/share/nginx/html + volumes: + - name: nginx-config + hostPath: + path: /configmaps/nginx-backend/nginx.conf + type: File + - name: nginx-html + hostPath: + path: /configmaps/nginx-backend/html + type: Directory +... +--- +apiVersion: v1 +kind: Service +metadata: + name: nginx-backend-service + namespace: authelia + labels: + app: nginx-backend +spec: + selector: + app: nginx-backend + ports: + - port: 80 + name: http + - port: 443 + name: https +... +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: nginx-backend-ingress + namespace: authelia + annotations: + kubernetes.io/ingress.class: traefik + traefik.ingress.kubernetes.io/router.entrypoints: websecure + traefik.ingress.kubernetes.io/router.middlewares: authelia-forwardauth-authelia@kubernetescrd +spec: + rules: + - host: home.example.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: nginx-backend-service + port: + number: 80 + - host: public.example.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: nginx-backend-service + port: + number: 80 + - host: admin.example.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: nginx-backend-service + port: + number: 80 + - host: dev.example.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: nginx-backend-service + port: + number: 80 + - host: mx1.mail.example.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: nginx-backend-service + port: + number: 80 + - host: mx2.mail.example.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: nginx-backend-service + port: + number: 80 + - host: singlefactor.example.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: nginx-backend-service + port: + number: 80 +... diff --git a/internal/suites/example/kube/apps/ssl/server.cert b/internal/suites/example/kube/apps/ssl/server.cert deleted file mode 100644 index 0fd2ff140..000000000 --- a/internal/suites/example/kube/apps/ssl/server.cert +++ /dev/null @@ -1,19 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDEzCCAfugAwIBAgIUJZXxXExVQPJhc8TnlD+uAAYHlvwwDQYJKoZIhvcNAQEL -BQAwGDEWMBQGA1UEAwwNKi5leGFtcGxlLmNvbTAgFw0xOTA5MjYyMDAwMTBaGA8y -MTE5MDkwMjIwMDAxMFowGDEWMBQGA1UEAwwNKi5leGFtcGxlLmNvbTCCASIwDQYJ -KoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3DFTAdrxG6iOj5UjSeB5lMjMQQyeYm -OxUvswwwBzmQYPUt0inAJ9QmXJ8i9Fbye8HHYUeqE5zsEfeHir81MiWfhi9oUzJt -u3bmxGLDXYaApejd18hBKITX6MYogmK2lWrl/F9zPYxc2xM/fqWnGg2xwdrMmida -hZjDUfh0rtoz8zqOzJaiiDoFMwNO+NTGmDbeOwBFYOF1OTkS3aJWwJCLZmINUG8h -Z3YPR+SL8CpGGl0xhJYAwXD1AtMlYwAteTILqrqvo2XkGsvuj0mx0w/D0DDpC48g -oSNsRIVTW3Ql3uu+kXDFtkf4I63Ctt85rZk1kX3QtYmS0pRzvmyY/b0CAwEAAaNT -MFEwHQYDVR0OBBYEFMTozK79Kp813+8TstjXRFw1MTE5MB8GA1UdIwQYMBaAFMTo -zK79Kp813+8TstjXRFw1MTE5MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL -BQADggEBALf1bJf3qF3m54+q98E6lSE+34yi/rVdzB9reAW1QzvvqdJRtsfjt39R -SznsbmrvCfK4SLyOj9Uhd8Z6bASPPNsUux1XAGN4AqaGmlYI8b7j3LhKCdRBZQ0I -zWgPhocyWwp5VkFe68zR06NHme/2B6eBRFsdd/69DIOv9YnEGUHk3A/9v1zvolt9 -krW57Oz63zWGYXmtPPTD8of/Ya6NKqwonVx1MUQ5QzqH3WySYhRsIYqwUEXm9jt5 -GEM3Nx0phEltaOLXa71nqS/Rhg/5Kod0cFaNoSKb6N93I8bqKKTK0m5wMJ5Fisrm -Pw5+AIar7RT5gHU2DD2/OTb9bXXww8I= ------END CERTIFICATE----- diff --git a/internal/suites/example/kube/apps/ssl/server.key b/internal/suites/example/kube/apps/ssl/server.key deleted file mode 100644 index 268a2a1c3..000000000 --- a/internal/suites/example/kube/apps/ssl/server.key +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEAvcMVMB2vEbqI6PlSNJ4HmUyMxBDJ5iY7FS+zDDAHOZBg9S3S -KcAn1CZcnyL0VvJ7wcdhR6oTnOwR94eKvzUyJZ+GL2hTMm27dubEYsNdhoCl6N3X -yEEohNfoxiiCYraVauX8X3M9jFzbEz9+pacaDbHB2syaJ1qFmMNR+HSu2jPzOo7M -lqKIOgUzA0741MaYNt47AEVg4XU5ORLdolbAkItmYg1QbyFndg9H5IvwKkYaXTGE -lgDBcPUC0yVjAC15Mguquq+jZeQay+6PSbHTD8PQMOkLjyChI2xEhVNbdCXe676R -cMW2R/gjrcK23zmtmTWRfdC1iZLSlHO+bJj9vQIDAQABAoIBAEZvkP/JJOCJwqPn -V3IcbmmilmV4bdi1vByDFgyiDyx4wOSA24+PubjvfFW9XcCgRPuKjDtTj/AhWBHv -B7stfa2lZuNV7/u562mZArA+IAr62Zp0LdIxDV8x3T8gbjVB3HhPYbv0RJZDKTYd -zV6jhfIrVu9mHpoY6ZnodhapCPYIyk/d49KBIHZuAc25CUjMXgTeaVtf0c996036 -UxW6ef33wAOJAvW0RCvbXAJfmBeEq2qQlkjTIlpYx71fhZWexHifi8Ouv3Zonc+1 -/P2Adq5uzYVBT92f9RKHg9QxxNzVrLjSMaxyvUtWQCAQfW0tFIRdqBGsHYsQrFtI -F4yzv8ECgYEA7ntpyN9HD9Z9lYQzPCR73sFCLM+ID99aVij0wHuxK97bkSyyvkLd -7MyTaym3lg1UEqWNWBCLvFULZx7F0Ah6qCzD4ymm3Bj/ADpWWPgljBI0AFml+HHs -hcATmXUrj5QbLyhiP2gmJjajp1o/rgATx6ED66seSynD6JOH8wUhhZUCgYEAy7OA -06PF8GfseNsTqlDjNF0K7lOqd21S0prdwrsJLiVzUlfMM25MLE0XLDUutCnRheeh -IlcuDoBsVTxz6rkvFGD74N+pgXlN4CicsBq5ofK060PbqCQhSII3fmHobrZ9Cr75 -HmBjAxHx998SKaAAGbBbcYGUAp521i1pH5CEPYkCgYEAkUd1Zf0+2RMdZhwm6hh/ -rW+l1I6IoMK70YkZsLipccRNld7Y9LbfYwYtODcts6di9AkOVfueZJiaXbONZfIE -Zrb+jkAteh9wGL9xIrnohbABJcV3Kiaco84jInUSmGDtPokncOENfHIEuEpuSJ2b -bx1TuhmAVuGWivR0+ULC7RECgYEAgS0cDRpWc9Xzh9Cl7+PLsXEvdWNpPsL9OsEq -0Ep7z9+/+f/jZtoTRCS/BTHUpDvAuwHglT5j3p5iFMt5VuiIiovWLwynGYwrbnNS -qfrIrYKUaH1n1oDS+oBZYLQGCe9/7EifAjxtjYzbvSyg//SPG7tSwfBCREbpZXj2 -qSWkNsECgYA/mCDzCTlrrWPuiepo6kTmN+4TnFA+hJI6NccDVQ+jvbqEdoJ4SW4L -zqfZSZRFJMNpSgIqkQNRPJqMP0jQ5KRtJrjMWBnYxktwKz9fDg2R2MxdFgMF2LH2 -HEMMhFHlv8NDjVOXh1KwRoltNGVWYsSrD9wKU9GhRCEfmNCGrvBcEg== ------END RSA PRIVATE KEY----- diff --git a/internal/suites/example/kube/authelia/authelia.yml b/internal/suites/example/kube/authelia/authelia.yml new file mode 100644 index 000000000..da1366902 --- /dev/null +++ b/internal/suites/example/kube/authelia/authelia.yml @@ -0,0 +1,153 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: authelia + namespace: authelia + labels: + app: authelia +spec: + replicas: 1 + selector: + matchLabels: + app: authelia + template: + metadata: + labels: + app: authelia + spec: + containers: + - name: authelia + image: authelia:dist + ports: + - containerPort: 443 + readinessProbe: + httpGet: + scheme: HTTPS + path: /api/health + port: 443 + initialDelaySeconds: 3 + periodSeconds: 3 + volumeMounts: + - name: authelia-config + mountPath: /config/configuration.yml + readOnly: true + - name: authelia-ssl + mountPath: /config/ssl + readOnly: true + - name: secrets + mountPath: /config/secrets + readOnly: true + env: + # We set secrets directly here for ease of deployment but all secrets + # should be stored in the Kube Vault in production. + - name: AUTHELIA_JWT_SECRET_FILE + value: /config/secrets/jwt_secret + - name: AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PASSWORD_FILE + value: /config/secrets/ldap_password + - name: AUTHELIA_SESSION_SECRET_FILE + value: /config/secrets/session + - name: AUTHELIA_STORAGE_MYSQL_PASSWORD_FILE + value: /config/secrets/sql_password + - name: AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE + value: /config/secrets/encryption_key + - name: ENVIRONMENT + value: dev + volumes: + - name: authelia-config + hostPath: + path: /configmaps/authelia/configuration.yml + type: File + - name: authelia-ssl + hostPath: + path: /configmaps/authelia/ssl + type: Directory + - name: secrets + secret: + secretName: authelia + items: + - key: jwt_secret + path: jwt_secret + - key: session + path: session + - key: sql_password + path: sql_password + - key: ldap_password + path: ldap_password + - key: encryption_key + path: encryption_key +... +--- +apiVersion: v1 +kind: Service +metadata: + name: authelia-service + namespace: authelia + annotations: + traefik.ingress.kubernetes.io/service.serverstransport: authelia-skipverify@kubernetescrd +spec: + selector: + app: authelia + ports: + - protocol: TCP + port: 443 + targetPort: 443 +... +--- +apiVersion: v1 +kind: Secret +type: Opaque +metadata: + name: authelia + namespace: authelia + labels: + app: authelia +data: + jwt_secret: YW5fdW5zZWN1cmVfc2VjcmV0 # an_unsecure_secret + ldap_password: cGFzc3dvcmQ= # password + session: dW5zZWN1cmVfcGFzc3dvcmQ= # unsecure_password + sql_password: cGFzc3dvcmQ= # password + encryption_key: YV9ub3Rfc29fc2VjdXJlX2VuY3J5cHRpb25fa2V5 +... +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: authelia-ingress + namespace: authelia + annotations: + kubernetes.io/ingress.class: traefik + traefik.ingress.kubernetes.io/router.entrypoints: websecure +spec: + rules: + - host: login.example.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: authelia-service + port: + number: 443 +... +--- +apiVersion: traefik.containo.us/v1alpha1 +kind: Middleware +metadata: + name: forwardauth-authelia + namespace: authelia + labels: + app.kubernetes.io/instance: authelia + app.kubernetes.io/name: authelia +spec: + forwardAuth: + address: https://authelia-service.authelia.svc.cluster.local/api/verify?rd=https://login.example.com:8080 + authResponseHeaders: + - Remote-User + - Remote-Name + - Remote-Email + - Remote-Groups + tls: + insecureSkipVerify: true +... diff --git a/internal/suites/example/kube/authelia/configs/configuration.yml b/internal/suites/example/kube/authelia/configs/configuration.yml index b4d3ece18..08a91542f 100644 --- a/internal/suites/example/kube/authelia/configs/configuration.yml +++ b/internal/suites/example/kube/authelia/configs/configuration.yml @@ -35,6 +35,8 @@ access_control: rules: # Rules applied to everyone + - domain: home.example.com + policy: bypass - domain: public.example.com policy: bypass - domain: secure.example.com diff --git a/internal/suites/example/kube/authelia/deployment.yml b/internal/suites/example/kube/authelia/deployment.yml deleted file mode 100644 index 6a4156ecf..000000000 --- a/internal/suites/example/kube/authelia/deployment.yml +++ /dev/null @@ -1,76 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: authelia - namespace: authelia - labels: - app: authelia -spec: - replicas: 1 - selector: - matchLabels: - app: authelia - template: - metadata: - labels: - app: authelia - spec: - containers: - - name: authelia - image: authelia:dist - ports: - - containerPort: 443 - volumeMounts: - - name: config-volume - mountPath: /config - - name: ssl-volume - mountPath: /config/ssl - - name: secrets - mountPath: /app/secrets - readOnly: true - env: - # We set secrets directly here for ease of deployment but all secrets - # should be stored in the Kube Vault in production. - - name: AUTHELIA_JWT_SECRET_FILE - value: /app/secrets/jwt_secret - - name: AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PASSWORD_FILE - value: /app/secrets/ldap_password - - name: AUTHELIA_SESSION_SECRET_FILE - value: /app/secrets/session - - name: AUTHELIA_STORAGE_MYSQL_PASSWORD_FILE - value: /app/secrets/sql_password - - name: AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE - value: /app/secrets/encryption_key - - name: ENVIRONMENT - value: dev - volumes: - - name: config-volume - configMap: - name: authelia-config - items: - - key: configuration.yml - path: configuration.yml - - name: ssl-volume - configMap: - name: authelia-ssl - items: - - key: cert.pem - path: cert.pem - - key: key.pem - path: key.pem - - name: secrets - secret: - secretName: authelia - items: - - key: jwt_secret - path: jwt_secret - - key: session - path: session - - key: sql_password - path: sql_password - - key: ldap_password - path: ldap_password - - key: encryption_key - path: encryption_key -... diff --git a/internal/suites/example/kube/authelia/ingress.yml b/internal/suites/example/kube/authelia/ingress.yml deleted file mode 100644 index 5d7f78cbf..000000000 --- a/internal/suites/example/kube/authelia/ingress.yml +++ /dev/null @@ -1,23 +0,0 @@ ---- -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: authelia-ingress - namespace: authelia - annotations: - kubernetes.io/ingress.class: "nginx" - nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" -spec: - tls: - - secretName: authelia-tls - hosts: - - login.example.com - rules: - - host: login.example.com - http: - paths: - - path: / - backend: - serviceName: authelia-service - servicePort: 443 -... diff --git a/internal/suites/example/kube/authelia/secret.yml b/internal/suites/example/kube/authelia/secret.yml deleted file mode 100644 index de5e501e5..000000000 --- a/internal/suites/example/kube/authelia/secret.yml +++ /dev/null @@ -1,16 +0,0 @@ ---- -apiVersion: v1 -kind: Secret -type: Opaque -metadata: - name: authelia - namespace: authelia - labels: - app: authelia -data: - jwt_secret: YW5fdW5zZWN1cmVfc2VjcmV0 # an_unsecure_secret - ldap_password: cGFzc3dvcmQ= # password - session: dW5zZWN1cmVfcGFzc3dvcmQ= # unsecure_password - sql_password: cGFzc3dvcmQ= # password - encryption_key: YV9ub3Rfc29fc2VjdXJlX2VuY3J5cHRpb25fa2V5 -... diff --git a/internal/suites/example/kube/authelia/service.yml b/internal/suites/example/kube/authelia/service.yml deleted file mode 100644 index af7686132..000000000 --- a/internal/suites/example/kube/authelia/service.yml +++ /dev/null @@ -1,14 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - name: authelia-service - namespace: authelia -spec: - selector: - app: authelia - ports: - - protocol: TCP - port: 443 - targetPort: 443 -... diff --git a/internal/suites/example/kube/authelia/ssl/cert.pem b/internal/suites/example/kube/authelia/ssl/cert.pem deleted file mode 100644 index 9fabcb421..000000000 --- a/internal/suites/example/kube/authelia/ssl/cert.pem +++ /dev/null @@ -1,19 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIC/jCCAeagAwIBAgIRAKF0IRxC55eee6icERVf6fgwDQYJKoZIhvcNAQELBQAw -EjEQMA4GA1UEChMHQWNtZSBDbzAgFw0yMDAzMDExMjMzMzlaGA8yMTIwMDIwNjEy -MzMzOVowEjEQMA4GA1UEChMHQWNtZSBDbzCCASIwDQYJKoZIhvcNAQEBBQADggEP -ADCCAQoCggEBAMi7/oSazFIxP3rHsSLjw5XPnpMKEaVwU1zLRzW6W80BDa/ER5to -I3POGLv8lAhtUwB6WvyilrCZfs/D5lkcCxswafU/2LNppFuODnW+PG9eobgOy6Nv -f+KbnZFPRV7PB2yK6DqMyb+tbTQ7F6rEf4i6n28DI0dNyNvUCk0ld3o93LZBvC/D -/+Ulf3Vtdfsd2TckXvdA8lH4VGQJ+FIxhboTlbW8VJlk1V7FZef7+m867kOnPSaj -zv5yygrIA0XPaMAZC/SZrXHMdhvcs43fgmmTel7JD4Sy/Z/pmFlrZr5Xa8jcWycJ -ILLuPnXhgKstgq5wtDkTMZ6rpgMrKcjMKcMCAwEAAaNNMEswDgYDVR0PAQH/BAQD -AgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwFgYDVR0RBA8w -DYILZXhhbXBsZS5jb20wDQYJKoZIhvcNAQELBQADggEBABdWkbipzPivAvvamMmQ -5iPPeStfdr5MBxJGT9nPbeXdtS/13FJnspLBMMYOw/2AZk7VFrNjxkXc4NHZSlGz -FcGMlSO40fyirdYaQTDtS230ucLB+LzfZx37y9dKpEKVmQ151kKJjJ4hAZ47LmAQ -aFoDLRo7PA2HmnJ60GrI9wVp96uy1sQ6PcToIyMcVEQ/tLEEow+ykSeiZb9+qBKV -K9GUcu2LorhBtUMmEWs0TJElaf6eKUoG6JXM2byulDg24w5b9gC26kAlHWc5WDU5 -pAXOjlN/OYHB0sDbYViWIL390376fYIfu2N5EDKY4QjEYsWEs4Wm9HVS9IgHP/Gi -Xbo= ------END CERTIFICATE----- diff --git a/internal/suites/example/kube/authelia/ssl/key.pem b/internal/suites/example/kube/authelia/ssl/key.pem deleted file mode 100644 index a190f8b44..000000000 --- a/internal/suites/example/kube/authelia/ssl/key.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDIu/6EmsxSMT96 -x7Ei48OVz56TChGlcFNcy0c1ulvNAQ2vxEebaCNzzhi7/JQIbVMAelr8opawmX7P -w+ZZHAsbMGn1P9izaaRbjg51vjxvXqG4Dsujb3/im52RT0Vezwdsiug6jMm/rW00 -OxeqxH+Iup9vAyNHTcjb1ApNJXd6Pdy2Qbwvw//lJX91bXX7Hdk3JF73QPJR+FRk -CfhSMYW6E5W1vFSZZNVexWXn+/pvOu5Dpz0mo87+csoKyANFz2jAGQv0ma1xzHYb -3LON34Jpk3peyQ+Esv2f6ZhZa2a+V2vI3FsnCSCy7j514YCrLYKucLQ5EzGeq6YD -KynIzCnDAgMBAAECggEAC13R0LJvRWwyewJZvm8FQTNreEoGq8aLgeKk2p792cLo -gn5ry5n+/+y4q9RmkX+XRpynEE0omUFn09306jDTVCvOpCuEWsxtmR2XJgWqqGfE -Yoa78zo6FJvZNUQ22mKAuh23frFAL1FjsKRz96B+1EA1DPUxhzUZXZFJMAsiE9LZ -PxqPmnqXbPZsOb1XG33TAdCp6CC3H8KHICC+i4IC8prjKHGH/Q1saoNw8jmgwv0S -DelQUbEtqfmE6BmyTGxdeu4uW2Nv/wcENwySAOPKi5gstlbSKTa4IpKGp7CdquWi -stUW6pnSiEeDrDAzwC8uWdncOvnkAy2lRJkz/F9YoQKBgQDrCCqYdvGshecBBnfQ -fowxak2YBfG2jhAKPMHzrvQn5FIb+11x/jeXPEfOB6FShIzZ97JpFIpH3tcONlj3 -OVzGCTD6WdRTcltzXVneJtNog7DliNFY4YmIPmQJ+y+EvJW1rSZTZAZI1Nbijg3n -fSd0PTzvgOGHSl1//RI1mFx7MwKBgQDapIPPSF0yf1UJ6Hhzam5NHGZ9fSqV5Qs0 -Gi7uM08iDV5K7xiPglBkbN2EuMlgVnHaa5g8X897uwRSYR6nL4PRvcJiNSvnhWhe -+K3x7iHewIPYVfcghoqzuPKsXH2Zm26usdXHxBBa3IBbKtGaHnAd9h65AOUYAmAx -C2BzN90XMQKBgE2MjEFyPZunMulrsOziVG+Zm7ClhXOuvCwkj/pPp8/hzhXdgp+y -ObV09lxMuDX59l+VExEI7fd414yg8gngq3PMZJS2PxCpkvMlwhlCxk6d5ShXVHv3 -LuH9dBS3BJ7PerZPQ24QeuJdF+n45S2UZgg8jHaaF9AEAYXRgsicVSdxAoGAJI0U -K/bg/awjv0BJwqGsRt/Ukm32TJC5ysAF0HRrajnp5YULChKy9dbtQV7S63QIHIeY -L5+kw/6DvnHV+gULeGjMsjZJXK8Ev7u6+JLivqZYZDYa1iknztvAVegwZxmA61t3 -bantQgNSwerql2U3QQsAH9Vydw0On6RTP2+7WkECgYBWD3u64hBKmAxPkqPotkgI -w/jdOlv8FLHO79+oH1PtKvkzspcYaecKGDm/RNLIXLYnt0AmZEK4qQ4/zDFaR/rc -AhoxK2cKTRltMrhp1ivtFfLggVGogtYNxEnjnsD4KMvH3SjSNdt06YgtZ92++fOp -UsE8Mpf4/G5X7DmcHJHk+w== ------END PRIVATE KEY----- diff --git a/internal/suites/example/kube/bootstrap-authelia.sh b/internal/suites/example/kube/bootstrap-authelia.sh deleted file mode 100755 index 80ad7c1e1..000000000 --- a/internal/suites/example/kube/bootstrap-authelia.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -start_authelia() { - kubectl create configmap authelia-config --namespace=authelia --from-file=authelia/configs/configuration.yml - kubectl create configmap authelia-ssl --namespace=authelia --from-file=authelia/ssl/cert.pem --from-file=authelia/ssl/key.pem - kubectl apply -f authelia -} - -start_authelia \ No newline at end of file diff --git a/internal/suites/example/kube/bootstrap-dashboard.sh b/internal/suites/example/kube/bootstrap-dashboard.sh deleted file mode 100755 index bbaddf893..000000000 --- a/internal/suites/example/kube/bootstrap-dashboard.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash - -start_dashboard() { - kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta8/aio/deploy/recommended.yaml - kubectl apply -f dashboard.yml - - echo "Bearer token for UI user." - kubectl -n kubernetes-dashboard describe secret $(kubectl -n kubernetes-dashboard get secret | grep admin-user | awk '{print $1}') -} - -start_dashboard diff --git a/internal/suites/example/kube/bootstrap.sh b/internal/suites/example/kube/bootstrap.sh deleted file mode 100755 index bdc087e70..000000000 --- a/internal/suites/example/kube/bootstrap.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/sh - -start_apps() { - # Create TLS certificate and key for HTTPS termination - kubectl create secret generic test-app-tls --namespace=authelia --from-file=apps/ssl/server.key --from-file=apps/ssl/server.cert - kubectl create configmap nginx-config --namespace=authelia --from-file=apps/configs/entrypoint.sh --from-file=apps/configs/nginx.conf --from-file=apps/configs/html.tar.gz - - # Spawn the applications - kubectl apply -f apps -} - -start_ingress_controller() { - kubectl apply -f ingress-controller -} - -# Spawn Redis and storage backend -# Please note they are not configured to be distributed on several machines -start_storage() { - kubectl apply -f storage -} - -# Create a fake mailbox to catch emails sent by Authelia -start_mail() { - kubectl apply -f mail -} - -start_ldap() { - kubectl create configmap ldap-config --namespace=authelia --from-file=ldap/base.ldif --from-file=ldap/access.rules - kubectl apply -f ldap -} - -# Create the Authelia namespace in the cluster -create_namespace() { - kubectl apply -f namespace.yml -} - -create_namespace -start_storage -start_ldap -start_mail -start_ingress_controller -start_apps diff --git a/internal/suites/example/kube/dashboard.yml b/internal/suites/example/kube/dashboard.yml deleted file mode 100644 index 4abe4a715..000000000 --- a/internal/suites/example/kube/dashboard.yml +++ /dev/null @@ -1,21 +0,0 @@ ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: admin-user - namespace: kubernetes-dashboard -... ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: admin-user -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: cluster-admin -subjects: - - kind: ServiceAccount - name: admin-user - namespace: kubernetes-dashboard -... diff --git a/internal/suites/example/kube/dashboards.yml b/internal/suites/example/kube/dashboards.yml new file mode 100644 index 000000000..9735a2c51 --- /dev/null +++ b/internal/suites/example/kube/dashboards.yml @@ -0,0 +1,346 @@ +# Kubernetes Dashboard +--- +apiVersion: v1 +kind: Namespace +metadata: + name: kubernetes-dashboard +... +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + k8s-app: kubernetes-dashboard + name: kubernetes-dashboard + namespace: kubernetes-dashboard +... +--- +kind: Service +apiVersion: v1 +metadata: + labels: + k8s-app: kubernetes-dashboard + name: kubernetes-dashboard + namespace: kubernetes-dashboard +spec: + ports: + - port: 443 + targetPort: 8443 + selector: + k8s-app: kubernetes-dashboard +... +--- +apiVersion: v1 +kind: Secret +metadata: + labels: + k8s-app: kubernetes-dashboard + name: kubernetes-dashboard-certs + namespace: kubernetes-dashboard +type: Opaque +... +--- +apiVersion: v1 +kind: Secret +metadata: + labels: + k8s-app: kubernetes-dashboard + name: kubernetes-dashboard-csrf + namespace: kubernetes-dashboard +type: Opaque +data: + csrf: "" +... +--- +apiVersion: v1 +kind: Secret +metadata: + labels: + k8s-app: kubernetes-dashboard + name: kubernetes-dashboard-key-holder + namespace: kubernetes-dashboard +type: Opaque +... +--- +kind: ConfigMap +apiVersion: v1 +metadata: + labels: + k8s-app: kubernetes-dashboard + name: kubernetes-dashboard-settings + namespace: kubernetes-dashboard +... +--- +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + labels: + k8s-app: kubernetes-dashboard + name: kubernetes-dashboard + namespace: kubernetes-dashboard +rules: + # Allow Dashboard to get, update and delete Dashboard exclusive secrets. + - apiGroups: [""] + resources: ["secrets"] + resourceNames: ["kubernetes-dashboard-key-holder", "kubernetes-dashboard-certs", "kubernetes-dashboard-csrf"] + verbs: ["get", "update", "delete"] + # Allow Dashboard to get and update 'kubernetes-dashboard-settings' config map. + - apiGroups: [""] + resources: ["configmaps"] + resourceNames: ["kubernetes-dashboard-settings"] + verbs: ["get", "update"] + # Allow Dashboard to get metrics. + - apiGroups: [""] + resources: ["services"] + resourceNames: ["heapster", "dashboard-metrics-scraper"] + verbs: ["proxy"] + - apiGroups: [""] + resources: ["services/proxy"] + resourceNames: ["heapster", "http:heapster:", "https:heapster:", "dashboard-metrics-scraper", "http:dashboard-metrics-scraper"] # yamllint disable-line rule:line-length + verbs: ["get"] +... +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + labels: + k8s-app: kubernetes-dashboard + name: kubernetes-dashboard +rules: + # Allow Metrics Scraper to get metrics from the Metrics server + - apiGroups: ["metrics.k8s.io"] + resources: ["pods", "nodes"] + verbs: ["get", "list", "watch"] +... +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: + k8s-app: kubernetes-dashboard + name: kubernetes-dashboard + namespace: kubernetes-dashboard +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: kubernetes-dashboard +subjects: + - kind: ServiceAccount + name: kubernetes-dashboard + namespace: kubernetes-dashboard +... +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: kubernetes-dashboard +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: kubernetes-dashboard +subjects: + - kind: ServiceAccount + name: kubernetes-dashboard + namespace: kubernetes-dashboard +... +--- +kind: Deployment +apiVersion: apps/v1 +metadata: + labels: + k8s-app: kubernetes-dashboard + name: kubernetes-dashboard + namespace: kubernetes-dashboard +spec: + replicas: 1 + revisionHistoryLimit: 10 + selector: + matchLabels: + k8s-app: kubernetes-dashboard + template: + metadata: + labels: + k8s-app: kubernetes-dashboard + spec: + securityContext: + seccompProfile: + type: RuntimeDefault + containers: + - name: kubernetes-dashboard + image: kubernetesui/dashboard:v2.7.0 + imagePullPolicy: Always + ports: + - containerPort: 8443 + protocol: TCP + args: + - --auto-generate-certificates + - --namespace=kubernetes-dashboard + # Uncomment the following line to manually specify Kubernetes API server Host + # If not specified, Dashboard will attempt to auto discover the API server and connect + # to it. Uncomment only if the default does not work. + # - --apiserver-host=http://my-address:port + volumeMounts: + - name: kubernetes-dashboard-certs + mountPath: /certs + # Create on-disk volume to store exec logs + - mountPath: /tmp + name: tmp-volume + livenessProbe: + httpGet: + scheme: HTTPS + path: / + port: 8443 + initialDelaySeconds: 30 + timeoutSeconds: 30 + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + runAsUser: 1001 + runAsGroup: 2001 + volumes: + - name: kubernetes-dashboard-certs + secret: + secretName: kubernetes-dashboard-certs + - name: tmp-volume + emptyDir: {} + serviceAccountName: kubernetes-dashboard + nodeSelector: + "kubernetes.io/os": linux + # Comment the following tolerations if Dashboard must not be deployed on master + tolerations: + - key: node-role.kubernetes.io/master + effect: NoSchedule +... +--- +kind: Service +apiVersion: v1 +metadata: + labels: + k8s-app: dashboard-metrics-scraper + name: dashboard-metrics-scraper + namespace: kubernetes-dashboard +spec: + ports: + - port: 8000 + targetPort: 8000 + selector: + k8s-app: dashboard-metrics-scraper +... +--- +kind: Deployment +apiVersion: apps/v1 +metadata: + labels: + k8s-app: dashboard-metrics-scraper + name: dashboard-metrics-scraper + namespace: kubernetes-dashboard +spec: + replicas: 1 + revisionHistoryLimit: 10 + selector: + matchLabels: + k8s-app: dashboard-metrics-scraper + template: + metadata: + labels: + k8s-app: dashboard-metrics-scraper + spec: + securityContext: + seccompProfile: + type: RuntimeDefault + containers: + - name: dashboard-metrics-scraper + image: kubernetesui/metrics-scraper:v1.0.8 + ports: + - containerPort: 8000 + protocol: TCP + livenessProbe: + httpGet: + scheme: HTTP + path: / + port: 8000 + initialDelaySeconds: 30 + timeoutSeconds: 30 + volumeMounts: + - mountPath: /tmp + name: tmp-volume + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + runAsUser: 1001 + runAsGroup: 2001 + serviceAccountName: kubernetes-dashboard + nodeSelector: + "kubernetes.io/os": linux + # Comment the following tolerations if Dashboard must not be deployed on master + tolerations: + - key: node-role.kubernetes.io/master + effect: NoSchedule + volumes: + - name: tmp-volume + emptyDir: {} +... +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: admin-user + namespace: kubernetes-dashboard +... +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: admin-user +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin +subjects: + - kind: ServiceAccount + name: admin-user + namespace: kubernetes-dashboard +... +--- +apiVersion: traefik.containo.us/v1alpha1 +kind: IngressRouteTCP +metadata: + name: kubernetes-dashboard-ingress + namespace: kubernetes-dashboard +spec: + entryPoints: + - websecure + routes: + - match: HostSNI(`kubernetes.example.com`) + services: + - name: kubernetes-dashboard + port: 443 + tls: + passthrough: true +... +# Traefik Dashboard +--- +apiVersion: traefik.containo.us/v1alpha1 +kind: IngressRoute +metadata: + name: traefik-dashboard-ingress + namespace: authelia +spec: + entryPoints: + - websecure + routes: + - match: Host(`traefik.example.com`) + kind: Rule + services: + - name: api@internal + kind: TraefikService +... +--- +apiVersion: traefik.containo.us/v1alpha1 +kind: ServersTransport +metadata: + name: skipverify + namespace: authelia +spec: + insecureSkipVerify: true +... diff --git a/internal/suites/example/kube/ingress-controller/deployment.yml b/internal/suites/example/kube/ingress-controller/deployment.yml deleted file mode 100644 index 432941e22..000000000 --- a/internal/suites/example/kube/ingress-controller/deployment.yml +++ /dev/null @@ -1,45 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: nginx-ingress-controller - namespace: authelia - labels: - app: nginx-ingress-controller -spec: - replicas: 1 - revisionHistoryLimit: 0 - selector: - matchLabels: - app: nginx-ingress-controller - template: - metadata: - labels: - app: nginx-ingress-controller - annotations: - prometheus.io/port: '10254' - prometheus.io/scrape: 'true' - spec: - terminationGracePeriodSeconds: 60 - serviceAccountName: nginx-ingress-controller-serviceaccount - containers: - - image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.23.0 - name: nginx-ingress-controller - imagePullPolicy: Always - ports: - - containerPort: 80 - - containerPort: 443 - env: - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - args: - - /nginx-ingress-controller - - --ingress-class=nginx - - --election-id=ingress-controller-leader -... diff --git a/internal/suites/example/kube/ingress-controller/rbac.yml b/internal/suites/example/kube/ingress-controller/rbac.yml deleted file mode 100644 index d4ec42faa..000000000 --- a/internal/suites/example/kube/ingress-controller/rbac.yml +++ /dev/null @@ -1,141 +0,0 @@ ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: nginx-ingress-controller-serviceaccount - namespace: authelia - labels: - app: nginx-ingress-controller -... ---- -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: ClusterRole -metadata: - name: nginx-ingress-controller-clusterrole - labels: - app: nginx-ingress-controller -rules: - - apiGroups: - - "" - resources: - - configmaps - - endpoints - - nodes - - pods - - secrets - verbs: - - list - - watch - - apiGroups: - - "" - resources: - - nodes - verbs: - - get - - apiGroups: - - "" - resources: - - services - verbs: - - get - - list - - watch - - apiGroups: - - "extensions" - resources: - - ingresses - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - - events - verbs: - - create - - patch - - apiGroups: - - "extensions" - resources: - - ingresses/status - verbs: - - update -... ---- -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: Role -metadata: - name: nginx-ingress-controller-role - namespace: authelia - labels: - app: nginx-ingress-controller -rules: - - apiGroups: - - "" - resources: - - configmaps - - pods - - secrets - - namespaces - verbs: - - get - - apiGroups: - - "" - resources: - - configmaps - resourceNames: - # Defaults to "-" - # Here: "-" - # This has to be adapted if you change either parameter - # when launching the nginx-ingress-controller. - - "ingress-controller-leader-nginx" - verbs: - - get - - update - - apiGroups: - - "" - resources: - - configmaps - verbs: - - create - - apiGroups: - - "" - resources: - - endpoints - verbs: - - get -... ---- -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: RoleBinding -metadata: - name: nginx-ingress-controller-role-nisa-binding - namespace: authelia - labels: - app: nginx-ingress-controller -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: nginx-ingress-controller-role -subjects: - - kind: ServiceAccount - name: nginx-ingress-controller-serviceaccount - namespace: authelia -... ---- -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: ClusterRoleBinding -metadata: - name: nginx-ingress-controller-clusterrole-nisa-binding - labels: - app: nginx-ingress-controller -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: nginx-ingress-controller-clusterrole -subjects: - - kind: ServiceAccount - name: nginx-ingress-controller-serviceaccount - namespace: authelia -... diff --git a/internal/suites/example/kube/ingress-controller/service.yml b/internal/suites/example/kube/ingress-controller/service.yml deleted file mode 100644 index ce299dd43..000000000 --- a/internal/suites/example/kube/ingress-controller/service.yml +++ /dev/null @@ -1,18 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - name: nginx-ingress-controller-service - namespace: authelia - labels: - app: nginx-ingress-controller -spec: - selector: - app: nginx-ingress-controller - type: NodePort - ports: - - port: 80 - name: http - - port: 443 - name: https -... diff --git a/internal/suites/example/kube/ldap/access.rules b/internal/suites/example/kube/ldap/access.rules deleted file mode 100644 index 8762639e2..000000000 --- a/internal/suites/example/kube/ldap/access.rules +++ /dev/null @@ -1,7 +0,0 @@ -olcAccess: {0}to attrs=userPassword,shadowLastChange by self write by anonymou - s auth by * none -# olcAccess: {1}to dn.base="" by * read -# olcAccess: {2}to * by * read - -olcPasswordHash: {CRYPT} -olcPasswordCryptSaltFormat: $6$rounds=50000$%.16s diff --git a/internal/suites/example/kube/ldap/base.ldif b/internal/suites/example/kube/ldap/base.ldif deleted file mode 100644 index e1a198e8a..000000000 --- a/internal/suites/example/kube/ldap/base.ldif +++ /dev/null @@ -1,67 +0,0 @@ -dn: ou=groups,dc=example,dc=com -objectClass: organizationalUnit -objectClass: top -ou: groups - -dn: ou=users,dc=example,dc=com -objectClass: organizationalUnit -objectClass: top -ou: users - -dn: cn=dev,ou=groups,dc=example,dc=com -cn: dev -member: uid=john,ou=users,dc=example,dc=com -member: uid=bob,ou=users,dc=example,dc=com -objectClass: groupOfNames -objectClass: top - -dn: cn=admins,ou=groups,dc=example,dc=com -cn: admins -member: uid=john,ou=users,dc=example,dc=com -objectClass: groupOfNames -objectClass: top - -dn: uid=john,ou=users,dc=example,dc=com -uid: john -cn: john -objectClass: inetOrgPerson -objectClass: top -mail: john.doe@authelia.com -sn: John Doe -userPassword: {CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/ - -dn: uid=harry,ou=users,dc=example,dc=com -uid: harry -cn: harry -objectClass: inetOrgPerson -objectClass: top -mail: harry.potter@authelia.com -sn: Harry Potter -userPassword: {CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/ - -dn: uid=bob,ou=users,dc=example,dc=com -uid: bob -cn: bob -objectClass: inetOrgPerson -objectClass: top -mail: bob.dylan@authelia.com -sn: Bob Dylan -userPassword: {CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/ - -dn: uid=james,ou=users,dc=example,dc=com -uid: james -cn: james -objectClass: inetOrgPerson -objectClass: top -mail: james.dean@authelia.com -sn: James Dean -userPassword: {CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/ - -dn: uid=blackhat,ou=users,dc=example,dc=com -uid: blackhat -cn: blackhat -objectClass: inetOrgPerson -objectClass: top -mail: billy.blackhat@authelia.com -sn: Billy BlackHat -userPassword: {CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/ diff --git a/internal/suites/example/kube/ldap/deployment.yml b/internal/suites/example/kube/ldap/ldap.yml similarity index 69% rename from internal/suites/example/kube/ldap/deployment.yml rename to internal/suites/example/kube/ldap/ldap.yml index 996895be6..ad010704f 100644 --- a/internal/suites/example/kube/ldap/deployment.yml +++ b/internal/suites/example/kube/ldap/ldap.yml @@ -41,19 +41,24 @@ spec: - name: LDAP_TLS_VERIFY_CLIENT value: try volumeMounts: - - name: config-volume - mountPath: /container/service/slapd/assets/config/bootstrap/ldif/custom/base.ldif - subPath: base.ldif - - name: config-volume - mountPath: /container/service/slapd/assets/config/bootstrap/ldif/custom/access.rules - subPath: access.rules + - name: ldap-config + mountPath: /container/service/slapd/assets/config/bootstrap/ldif/custom volumes: - - name: config-volume - configMap: - name: ldap-config - items: - - key: base.ldif - path: base.ldif - - key: access.rules - path: access.rules + - name: ldap-config + hostPath: + path: /configmaps/ldap + type: Directory +... +--- +apiVersion: v1 +kind: Service +metadata: + name: ldap-service + namespace: authelia +spec: + selector: + app: ldap + ports: + - protocol: TCP + port: 636 ... diff --git a/internal/suites/example/kube/ldap/service.yml b/internal/suites/example/kube/ldap/service.yml deleted file mode 100644 index e932f4e77..000000000 --- a/internal/suites/example/kube/ldap/service.yml +++ /dev/null @@ -1,13 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - name: ldap-service - namespace: authelia -spec: - selector: - app: ldap - ports: - - protocol: TCP - port: 636 -... diff --git a/internal/suites/example/kube/mail/deployment.yml b/internal/suites/example/kube/mail/deployment.yml deleted file mode 100644 index 6bec15f5d..000000000 --- a/internal/suites/example/kube/mail/deployment.yml +++ /dev/null @@ -1,25 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: mailcatcher - namespace: authelia - labels: - app: mailcatcher -spec: - replicas: 1 - selector: - matchLabels: - app: mailcatcher - template: - metadata: - labels: - app: mailcatcher - spec: - containers: - - name: mailcatcher - image: schickling/mailcatcher - ports: - - containerPort: 1025 - - containerPort: 1080 -... diff --git a/internal/suites/example/kube/mail/ingress.yml b/internal/suites/example/kube/mail/ingress.yml deleted file mode 100644 index ed2291f95..000000000 --- a/internal/suites/example/kube/mail/ingress.yml +++ /dev/null @@ -1,22 +0,0 @@ ---- -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: mailcatcher-ingress - namespace: authelia - annotations: - kubernetes.io/ingress.class: "nginx" -spec: - tls: - - secretName: mail-tls - hosts: - - mail.example.com - rules: - - host: mail.example.com - http: - paths: - - path: / - backend: - serviceName: mailcatcher-service - servicePort: 1080 -... diff --git a/internal/suites/example/kube/mail/mail.yml b/internal/suites/example/kube/mail/mail.yml new file mode 100644 index 000000000..b26464e72 --- /dev/null +++ b/internal/suites/example/kube/mail/mail.yml @@ -0,0 +1,64 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mailcatcher + namespace: authelia + labels: + app: mailcatcher +spec: + replicas: 1 + selector: + matchLabels: + app: mailcatcher + template: + metadata: + labels: + app: mailcatcher + spec: + containers: + - name: mailcatcher + image: schickling/mailcatcher + ports: + - containerPort: 1025 + - containerPort: 1080 +... +--- +apiVersion: v1 +kind: Service +metadata: + name: mailcatcher-service + namespace: authelia +spec: + selector: + app: mailcatcher + ports: + - protocol: TCP + port: 1080 + name: ui + - protocol: TCP + port: 1025 + name: smtp +... +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: mailcatcher-ingress + namespace: authelia + annotations: + kubernetes.io/ingress.class: traefik + traefik.ingress.kubernetes.io/router.entrypoints: websecure +spec: + rules: + - host: mail.example.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: mailcatcher-service + port: + number: 1080 +... diff --git a/internal/suites/example/kube/mail/service.yml b/internal/suites/example/kube/mail/service.yml deleted file mode 100644 index 1d33a5c5e..000000000 --- a/internal/suites/example/kube/mail/service.yml +++ /dev/null @@ -1,17 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - name: mailcatcher-service - namespace: authelia -spec: - selector: - app: mailcatcher - ports: - - protocol: TCP - port: 1080 - name: ui - - protocol: TCP - port: 1025 - name: smtp -... diff --git a/internal/suites/example/kube/registry.yml b/internal/suites/example/kube/registry.yml new file mode 100644 index 000000000..32cb0459e --- /dev/null +++ b/internal/suites/example/kube/registry.yml @@ -0,0 +1,6 @@ +--- +mirrors: + "docker.io": + endpoint: + - http://registrycache.internal:5000 +... diff --git a/internal/suites/example/kube/storage/mariadb.yml b/internal/suites/example/kube/storage/mariadb.yml index 711dee245..d8c6c1aa7 100644 --- a/internal/suites/example/kube/storage/mariadb.yml +++ b/internal/suites/example/kube/storage/mariadb.yml @@ -21,9 +21,11 @@ spec: image: mariadb:10.4.10 ports: - containerPort: 3306 + readinessProbe: + tcpSocket: + port: 3306 + periodSeconds: 1 env: - - name: SLAPD_ORGANISATION - value: MyCompany - name: MYSQL_ROOT_PASSWORD value: rootpassword - name: MYSQL_USER @@ -32,13 +34,6 @@ spec: value: password - name: MYSQL_DATABASE value: authelia - volumeMounts: - - name: data-volume - mountPath: /var/lib/mysql - volumes: - - name: data-volume - hostPath: - path: /data/storage/mysql ... --- apiVersion: v1 diff --git a/internal/suites/example/kube/storage/redis.yml b/internal/suites/example/kube/storage/redis.yml index 7cb4fb3d9..2819fed1d 100644 --- a/internal/suites/example/kube/storage/redis.yml +++ b/internal/suites/example/kube/storage/redis.yml @@ -21,6 +21,10 @@ spec: image: redis:3.2.11-alpine ports: - containerPort: 6379 + readinessProbe: + tcpSocket: + port: 6379 + periodSeconds: 1 ... --- apiVersion: v1 diff --git a/internal/suites/example/kube/test.yml b/internal/suites/example/kube/test.yml deleted file mode 100644 index af95181a2..000000000 --- a/internal/suites/example/kube/test.yml +++ /dev/null @@ -1,23 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: test-app1 - namespace: kube-public - labels: - app: test-app1 -spec: - replicas: 1 - selector: - matchLabels: - app: test-app1 - template: - metadata: - labels: - app: test-app1 - spec: - containers: - - name: test-app1 - image: authelia/authelia:kube - imagePullPolicy: Never -... diff --git a/internal/suites/example/swarm/docker-compose.yml b/internal/suites/example/swarm/docker-compose.yml deleted file mode 100644 index 4a082bc0e..000000000 --- a/internal/suites/example/swarm/docker-compose.yml +++ /dev/null @@ -1,53 +0,0 @@ ---- -version: '3.4' -services: - authelia: - image: authelia/authelia:latest - # Used for Docker configs - configs: - - source: authelia - target: /config/configuration.yml - uid: '0' - gid: '0' - mode: 0444 # yamllint disable-line rule:octal-values - environment: - - NODE_TLS_REJECT_UNAUTHORIZED=0 - # Where the authelia volume is to be mounted. To only use a single volume, the minimal config - # needs to be changed to read the users_database.yml also from this subdirectory. - # Otherwise a second volume will need to be configured here to mount the users_database.yml. - volumes: - - authelia:/config/storage - networks: - - overlay - deploy: - # Configure Authelia to automatically restart on failure. - restart_policy: - condition: on-failure - delay: 5s - max_attempts: 3 - window: 120s - # Mode: global would start authelia on all available nodes, - # replicated limits it to how many replicas are configured. - mode: replicated - # How many replicas are wanted. Can be any number >0 up to however many nodes are available. - replicas: 1 - placement: - constraints: - - node.role == worker - -# The volume for authelia needs to be configured. -# There are many drivers available. Such as local storage, ceph-rdb, nfs, cifs etc. -volumes: - authelia: - driver: default - name: volume-authelia - -networks: - overlay: - external: true - -# This is needed if Docker configs are being used to provide Authelia with its configuration. -configs: - authelia: - external: true -... diff --git a/internal/suites/kubernetes.go b/internal/suites/kubernetes.go index c68da2495..82bda5d43 100644 --- a/internal/suites/kubernetes.go +++ b/internal/suites/kubernetes.go @@ -3,53 +3,41 @@ package suites import ( "fmt" "os/exec" + "regexp" "strings" "time" "github.com/authelia/authelia/v4/internal/utils" ) -var kindImageName = "authelia-kind-proxy" -var dockerCmdLine = fmt.Sprintf("docker-compose -p authelia -f internal/suites/docker-compose.yml -f internal/suites/example/compose/kind/docker-compose.yml run -T --rm %s", kindImageName) +var k3dImageName = "k3d" +var dockerCmdLine = fmt.Sprintf("docker-compose -p authelia -f internal/suites/docker-compose.yml -f internal/suites/example/compose/k3d/docker-compose.yml exec -T %s", k3dImageName) -// Kind used for running kind commands. -type Kind struct{} +// K3D used for running kind commands. +type K3D struct{} -func kindCommand(cmdline string) *exec.Cmd { +func k3dCommand(cmdline string) *exec.Cmd { cmd := fmt.Sprintf("%s %s", dockerCmdLine, cmdline) return utils.Shell(cmd) } // CreateCluster create a new Kubernetes cluster. -func (k Kind) CreateCluster() error { - cmd := kindCommand("kind create cluster --config /etc/kind/config.yml") - if err := cmd.Run(); err != nil { - return err - } - - cmd = kindCommand("patch-kubeconfig.sh") - if err := cmd.Run(); err != nil { - return err - } - - // This command is necessary to fix the coredns loop detected when using user-defined docker network. - // In that case /etc/resolv.conf use 127.0.0.11 as DNS and CoreDNS thinks it is talking to itself which is wrong. - // This IP is the docker internal DNS so it is safe to disable the loop check. - cmd = kindCommand("sh -c 'kubectl -n kube-system get configmap/coredns -o yaml | grep -v loop | kubectl replace -f -'") +func (k K3D) CreateCluster() error { + cmd := k3dCommand("k3d cluster create --registry-config /authelia/registry.yml -v /authelia:/var/lib/rancher/k3s/server/manifests/custom -v /configmaps:/configmaps -p 8080:443") err := cmd.Run() return err } // DeleteCluster delete a Kubernetes cluster. -func (k Kind) DeleteCluster() error { - cmd := kindCommand("kind delete cluster") +func (k K3D) DeleteCluster() error { + cmd := k3dCommand("k3d cluster delete") return cmd.Run() } // ClusterExists check whether a cluster exists. -func (k Kind) ClusterExists() (bool, error) { - cmd := kindCommand("kind get clusters") +func (k K3D) ClusterExists() (bool, error) { + cmd := k3dCommand("k3d cluster list") cmd.Stdout = nil cmd.Stderr = nil output, err := cmd.Output() @@ -58,63 +46,27 @@ func (k Kind) ClusterExists() (bool, error) { return false, err } - return strings.Contains(string(output), "kind"), nil + return strings.Contains(string(output), "k3s-default"), nil } // LoadImage load an image in the Kubernetes container. -func (k Kind) LoadImage(imageName string) error { - cmd := kindCommand(fmt.Sprintf("kind load docker-image %s", imageName)) +func (k K3D) LoadImage(imageName string) error { + cmd := k3dCommand(fmt.Sprintf("k3d image import %s", imageName)) return cmd.Run() } // Kubectl used for running kubectl commands. type Kubectl struct{} -// StartProxy start a proxy. -func (k Kubectl) StartProxy() error { - cmd := utils.Shell("docker-compose -p authelia -f internal/suites/docker-compose.yml -f internal/suites/example/compose/kind/docker-compose.yml up -d authelia-kind-proxy") - return cmd.Run() -} - -// StopProxy stop a proxy. -func (k Kubectl) StopProxy() error { - cmd := utils.Shell("docker-compose -p authelia -f internal/suites/docker-compose.yml -f internal/suites/example/compose/kind/docker-compose.yml rm -s -f authelia-kind-proxy") - return cmd.Run() -} - -// StartDashboard start Kube dashboard. -func (k Kubectl) StartDashboard() error { - if err := kindCommand("sh -c 'cd /authelia && ./bootstrap-dashboard.sh'").Run(); err != nil { - return err - } - - err := utils.Shell("docker-compose -p authelia -f internal/suites/docker-compose.yml -f internal/suites/example/compose/kind/docker-compose.yml up -d kube-dashboard").Run() - - return err -} - -// StopDashboard stop kube dashboard. -func (k Kubectl) StopDashboard() error { - cmd := utils.Shell("docker-compose -p authelia -f internal/suites/docker-compose.yml -f internal/suites/example/compose/kind/docker-compose.yml rm -s -f kube-dashboard") - return cmd.Run() -} - -// DeployThirdparties deploy thirdparty services (ldap, db, ingress controllers, etc...). -func (k Kubectl) DeployThirdparties() error { - cmd := kindCommand("sh -c 'cd /authelia && ./bootstrap.sh'") - return cmd.Run() -} - -// DeployAuthelia deploy Authelia application. -func (k Kubectl) DeployAuthelia() error { - cmd := kindCommand("sh -c 'cd /authelia && ./bootstrap-authelia.sh'") - return cmd.Run() +// GetDashboardToken generates bearer token for Kube Dashboard. +func (k Kubectl) GetDashboardToken() error { + return k3dCommand("kubectl -n kubernetes-dashboard create token admin-user;echo ''").Run() } // WaitPodsReady wait for all pods to be ready. -func (k Kubectl) WaitPodsReady(timeout time.Duration) error { +func (k Kubectl) WaitPodsReady(namespace string, timeout time.Duration) error { return utils.CheckUntil(5*time.Second, timeout, func() (bool, error) { - cmd := kindCommand("kubectl get -n authelia pods --no-headers") + cmd := k3dCommand(fmt.Sprintf("kubectl get -n %s pods --no-headers --field-selector=status.phase!=Succeeded", namespace)) cmd.Stdout = nil cmd.Stderr = nil output, _ := cmd.Output() @@ -129,10 +81,12 @@ func (k Kubectl) WaitPodsReady(timeout time.Duration) error { } for _, line := range nonEmptyLines { - if !strings.Contains(line, "1/1") { + re := regexp.MustCompile(`1/1|2/2`) + if !re.MatchString(line) { return false, nil } } + return true, nil }) } diff --git a/internal/suites/suite_kubernetes.go b/internal/suites/suite_kubernetes.go index ba99bf3f8..0641ef1d5 100644 --- a/internal/suites/suite_kubernetes.go +++ b/internal/suites/suite_kubernetes.go @@ -1,7 +1,6 @@ package suites import ( - "fmt" "os" "time" @@ -13,94 +12,87 @@ import ( var kubernetesSuiteName = "Kubernetes" func init() { - kind := Kind{} + dockerEnvironment := NewDockerEnvironment([]string{ + "internal/suites/docker-compose.yml", + "internal/suites/example/compose/k3d/docker-compose.yml", + }) + + k3d := K3D{} kubectl := Kubectl{} setup := func(suitePath string) error { - cmd := utils.Shell("docker-compose -p authelia -f internal/suites/docker-compose.yml -f internal/suites/example/compose/kind/docker-compose.yml build") - if err := cmd.Run(); err != nil { + if err := dockerEnvironment.Up(); err != nil { return err } - exists, err := kind.ClusterExists() + err := waitUntilK3DIsReady(dockerEnvironment) + if err != nil { + return err + } + exists, err := k3d.ClusterExists() if err != nil { return err } if exists { - log.Debug("Kubernetes cluster already exists") + log.Info("Kubernetes cluster already exists") } else { - err = kind.CreateCluster() - + err = k3d.CreateCluster() if err != nil { return err } } - log.Debug("Building authelia:dist image or use cache if already built...") + log.Info("Building authelia:dist image or use cache if already built...") if os.Getenv("CI") != t { if err := utils.Shell("authelia-scripts docker build").Run(); err != nil { return err } + + if err := utils.Shell("docker save authelia:dist -o internal/suites/example/kube/authelia-image-dev.tar").Run(); err != nil { + return err + } } - log.Debug("Loading images into Kubernetes container...") + log.Info("Loading images into Kubernetes container...") if err := loadDockerImages(); err != nil { return err } - log.Debug("Starting Kubernetes dashboard...") + log.Info("Waiting for cluster to be ready...") - if err := kubectl.StartDashboard(); err != nil { + if err := waitAllPodsAreReady(namespaceKube, 5*time.Minute); err != nil { return err } - log.Debug("Deploying thirdparties...") + log.Info("Waiting for dashboard to be ready...") - if err := kubectl.DeployThirdparties(); err != nil { + err = waitAllPodsAreReady(namespaceDashboard, 2*time.Minute) + + log.Info("Bearer token for UI user:") + + if err := kubectl.GetDashboardToken(); err != nil { return err } - log.Debug("Waiting for services to be ready...") + log.Info("Waiting for services to be ready...") - if err := waitAllPodsAreReady(5 * time.Minute); err != nil { + if err := waitAllPodsAreReady(namespaceAuthelia, 5*time.Minute); err != nil { return err } - log.Debug("Deploying Authelia...") - - if err = kubectl.DeployAuthelia(); err != nil { - return err - } - - log.Debug("Waiting for services to be ready...") - - if err := waitAllPodsAreReady(2 * time.Minute); err != nil { - return err - } - - log.Debug("Starting proxy...") - - err = kubectl.StartProxy() - return err } teardown := func(suitePath string) error { - err := kubectl.StopDashboard() - if err != nil { - log.Errorf("Unable to stop Kubernetes dashboard: %s", err) + if err := k3d.DeleteCluster(); err != nil { + return err } - err = kubectl.StopProxy() - if err != nil { - log.Errorf("Unable to stop Kind proxy: %s", err) - } - - return kind.DeleteCluster() + return dockerEnvironment.Down() } GlobalRegistry.Register(kubernetesSuiteName, Suite{ @@ -109,16 +101,20 @@ func init() { TestTimeout: 2 * time.Minute, TearDown: teardown, TearDownTimeout: 2 * time.Minute, - Description: "This suite has been created to test Authelia in a Kubernetes context and using nginx as the ingress controller.", + Description: "This suite has been created to test Authelia in a Kubernetes context and using Traefik as the ingress controller.", }) } func loadDockerImages() error { - kind := Kind{} - images := []string{"authelia:dist"} + k3d := K3D{} + images := []string{"/authelia/authelia-image-coverage.tar"} + + if os.Getenv("CI") != t { + images = []string{"/authelia/authelia-image-dev.tar"} + } for _, image := range images { - err := kind.LoadImage(image) + err := k3d.LoadImage(image) if err != nil { return err @@ -128,17 +124,16 @@ func loadDockerImages() error { return nil } -func waitAllPodsAreReady(timeout time.Duration) error { +func waitAllPodsAreReady(namespace string, timeout time.Duration) error { kubectl := Kubectl{} - // Wait in case the deployment has just been done and some services do not appear in kubectl logs. - time.Sleep(1 * time.Second) - fmt.Println("Check services are running") - if err := kubectl.WaitPodsReady(timeout); err != nil { + log.Infof("Checking services in %s namespace are running...", namespace) + + if err := kubectl.WaitPodsReady(namespace, timeout); err != nil { return err } - fmt.Println("All pods are ready") + log.Info("All pods are ready") return nil }