From d245e640b9d23f984f8f4ee5b55f0f04b46cb4c4 Mon Sep 17 00:00:00 2001 From: Alex Chapellon Date: Fri, 2 Feb 2024 11:03:15 +0100 Subject: [PATCH] OPSEXP-2390: add an example chart for educational purpose (#1084) --- .github/workflows/helm-community.yml | 41 +- .github/workflows/helm-enterprise.yml | 20 +- .github/workflows/helm-static-checks.yml | 11 +- .github/workflows/pre-commit-helm.yml | 14 +- .gitignore | 4 +- .pre-commit-config.yaml | 4 +- helm/acs-sso-example/.helmignore | 23 + helm/acs-sso-example/Chart.lock | 21 + helm/acs-sso-example/Chart.yaml | 50 ++ helm/acs-sso-example/README.md | 210 ++++++++ helm/acs-sso-example/README.md.gotmpl | 16 + helm/acs-sso-example/docs/sso-guide.md | 474 ++++++++++++++++++ .../docs/step-by-step-guide.md | 465 +++++++++++++++++ helm/acs-sso-example/templates/_helpers.tpl | 62 +++ .../templates/configmap-db.yaml | 16 + .../templates/configmap-idp.yaml | 7 + .../templates/configmap-mq.yaml | 15 + .../templates/configmap-repo.yaml | 13 + .../templates/configmap-share-properties.yaml | 17 + .../templates/configmap-share.yaml | 12 + helm/acs-sso-example/templates/secret-db.yaml | 13 + .../templates/secret-idp-realm.yaml | 15 + .../acs-sso-example/templates/secret-idp.yaml | 14 + helm/acs-sso-example/templates/secret-mq.yaml | 10 + helm/acs-sso-example/values.yaml | 260 ++++++++++ 25 files changed, 1779 insertions(+), 28 deletions(-) create mode 100644 helm/acs-sso-example/.helmignore create mode 100644 helm/acs-sso-example/Chart.lock create mode 100644 helm/acs-sso-example/Chart.yaml create mode 100644 helm/acs-sso-example/README.md create mode 100644 helm/acs-sso-example/README.md.gotmpl create mode 100644 helm/acs-sso-example/docs/sso-guide.md create mode 100644 helm/acs-sso-example/docs/step-by-step-guide.md create mode 100644 helm/acs-sso-example/templates/_helpers.tpl create mode 100644 helm/acs-sso-example/templates/configmap-db.yaml create mode 100644 helm/acs-sso-example/templates/configmap-idp.yaml create mode 100644 helm/acs-sso-example/templates/configmap-mq.yaml create mode 100644 helm/acs-sso-example/templates/configmap-repo.yaml create mode 100644 helm/acs-sso-example/templates/configmap-share-properties.yaml create mode 100644 helm/acs-sso-example/templates/configmap-share.yaml create mode 100644 helm/acs-sso-example/templates/secret-db.yaml create mode 100644 helm/acs-sso-example/templates/secret-idp-realm.yaml create mode 100644 helm/acs-sso-example/templates/secret-idp.yaml create mode 100644 helm/acs-sso-example/templates/secret-mq.yaml create mode 100644 helm/acs-sso-example/values.yaml diff --git a/.github/workflows/helm-community.yml b/.github/workflows/helm-community.yml index 9e053eed2..959c33743 100644 --- a/.github/workflows/helm-community.yml +++ b/.github/workflows/helm-community.yml @@ -19,9 +19,40 @@ concurrency: group: helm-com-${{ github.head_ref || github.ref_name }} cancel-in-progress: true jobs: + build_vars: + runs-on: ubuntu-latest + outputs: + ver_json: ${{ steps.app_versions.outputs.json }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Get charts + id: getcharts + uses: ./.github/actions/charts-as-json + with: + charts-root: helm + - name: Keep only ACS enterprise + id: app_versions + env: + JSON: ${{ toJSON(fromJSON(steps.getcharts.outputs.all)) }} + JQ_FILTER: >- + [inputs | .charts[] | {name: .name, values: .values[]} + | select(.values=="community_values.yaml" or .name=="acs-sso-example")] + run: | + echo "${JSON}" | jq -nc '${{ env.JQ_FILTER }}' + VERS=$(echo "${JSON}" | jq -nc '${{ env.JQ_FILTER }}') + echo "json=$VERS" >> $GITHUB_OUTPUT + community_charts: runs-on: ubuntu-latest timeout-minutes: 10 + needs: + - build_vars + strategy: + fail-fast: false + matrix: + include: ${{ fromJSON(needs.build_vars.outputs.ver_json) }} steps: - uses: actions/checkout@v4 @@ -55,14 +86,15 @@ jobs: - name: Helm install run: | - helm dep up ./helm/alfresco-content-services - helm install acs ./helm/alfresco-content-services \ + helm dep up . + helm install ${{ matrix.name }} . \ --set global.search.sharedSecret="$(openssl rand -hex 24)" \ --set global.known_urls=http://localhost \ --set global.alfrescoRegistryPullSecrets=regcred \ --wait --timeout 5m0s \ - --values helm/alfresco-content-services/community_values.yaml \ - --values test/community-integration-test-values.yaml + --values ${{ matrix.values }} \ + --values ../../test/community-integration-test-values.yaml + working-directory: helm/${{ matrix.name }} - name: Spit cluster status if: always() @@ -76,6 +108,7 @@ jobs: - uses: nick-fields/retry@v2 id: newman + if: matrix.name == 'alfresco-content-services' with: timeout_minutes: 1 retry_wait_seconds: 30 diff --git a/.github/workflows/helm-enterprise.yml b/.github/workflows/helm-enterprise.yml index 0b8861500..59af1b2c5 100644 --- a/.github/workflows/helm-enterprise.yml +++ b/.github/workflows/helm-enterprise.yml @@ -28,34 +28,28 @@ jobs: && github.actor != 'dependabot[bot]' ) outputs: - app_json: ${{ steps.getcharts.outputs.app }} ver_json: ${{ steps.app_versions.outputs.json }} - chart_names: ${{ steps.chart_names.outputs.json}} steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - - id: getcharts + - name: Get charts + id: getcharts uses: ./.github/actions/charts-as-json with: charts-root: helm - - id: app_versions + - name: Keep only ACS enterprise + id: app_versions env: JSON: ${{ toJSON(fromJSON(steps.getcharts.outputs.all)) }} JQ_FILTER: >- - [inputs | .charts[] | {name: .name, values: .values[]}] - | del(.[] | select(.values=="community_values.yaml")) + [inputs | .charts[] | {name: .name, values: .values[]} + | del(. | select(.values=="community_values.yaml")) + | select(.name=="alfresco-content-services")] run: | echo "${JSON}" | jq -nc '${{ env.JQ_FILTER }}' VERS=$(echo "${JSON}" | jq -nc '${{ env.JQ_FILTER }}') echo "json=$VERS" >> $GITHUB_OUTPUT - - id: chart_names - env: - JSON: ${{ toJSON(fromJSON(steps.getcharts.outputs.all)) }} - JQ_FILTER: $json | [.charts[].name] - run: | - CHARTS=$(jq -nc --argjson json '${{ env.JSON }}' '${{ env.JQ_FILTER }}') - echo "json=$CHARTS" >> $GITHUB_OUTPUT helm_integration: runs-on: alfrescoPub-ubuntu2204-16G-4CPU diff --git a/.github/workflows/helm-static-checks.yml b/.github/workflows/helm-static-checks.yml index 448066dd9..be881dc8b 100644 --- a/.github/workflows/helm-static-checks.yml +++ b/.github/workflows/helm-static-checks.yml @@ -46,8 +46,11 @@ jobs: Alfresco/alfresco-build-tools/.github/actions/helm-plugin@v5.13.0 with: plugin_url: https://github.com/helm-unittest/helm-unittest - - run: | - helm unittest helm/${{ matrix.charts.name }} + - name: Run Helm unit tests if present + run: | + if [ -d "helm/${{ matrix.charts.name }}/tests" ]; then helm unittest helm/${{ matrix.charts.name }} + else echo "${{ matrix.charts.name }} chart has no unit tests... skipping." + fi helm_yaml_lint: needs: - build_vars @@ -65,4 +68,6 @@ jobs: Alfresco/alfresco-build-tools/.github/actions/helm-template-yamllint@v5.13.0 with: chart-dir: helm/${{ matrix.charts.name }} - helm-options: --values tests/values/test_values.yaml + helm-options: >- + --set global.search.sharedSecret=dummy + --set global.search.alfrescoRegistryPullSecrets=dummy diff --git a/.github/workflows/pre-commit-helm.yml b/.github/workflows/pre-commit-helm.yml index 5c177c7c9..3327f83f0 100644 --- a/.github/workflows/pre-commit-helm.yml +++ b/.github/workflows/pre-commit-helm.yml @@ -27,11 +27,15 @@ jobs: name: Run pre-commit runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # 4.1.1 - uses: Alfresco/alfresco-build-tools/.github/actions/setup-helm-docs@v5.13.0 - name: Add dependency chart repos run: | - helm repo add alfresco-helm-charts https://alfresco.github.io/alfresco-helm-charts - helm repo add activiti-cloud-helm-charts https://activiti.github.io/activiti-cloud-helm-charts - helm repo add elasticsearch https://helm.elastic.co - - uses: pre-commit/action@v3.0.0 + for repo in $(yq eval-all \ + '. as $item ireduce ({}; . *+ $item ) | [.dependencies[].repository | select(. == "http*")] | unique | .[]' \ + ./helm/*/Chart.yaml); do repo_name=$(echo "$repo" | awk -F/ '{print $3}') + helm repo add "$repo_name" "$repo" + done + + - name: Run Pre-commit hooks + uses: pre-commit/action@646c83fcd040023954eafda54b4db0192ce70507 # v3.0.0 diff --git a/.gitignore b/.gitignore index d1dd51e1f..843166d35 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ *.class -war/overlays -alfresco/* +# vim +.*.swp # Eclipse .classpath diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5de30026a..c87e4bb3b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -31,10 +31,12 @@ repos: rev: 2.3.288 hooks: - id: checkov - files: \.yaml$ + types: [yaml] args: - --quiet - --compact + - --config-file + - .checkov.yaml # Docker Compose hooks section (excluded in pre-commit-helm workflow) - repo: https://github.com/IamTheFij/docker-pre-commit rev: v2.1.1 diff --git a/helm/acs-sso-example/.helmignore b/helm/acs-sso-example/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/helm/acs-sso-example/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/helm/acs-sso-example/Chart.lock b/helm/acs-sso-example/Chart.lock new file mode 100644 index 000000000..1ce4e4b81 --- /dev/null +++ b/helm/acs-sso-example/Chart.lock @@ -0,0 +1,21 @@ +dependencies: +- name: postgresql + repository: oci://registry-1.docker.io/bitnamicharts + version: 13.4.0 +- name: keycloakx + repository: https://codecentric.github.io/helm-charts + version: 2.3.0 +- name: alfresco-repository + repository: https://alfresco.github.io/alfresco-helm-charts/ + version: 0.1.3 +- name: activemq + repository: https://alfresco.github.io/alfresco-helm-charts/ + version: 3.4.1 +- name: alfresco-share + repository: https://alfresco.github.io/alfresco-helm-charts/ + version: 0.3.0 +- name: common + repository: https://activiti.github.io/activiti-cloud-helm-charts + version: 8.2.0 +digest: sha256:ace366990857f02b8ea2848d2f7ac9c6fa7825e5b0176dc061bcd35e623ac318 +generated: "2024-01-25T23:34:16.851973+01:00" diff --git a/helm/acs-sso-example/Chart.yaml b/helm/acs-sso-example/Chart.yaml new file mode 100644 index 000000000..95b6c27d8 --- /dev/null +++ b/helm/acs-sso-example/Chart.yaml @@ -0,0 +1,50 @@ +apiVersion: v2 +name: acs-sso-example +description: | + An example Chart to demonstrate how to compose your own Alfresco platform + with SSO on kubernetes using a nthrid party Keycloak. + if you're familiar with [Helm](ttps://helm.sh) & + [Kubernetes](https://kubernetes.io) taking a look at the `values.yaml` should + be enough but the principals are also documented in two differents steps: + + * Composing your ACS from individual component charts we provide. + Check the [step by step documentation](./docs/step-by-step-guide.md) + * SSO integration, to add keycloak and configure Alfresco applications + accordingly: [SSO guide](./docs/step-by-step-guide.md) + + > Note: this chart is just an example that can run on a localhost only. + > It ships ACS repo, the repository database, the message broker, the + > Keycloak IdP and front end applications (Share and Content app) & no other + > component. + + :warning: All components have persistence disabled so all data is lost after a + deployment is destroyed or rolled back! + +type: application +version: 0.1.0 +appVersion: 23.2.0-A12 +home: https://www.alfresco.com +sources: + - https://github.com/Alfresco/acs-deployment/helm/acs-sso-example +dependencies: + - name: postgresql + repository: oci://registry-1.docker.io/bitnamicharts + version: 13.4.0 + alias: repository-database + - name: keycloakx + repository: https://codecentric.github.io/helm-charts + version: 2.3.0 + - name: alfresco-repository + repository: https://alfresco.github.io/alfresco-helm-charts/ + version: 0.1.3 + - name: activemq + repository: https://alfresco.github.io/alfresco-helm-charts/ + version: 3.4.1 + - name: alfresco-share + repository: https://alfresco.github.io/alfresco-helm-charts/ + version: 0.3.0 + - name: common + alias: alfresco-content-app + repository: https://activiti.github.io/activiti-cloud-helm-charts + version: 8.2.0 +icon: https://avatars0.githubusercontent.com/u/391127?s=200&v=4 diff --git a/helm/acs-sso-example/README.md b/helm/acs-sso-example/README.md new file mode 100644 index 000000000..0d4907590 --- /dev/null +++ b/helm/acs-sso-example/README.md @@ -0,0 +1,210 @@ +# acs-sso-example + +![Version: 0.1.0](https://img.shields.io/badge/Version-0.1.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 23.2.0-A12](https://img.shields.io/badge/AppVersion-23.2.0--A12-informational?style=flat-square) + +An example Chart to demonstrate how to compose your own Alfresco platform +with SSO on kubernetes using a nthrid party Keycloak. +if you're familiar with [Helm](ttps://helm.sh) & +[Kubernetes](https://kubernetes.io) taking a look at the `values.yaml` should +be enough but the principals are also documented in two differents steps: + +* Composing your ACS from individual component charts we provide. + Check the [step by step documentation](./docs/step-by-step-guide.md) +* SSO integration, to add keycloak and configure Alfresco applications + accordingly: [SSO guide](./docs/step-by-step-guide.md) + +> Note: this chart is just an example that can run on a localhost only. +> It ships ACS repo, the repository database, the message broker, the +> Keycloak IdP and front end applications (Share and Content app) & no other +> component. + +:warning: All components have persistence disabled so all data is lost after a +deployment is destroyed or rolled back! + +**Homepage:** + +## Source Code + +* + +## Requirements + +| Repository | Name | Version | +|------------|------|---------| +| https://activiti.github.io/activiti-cloud-helm-charts | alfresco-content-app(common) | 8.2.0 | +| https://alfresco.github.io/alfresco-helm-charts/ | activemq | 3.4.1 | +| https://alfresco.github.io/alfresco-helm-charts/ | alfresco-repository | 0.1.3 | +| https://alfresco.github.io/alfresco-helm-charts/ | alfresco-share | 0.3.0 | +| https://codecentric.github.io/helm-charts | keycloakx | 2.3.0 | +| oci://registry-1.docker.io/bitnamicharts | repository-database(postgresql) | 13.4.0 | + +## Values + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyTypeDefaultDescription
activemqobject
+check values.yaml
+
+
Configure the ACS ActiveMQ message broker as per https://github.com/Alfresco/alfresco-helm-charts/tree/activemq-3.4.1/charts/activemq
alfresco-content-appobject
+check values.yaml
+
+
Configure the Alfresco Conent-app as per https://github.com/Activiti/activiti-cloud-common-chart/tree/8.2.0/charts/common
alfresco-repositoryobject
+check values.yaml
+
+
Configure the ACS repository as per https://github.com/Alfresco/alfresco-helm-charts/tree/alfresco-repository-0.1.3/charts/alfresco-repository
alfresco-shareobject
+check values.yaml
+
+
Configure the Alfresco Share as per https://github.com/Alfresco/alfresco-helm-charts/tree/alfresco-share-0.3.0/charts/alfresco-share
global.known_urlslist
+[
+  "http://localhost"
+]
+
+
list of trusted URLs. URLs a re used to configure Cross-origin protections Also the first entry is considered the main hosting domain of the platform.
keycloakxobject
+check values.yaml
+
+
Configure the ACS Keycloak Identity provider as per https://github.com/codecentric/helm-charts/tree/keycloakx-2.3.0
keycloakx.admin.passwordstring
+random ascii string
+
+
Keycloak admin password. By default generated on first deployment, to get its value use:
kubectl get secrets keycloak -o jsonpath='{@.data.KEYCLOAK_ADMIN_PASSWORD}' | base64 -d
keycloakx.admin.realm[0]object
+{
+  "clients": [
+    {
+      "clientId": "alfresco",
+      "enabled": true,
+      "implicitFlowEnabled": true,
+      "publicClient": true,
+      "redirectUris": "{{- $redirectUris := list }} {{- range (index (include \"alfresco-common.known.urls\" $ | mustFromJson) \"known_urls\") }} {{- $redirectUris = append $redirectUris (printf \"%s/*\" .) }} {{- end }} {{- $redirectUris }}",
+      "standardFlowEnabled": true,
+      "webOrigins": "{{ index (include \"alfresco-common.known.urls\" $ | mustFromJson) \"known_urls\" }}"
+    }
+  ],
+  "defaultLocale": "en",
+  "enabled": true,
+  "id": "alfresco",
+  "internationalizationEnabled": true,
+  "loginTheme": "alfresco",
+  "realm": "alfresco",
+  "sslRequired": "none",
+  "supportedLocales": [
+    "ca",
+    "de",
+    "en",
+    "es",
+    "fr",
+    "it",
+    "ja",
+    "lt",
+    "nl",
+    "no",
+    "pt-BR",
+    "ru",
+    "sv",
+    "zh-CN"
+  ],
+  "users": [
+    {
+      "credentials": [
+        {
+          "type": "password",
+          "value": "secret"
+        }
+      ],
+      "enabled": true,
+      "username": "admin"
+    }
+  ]
+}
+
+
Alfresco Realm definition
keycloakx.admin.realm[0].users[0].credentials[0].valuestring
+"secret"
+
+
default Alfresco admin password
keycloakx.admin.realm[0].users[0].usernamestring
+"admin"
+
+
default Alfresco admin user
keycloakx.admin.usernamestring
+"admin"
+
+
Keycloak admin username
repository-databaseobject
+check values.yaml
+
+
Configure the ACS repository Postgres database as per https://github.com/bitnami/charts/tree/002c752f871c8fa068a770dc80fec4cf798798ab/bitnami/postgresql
+ diff --git a/helm/acs-sso-example/README.md.gotmpl b/helm/acs-sso-example/README.md.gotmpl new file mode 100644 index 000000000..4ce76be30 --- /dev/null +++ b/helm/acs-sso-example/README.md.gotmpl @@ -0,0 +1,16 @@ +{{ template "chart.header" . }} +{{ template "chart.deprecationWarning" . }} + +{{ template "chart.badgesSection" . }} + +{{ template "chart.description" . }} + +{{ template "chart.homepageLine" . }} + +{{ template "chart.maintainersSection" . }} + +{{ template "chart.sourcesSection" . }} + +{{ template "chart.requirementsSection" . }} + +{{ template "chart.valuesSectionHtml" . }} diff --git a/helm/acs-sso-example/docs/sso-guide.md b/helm/acs-sso-example/docs/sso-guide.md new file mode 100644 index 000000000..351f55b86 --- /dev/null +++ b/helm/acs-sso-example/docs/sso-guide.md @@ -0,0 +1,474 @@ +# SSO integration with Keycloak (vanilla) + +This is an extension of the base setup presented in the [step by step +guide](./step-by-step-guide.md). Make sure you have it running before reading +further (unless you just want to look at how to integrate Keycloak with ACS +component without trying it on your local machine). + +## Architecture of the deployment + +The following components are deployed by the example chart: + +```mermaid +flowchart TB +classDef alf fill:#0c0 +classDef thrdP fill:#ffa + +subgraph legend + t[3rd party component]:::thrdP + a[Alfresco component]:::alf +end + +repodb[(Repository\nDatabase)]:::thrdP +amq{{Message\nBroker}}:::thrdP +repo[Alfresco\nRepository]:::alf +keycloak[Identity\nProvider]:::thrdP +share(Alfreso\nShare UI):::alf +adf(Alfreso\nContent App):::alf + +repo ==> amq +repo ==> repodb +share --> repo +adf --> repo +repo --> keycloak +share --> keycloak +adf --> keycloak +``` + +## Keycloak + +As of Alfresco 23.1 Alfresco Identity Service is notrequired anymore. It is +possible to use a vanilla Keyloak distribution. In this document we will use +the [Codecentric Keyloak +chart](https://github.com/codecentric/helm-charts/tree/keycloakx-2.3.0/charts/keycloakx) +so we can reuse similar patterns of integration we've been using earlier. + +### Declaring the dependency + +Add elow lines in `Chart.yaml` + +```yaml +dependencies: + - name: keycloakx + repository: https://codecentric.github.io/helm-charts + version: 2.3.0 +``` + +### Configure Keycloak + +If you want to aply custom configuration as you build your own charts, refer to +the [Codecentric keycloak chart's +doc](https://github.com/codecentric/helm-charts/tree/keycloakx-2.3.0/charts/keycloakx). + +In this example we'll start by simply adding the basic configuration in the +`values.yaml` file: + +```yaml +keycloakx: + nameOverride: keycloak + command: + - /opt/keycloak/bin/kc.sh + - start + - --http-enabled=true + - --http-port=8080 + - --hostname-strict=false + - --hostname-strict-https=false + - --import-realm + http: + relativePath: /auth # keycloak http api will be available under this path + ingress: + enabled: true # enabled extrenal accesss the keycloak + tls: [] # disable https for this example + rules: + - host: >- + {{ template "alfresco-common.external.host" $ }} # external hostname + paths: + - path: "{{ .Values.http.relativePath }}" + pathType: Prefix + extraEnvFrom: | + - configMapRef: + name: keycloak + extraEnv: | + - name: JAVA_OPTS_APPEND + value: >- + -Djgroups.dns.query={{ include "keycloak.fullname" . }}-headless +``` + +And create a configmap for basic configuration: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: keycloak + labels: {{- include "acs-sso-example.labels" . | nindent 4 }} +data: + KC_HOSTNAME: {{ template "alfresco-common.external.host" . }} +``` + +> Again here some named templates provided in the alfresco-common chart might +> come handy to avoid duplicating values. + +This will start a keycloak instance with basic parameters and only a master +realm. To make it usable we need to give it an admin username & password and +also a realm Alfresco applications will be configured in as client(s). + +#### Keycloak admin + +As explained in the [Codecentric keycloak chart's +doc](https://github.com/codecentric/helm-charts/tree/keycloakx-2.3.0/charts/keycloakx) +admin creadentails can be passed as a kubernetes secret. Here we will create +this secret from the umbrella chart values which we'll add as shown below in +the same `values.yaml` file: + +```yaml +keycloakx: + nameOverride: keycloak + admin: + # -- Keycloak admin username + username: admin + # -- Keycloak admin password. + password: null # autogenerate +``` + +Now, let's create the secret we'll use to pass to the keycloakx chart in +`templates/secret-idp.yaml: + +```yaml +{{- if empty (lookup "v1" "Secret" $.Release.Namespace "keycloak") }} +apiVersion: v1 +kind: Secret +metadata: + name: keycloak + labels: {{- include "acs-sso-example.labels" . | nindent 4 }} + annotations: + "helm.sh/resource-policy": keep +data: + {{- with .Values.keycloakx }} + KEYCLOAK_ADMIN: {{ .admin.username | default "admin" | b64enc | quote }} + KEYCLOAK_ADMIN_PASSWORD: >- + {{ (.admin.password | default (randAscii 16)) | b64enc }} + {{- end }} +{{- end }} +``` + +#### Alfresco realm + +Still, relying on the [Codecentric keycloak chart's +doc](https://github.com/codecentric/helm-charts/tree/keycloakx-2.3.0/charts/keycloakx) +we can see that in order to create a realm we need to: + +- provide the json definition of the realm +- mount it in the `/opt/keycloak/data/import` folder in the pod +- ensure keycloak is started with the `--import` switch. + +Again, in order to provide the realm definition we'll use values in the +umbrealla chart `values.yaml`: + +```yaml +keycloakx: + extraEnvFrom: | + - secretRef: + name: keycloak + realm: + # -- Alfresco Realm definition + - id: alfresco + realm: alfresco + enabled: true + sslRequired: none + loginTheme: alfresco + clients: + - clientId: alfresco + enabled: true + standardFlowEnabled: true + implicitFlowEnabled: true + publicClient: true + redirectUris: >- + {{- $redirectUris := list }} + {{- range (index (include "alfresco-common.known.urls" $ | mustFromJson) "known_urls") }} + {{- $redirectUris = append $redirectUris (printf "%s/*" .) }} + {{- end }} + {{- $redirectUris }} + webOrigins: >- + {{ index (include "alfresco-common.known.urls" $ | mustFromJson) "known_urls" }} + users: + - # -- default Alfresco admin user + username: admin + enabled: true + credentials: + - type: password + # -- default Alfresco admin password + value: secret + internationalizationEnabled: true + defaultLocale: en + supportedLocales: + - "ca" + - "de" + - "en" + - "es" + - "fr" + - "it" + - "ja" + - "lt" + - "nl" + - "no" + - "pt-BR" + - "ru" + - "sv" + - "zh-CN" +``` + +And a new secret in `templates/secret-idp-realm.yaml`: + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: keycloak-realm + labels: {{- include "acs-sso-example.labels" . | nindent 4 }} +data: + {{- with .Values.keycloakx.admin.realm }} + {{- range . }} + {{- range .clients }} + {{- $_ := set . "redirectUris" (tpl .redirectUris $ | list) }} + {{- $_ := set . "webOrigins" (tpl .webOrigins $ | list) }} + {{- end }} + {{- printf "%s.json" .id | nindent 2 }}: {{ mustToJson . | b64enc | quote }} + {{- end }} + {{- end }} +``` + +#### Alfresco theme + +According to the [Codecentric keycloak chart's + doc](https://github.com/codecentric/helm-charts/tree/keycloakx-2.3.0/charts/keycloakx) +importing a theme requires adding the theme's code to the `/opt/keycloak/themes` +directory. configmap or secrets are not well suited for that as this is a whole +directory structure we need to mount and also because such resources are also +limited in size. A good alternative is to create an [ephemeral +volume](https://kubernetes.io/docs/concepts/storage/ephemeral-volumes/) and +use an [init +container](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/) +and use it to populate the ephemral volume the main container of the keycloak will use later on in the pod's lifecycle. +All of this is done using values in the `values.yaml` file as shown below: + +```yaml +# Ephemeral volume +extraVolumes: | + - name: theme + emptyDir: {} +# volume mount for the main container +extraVolumeMounts: | + - name: theme + mountPath: /opt/keycloak/themes +extraInitContainers: | + - image: busybox:1.36 + imagePullPolicy: IfNotPresent + name: theme-fetcher + command: [sh] + args: + - -c + - | + wget https://github.com/Alfresco/alfresco-keycloak-theme/releases/download/0.3.5/alfresco-keycloak-theme-0.3.5.zip -O alfresco.zip + unzip -d /themes alfresco.zip + volumeMounts: + - name: theme + mountPath: /themes +``` + +## Alfresco repository SSO configuration + +Now let's amend the ACS config to enable SSO. Well do it using a feature of th +[alfresco-repository](ihttps://github.com/Alfresco/alfresco-helm-charts/tree/alfresco-repository-0.1.3/charts/alfresco-repository) +chart which allow us use a configmap as the `alfresco-global.properties` file. + +The configmap needs to contains what you you put in the `alfresco-global.properties` file and you can use templating to populate it. +E.g. in `templates/configmap-repo.yaml` + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: repository-properties + labels: {{- include "acs-sso-example.labels" . | nindent 4 }} +data: + alfresco-global.properties: | + authentication.chain = identity-service1:identity-service,alfrescoNtlm1:alfrescoNtlm + identity-service.authentication.enabled = true + identity-service.realm = alfresco + {{- $kCtx := dict "Values" .Values.keycloakx "Chart" .Chart "Release" .Release }} + identity-service.auth-server-url = http://{{ include "keycloak.fullname" $kCtx }}-http{{ .Values.keycloakx.http.relativePath }} + identity-service.enable-basic-auth = true +``` + +`identity-service.realm` needs to match the name of the realm defined earlier. +To get the right `identity-service.auth-server-url` we are computing the ontext +of the keycloakx subcharts in `$kCtx` (using `nameOverride`) and pass that +ontext to the same templating code used in the subchart to give the service a +name. This is because here you here we're using localhost as a domain, but if +you use a true DNS domain the repo ccould point tpo this instead (which you can +set in `known_urls` and use `alfresco-common.externak.url`). + +Then in the `values.yaml` file add below configuration to `alfresco-repository`: + +```yaml +alfresco-repository: + configuration: + repository: + existingConfigMap: repository-properties +``` + +## Alfresco Share + +For Share the approach is very similar. + +### Declaring Share dependency + +In `Chart.yaml` + +```yaml + - name: alfresco-share + repository: https://alfresco.github.io/alfresco-helm-charts/ + version: 0.3.0 +``` + +### Configuring Alfresco Share + +In `values .yaml` we add the required config as per the [chart's +doc](https://github.com/Alfresco/alfresco-helm-charts/tree/alfresco-repository-0.1.3/charts/alfresco-share): + +```yaml +alfresco-share + nameOverride: alfresco-share + image: + repository: alfresco/alfresco-share + tag: 23.2.0-A13 + repository: + existingConfigMap: + name: share-repository + extraVolumes: + - name: share-properties + configMap: + name: share-properties + extraVolumeMounts: + - name: share-properties + mountPath: >- + /usr/local/tomcat/webapps/share/WEB-INF/classes/share-config.properties + subPath: share.properties + ingress: + hosts: + - host: localhost + paths: + - path: /share + pathType: Prefix +``` + +And create the configmap we need. + +The first one to tell Share where the repo is in `templates/configmap-share.yaml`: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: share-repository + labels: {{- include "acs-sso-example.labels" . | nindent 4 }} +data: + {{- with (index .Values "alfresco-repository") }} + {{- $repoCtx := dict "Values" . "Chart" $.Chart "Release" $.Release }} + {{- $reposvc := .service | default dict }} + REPO_HOST: {{ template "alfresco-repository.fullname" $repoCtx }} + REPO_PORT: {{ $reposvc.port | default 80 | quote }} + {{- end }} +``` + +And the second one to hold the SSO config in `templates/configmap-share-properties.yaml`: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: share-properties + labels: {{- include "acs-sso-example.labels" . | nindent 4 }} +data: + share.properties: | + aims.enabled = true + {{- with .Values.keycloakx }} + {{- $kCtx := dict "Values" . "Chart" $.Chart "Release" $.Release }} + aims.realm = {{ index .admin.realm 0 "realm" }} + aims.resource = {{ index .admin.realm 0 "clients" 0 "clientId" }} + aims.publicClient=true + aims.principalAttribute=sub + aims.publicClient=true + aims.authServerUrl = {{ printf "http://%s-http%s" (include "keycloak.fullname" $kCtx) .http.relativePath }} + {{- end }} +``` + +## Alfresco Content App + +### Declaring Content dependency + +In `Chart.yaml: + +```yaml + - name: common + alias: alfresco-content-app + repository: https://activiti.github.io/activiti-cloud-helm-charts + version: 8.2.0 +``` + +### Configurinf Alfresco Content App + +The content-app basic and SSO configuration sits only in the `values.yaml` file. +Pay special attention to providing OAUTH2 urls that match your realm +configuration (realm name & client id). + +```yaml +alfresco-content-app: + nameOverride: alfresco-content-app + enabled: true + service: + envType: frontend + ingress: + ingressClassName: nginx + hostName: localhost + path: /workspace + annotations: + nginx.ingress.kubernetes.io/proxy-body-size: 5g + nginx.ingress.kubernetes.io/proxy-buffer-size: 8k + tls: [] + image: + repository: alfresco/alfresco-content-app + tag: 4.3.0 + pullPolicy: IfNotPresent + env: + APP_CONFIG_PROVIDER: ECM + APP_CONFIG_AUTH_TYPE: OAUTH + API_URL: "{protocol}//{hostname}{:port}" + APP_CONFIG_OAUTH2_HOST: "{protocol}//{hostname}{:port}/auth/realms/alfresco" + APP_CONFIG_OAUTH2_CLIENTID: alfresco + APP_CONFIG_OAUTH2_REDIRECT_SILENT_IFRAME_URI: "{protocol}//{hostname}{:port}/assets/silent-refresh.html" + securityContext: + runAsNonRoot: true + runAsUser: 101 + capabilities: + drop: + - NET_RAW + - ALL + resources: + requests: + cpu: "0.25" + memory: "256Mi" + limits: + cpu: "1" + memory: "1024Mi" +``` + +## Deployment + +We can now build and deploy the chart: + +```bash +helm dep up # pull dependencies +helm install --generate-name --atomic . +``` diff --git a/helm/acs-sso-example/docs/step-by-step-guide.md b/helm/acs-sso-example/docs/step-by-step-guide.md new file mode 100644 index 000000000..ff30a87cd --- /dev/null +++ b/helm/acs-sso-example/docs/step-by-step-guide.md @@ -0,0 +1,465 @@ +# Anatomy of the example chart (and how you can build your own) + +This document explains the mechanisms used in this chart to build a Alfresco +platform to deploy on [Kubernetes](https://kubernetes.io/). + +## Why an example charts when there is already the alfresco-content-services? + +With [alfresco-content-services chart](../../alfrescocontent-services/) we +tried to provide something that can deploy most of our software components - +still not all of them are included - but also serves as a basis for +customization for real world scenarios. These two paradigms have actually +proven to fight one another and we think this chart is doing way too much +things to really be both understandable - and serve the example purpose and to +build upon - and to also offer an holistic and straight forward deployment +mean: There's no one size fit all configuration and when it comes to deployment +and configuration of a platform which involves so many different components, +including third party ones (database, message broker, Identity provider, ...). + +For that reason we have started creating individual charts for Alfresco +components in the [alfresco-helm-charts +repository](https://github.com/Alfresco/alfreso-helm-charts/charts/) (more to +come and PR are welcome). + +## High overview of the example chart + +This example chart extensively leverages the concept of [chart +dependencies](https://helm.sh/docs/topics/charts/#chart-dependencies) in Helm. + +One of the goal is to make this chart as simple as possible while still +providing way to deploy exactly the platform you. So most of the kubernetes +resources are actually provided in the individual component charts we declare +as dependencies and this chart is mostly creating the plumbing between each +components we want to use. This type of Helm chart is often referred to as an +*umbrella* chart. + +Here we will see how to declare dependencies an configure them properly so they +work together. + +### Architecture of the deployment + +In the document bellow we discuss an initial basic setup as shown below: + +```mermaid +flowchart TB +classDef alf fill:#0c0 +classDef thrdP fill:#ffa + +subgraph legend + t[3rd party component]:::thrdP + a[Alfresco component]:::alf +end + +repodb[(Repository\nDatabase)]:::thrdP +amq{{Message\nBroker}}:::thrdP +repo[Alfresco\nRepository]:::alf + +repo ==> amq +repo ==> repodb +``` + +> Note: there is no search component neither is there a transformation service. + +This set up will be enriched with more components configured for SSO using +vanilla keycloak [here](./sso-guide.md) + +## Pre-requisites + +### Kubernetes + +As this chart is meant to deploy on localhost if you want to use it you'll +need a kubernetes distribution setup on your local machine. + +> We usually use +> [KinD](https://kind.sigs.k8s.io/docs/user/quick-start/#installation) but +> Docker-desktop, Podman or miinkube should be OK to use if properly configured. +i +Give your kubernetes setup 8GB of RAM and a few CPUs. + +### Ingress + +You will also need to have the [nginx-ingress](https://docs.nginx.com/nginx-ingress-controller/) +installed and configured to handle local traffic on port 80. + +> :warning: If you use KinD, you need to install a patched version of the NGINX +> ingress as described +> [here](https://kind.sigs.k8s.io/docs/user/ingress/#ingress-nginx) +> If using another kubernetes distribution check it doesn't come with a default +> ingress controller different from NGINX and if so, disable it. Once done +> install the [NGINX ingress +> controller](https://docs.nginx.com/nginx-ingress-controller/installation/installing-nic/) + +Make sure the nginx ingress controller have the following settings enabled: + +- `allow-snippet-annotations` set to`true` +- `proxy-buffer-size` set to `12k` + +You can do that at installation time using [nginx-ingress +annotations](https://docs.nginx.com/nginx-ingress-controller/configuration/ingress-resources/advanced-configuration-with-annotations/) +or after the installation of the ingress, using the command below (e.g. for KinD): + +```bash +kubectl -n ingress-nginx patch cm ingress-nginx-controller -p \ + '{"data": {"allow-snippet-annotations":"true","proxy-buffer-size":"12k"}}' +``` + +### Helm + +Make sure you have [Helm](https://helm.sh) installed on your machine. It is +often provided has part of the kubernetes desktop distributions but if you +don't have [install it](https://helm.sh/docs/intro/install/). + +## Starting building the example (your) chart + +### Base skeleton + +Before we start referencing components' charts we need to create a [chart +structure](https://helm.sh/docs/topics/charts/#the-chart-file-structure). + +To do that, use the command below: + +```bash +helm create mychart && cd $_ +``` + +As the chart we want to create is simply an umbrella chart, there are actually +too much things this command scaffolds. We'll continue and cleanup what we +don't need. + +```bash +rm templates/*.yaml templates/NOTES.txt +``` + +Now we can give the chart some metadata, like a version, a description and so +on. Find more details in the [Helm doc](https://helm.sh/docs/topics/charts/#the-chartyaml-file). + +### Repository Database + +To start with, we need to give Alfresco a database. Here we will use the +[PostgreSQL Bitnami chart](https://github.com/bitnami/charts/tree/main/bitnami/postgresql). +It is simple and lightweight enough for the purpose of this example. + +#### Declaring the dependency + +Dependencies are declared in the `Chart.yaml` file adding the section below: + +```yaml +dependencies: + - name: postgresql + repository: oci://registry-1.docker.io/bitnamicharts + version: 13.4.0 + alias: repository-database +``` + +The charts declared as dependencies are also called "subcharts". + +> If you're building your own chart to deploy on a production environment, you +> may want to use a database service that either lives outside of the kubernetes +> cluster (e.g. RDS) or use a more "production ready" deployment for Kubernetes +> (There are some very good PostgreSQL Kubernetes operators such as +> [CrunchyData](https://github.com/CrunchyData/postgres-operator)). + +#### Configuring the database subchart + +Now that the dependency is declared we can configure the subchart to match our +needs. Each chart should provide its own set of values, which are usually +documented in the main `README.md` file of the source repository. In our case +the documentation useful to us is +[here](https://github.com/bitnami/charts/tree/main/bitnami/postgresql). + +For example we want to: + +- Set the database name +- Set the database username +- Set the database password +- Disable persistence + +As per the documentation mentioned above, this translates to the yaml +configuration below in the values.yaml file of the umbrella chart: + +```yaml +repository-database: + nameOverride: repository-database + auth: + database: alfresco + username: alfresco + password: alfresco + primary: + persistence: + enabled: false +``` + +The values documented for the chart we depend on are placed under a YAML key +named after the chart name or its declared alias (here `repository-database`). + +Also note we set a `nameOverride` value. This ensures consistent resource naming +when the Helm template is rendered, and in particular when giving the service a +name (as this name is needed to tell other components how to connect to the +database). + +### Message Broker + +#### Declaring the broker dependency + +For the message broker we will use an Alfresco provided chart. This is because +there no official or well maintained chart one can rely on. In a real world +scenario the best options remains to use a managed ActiveMQ instance outside of +the kubernetes cluster. + +Just as for the database chart we declare the activemq chart as a dependency of +our umbrella chart. + +```yaml + - name: activemq + repository: https://alfresco.github.io/alfresco-helm-charts/ + version: 3.4.1 +``` + +#### Configuring the message broker subchart + +Again, we start by taking a look at the [documented +values](https://github.com/Alfresco/alfresco-helm-charts/tree/main/charts/activemq) +for the chart we want to use. + +For our example purpose we'll configure the message broker with: + +- a defined username and password +- persistence disabled + +So we're adding the values below in the `values.yaml`file of the umbrella chart: + +```yaml +activemq: + nameOverride: activemq + persistence: + enabled: false + adminUser: + user: alfresco + password: alfresco +``` + +### Now step back and think + +So far w have just setup 2 independent components. They don't interact together. +But at this point we need to wonder what are the key information generated by +this chart, that we'll need to configure other charts? + +That's basically the connection details: + +- database URL +- database username +- database password +- message broker URL +- message broker username +- message broker password + +The credentials are statically defined in the values file so that's easy. +The URLs on the other hand, are slightly more tricky as they are built +dynamically by the each subchart. + +All Alfresco components' charts support 2 ways to provide this type of configuration: + +- through the usual values +- through configmaps and secrets + +For example, if we want to tell the ACS repo where its database is located we +can use either of the following YAML data structure: + +```yaml +# value based configuration +... + database: + url: url://... + username: scott + password: tiger +``` + +```yaml +# resource based configuration +... + database: + existingConfigMap: + name: db-cm + keys: + url: DB_URL + existingSecret: + name: db-secret + keys: + username: DB_USER + password: DB_PASS +``` + +> Note: the path to the `database` key may vary from one Alfreso chart to +> another, check each chart README page. + +The key difference between values based config and resource based config is +that values can only take static strings, while resource can be pre-existing +configmaps or secrets, or can even be rendered from template in the main +umbrella chart, thus allowing for a bit of manipulation. The later is the +approach we prefer using to configure Alfresco component charts. + +### Alfresco Repository + +#### Declaring the repository dependency + +```yaml + - name: alfresco-repository + repository: https://alfresco.github.io/alfresco-helm-charts/ + version: 0.1.3 +``` + +#### Configuring the repository subchart + +The [Alfresco repository chart +documentation](ihttps://github.com/Alfresco/alfresco-helm-charts/tree/main/charts/alfresco-repository) +shows how to configure the repo db and message broker using configmaps and secrets: + +```yaml +alfresco-repository: + nameOverride: alfresco-repository + # Use Community + replicaCount: 1 + image: + repository: alfresco/alfresco-content-repository-community + # Ensure Alfresco is served on the localhost domain + ingress: + hosts: + - host: localhost + paths: + - path: / + pathType: Prefix + - path: /api-explorer + pathType: Prefix + # Actual component configuration + configuration: + db: + existingConfigMap: + name: repository-database + existingSecret: + name: repository-database + messageBroker: + existingConfigMap: + name: repository-message-broker + existingSecret: + name: repository-message-broker +``` + +Here we omit the `*.keys.*` values as we will create both the configmap and the +secret and we have the freedom to use the default keys keys as documented in +the subchart README. + +#### Creating the config resources + +Let's first create the secrets where we credentials will be available to +components which needs them. To avoid spreading credentials where not needed, +we'll have one for each service: + +- the database secret can be defined as follow in `templates/secret-db.yaml + + ```yaml + apiVersion: v1 + kind: Secret + metadata: + name: repository-database + labels: {{- include "acs-sso-example.labels" . | nindent 4 }} + data: + {{- with (index .Values "repository-database") }} + DATABASE_USERNAME: {{ .auth.username | b64enc | quote }} + DATABASE_PASSWORD: {{ .auth.password | b64enc | quote }} + {{- end }} + ``` + +- the message broker secret in `templates/secret-mq.yaml + + ```yaml + apiVersion: v1 + kind: Secret + metadata: + name: repository-message-broker + labels: {{- include "acs-sso-example.labels" . | nindent 4 }} + data: + {{- with .Values.activemq.adminUser }} + BROKER_USERNAME: {{ .user | b64enc | quote }} + BROKER_PASSWORD: {{ .password | b64enc | quote }} + {{- end }} + ``` + +Now we can create configmaps to compute the services URL: + +- the database configmap in `templates/confgimap-db.yaml` + + ```yaml + apiVersion: v1 + kind: ConfigMap + metadata: + name: repository-database + labels: {{- include "acs-sso-example.labels" . | nindent 4 }} + data: + DATABASE_DRIVER: org.postgres.Driver + {{- with (index .Values "repository-database") }} + {{- $dbCtx := dict "Values" . "Chart" $.Chart "Release" $.Release }} + {{- $dbHost := include "postgresql.v1.primary.fullname" $dbCtx }} + DATABASE_URL: >- + {{ printf "jdbc:postgresql://%s:5432/%s" $dbHost .auth.database }} + {{- end }} + ``` + +The URL is built dynamically using string concatenation and the very same [named +template](https://helm.sh/docs/chart_template_guide/named_templates/) that's +used in the postgresql subchart to define the postgresql service name: see the +[code](https://github.com/bitnami/charts/blob/fc36e80c9ae42fd6a423a567c7fa1f6dab44ffd3/bitnami/postgresql/templates/primary/svc.yaml#L9). + +> Note we are building a `$dbCtx` to mimic the context the subchart uses when +> evaluating `postgresql.v1.primary.fullname`. This is where it's important to +> have a `nameOverride`value defined for each subchart which provides a service +> that must be accessed by another subchart. + +- message broker configmap in `templates/configmap-mq.yaml` + + ```yaml + apiVersion: v1 + kind: ConfigMap + metadata: + name: repository-message-broker + labels: {{- include "acs-sso-example.labels" . | nindent 4 }} + data: + {{- with .Values.activemq }} + {{- $mqCtx := dict "Values" . "Chart" $.Chart "Release" $.Release }} + {{- $mqUrl := printf "nio://%s-broker" (include "activemq.fullname" $mqCtx) }} + BROKER_URL: >- + {{ include "alfresco-common.activemq.url.withFailover" $mqUrl }} + {{- end }} + ``` + +We also provide [named template](https://helm.sh/docs/chart_template_guide/named_templates/) +one can use to ease creating config resources. Here we're using +`alfresco-common.activemq.url.withFailover` - which returns a valid failover +activemq URL as expected by Alfresco components - but there are some others you +may find handy in the +[alfresco-common](https://github.com/Alfresco/alfresco-helm-charts/tree/main/charts/alfresco-common/templates) +chart. + +> The config resources presented here have been slightly simplified for the +> sake of readability, so for instance they do not support changing the default +> port in the postgresql or activemq chart but that doesn't change the higher +> level logic. + +## First deployment + +It is now time to test our deployment as we have a system that matches the +architecture we wanted and all the configured components should be configured +properly to work together. + +```bash +helm dep up # pull dependencies +helm install --generate-name --atomic . +``` + +You can now open your browser on [http://localhost/alfresco](http://localhost/alfresco) + +## Next steps + +To discover more ways to configure Alfresco components you can take a look at +the [SSO part](./sso-guide.md) of this chart. It explains how to use a vanilla +Keycloak chart with various Alfresco components, thus exposing other means to +tweak them for your needs. diff --git a/helm/acs-sso-example/templates/_helpers.tpl b/helm/acs-sso-example/templates/_helpers.tpl new file mode 100644 index 000000000..0aceaafb0 --- /dev/null +++ b/helm/acs-sso-example/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "acs-sso-example.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "acs-sso-example.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "acs-sso-example.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "acs-sso-example.labels" -}} +helm.sh/chart: {{ include "acs-sso-example.chart" . }} +{{ include "acs-sso-example.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "acs-sso-example.selectorLabels" -}} +app.kubernetes.io/name: {{ include "acs-sso-example.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "acs-sso-example.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "acs-sso-example.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/helm/acs-sso-example/templates/configmap-db.yaml b/helm/acs-sso-example/templates/configmap-db.yaml new file mode 100644 index 000000000..d5e4f6fbf --- /dev/null +++ b/helm/acs-sso-example/templates/configmap-db.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: repository-database + labels: {{- include "acs-sso-example.labels" . | nindent 4 }} +data: + DATABASE_DRIVER: org.postgresql.Driver + {{- with (index .Values "repository-database") }} + {{- $pgPort := $.Values.global | default dict }} + {{- $pgPort = $pgPort | default dict }} + {{- $pgPort = $pgPort.service | default dict }} + {{- $pgPort = $pgPort.ports | default dict }} + {{- $pgPort = coalesce $pgPort.postgresql .primary.service.ports.postgresql 5432 }} + {{- $dbCtx := dict "Values" . "Chart" $.Chart "Release" $.Release }} + DATABASE_URL: {{ printf "jdbc:postgresql://%s:%v/%s" (include "postgresql.v1.primary.fullname" $dbCtx) $pgPort .auth.database | quote }} + {{- end }} diff --git a/helm/acs-sso-example/templates/configmap-idp.yaml b/helm/acs-sso-example/templates/configmap-idp.yaml new file mode 100644 index 000000000..b413292fb --- /dev/null +++ b/helm/acs-sso-example/templates/configmap-idp.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: keycloak + labels: {{- include "acs-sso-example.labels" . | nindent 4 }} +data: + KC_HOSTNAME: {{ template "alfresco-common.external.host" . }} diff --git a/helm/acs-sso-example/templates/configmap-mq.yaml b/helm/acs-sso-example/templates/configmap-mq.yaml new file mode 100644 index 000000000..1fa676336 --- /dev/null +++ b/helm/acs-sso-example/templates/configmap-mq.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: repository-message-broker + labels: {{- include "acs-sso-example.labels" . | nindent 4 }} +data: + {{- with .Values.activemq }} + {{- $mqPort := .services | default dict }} + {{- $mqPort = $mqPort.broker | default dict }} + {{- $mqPort = $mqPort.ports| default dict }} + {{- $mqPort = $mqPort.external | default dict }} + {{- $mqPort = $mqPort.openwire | default 61616 }} + {{- $mqCtx := dict "Values" . "Chart" $.Chart "Release" $.Release }} + BROKER_URL: {{ include "alfresco-common.activemq.url.withFailover" (printf "nio://%s-broker:%v" (include "activemq.fullname" $mqCtx) $mqPort) | quote }} + {{- end }} diff --git a/helm/acs-sso-example/templates/configmap-repo.yaml b/helm/acs-sso-example/templates/configmap-repo.yaml new file mode 100644 index 000000000..2e616369c --- /dev/null +++ b/helm/acs-sso-example/templates/configmap-repo.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: repository-properties + labels: {{- include "acs-sso-example.labels" . | nindent 4 }} +data: + alfresco-global.properties: | + authentication.chain = identity-service1:identity-service,alfrescoNtlm1:alfrescoNtlm + identity-service.authentication.enabled = true + identity-service.realm = alfresco + {{- $kCtx := dict "Values" .Values.keycloakx "Chart" .Chart "Release" .Release }} + identity-service.auth-server-url = http://{{ include "keycloak.fullname" $kCtx }}-http{{ .Values.keycloakx.http.relativePath }} + identity-service.enable-basic-auth = true diff --git a/helm/acs-sso-example/templates/configmap-share-properties.yaml b/helm/acs-sso-example/templates/configmap-share-properties.yaml new file mode 100644 index 000000000..e8359546a --- /dev/null +++ b/helm/acs-sso-example/templates/configmap-share-properties.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: share-properties + labels: {{- include "acs-sso-example.labels" . | nindent 4 }} +data: + share.properties: | + aims.enabled = true + {{- with .Values.keycloakx }} + {{- $kCtx := dict "Values" . "Chart" $.Chart "Release" $.Release }} + aims.realm = {{ index .admin.realm 0 "realm" }} + aims.resource = {{ index .admin.realm 0 "clients" 0 "clientId" }} + aims.publicClient=true + aims.principalAttribute=sub + aims.publicClient=true + aims.authServerUrl = {{ printf "http://%s-http%s" (include "keycloak.fullname" $kCtx) .http.relativePath }} + {{- end }} diff --git a/helm/acs-sso-example/templates/configmap-share.yaml b/helm/acs-sso-example/templates/configmap-share.yaml new file mode 100644 index 000000000..cb3c65f42 --- /dev/null +++ b/helm/acs-sso-example/templates/configmap-share.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: share-repository + labels: {{- include "acs-sso-example.labels" . | nindent 4 }} +data: + {{- with (index .Values "alfresco-repository") }} + {{- $repoCtx := dict "Values" . "Chart" $.Chart "Release" $.Release }} + {{- $reposvc := .service | default dict }} + REPO_HOST: {{ template "alfresco-repository.fullname" $repoCtx }} + REPO_PORT: {{ $reposvc.port | default 80 | quote }} + {{- end }} diff --git a/helm/acs-sso-example/templates/secret-db.yaml b/helm/acs-sso-example/templates/secret-db.yaml new file mode 100644 index 000000000..aaf01fd91 --- /dev/null +++ b/helm/acs-sso-example/templates/secret-db.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Secret +metadata: + name: repository-database + labels: {{- include "acs-sso-example.labels" . | nindent 4 }} +data: +{{- with (index .Values "repository-database") }} + {{- $pgPort := $.Values.global | default dict }} + {{- $pgPort = $pgPort.postgresql | default dict }} + {{- $pgPort = $pgPort.auth | default dict }} + DATABASE_USERNAME: {{ coalesce $pgPort.username .auth.username | b64enc | quote }} + DATABASE_PASSWORD: {{ coalesce $pgPort.password .auth.password | b64enc | quote }} +{{- end }} diff --git a/helm/acs-sso-example/templates/secret-idp-realm.yaml b/helm/acs-sso-example/templates/secret-idp-realm.yaml new file mode 100644 index 000000000..2e6217fc5 --- /dev/null +++ b/helm/acs-sso-example/templates/secret-idp-realm.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Secret +metadata: + name: keycloak-realm + labels: {{- include "acs-sso-example.labels" . | nindent 4 }} +data: + {{- with .Values.keycloakx.admin.realm }} + {{- range . }} + {{- range .clients }} + {{- $_ := set . "redirectUris" (tpl .redirectUris $ | fromYamlArray) }} + {{- $_ := set . "webOrigins" (tpl .webOrigins $ | fromYamlArray) }} + {{- end }} + {{- printf "%s.json" .id | nindent 2 }}: {{ mustToJson . | b64enc | quote }} + {{- end }} + {{- end }} diff --git a/helm/acs-sso-example/templates/secret-idp.yaml b/helm/acs-sso-example/templates/secret-idp.yaml new file mode 100644 index 000000000..ba71ea82f --- /dev/null +++ b/helm/acs-sso-example/templates/secret-idp.yaml @@ -0,0 +1,14 @@ +{{- if empty (lookup "v1" "Secret" $.Release.Namespace "keycloak") }} +apiVersion: v1 +kind: Secret +metadata: + name: keycloak + labels: {{- include "acs-sso-example.labels" . | nindent 4 }} + annotations: + "helm.sh/resource-policy": keep +data: + {{- with .Values.keycloakx }} + KEYCLOAK_ADMIN: {{ .admin.username | default "admin" | b64enc | quote }} + KEYCLOAK_ADMIN_PASSWORD: {{ (.admin.password | default (randAscii 16)) | b64enc | quote }} + {{- end }} +{{- end }} diff --git a/helm/acs-sso-example/templates/secret-mq.yaml b/helm/acs-sso-example/templates/secret-mq.yaml new file mode 100644 index 000000000..40cf6a54b --- /dev/null +++ b/helm/acs-sso-example/templates/secret-mq.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Secret +metadata: + name: repository-message-broker + labels: {{- include "acs-sso-example.labels" . | nindent 4 }} +data: +{{- with .Values.activemq.adminUser }} + BROKER_USERNAME: {{ .user | b64enc | quote }} + BROKER_PASSWORD: {{ .password | b64enc | quote }} +{{- end }} diff --git a/helm/acs-sso-example/values.yaml b/helm/acs-sso-example/values.yaml new file mode 100644 index 000000000..6348222ae --- /dev/null +++ b/helm/acs-sso-example/values.yaml @@ -0,0 +1,260 @@ +# Default values for acs-sso-example. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +global: + # -- list of trusted URLs. + # URLs a re used to configure Cross-origin protections + # Also the first entry is considered the main hosting domain of the platform. + known_urls: + - http://localhost +# -- Configure the ACS repository Postgres database as per +# https://github.com/bitnami/charts/tree/002c752f871c8fa068a770dc80fec4cf798798ab/bitnami/postgresql +# @default -- check values.yaml +repository-database: + nameOverride: repository-database + auth: + database: alfresco + username: alfresco + password: alfresco + primary: + persistence: + enabled: false + extendedConfiguration: | + max_connections = 150 + shared_buffers = 512MB + effective_cache_size = 2GB + wal_level = minimal + max_wal_senders = 0 + max_replication_slots = 0 + log_min_messages = LOG + resources: + requests: + cpu: 250m + memory: 1Gi + limits: + cpu: "4" + memory: 4Gi + +# -- Configure the ACS Keycloak Identity provider as per +# https://github.com/codecentric/helm-charts/tree/keycloakx-2.3.0 +# @default -- check values.yaml +keycloakx: + nameOverride: keycloak + admin: + # -- Keycloak admin username + username: admin + # -- Keycloak admin password. + # By default generated on first deployment, to get its value use:
+ # kubectl get secrets keycloak -o jsonpath='{@.data.KEYCLOAK_ADMIN_PASSWORD}' | base64 -d + # @default -- random ascii string + password: null + realm: + # -- Alfresco Realm definition + - id: alfresco + realm: alfresco + enabled: true + sslRequired: none + loginTheme: alfresco + clients: + - clientId: alfresco + enabled: true + standardFlowEnabled: true + implicitFlowEnabled: true + publicClient: true + redirectUris: >- + {{- $redirectUris := list }} + {{- range (index (include "alfresco-common.known.urls" $ | mustFromJson) "known_urls") }} + {{- $redirectUris = append $redirectUris (printf "%s/*" .) }} + {{- end }} + {{- $redirectUris }} + webOrigins: >- + {{ index (include "alfresco-common.known.urls" $ | mustFromJson) "known_urls" }} + users: + - # -- default Alfresco admin user + username: admin + enabled: true + credentials: + - type: password + # -- default Alfresco admin password + value: secret + internationalizationEnabled: true + defaultLocale: en + supportedLocales: + - "ca" + - "de" + - "en" + - "es" + - "fr" + - "it" + - "ja" + - "lt" + - "nl" + - "no" + - "pt-BR" + - "ru" + - "sv" + - "zh-CN" + command: + - /opt/keycloak/bin/kc.sh + - start + - --http-enabled=true + - --http-port=8080 + - --hostname-strict=false + - --hostname-strict-https=false + - --import-realm + http: + relativePath: /auth + ingress: + enabled: true + tls: [] + rules: + - host: >- + {{ template "alfresco-common.external.host" $ }} + paths: + - path: "{{ .Values.http.relativePath }}" + pathType: Prefix + extraEnvFrom: | + - configMapRef: + name: keycloak + - secretRef: + name: keycloak + extraEnv: | + - name: JAVA_OPTS_APPEND + value: >- + -Djgroups.dns.query={{ include "keycloak.fullname" . }}-headless + extraVolumeMounts: | + - name: theme + mountPath: /opt/keycloak/themes + - name: realm + mountPath: /opt/keycloak/data/import + extraVolumes: | + - name: theme + emptyDir: {} + - name: realm + secret: + secretName: keycloak-realm + extraInitContainers: | + - image: busybox:1.36 + imagePullPolicy: IfNotPresent + name: theme-fetcher + command: [sh] + args: + - -c + - | + wget https://github.com/Alfresco/alfresco-keycloak-theme/releases/download/0.3.5/alfresco-keycloak-theme-0.3.5.zip -O alfresco.zip + unzip -d /themes alfresco.zip + volumeMounts: + - name: theme + mountPath: /themes + +# -- Configure the ACS ActiveMQ message broker as per +# https://github.com/Alfresco/alfresco-helm-charts/tree/activemq-3.4.1/charts/activemq +# @default -- check values.yaml +activemq: + nameOverride: activemq + persistence: + enabled: false + adminUser: + user: alfresco + password: alfresco + +# -- Configure the ACS repository as per +# https://github.com/Alfresco/alfresco-helm-charts/tree/alfresco-repository-0.1.3/charts/alfresco-repository +# @default -- check values.yaml +alfresco-repository: + nameOverride: alfresco-repository + replicaCount: 1 + image: + repository: alfresco/alfresco-content-repository-community + tag: 23.2.0-A12 + configuration: + repository: + existingConfigMap: repository-properties + db: + existingConfigMap: + name: repository-database + existingSecret: + name: repository-database + messageBroker: + existingConfigMap: + name: repository-message-broker + existingSecret: + name: repository-message-broker + ingress: + hosts: + - host: localhost + paths: + - path: / + pathType: Prefix + - path: /api-explorer + pathType: Prefix + +# -- Configure the Alfresco Share as per +# https://github.com/Alfresco/alfresco-helm-charts/tree/alfresco-share-0.3.0/charts/alfresco-share +# @default -- check values.yaml +alfresco-share: + nameOverride: alfresco-share + image: + repository: alfresco/alfresco-share + tag: 23.2.0-A13 + repository: + existingConfigMap: + name: share-repository + extraVolumes: + - name: share-properties + configMap: + name: share-properties + extraVolumeMounts: + - name: share-properties + mountPath: >- + /usr/local/tomcat/webapps/share/WEB-INF/classes/share-config.properties + subPath: share.properties + ingress: + hosts: + - host: localhost + paths: + - path: /share + pathType: Prefix + +# -- Configure the Alfresco Conent-app as per +# https://github.com/Activiti/activiti-cloud-common-chart/tree/8.2.0/charts/common +# @default -- check values.yaml +alfresco-content-app: + nameOverride: alfresco-content-app + enabled: true + service: + envType: frontend + ingress: + ingressClassName: nginx + hostName: localhost + path: /workspace + annotations: + nginx.ingress.kubernetes.io/proxy-body-size: 5g + nginx.ingress.kubernetes.io/proxy-buffer-size: 8k + tls: [] + image: + repository: alfresco/alfresco-content-app + tag: 4.3.0 + pullPolicy: IfNotPresent + env: + APP_CONFIG_PROVIDER: ECM + APP_CONFIG_AUTH_TYPE: OAUTH + API_URL: "{protocol}//{hostname}{:port}" + APP_CONFIG_OAUTH2_HOST: "{protocol}//{hostname}{:port}/auth/realms/alfresco" + APP_CONFIG_OAUTH2_CLIENTID: alfresco + APP_CONFIG_OAUTH2_REDIRECT_SILENT_IFRAME_URI: "{protocol}//{hostname}{:port}/assets/silent-refresh.html" + securityContext: + runAsNonRoot: true + runAsUser: 101 + capabilities: + drop: + - NET_RAW + - ALL + resources: + requests: + cpu: "0.25" + memory: "256Mi" + limits: + cpu: "1" + memory: "1024Mi"