diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d500cc3176a3c5e79190d9a2de35e3ed28532b88..caaab8360eaed0926cd30bf2d01f0816cbefd3d7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -18,15 +18,13 @@ include: - | echo "Env vars:" echo - echo "HOSTNAME: $HOSTNAME" - echo "IP_ADDRESS: $IP_ADDRESS" + env | grep -E '^(HOSTNAME|CLUSTER_NAME|FQDN|IP_ADDRESS|CLUSTER_DIR|ANSIBLE_HOST_KEY_CHECKING|KANIKO_BUILD_IMAGENAME|SSH_KEY_ID|SHELL|CI_PROJECT_DIR)=' + echo echo "Uptime: $(uptime)" - echo "ANSIBLE_HOST_KEY_CHECKING: $ANSIBLE_HOST_KEY_CHECKING" - echo "KANIKO_BUILD_IMAGENAME: $KANIKO_BUILD_IMAGENAME" echo "KANIKO build image ref: ${CI_REGISTRY_IMAGE}/${KANIKO_BUILD_IMAGENAME}:${CI_CONTAINER_TAG}" - echo "SSH_KEY_ID: $SSH_KEY_ID" - echo "SHELL $SHELL" - echo "CI_PROJECT_DIR: $CI_PROJECT_DIR" + echo + - if [ -f .ci.env ]; then echo "Content of .ci.env:"; cat .ci.env; fi + - if [ -f .cluster.env ]; then echo "Content of .ci.env:"; cat .cluster.env; fi # The dotenv report requires us to report the artifacts in every job that is # required with a `needs:` from another job. @@ -93,22 +91,6 @@ include: - if: '$CI_COMMIT_MESSAGE =~ /TRIGGER_JOBS=.*enable-monitoring/' - if: '$CI_COMMIT_BRANCH == "main"' -.eventrouter_rules: - extends: - - .monitoring_rules - -.loki_rules: - extends: - - .monitoring_rules - -.promtail_rules: - extends: - - .monitoring_rules - -.kube_prometheus_stack_rules: - extends: - - .monitoring_rules - .nextcloud_rules: rules: - changes: @@ -122,14 +104,6 @@ include: - if: '$CI_COMMIT_MESSAGE =~ /TRIGGER_JOBS=.*enable-nextcloud/' - if: '$CI_COMMIT_BRANCH == "main"' -.cert_manager_rules: - extends: - - .general_rules - -.local_path_provisioner_rules: - extends: - - .general_rules - .single_sign_on_rules: rules: - changes: @@ -187,14 +161,13 @@ include: stages: - build - - create-vps - - setup-cluster - - configure-cluster - - kustomization - - install-apps - - apps-kustomizations-ready + - install-cluster + - install-stackspin + - base-ready + - configure-stackspin + - optional-apps-ready - certs - - health-test + - cluster-health - integration-test variables: @@ -221,7 +194,7 @@ ci-test-image-build: - *debug_information after_script: - | - echo "CI_CONTAINER_TAG=${CI_COMMIT_REF_SLUG}" > .ci.env + echo "CI_CONTAINER_TAG=${CI_COMMIT_REF_SLUG}" | tee .ci.env artifacts: paths: - .ci.env @@ -256,13 +229,14 @@ report-ci-image-tag: - *debug_information script: - | - TAG_INFORMATION=$(curl https://open.greenhost.net/api/v4/projects/stackspin%2Fstackspin/registry/repositories/73/tags/${CI_COMMIT_REF_SLUG}); + TAG_INFORMATION=$(curl -sS https://open.greenhost.net/api/v4/projects/stackspin%2Fstackspin/registry/repositories/73/tags/${CI_COMMIT_REF_SLUG}); echo "Tag information: ${TAG_INFORMATION}" if [ "$TAG_INFORMATION" == '{"message":"404 Tag Not Found"}' ]; then - echo "CI_CONTAINER_TAG=main" > .ci.env + CI_CONTAINER_TAG="main" else - echo "CI_CONTAINER_TAG=${CI_COMMIT_REF_SLUG}" > .ci.env + CI_CONTAINER_TAG="${CI_COMMIT_REF_SLUG}" fi + echo "CI_CONTAINER_TAG=${CI_CONTAINER_TAG}" | tee .ci.env artifacts: paths: - .ci.env @@ -286,13 +260,14 @@ report-ci-image-tag: interruptible: true -# Stage: create-vps -# ================= +# Stage: install-cluster +# ====================== # -# Creates the vps for the pipeline +# * Creates the vps for the pipeline +# * Installs k8s with ansible create-vps: - stage: create-vps + stage: install-cluster variables: SUBDOMAIN: "${CI_COMMIT_REF_SLUG}.ci" DOMAIN: "stackspin.net" @@ -304,7 +279,6 @@ create-vps: # Make sure .ci.env variables are not lost - cat .ci.env >> ${CLUSTER_DIR}/.cluster.env extends: - - .ssh_setup - .report_artifacts - .general_rules environment: @@ -314,16 +288,11 @@ create-vps: auto_stop_in: 1 week interruptible: true - -# Stage: setup-cluster -# ==================== -# -# Installs Stackspin - test-dns: - stage: setup-cluster + stage: install-cluster needs: - job: create-vps + # Needs a pytest ansible connection to get the configured system resolvers script: - *debug_information - cd ansible/ @@ -332,8 +301,10 @@ test-dns: - .general_rules interruptible: true -setup-stackspin: - stage: setup-cluster +install-k8s: + stage: install-cluster + needs: + - job: create-vps script: - *debug_information # Copy inventory files to ansible folder for use in install-apps step @@ -341,60 +312,132 @@ setup-stackspin: - cp ${CLUSTER_DIR}/inventory.yml ansible/ # Set up cluster - python3 -m stackspin $HOSTNAME install + extends: + - .ssh_setup + - .report_artifacts + - .general_rules + interruptible: true + +# Terminates a droplet and deletes the branch container image once the MR for it is merged +terminate-droplet: + # Stage has to be the same as the step that created the VPS + # https://docs.gitlab.com/ee/ci/environments.html#automatically-stopping-an-environment + stage: install-cluster + # Gets triggered by on_stop of create-vps job + when: manual + variables: + GIT_STRATEGY: none + script: + - *debug_information + # Delete droplet + - python3 -c "import greenhost_cloud; greenhost_cloud.terminate_droplets_by_name(\"^${CI_COMMIT_REF_SLUG}\")" + # Delete container image if one was created + - > + "if [ \"$CI_CONTAINER_TAG\" != \"main\" ]; then + curl --request DELETE --header \"PRIVATE-TOKEN: ${CLEANER_TOKEN}\" + https://open.greenhost.net/api/v4/projects/stackspin%2Fstackspin/registry/repositories/73/tags/${CI_CONTAINER_TAG}; + fi" + environment: + name: $CI_COMMIT_REF_SLUG + action: stop + +# Stage: install-stackspin +# ======================== +# +# Installs flux and stackspin with it + +install-stackspin: + stage: install-stackspin + needs: + - job: test-dns + - job: install-k8s + script: + - *debug_information # Customize env file, remove all comments and empty lines - - sed "s/1.2.3.4/$IP_ADDRESS/; s/example.org/$FQDN/; s/acme_staging=false/acme_staging=true/; s/acme-v02/acme-staging-v02/; /^\s*#.*$/d; /^\s*$/d" install/.flux.env.example >> ${CLUSTER_DIR}/.flux.env + - cp install/.flux.env.example ${CLUSTER_DIR}/.flux.env + - sed -i "s/1.2.3.4/$IP_ADDRESS/" ${CLUSTER_DIR}/.flux.env + - sed -i "s/example.org/$FQDN/" ${CLUSTER_DIR}/.flux.env + - sed -i "/^\s*#.*$/d; /^\s*$/d" ${CLUSTER_DIR}/.flux.env + # Use LE Staging in CI + - sed -i "s/acme-v02.api.letsencrypt.org/acme-staging-v02.api.letsencrypt.org/" ${CLUSTER_DIR}/.flux.env # Deploy secret/stackspin-cluster-variables - cp install/kustomization.yaml ${CLUSTER_DIR} - kubectl create namespace flux-system - kubectl apply -k ${CLUSTER_DIR} + # NOTE: Temporarily disabled because ZeroSSL is unstable # Add an override so cert-manager uses the ZeroSSL ClusterIssuer - - kubectl create namespace cert-manager - - kubectl apply -n cert-manager -f ./install/overrides/stackspin-cert-manager-override.yaml + # - kubectl create namespace cert-manager + # - kubectl apply -n cert-manager -f ./install/overrides/stackspin-cert-manager-override.yaml # Install flux and general, non-app specific secrets - bash ./install/install-stackspin.sh extends: - - .ssh_setup - .report_artifacts - .general_rules interruptible: true - -# Stage: configure-cluster -# ==================== -# -# Configure cluster after basic installation -# i.e. CI-related config like zerossl clusterIssuer - -configure-stackspin: - stage: configure-cluster +.enable_app_template: + stage: install-stackspin + needs: + - job: install-stackspin script: - *debug_information - # Install custom ClusterIssuer for ZeroSSL production certificates - - bash ./.gitlab/ci_scripts/install_zerossl_issuer.sh - extends: - - .report_artifacts - - .general_rules + # Add optional override values we need for the CI pipeline only + - > + [ -f ./install/overrides/stackspin-${RESOURCE}-override.yaml ] && + kubectl apply -n stackspin-apps -f ./install/overrides/stackspin-${RESOURCE}-override.yaml + - bash ./install/install-app.sh ${RESOURCE} interruptible: true +enable-monitoring: + variables: + RESOURCE: "monitoring" + extends: + - .enable_app_template + - .monitoring_rules +enable-nextcloud: + variables: + RESOURCE: "nextcloud" + extends: + - .enable_app_template + - .nextcloud_rules +enable-wekan: + variables: + RESOURCE: "wekan" + extends: + - .enable_app_template + - .wekan_rules -# Stage: kustomization +enable-wordpress: + variables: + RESOURCE: "wordpress" + extends: + - .enable_app_template + - .wordpress_rules + +enable-zulip: + variables: + RESOURCE: "zulip" + extends: + - .enable_app_template + - .zulip_rules + +# Stage: base-ready # ==================== # -# Tests if all kustomizations are ready +# Test if base kustomizations are ready, before configuration can get applied +# that makes use of CRDs, i.e. clusterIssuer .kustomization-ready: - stage: kustomization + stage: base-ready needs: - - job: configure-stackspin - - job: test-dns + - job: install-stackspin script: - *debug_information - - cd ansible/ + - cd test/ - export KUBECONFIG="${PWD}/../clusters/${HOSTNAME}/kube_config_cluster.yml" - - pytest -v -s -m 'kustomizations' --resource="$RESOURCE" --connection=ansible --ansible-inventory=../${CLUSTER_DIR}/inventory.yml --hosts='ansible://*' --reruns 120 --reruns-delay 20 + - pytest -v -s -m 'kustomizations' --resource="$RESOURCE" --reruns 120 --reruns-delay 20 extends: - - .ssh_setup - .general_rules interruptible: true @@ -458,70 +501,40 @@ stackspin-kustomization-ready: extends: - .kustomization-ready -# Stage: install-apps -# ================== +# Stage: configure-stackspin # -# Checks if application needs to get installed - -.enable_app_template: - stage: install-apps +# Configure cluster after basic installation +# i.e. CI-related config like zerossl clusterIssuer +# +configure-zerossl-issuer: + stage: configure-stackspin + needs: + - job: install-stackspin + - job: cert-manager-kustomization-ready script: - *debug_information - # Add optional override values we need for the CI pipeline only - - '[ -f ./install/overrides/stackspin-${RESOURCE}-override.yaml ] && kubectl apply -n stackspin-apps -f ./install/overrides/stackspin-${RESOURCE}-override.yaml' - - bash ./install/install-app.sh ${RESOURCE} + # Install custom ClusterIssuer for ZeroSSL production certificates + - bash ./.gitlab/ci_scripts/install_zerossl_issuer.sh extends: - - .ssh_setup + - .report_artifacts + - .general_rules interruptible: true -enable-monitoring: - variables: - RESOURCE: "monitoring" - extends: - - .enable_app_template - - .monitoring_rules - -enable-nextcloud: - variables: - RESOURCE: "nextcloud" - extends: - - .enable_app_template - - .nextcloud_rules -enable-wekan: - variables: - RESOURCE: "wekan" - extends: - - .enable_app_template - - .wekan_rules -enable-wordpress: - variables: - RESOURCE: "wordpress" - extends: - - .enable_app_template - - .wordpress_rules - -enable-zulip: - variables: - RESOURCE: "zulip" - extends: - - .enable_app_template - - .zulip_rules - -# Stage: apps-kustomizations-ready +# Stage: optional-apps-ready # ================ # # Check that the kustomizations of all installed apps are ready. .app-kustomization-ready: - stage: apps-kustomizations-ready + stage: optional-apps-ready extends: - .kustomization-ready monitoring-kustomization-ready: needs: - - job: configure-stackspin + - job: install-stackspin - job: enable-monitoring variables: RESOURCE: "monitoring" @@ -531,7 +544,7 @@ monitoring-kustomization-ready: nextcloud-kustomization-ready: needs: - - job: configure-stackspin + - job: install-stackspin - job: enable-nextcloud variables: RESOURCE: "nextcloud" @@ -541,7 +554,7 @@ nextcloud-kustomization-ready: wekan-kustomization-ready: needs: - - job: configure-stackspin + - job: install-stackspin - job: enable-wekan variables: RESOURCE: "wekan" @@ -551,7 +564,7 @@ wekan-kustomization-ready: wordpress-kustomization-ready: needs: - - job: configure-stackspin + - job: install-stackspin - job: enable-wordpress variables: RESOURCE: "wordpress" @@ -561,7 +574,7 @@ wordpress-kustomization-ready: zulip-kustomization-ready: needs: - - job: configure-stackspin + - job: install-stackspin - job: enable-zulip variables: RESOURCE: "zulip" @@ -578,18 +591,16 @@ zulip-kustomization-ready: stage: certs script: - *debug_information - - cd ansible/ - - pytest -v -s -m 'certs' --resource="$RESOURCE" --connection=ansible --ansible-inventory=../${CLUSTER_DIR}/inventory.yml --hosts='ansible://*' --reruns 120 --reruns-delay 10 - extends: - - .ssh_setup + - cd test/ + - pytest -v -s -m 'certs' --resource="$RESOURCE" --reruns 120 --reruns-delay 10 interruptible: true nextcloud-cert: variables: RESOURCE: "nextcloud" needs: - - job: enable-nextcloud - - job: configure-stackspin + - job: configure-zerossl-issuer + - job: install-stackspin extends: - .apps-cert - .nextcloud_rules @@ -598,18 +609,18 @@ kube-prometheus-stack-cert: variables: RESOURCE: "kube-prometheus-stack" needs: - - job: enable-monitoring - - job: configure-stackspin + - job: configure-zerossl-issuer + - job: install-stackspin extends: - .apps-cert - - .kube_prometheus_stack_rules + - .monitoring_rules single-sign-on-cert: variables: RESOURCE: "single-sign-on" needs: - - job: single-sign-on-kustomization-ready - - job: configure-stackspin + - job: configure-zerossl-issuer + - job: install-stackspin extends: - .apps-cert - .general_rules @@ -618,8 +629,8 @@ dashboard-cert: variables: RESOURCE: "dashboard" needs: - - job: dashboard-kustomization-ready - - job: configure-stackspin + - job: configure-zerossl-issuer + - job: install-stackspin extends: - .apps-cert - .general_rules @@ -628,8 +639,8 @@ wekan-cert: variables: RESOURCE: "wekan" needs: - - job: enable-wekan - - job: configure-stackspin + - job: configure-zerossl-issuer + - job: install-stackspin extends: - .apps-cert - .wekan_rules @@ -638,8 +649,8 @@ wordpress-cert: variables: RESOURCE: "wordpress" needs: - - job: enable-wordpress - - job: configure-stackspin + - job: configure-zerossl-issuer + - job: install-stackspin extends: - .apps-cert - .wordpress_rules @@ -648,20 +659,22 @@ zulip-cert: variables: RESOURCE: "zulip" needs: - - job: enable-zulip - - job: configure-stackspin + - job: configure-zerossl-issuer + - job: install-stackspin extends: - .apps-cert - .zulip_rules -# Stage: health-test -# ================== +# Stage: cluster-health +# ===================== # # General cluster health checks testinfra: - stage: health-test + stage: cluster-health + needs: + - job: install-stackspin script: - *debug_information - cd ansible/ @@ -671,22 +684,21 @@ testinfra: - .general_rules interruptible: true -kube-prometheus-stack-alerts: - stage: health-test +prometheus-alerts: + stage: cluster-health + needs: + - job: install-stackspin + - job: kube-prometheus-stack-cert variables: - # RESOURCE var is used in job specific rules (i.e. .kube_prometheus_stack_rules) + # RESOURCE var is used in job specific rules (i.e. ..monitoring_rules) RESOURCE: "kube-prometheus-stack" - # Enforce python requests using the system cert store, where LE staging - # cacert is added - REQUESTS_CA_BUNDLE: "/etc/ssl/certs/ca-certificates.crt" script: - *debug_information - export BASIC_AUTH_PW=$(python3 -m stackspin $HOSTNAME secrets | grep stackspin-prometheus-basic-auth | cut -d'=' -f2) - cd test/ - - bash ../.gitlab/ci_scripts/retry_cmd_until_success.sh 30 10 pytest -s -m 'prometheus' --connection=ansible --ansible-inventory=../${CLUSTER_DIR}/inventory.yml --hosts='ansible://*' + - bash ../.gitlab/ci_scripts/retry_cmd_until_success.sh 30 10 pytest -s -m prometheus extends: - - .ssh_setup - - .kube_prometheus_stack_rules + - .monitoring_rules interruptible: true @@ -714,7 +726,7 @@ dashboard-taiko: variables: RESOURCE: "dashboard" needs: - - job: configure-stackspin + - job: install-stackspin - job: dashboard-cert - job: dashboard-kustomization-ready extends: @@ -725,18 +737,18 @@ grafana-taiko: variables: RESOURCE: "grafana" needs: - - job: configure-stackspin + - job: install-stackspin - job: kube-prometheus-stack-cert - job: monitoring-kustomization-ready extends: - .taiko - - .kube_prometheus_stack_rules + - .monitoring_rules nextcloud-taiko: variables: RESOURCE: "nextcloud" needs: - - job: configure-stackspin + - job: install-stackspin - job: nextcloud-cert - job: nextcloud-kustomization-ready extends: @@ -747,7 +759,7 @@ wekan-taiko: variables: RESOURCE: "wekan" needs: - - job: configure-stackspin + - job: install-stackspin - job: wekan-cert - job: wekan-kustomization-ready extends: @@ -758,7 +770,7 @@ wordpress-taiko: variables: RESOURCE: "wordpress" needs: - - job: configure-stackspin + - job: install-stackspin - job: wordpress-cert - job: wordpress-kustomization-ready extends: @@ -769,33 +781,9 @@ zulip-taiko: variables: RESOURCE: "zulip" needs: - - job: configure-stackspin + - job: install-stackspin - job: zulip-cert - job: zulip-kustomization-ready extends: - .taiko - .zulip_rules - - -# Etc -# === - - -# Terminates a droplet and deletes the branch container image once the MR for it is merged -terminate-droplet: - # Stage has to be the same as the step that created the VPS - # https://docs.gitlab.com/ee/ci/environments.html#automatically-stopping-an-environment - stage: create-vps - # Gets triggered by on_stop of create-vps job - when: manual - variables: - GIT_STRATEGY: none - script: - - *debug_information - # Delete droplet - - python3 -c "import greenhost_cloud; greenhost_cloud.terminate_droplets_by_name(\"^${CI_COMMIT_REF_SLUG}\")" - # Delete container image if one was created - - "if [ \"$CI_CONTAINER_TAG\" != \"main\" ]; then curl --request DELETE --header \"PRIVATE-TOKEN: ${CLEANER_TOKEN}\" https://open.greenhost.net/api/v4/projects/stackspin%2Fstackspin/registry/repositories/73/tags/${CI_CONTAINER_TAG}; fi" - environment: - name: $CI_COMMIT_REF_SLUG - action: stop diff --git a/.gitlab/ci_scripts/install_zerossl_issuer.sh b/.gitlab/ci_scripts/install_zerossl_issuer.sh index d6f41df3a48e28de5f7ac9a39ce25e318ac53393..beed27a206c3dc695f297ebeb33c9503ea700d84 100755 --- a/.gitlab/ci_scripts/install_zerossl_issuer.sh +++ b/.gitlab/ci_scripts/install_zerossl_issuer.sh @@ -11,9 +11,6 @@ set -euo pipefail # Create secret with HMAC key b64tlskey=$(echo -n "${ZEROSSL_TLS_KEY}" | base64 -w0) -# Wait until cert-manager is ready -"$(dirname "$0")/retry_cmd_until_success.sh" 30 10 "flux get kustomization --status-selector ready=true --no-header | grep '^cert-manager'" - # Add ZeroSSL ClusterIssuer kubectl apply -n cert-manager -f - <<EOF --- diff --git a/.gitlab/ci_templates/helm_package.yml b/.gitlab/ci_templates/helm_package.yml new file mode 100644 index 0000000000000000000000000000000000000000..08eaf68285d0e2af15fc095d8082298d3a2c1076 --- /dev/null +++ b/.gitlab/ci_templates/helm_package.yml @@ -0,0 +1,63 @@ +# Include this file if you want to package your helm chart to a helm registry. +# You'll need to set two variables: +# +# 1. CHART_NAME: the name of the helm chart. Should correspond to the name in +# Chart.yaml +# 2. CHART_DIR (optional): the directory where your helm chart is in you +# repository. HAS TO END WITH A SLASH if you choose to override it. + +variables: + CHART_DIR: "" + +.chart_release_rules: + rules: + - changes: + - ${CHART_DIR}Chart.yaml + +lint-helm: + stage: lint-helm-chart + image: + name: alpine/helm:3.7.1 + entrypoint: ["/bin/sh", "-c"] + script: + - cd ${CHART_DIR:-"."} + - helm dep update + - helm lint . + artifacts: + paths: + - '${CHART_DIR}charts/**' + expire_in: 1 week + # Even if lint fails, upload the charts/ folder as artifact + when: always + rules: + - changes: + - ${CHART_DIR}*.yaml + - ${CHART_DIR}templates/*.yaml + +package-chart: + stage: package-helm-chart + image: + name: alpine/helm:3.7.1 + entrypoint: ["/bin/sh", "-c"] + script: + - cd ${CHART_DIR:-"."} + - helm package . + artifacts: + paths: + - ${CHART_DIR}${CHART_NAME}-* + expire_in: 1 week + extends: + - .chart_release_rules + +# Push helm chart. Charts on the default branch are pushed to `stable`, others +# are pushed to the `unstable` channel. +release-helm: + image: "rancher/curlimages-curl:7.73.0" + stage: release-helm-chart + script: + - cd ${CHART_DIR:-"."} + - if [ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ]; then export HELM_CHANNEL='stable'; else export HELM_CHANNEL='unstable'; fi + - export CHART_FILE=$(ls ${CHART_NAME}-*.tgz) + - curl --fail --request POST --user gitlab-ci-token:$CI_JOB_TOKEN --form "chart=@${CHART_FILE}" "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/helm/api/${HELM_CHANNEL}/charts" + extends: + - .chart_release_rules diff --git a/.gitlab/commit_template.txt b/.gitlab/commit_template.txt index de8d77085d583220987c6e2fba3afb5edfed0b1b..f87d232ce6dc7be34f585b3a324685abe0943e14 100644 --- a/.gitlab/commit_template.txt +++ b/.gitlab/commit_template.txt @@ -9,7 +9,7 @@ # TRIGGER_JOBS=enable-nextcloud # # or trigger all jobs: -# TRIGGER_JOBS=enable-monitoring,enable-nextcloud,enable-single-sign-on,enable-wekan,enable-wordpress,enable-zulip +# TRIGGER_JOBS=enable-monitoring,enable-nextcloud,enable-wekan,enable-wordpress,enable-zulip # # Reference issue number with one of: # diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 21366c08015344a4d137f4e95ed17e97109d59f4..03dfb78c0492f6f92ce82508ed58b7eefccd189f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.4.0 + rev: v4.0.1 hooks: - id: check-added-large-files - id: check-ast diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bbfba419c31ecb76cfc24339962c8de8ffa8fed..6cbcca3829a62dae86c10e1f8863ce0b4c7c6e5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ # Changelog + All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). @@ -7,7 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Changed project name from OpenAppStack to Stackspin * Update: - * Kube-prometheus-stack to helm chart version 18.0.12 + * Kube-prometheus-stack to helm chart version 22.0.0 ## [0.7.0] - 2021-08-19 diff --git a/Dockerfile b/Dockerfile index de840cd3f0e2f575a783b4760e8497e8a8f2cdca..7288c2fc7f2e8b685c3753b36c4a2b8d443d5c7c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,6 +10,7 @@ ENV TAIKO_BROWSER_PATH=/usr/bin/chromium-browser ENV TAIKO_BROWSER_ARGS=--no-sandbox,--start-maximized,--disable-dev-shm-usage,--ignore-certificate-errors ADD https://github.com/fluxcd/flux2/releases/download/v0.22.0/flux_0.22.0_linux_amd64.tar.gz /tmp/ +COPY ./test/pytest/le-staging-bundle.pem /usr/local/share/ca-certificates/le-staging-bundle.pem COPY ./requirements.txt /requirements.txt RUN \ # Install kubectl from alpine edge until alpine 3.16 is released @@ -28,7 +29,7 @@ RUN \ libffi-dev=~3.4.2-r1 \ make=~4.3-r0 \ # Needed for timestamp cmd "ts" - moreutils=~0.66-r0 \ + moreutils=~0.66-r1 \ npm=~8.1.3-r0 \ openssh-client-default=~8.8_p1-r1 \ py3-pip=~20.3.4-r1 \ @@ -37,6 +38,7 @@ RUN \ yq=~4.14.1-r0 && \ rm -rf /var/cache/* && \ mkdir /var/cache/apk && \ + update-ca-certificates && \ pip install --no-cache-dir --ignore-installed six -r /requirements.txt && \ ln -s /usr/bin/python3 /usr/bin/python && \ tar -xzf /tmp/flux*.tar.gz && mv ./flux /usr/local/bin && \ diff --git a/docs/conf.py b/docs/conf.py index 85ff4759ee5feef79897fd5c767ad47695656380..c41798da51e365d7acf639dd8098edf497d0c0ea 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -61,7 +61,6 @@ html_static_path = ['_static'] # 'contents' master_doc = 'index' - # https://www.sphinx-doc.org/en/master/usage/extensions/autosectionlabel.html # # Suppress autosectionlabel extension warnings about duplicate labels, i.e. @@ -69,5 +68,7 @@ master_doc = 'index' # docs/usage.rst:105: WARNING: duplicate label wordpress, other instance in docs/testing.rst # # https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-suppress_warnings -suppress_warnings = ['autosectionlabel.*'] autosectionlabel_prefix_document = True +autosectionlabel_maxdepth = 5 + +suppress_warnings = ['autosectionlabel.*'] diff --git a/docs/index.rst b/docs/index.rst index fe6d38116522326477fd536737b7293f85148c17..082dbdae91af60c29b0bbc0986ae42bcfd2eab43 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -41,6 +41,7 @@ For more information, go to `the Stackspin website`_. :maxdepth: 2 :caption: Administration + logging maintenance upgrading customizing diff --git a/docs/logging.rst b/docs/logging.rst new file mode 100644 index 0000000000000000000000000000000000000000..6f2e4d779a981e8352fd390a17552f0442621b95 --- /dev/null +++ b/docs/logging.rst @@ -0,0 +1,179 @@ +Logging +======= + +Logs from pods and containers can be read in different ways: + +- In the cluster filesystem at ``/var/log/pods/`` or + ``/var/logs/containers/``. +- Using `kubectl logs`_ +- Querying aggregated logs with Grafana, see below. + +Central log aggregation +----------------------- + +We use `Promtail`_, `Loki`_ and `Grafana`_ for easy access of aggregated +logs. The `Loki documentation`_ is a good starting point how this setup +works. +There are two ways of viewing aggregated logs: + +* Via the Grafana web interface +* Using the ``logcli`` command line tool + + +Viewing logs in Grafana +~~~~~~~~~~~~~~~~~~~~~~~ + +The `Using Loki in Grafana`_ gets you started with querying +your cluster logs with Grafana. +You will find the Loki Grafana integration on your cluster at +https://grafana.stackspin.example.org/explore together with some generic query +examples. + +Please follow :ref:`logging:LogQL query examples` for more LogQL query examples. + +Query logs with logcli +~~~~~~~~~~~~~~~~~~~~~~~ + +Please refer to `logcli`_ for installing ``logcli`` on your Laptop. +The create a port-forwarding to your cluster using the ``kubectl`` tool: + +.. code:: bash + + kubectl -n stackspin port-forward pod/loki-0 3100 + +In another terminal you can now use ``logcli`` to query ``loki`` like this: + +.. code:: bash + + logcli query '{app=~".+"}' + +Please follow :ref:`logging:LogQL query examples` for more LogQL query examples. + +Search older messages (in this case the last week and limit the output to 2000 +lines): + +.. code:: bash + + logcli query --since=168h --limit=2000 --forward '{app="helm-controller"}' + +LogQL query examples +~~~~~~~~~~~~~~~~~~~~ + +Please also refer to the `LogQL documentation`_ and the +`log queries documentation`_ . + +Query all aggregated logs (unfortunatly we can’t find a better way of +doing this since LogQL always expects a stream label to get queried): + +.. code:: PromQL + + {app=~".+"} + +Query all logs for a keyword: + +.. code:: + + {app=~".+"} |= "error" + +Query all k8s apps for errors using a regular expression: + +.. code:: + + {app=~".+"} |~ `(error|fail|exception|fatal)` + +Flux +^^^^ + +`Flux`_ is responsible for installing applications. It uses four +controllers: + +- ``source-controller`` that tracks Helm and Git repositories like + https://open.greenhost.net/stackspin/stackspin for updates. +- ``kustomize-controller`` to deploy ``kustomizations`` that often + install ``helmreleases``. +- ``helm-controller`` to deploy the ``helmreleases``. +- ``notification-controller`` that is responsible for inbound and + outbound flux messages + +Query all messages from the ``source-controller``: + +.. code:: PromQL + + {app="source-controller"} + +Query all messages from ``flux`` and ``helm-controller``: + +.. code:: PromQL + + {app=~"(source-controller|helm-controller)"} + +``helm-controller`` messages containing ``wordpress``: + +.. code:: PromQL + + '{app = "helm-controller"} |= "wordpress"' + +``helm-controller`` messages containing ``wordpress`` without +``unchanged`` events (to only show the installation messages): + +.. code:: PromQL + + '{app = "helm-controller"} |= "wordpress" != "unchanged"' + +Filter out redundant ``helm-controller`` messages: + +.. code:: PromQL + + '{app="helm-controller"} !~ `(unchanged|event=refreshed|method=Sync|component=checkpoint)`' + + +Cert-manager +^^^^^^^^^^^^ + +Cert manager is responsible for requesting Let’s Encrypt TLS +certificates. + +Query ``cert-manager`` messages containing ``chat``: + +.. code:: PromQL + + '{app="cert-manager"} |= "chat"' + +Hydra +^^^^^ + +Hydra is the single sign-on system. + +Show only warnings and errors from ``hydra``: + +.. code:: PromQL + + {container_name="hydra"} != "level=info" + +Debug oauth2 single sign-on with zulip: + +.. code:: PromQL + + {container_name=~"(hydra|zulip)"} + +Etc +^^^ + +Query kubernetes events processed by the ``eventrouter`` app containing +``warning``: + +.. code:: PromQL + + '{app="eventrouter"} |~ "warning"' + + +.. _kubectl logs: https://kubernetes.io/docs/concepts/cluster-administration/logging +.. _Promtail: https://grafana.com/docs/loki/latest/clients/promtail/ +.. _Loki: https://grafana.com/oss/loki/ +.. _Grafana: https://grafana.com/ +.. _Loki documentation: https://grafana.com/docs/loki/latest/ +.. _Using Loki in Grafana: https://grafana.com/docs/grafana/latest/datasources/loki +.. _logcli: https://grafana.com/docs/loki/latest/getting-started/logcli/ +.. _LogQL documentation: https://grafana.com/docs/loki/latest/logql +.. _log queries documentation: https://grafana.com/docs/loki/latest/logql/log_queries/ +.. _Flux: https://fluxcd.io/ diff --git a/docs/maintenance.rst b/docs/maintenance.rst index 81d002615a8ef4557e7ee267b716ae26ad2494f5..544fb0c92e13d358daa1329b2a6bd7861e3bc66d 100644 --- a/docs/maintenance.rst +++ b/docs/maintenance.rst @@ -1,133 +1,6 @@ Maintenance =========== -Logging -------- - -Logs from pods and containers can be read in different ways: - -- In the cluster filesystem at ``/var/log/pods/`` or - ``/var/logs/containers/``. -- Using `kubectl logs`_ -- Querying aggregated logs with Grafana, see below. - -Central log aggregation ------------------------ - -We use `Promtail`_, `Loki`_ and `Grafana`_ for easy access of aggregated -logs. The `Loki documentation`_ is a good starting point how this setup -works, and the `Using Loki in Grafana`_ gets you started with querying -your cluster logs with Grafana. - -You will find the Loki Grafana integration on your cluster at -https://grafana.stackspin.example.org/explore together with some generic query -examples. - -LogQL query examples -~~~~~~~~~~~~~~~~~~~~ - -Please also refer to the `LogQL documentation`_. - -Query all aggregated logs (unfortunatly we can’t find a better way of -doing this since LogQL always expects a stream label to get queried): - -.. code:: bash - - logcli query '{foo!="bar"}' - -Query all logs for a keyword: - -.. code:: bash - - logcli query '{foo!="bar"} |= "error"' - -Query all k8s apps for errors using a regular expression: - -.. code:: bash - - logcli query '{job=~".*"} |~ "error|fail|exception|fatal"' - -Flux -^^^^ - -`Flux`_ is responsible for installing applications. It uses four -controllers: - -- ``source-controller`` that tracks Helm and Git repositories like - https://open.greenhost.net/stackspin/stackspin for updates. -- ``kustomize-controller`` to deploy ``kustomizations`` that often - install ``helmreleases``. -- ``helm-controller`` to deploy the ``helmreleases``. -- ``notification-controller`` that is responsible for inbound and - outbound flux messages - -Query all messages from the ``source-controller``: - -.. code:: bash - - {app="source-controller"} - -Query all messages from ``flux`` and ``helm-controller``: - -.. code:: bash - - {app=~"(source-controller|helm-controller)"} - -``helm-controller`` messages containing ``wordpress``: - -.. code:: bash - - {app = "helm-controller"} |= "wordpress" - -``helm-controller`` messages containing ``wordpress`` without -``unchanged`` events (to only show the installation messages): - -.. code:: bash - - {app = "helm-controller"} |= "wordpress" != "unchanged" - -Filter out redundant ``helm-controller`` messages: - -.. code:: bash - - { app = "helm-controller" } !~ "(unchanged | event=refreshed | method=Sync | component=checkpoint)" - -Debug oauth2 single sign-on with zulip: - -.. code:: bash - - {container_name=~"(hydra|zulip)"} - -Query kubernetes events processed by the ``eventrouter`` app containing -``warning``: - -.. code:: bash - - logcli query '{app="eventrouter"} |~ "warning"' - -Cert-manager -^^^^^^^^^^^^ - -Cert manager is responsible for requesting Let’s Encrypt TLS -certificates. - -Query ``cert-manager`` messages containing ``chat``: - -.. code:: bash - - {app="cert-manager"} |= "chat" - -Hydra -^^^^^ - -Hydra is the single sign-on system. - -Show only warnings and errors from ``hydra``: - -.. code:: bash - - {container_name="hydra"} != "level=info" - Backup ------ @@ -204,14 +77,6 @@ following command that will apply the changes to all installed kustomizations: flux get -A kustomizations --no-header | awk -F' ' '{system("flux reconcile -n " $1 " kustomization " $2)}' -.. _kubectl logs: https://kubernetes.io/docs/concepts/cluster-administration/logging -.. _Promtail: https://grafana.com/docs/loki/latest/clients/promtail/ -.. _Loki: https://grafana.com/oss/loki/ -.. _Grafana: https://grafana.com/ -.. _Loki documentation: https://grafana.com/docs/loki/latest/ -.. _Using Loki in Grafana: https://grafana.com/docs/grafana/latest/datasources/loki -.. _LogQL documentation: https://grafana.com/docs/loki/latest/logql -.. _Flux: https://fluxcd.io/ .. _Velero’s documentation: https://velero.io/docs/v1.4/ .. _reach out to us: https://stackspin.net/contact.html .. _taints: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ diff --git a/docs/requirements.in b/docs/requirements.in index 16f51618fa5d19bc02c2bb909ac79eebaca227f4..957a65b28f6b240a182ba3485567cf2826f5b153 100644 --- a/docs/requirements.in +++ b/docs/requirements.in @@ -5,7 +5,7 @@ # Please add developer dependencies which are not needed to install # Stackspin to requirements-dev.txt! # +recommonmark sphinx sphinx-design sphinx-rtd-theme -recommonmark diff --git a/docs/requirements.txt b/docs/requirements.txt index f39411896b309d080bd07b6b01155ce8d45fc009..dfbd6ae61cc2f23d6c210d33e9d0e8fd46c2a70a 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -14,7 +14,7 @@ charset-normalizer==2.0.9 # via requests commonmark==0.9.1 # via recommonmark -docutils==0.18.1 +docutils==0.17.1 # via # recommonmark # sphinx @@ -30,8 +30,10 @@ markupsafe==2.0.1 packaging==21.3 # via sphinx pygments==2.10.0 - # via sphinx -pyparsing==2.4.7 + # via + # -r requirements.in + # sphinx +pyparsing==3.0.6 # via packaging pytz==2021.3 # via babel diff --git a/docs/troubleshooting.rst b/docs/troubleshooting.rst index 10fee5a0593bf7a68b212bd64bd21ed2e5a9a6ba..5db3248aaacc9c95c42371490178508d287f1b74 100644 --- a/docs/troubleshooting.rst +++ b/docs/troubleshooting.rst @@ -95,7 +95,7 @@ Tests a specific application Known Issues '''''''''''' -The Default ssh backend for testinfra tests is ``paramiko``, which doesn't work +The default ssh backend for testinfra tests is ``paramiko``, which doesn't work out of the box. It fails to connect to the host because the ``ed25519`` hostkey was not verified. Therefore we need to force plain ssh:// with either ``connection=ssh`` or ``--hosts=ssh://…`` @@ -190,8 +190,8 @@ then: gitlab-runner exec docker --env CI_REGISTRY_IMAGE="$CI_REGISTRY_IMAGE" --env SSH_PRIVATE_KEY="$SSH_PRIVATE_KEY" --env COSMOS_API_TOKEN="$COSMOS_API_TOKEN" bootstrap -Taiko tests -''''''''''' +Advanced Taiko tests +'''''''''''''''''''' If you want to use Taiko without invoking the stackspin CLI, go to the ``test/taiko`` directory and run: diff --git a/docs/upgrading.rst b/docs/upgrading.rst index 76824490a1ab9775af156ed9904997cfa2851965..9155d76909c906b3c35ab166d208aa2cb804ef20 100644 --- a/docs/upgrading.rst +++ b/docs/upgrading.rst @@ -96,10 +96,9 @@ renamed from ``oas`` to ``stackspin``. You can choose from these options: Rocket.Chat ~~~~~~~~~~~ -We replaced Rocket.Chat with `Zulip <https://zulip.com>`__ in this release. -If you want to migrate your Rocket.Chat data to your new Zulip installation -please refer to -`Import from Rocket.Chat https://api.zulip.com/help/import-from-rocketchat`__. +We replaced Rocket.Chat with `Zulip`_ in this release. +If you want to migrate your Rocket.Chat data to your new `Zulip`_ installation +please refer to `Import from Rocket.Chat`_. Monitoring ~~~~~~~~~~ @@ -131,13 +130,12 @@ from v0.6 to v0.7!** .. note:: Before you start, please ensure that you have the right ``yq`` tool installed, because you will need it later. There are two very different versions of - ``yq``. The one you need is the go based `yq from Mike Farah - <http://mikefarah.github.io/yq>`_, which installs the same binary name ``yq`` - as the `python-yq <https://github.com/kislyuk/yq>`_, while both have different - command sets. + ``yq``. The one you need is the go based `yq from Mike Farah`_, + which installs the same binary name as the `python-yq`_ one, while both have + different command sets. The yq needed here can be installed by running ``sudo snap install yq``, - ``brew install yq`` or with other methods from the `yq installation - instructions <http://mikefarah.github.io/yq/#install>`_. + ``brew install yq`` or with other methods from the + `yq installation instructions`_. If you're unsure which ``yq`` you have installed, look at the output of ``yq --help`` and make sure ``eval`` shows up under ``Available Commands:``. @@ -394,3 +392,8 @@ intervention. .. _reach out to us: https://openappstack.net/contact.html .. _Flux: https://fluxcd.io +.. _yq from Mike Farah: https://mikefarah.github.io/yq +.. _yq installation instructions: https://mikefarah.github.io/yq/#install +.. _python-yq: https://github.com/kislyuk/yq +.. _Zulip: https://zulip.com +.. _Import from Rocket.Chat: https://api.zulip.com/help/import-from-rocketchat diff --git a/docs/usage.rst b/docs/usage.rst index b618c09fa914471f1a07cdfebd594ce35e9c9c19..d7ea1299e7f7a1b03872b917062dd4f63625b707 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -24,7 +24,7 @@ them access to applications, take a look at the `user panel documentation .. note:: If you don't see applications, make sure you have installed at least one - optional application in :ref:`additional_apps` of the installation procedure. + optional application in :ref:`install_additional_apps` of the installation procedure. For creating users follow the `user creation documentation <https://docs.stackspin.net/projects/user-panel/en/latest/#creating-a-new-user>`_. diff --git a/flux2/apps/monitoring/kube-prometheus-stack-release.yaml b/flux2/apps/monitoring/kube-prometheus-stack-release.yaml index 1f4e6578f0b9885abaa81b52fd3d8bc7b312c112..a911f89766290df89d3ab2e8c6a2832ad1925ae7 100644 --- a/flux2/apps/monitoring/kube-prometheus-stack-release.yaml +++ b/flux2/apps/monitoring/kube-prometheus-stack-release.yaml @@ -11,7 +11,7 @@ spec: # https://artifacthub.io/packages/helm/prometheus-community/kube-prometheus-stack # renovate: registryUrl=https://prometheus-community.github.io/helm-charts chart: kube-prometheus-stack - version: 22.0.0 + version: 23.2.0 sourceRef: kind: HelmRepository name: prometheus-community diff --git a/flux2/apps/monitoring/loki-values-configmap.yaml b/flux2/apps/monitoring/loki-values-configmap.yaml index 3412fce66597c06ee4d0e7571825c8c69ed76332..86ec319cb6148f990373e68d1513f94166ef188b 100644 --- a/flux2/apps/monitoring/loki-values-configmap.yaml +++ b/flux2/apps/monitoring/loki-values-configmap.yaml @@ -6,6 +6,11 @@ metadata: data: values.yaml: | # https://github.com/grafana/helm-charts/blob/main/charts/loki/values.yaml + image: + repository: grafana/loki + # Downgrade loki because of mem leak + # (https://open.greenhost.net/stackspin/stackspin/-/issues/1077) + tag: 2.4.0 resources: limits: cpu: 800m diff --git a/flux2/cluster/base/single-sign-on.yaml b/flux2/cluster/base/single-sign-on.yaml index 78133014d2b1560c39dce7ba9409144f8fad8e9d..e5efa49f8da028aa6d17f25a9203b03c7a3f96b4 100644 --- a/flux2/cluster/base/single-sign-on.yaml +++ b/flux2/cluster/base/single-sign-on.yaml @@ -30,11 +30,11 @@ spec: namespace: stackspin - apiVersion: apps/v1 kind: Deployment - name: single-sign-on-userbackend + name: single-sign-on-hydra namespace: stackspin - apiVersion: apps/v1 kind: Deployment - name: single-sign-on-hydra + name: single-sign-on-kratos namespace: stackspin - apiVersion: apps/v1 kind: Deployment diff --git a/flux2/core/base/metallb/release.yaml b/flux2/core/base/metallb/release.yaml index faf53c8b5124755686ac934c05e2153ad9fcf565..083e6024648cc87d3474e4086219686ed4a38e0e 100644 --- a/flux2/core/base/metallb/release.yaml +++ b/flux2/core/base/metallb/release.yaml @@ -11,7 +11,7 @@ spec: # https://artifacthub.io/packages/helm/bitnami/metallb # renovate: registryUrl=https://charts.bitnami.com/bitnami chart: metallb - version: 2.5.13 + version: 2.5.14 sourceRef: kind: HelmRepository name: bitnami diff --git a/flux2/core/base/single-sign-on/kustomization.yaml b/flux2/core/base/single-sign-on/kustomization.yaml index 354f7bb3bf7f25e633ada0129e9c5f96284f468a..0103cabedd67afd76a28bf0a0d4621dd5425300b 100644 --- a/flux2/core/base/single-sign-on/kustomization.yaml +++ b/flux2/core/base/single-sign-on/kustomization.yaml @@ -3,7 +3,6 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namespace: stackspin resources: - - pvc-userbackend.yaml - pvc-database.yaml - release.yaml - single-sign-on-values-configmap.yaml diff --git a/flux2/core/base/single-sign-on/pvc-userbackend.yaml b/flux2/core/base/single-sign-on/pvc-userbackend.yaml deleted file mode 100644 index e21e9d6f89efd66e56682d5d74dcaf3c193d3311..0000000000000000000000000000000000000000 --- a/flux2/core/base/single-sign-on/pvc-userbackend.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: single-sign-on-userbackend -spec: - accessModes: - - ReadWriteOnce - volumeMode: Filesystem - resources: - requests: - storage: 1Gi - storageClassName: local-path diff --git a/flux2/core/base/single-sign-on/release.yaml b/flux2/core/base/single-sign-on/release.yaml index 02aefb7bf86fb14079fa560aecf22a64d30ab1db..7f240d648da115909bfba8978f287c03e2ac847c 100644 --- a/flux2/core/base/single-sign-on/release.yaml +++ b/flux2/core/base/single-sign-on/release.yaml @@ -17,9 +17,7 @@ spec: namespace: flux-system interval: 1h0m0s install: - remediation: - retries: 3 - timeout: 10m + timeout: 20m upgrade: crds: CreateReplace valuesFrom: diff --git a/flux2/core/base/single-sign-on/single-sign-on-values-configmap.yaml b/flux2/core/base/single-sign-on/single-sign-on-values-configmap.yaml index 682841595af6cbf9a333390805333816f290bacc..35fadcef734a38e739fb95d416fa2097fb059063 100644 --- a/flux2/core/base/single-sign-on/single-sign-on-values-configmap.yaml +++ b/flux2/core/base/single-sign-on/single-sign-on-values-configmap.yaml @@ -7,39 +7,11 @@ data: values.yaml: | singleSignOnHost: &SSO_HOST "sso.${domain}" - userpanel: - applicationName: &USER_PANEL user-panel - ingress: - host: "admin.${domain}" - - userbackend: - applications: - - name: *USER_PANEL - description: Administration interface to manage user accounts - - name: &NEXTCLOUD nextcloud - description: "Nextcloud Files offers an on-premise Universal File Access and sync platform with powerful collaboration capabilities and desktop, mobile and web interfaces." - - name: &WORDPRESS wordpress - description: "WordPress website hosting." - - name: &GRAFANA grafana - description: "Grafana allows you to query, visualize, alert on and understand metrics generated by Stackspin. It can be used to create explore and share dashboards." - - name: &WEKAN wekan - description: "Wekan Kanban board." - - name: &ZULIP zulip - description: "Communicate and collaborate using team chat and switch to video or audio calls with screen sharing for more efficient teamwork." - - name: &DASHBOARD dashboard - description: "Stackspin dashboard." - username: "${userbackend_admin_username}" - password: "${userbackend_admin_password}" - email: "${admin_email}" - postgres: - password: "${userbackend_postgres_password}" - persistence: - enabled: true - size: 1Gi - existingClaim: single-sign-on-userbackend - podAnnotations: - # Let the backup system include nextcloud database data. - backup.velero.io/backup-volumes: "database" + login: + user: ${admin_email} + password: ${userbackend_admin_password} + db: + password: ${userbackend_postgres_password} postgresql: persistence: @@ -59,8 +31,9 @@ data: urls: self: issuer: "https://sso.${domain}" - login: "https://sso.${domain}/login" - consent: "https://sso.${domain}/consent" + login: "https://sso.${domain}/login/auth" + consent: "https://sso.${domain}/login/consent" + logout: "https://sso.${domain}/login/logout" secrets: system: - "${hydra_system_secret}" @@ -87,20 +60,35 @@ data: kratos: config: dsn: "postgres://kratos:${kratos_postgresql_password}@single-sign-on-postgresql:5432/kratos" + serve: + public: + base_url: https://sso.${domain}/api/ + courier: + smtp: + connection_uri: smtp://${outgoing_mail_smtp_user}:${outgoing_mail_smtp_password}@${outgoing_mail_smtp_host}:${outgoing_mail_smtp_port}/ + from_address: ${outgoing_mail_from_address} + secrets: + session: + - "${kratos_session_secret}" + selfservice: + # The URL to redirect to if there is a call to kratos on another URL + # than the flows listed below + default_browser_return_url: https://sso.${domain}/login/login + flows: + recovery: + ui_url: https://sso.${domain}/login/recovery + login: + ui_url: https://sso.${domain}/login/login + settings: + ui_url: https://sso.${domain}/login/settings + # Registration is not (yet) possible, but if it will be, it should + # be on this link: + registration: + ui_url: https://sso.${domain}/login/registration + oAuthClients: - - clientName: *USER_PANEL - clientSecret: "${userpanel_oauth_client_secret}" - redirectUri: "https://admin.${domain}/callback" - scopes: "openid profile email stackspin_roles" - clientUri: "https://admin.${domain}" - clientLogoUri: "https://admin.${domain}/favicon.ico" - tokenEndpointAuthMethod: "client_secret_basic" - responseTypes: - - "token" - grantTypes: - - "implicit" - - clientName: *NEXTCLOUD + - clientName: nextcloud clientSecret: "${nextcloud_oauth_client_secret}" redirectUri: "https://files.${domain}/apps/sociallogin/custom_oidc/stackspin" scopes: "openid profile email stackspin_roles" @@ -114,7 +102,7 @@ data: - "authorization_code" - "refresh_token" - "client_credentials" - - clientName: *WORDPRESS + - clientName: wordpress clientSecret: "${wordpress_oauth_client_secret}" redirectUri: "https://www.${domain}/wp-admin/admin-ajax.php?action=openid-connect-authorize" scopes: "openid profile email stackspin_roles offline_access" @@ -129,7 +117,7 @@ data: - "refresh_token" - "client_credentials" - "implicit" - - clientName: *GRAFANA + - clientName: grafana clientSecret: "${grafana_oauth_client_secret}" redirectUri: "https://grafana.${domain}/login/generic_oauth" scopes: "openid profile email stackspin_roles" @@ -144,7 +132,7 @@ data: - "refresh_token" - "client_credentials" # https://github.com/wekan/wekan/wiki/Keycloak - - clientName: *WEKAN + - clientName: wekan clientSecret: "${wekan_oauth_client_secret}" redirectUri: "https://wekan.${domain}/_oauth/oidc" scopes: "openid profile email" @@ -160,13 +148,13 @@ data: - "client_credentials" - "implicit" # https://zulip.readthedocs.io/en/latest/production/authentication-methods.html#openid-connect - - clientName: *ZULIP + - clientName: zulip clientSecret: "${zulip_oauth_client_secret}" redirectUri: "https://zulip.${domain}/complete/oidc/" scopes: "openid profile email" clientUri: "https://zulip.${domain}" clientLogoUri: "https://zulip.${domain}/static/images/zulip-logo.svg" - - clientName: *DASHBOARD + - clientName: dashboard clientSecret: "${dashboard_oauth_client_secret}" redirectUri: "https://dashboard.${domain}/_oauth/oidc" scopes: "openid profile email" diff --git a/flux2/core/base/sources/single-sign-on.yaml b/flux2/core/base/sources/single-sign-on.yaml index 4faf6956c6885e4795c1be458236e6512c4b1c21..87adf56b07fde830195830563f9b261c0cac9a6a 100644 --- a/flux2/core/base/sources/single-sign-on.yaml +++ b/flux2/core/base/sources/single-sign-on.yaml @@ -14,4 +14,4 @@ spec: # For all available options, see: # https://toolkit.fluxcd.io/components/source/api/#source.toolkit.fluxcd.io/v1beta1.GitRepositoryRef ref: - tag: 0.4.3 + tag: 0.5.0 diff --git a/install/templates/stackspin-single-sign-on-variables.yaml.jinja b/install/templates/stackspin-single-sign-on-variables.yaml.jinja index 70caab6571ab5622d5d681b67baa39696db28e83..56ccc93f9bc7c944bc362d67afa7c01d83cb28f5 100644 --- a/install/templates/stackspin-single-sign-on-variables.yaml.jinja +++ b/install/templates/stackspin-single-sign-on-variables.yaml.jinja @@ -4,10 +4,10 @@ kind: Secret metadata: name: stackspin-single-sign-on-variables data: - userbackend_admin_username: '{{ "admin" | b64encode }}' - userbackend_admin_password: "{{ 32 | generate_password | b64encode }}" - userbackend_postgres_password: "{{ 32 | generate_password | b64encode }}" - hydra_system_secret: "{{ 32 | generate_password | b64encode }}" + dashboard_postgresql_password: "{{ 32 | generate_password | b64encode }}" hydra_postgresql_password: "{{ 32 | generate_password | b64encode }}" + hydra_system_secret: "{{ 32 | generate_password | b64encode }}" kratos_postgresql_password: "{{ 32 | generate_password | b64encode }}" - dashboard_postgresql_password: "{{ 32 | generate_password | b64encode }}" + kratos_session_secret: "{{ 32 | generate_password | b64encode }}" + userbackend_admin_password: "{{ 32 | generate_password | b64encode }}" + userbackend_postgres_password: "{{ 32 | generate_password | b64encode }}" diff --git a/requirements.txt b/requirements.txt index 92e73521090300079b784fa30a98913b554436ea..a3f536f987dbd545af833aaa09393b464620a07a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -25,7 +25,7 @@ cffi==1.15.0 # pynacl charset-normalizer==2.0.9 # via requests -cryptography==36.0.0 +cryptography==36.0.1 # via # ansible # paramiko @@ -86,7 +86,7 @@ pytest==6.2.5 # pytest-testinfra pytest-rerunfailures==10.2 # via -r requirements.in -pytest-testinfra==6.4.0 +pytest-testinfra==6.5.0 # via -r requirements.in python-dateutil==2.8.2 # via kubernetes @@ -124,7 +124,7 @@ urllib3==1.26.7 # via # kubernetes # requests -websocket-client==1.2.2 +websocket-client==1.2.3 # via kubernetes wheel==0.37.0 # via -r requirements.in diff --git a/test/pytest/test_certs.py b/test/pytest/test_certs.py index 9cfb26f7e5be7437d21bc901d4461b5399e14cf5..5d1e2963d3919e0396fd91060652bf5d87508f80 100755 --- a/test/pytest/test_certs.py +++ b/test/pytest/test_certs.py @@ -2,9 +2,11 @@ """Test if application ingress uses a valid certificate.""" import os +import shutil import socket import sys +import certifi import pytest import requests from OpenSSL import SSL @@ -17,6 +19,20 @@ def test_cert_validation(host, resource): # pylint: disable=too-many-statements Check is executed on the local provisioning machine. """ + def add_custom_cert_authorities(ca_file: str, + custom_ca_files: list, + dest_file: str = + '/tmp/custom_ca_bundle.crt'): + """Concatenates existing cert bundle with custom CAs.""" + + destination = open(dest_file, 'wb') + with open(dest_file, 'wb') as destination, open(ca_file, 'rb') as cert_auth: + shutil.copyfileobj(cert_auth, destination) + for custom_ca_file in custom_ca_files: + with open(custom_ca_file, 'rb') as custom_ca: + shutil.copyfileobj(custom_ca, destination) + + def fetch_certs(domain: str, port: int = 443): """Fetches cert fom given domain.""" @@ -52,8 +68,9 @@ def test_cert_validation(host, resource): # pylint: disable=too-many-statements print('CN: {0} (Issuer: {1})'.format(common_name, issuer)) - def valid_cert(domain: str): - """Validate cert of given domain.""" + def valid_cert(domain: str, ca_file: str = '/tmp/custom_ca_bundle.crt', + app: str = "all"): + """Validate cert of given domain against a ca_file bundle.""" valid = False @@ -63,14 +80,17 @@ def test_cert_validation(host, resource): # pylint: disable=too-many-statements print_cert_info(certs) try: - requests.get(url) + requests.get(url, verify=ca_file) except requests.exceptions.SSLError as ex: print('SSL Verification Error {}'.format(ex)) - #for cert in certs: - # issuer = cert.get_issuer().CN + for cert in certs: + issuer = cert.get_issuer().CN + if issuer == 'cert-manager.local': + print('Allowing exception for self-signed cert-mananger cert.') + valid = True return valid - print('Successfully Verified SSL Cert. \n') + print('Successfully Verified SSL Cert.\n') return True @@ -91,8 +111,7 @@ def test_cert_validation(host, resource): # pylint: disable=too-many-statements elif resource == 'kube-prometheus-stack': apps = ['grafana', 'prometheus'] else: - assert resource in app_subdomains, \ - "Error: Unknown app: {}".format(resource) + assert resource in app_subdomains, "Error: Unknown app: {}".format(app) apps = [resource] print('\n') @@ -107,5 +126,8 @@ def test_cert_validation(host, resource): # pylint: disable=too-many-statements domain = ansible_vars["domain"] print("Using domain %s from ansible inventory." % domain) + add_custom_cert_authorities(certifi.where(), + ['pytest/le-staging-bundle.pem']) + fqdn = app_subdomains[app_name] + '.' + domain - assert valid_cert(domain=fqdn) + assert valid_cert(domain=fqdn, app=resource) diff --git a/test/pytest/test_resources.py b/test/pytest/test_resources.py index 83d29ae2cd6e14947994196bfc353dba280f56c9..35373ed245ef5dacaa17445d3ba67cf21c8a6670 100644 --- a/test/pytest/test_resources.py +++ b/test/pytest/test_resources.py @@ -10,10 +10,10 @@ Documentation for the kubernetes client: * https://github.com/kubernetes-client/python/tree/master/examples """ import os -from kubernetes import client, config -from kubernetes.client.rest import ApiException import pytest +from kubernetes import client, config +from kubernetes.client.rest import ApiException # Helper functions @@ -134,7 +134,10 @@ def run_around_tests(): Prepare kube config before running a test """ cluster_dir = os.environ.get("CLUSTER_DIR") - kubeconfig = os.path.join('..', str(cluster_dir), 'kube_config_cluster.yml') + if cluster_dir: + kubeconfig = os.path.join('..', str(cluster_dir), 'kube_config_cluster.yml') + else: + kubeconfig = os.path.join(os.environ.get("KUBECONFIG")) config.load_kube_config(config_file=kubeconfig) yield