From 8649b5f5c398a484dd2139511da20f5a9f65ab95 Mon Sep 17 00:00:00 2001 From: pat-s Date: Fri, 19 Jul 2024 14:37:28 +0200 Subject: [PATCH 1/7] allow setting launcherPem via secret --- charts/rstudio-workbench/templates/NOTES.txt | 4 ++-- charts/rstudio-workbench/templates/_helpers.tpl | 4 ++-- .../rstudio-workbench/templates/configmap-secret.yaml | 10 ++++++++++ charts/rstudio-workbench/values.yaml | 4 +++- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/charts/rstudio-workbench/templates/NOTES.txt b/charts/rstudio-workbench/templates/NOTES.txt index 0cf600e8..30bd3cf6 100644 --- a/charts/rstudio-workbench/templates/NOTES.txt +++ b/charts/rstudio-workbench/templates/NOTES.txt @@ -1,10 +1,10 @@ {{ include "rstudio-workbench.fullname" . }} successfully deployed to namespace {{ $.Release.Namespace }} -{{- if eq .Values.launcherPem "" }} +{{- if eq .Values.launcherPem.value "" }} NOTE: Using auto-generated value for "launcher.pem" - - We recommend making this value persistent by setting `.Values.launcherPem` + - We recommend making this value persistent by setting `.Values.launcherPem.value` or `.Values.launcherPem.existingSecret` - If the value changes, sessions started before the change will not be accessible - You can get the current value with: ``` diff --git a/charts/rstudio-workbench/templates/_helpers.tpl b/charts/rstudio-workbench/templates/_helpers.tpl index 29f9ffdd..1b70eec6 100644 --- a/charts/rstudio-workbench/templates/_helpers.tpl +++ b/charts/rstudio-workbench/templates/_helpers.tpl @@ -440,8 +440,8 @@ app.kubernetes.io/instance: {{ .Release.Name }} - if it is, we warn and leave it alone */}} {{- define "rstudio-workbench.launcherPem" -}} -{{- $pemVar := $.Values.launcherPem -}} -{{- if eq ($.Values.launcherPem) ("") -}} +{{- $pemVar := $.Values.launcherPem.value -}} +{{- if and (eq $.Values.launcherPem.value "") (eq $.Values.launcherPem.existingSecret "") -}} {{- $secretName := print (include "rstudio-workbench.fullname" .) "-secret" }} {{- $currentSecret := lookup "v1" "Secret" $.Release.Namespace $secretName }} {{- if and $currentSecret (not .Values.dangerRegenerateAutomatedValues) }} diff --git a/charts/rstudio-workbench/templates/configmap-secret.yaml b/charts/rstudio-workbench/templates/configmap-secret.yaml index b15919a1..f821694a 100644 --- a/charts/rstudio-workbench/templates/configmap-secret.yaml +++ b/charts/rstudio-workbench/templates/configmap-secret.yaml @@ -11,8 +11,18 @@ spec: encryptedData: {{- include "rstudio-library.config.ini" .Values.config.secret | nindent 4 }} {{- /* do not auto-generate value as the secret will not be encrypted */}} + {{- if .Values.launcherPem.existingSecret }} + launcher.pem: | + {{- $launcherPemSecret := (lookup "v1" "Secret" $.Release.Namespace .Values.launcherPem.existingSecret) }} + {{- if $launcherPemSecret }} + {{- $launcherPem := index $launcherPemSecret.data "private_key" | b64dec }} + {{- $launcherPem | nindent 6 }} + {{- end }} + {{- end }} + {{- if .Values.launcherPem.value }} launcher.pem: | {{- .Values.launcherPem | nindent 6 }} + {{- end }} {{- /* do not auto-generate value as the secret will not be encrypted */}} secure-cookie-key: | {{- default .Values.secureCookieKey .Values.global.secureCookieKey | nindent 6 }} diff --git a/charts/rstudio-workbench/values.yaml b/charts/rstudio-workbench/values.yaml index 5c098577..daf34069 100644 --- a/charts/rstudio-workbench/values.yaml +++ b/charts/rstudio-workbench/values.yaml @@ -376,7 +376,9 @@ extraObjects: [] jobJsonOverridesFiles: {} # -- An inline launcher.pem key. If not provided, one will be auto-generated. See README for more details. -launcherPem: "" +launcherPem: + value: "" + existingSecret: "" # -- An inline launcher.pub key to pair with launcher.pem. If `false` (the default), we will try to generate a `launcher.pub` from the provided `launcher.pem` launcherPub: false From 805edcbb536d5c33a618eeaa1a4727248efb799b Mon Sep 17 00:00:00 2001 From: pat-s Date: Fri, 19 Jul 2024 16:27:25 +0200 Subject: [PATCH 2/7] use individual secrets for sensitive vars --- charts/rstudio-workbench/templates/NOTES.txt | 4 +- .../rstudio-workbench/templates/_helpers.tpl | 39 ++++++++++++++++++- .../templates/configmap-secret.yaml | 2 +- charts/rstudio-workbench/values.yaml | 13 ++++++- 4 files changed, 52 insertions(+), 6 deletions(-) diff --git a/charts/rstudio-workbench/templates/NOTES.txt b/charts/rstudio-workbench/templates/NOTES.txt index 30bd3cf6..204db5fe 100644 --- a/charts/rstudio-workbench/templates/NOTES.txt +++ b/charts/rstudio-workbench/templates/NOTES.txt @@ -11,10 +11,10 @@ NOTE: Using auto-generated value for "launcher.pem" kubectl -n {{ $.Release.Namespace }} get secret {{ include "rstudio-workbench.fullname" . }}-secret --template='{{print "{{" }}index .data "launcher.pem" | base64decode {{print "}}" }}' ``` {{- end }} -{{- if eq (default .Values.secureCookieKey .Values.global.secureCookieKey) "" }} +{{- if eq (default .Values.secureCookieKey.value .Values.global.secureCookieKey.value) "" }} NOTE: Using an auto-generated value for "secure-cookie-key" - - We recommend making this value persistent by setting `.Values.global.secureCookieKey` + - We recommend making this value persistent by setting `.Values.global.secureCookieKey.value` - If the value changes, authenticated sessions will be invalidated (all users will be logged out) and some old sessions will not be accessible - You can get the current value with: ``` diff --git a/charts/rstudio-workbench/templates/_helpers.tpl b/charts/rstudio-workbench/templates/_helpers.tpl index 1b70eec6..808871a5 100644 --- a/charts/rstudio-workbench/templates/_helpers.tpl +++ b/charts/rstudio-workbench/templates/_helpers.tpl @@ -122,8 +122,25 @@ containers: - name: rstudio-session-secret mountPath: {{ .Values.session.defaultSecretMountPath }} {{- end }} + {{- if or (not .Values.launcherPem.existingSecret) (not .Values.secureCookieKey.existingSecret) }} - name: rstudio-secret mountPath: "/mnt/secret-configmap/rstudio/" + {{- end }} + {{- if .Values.launcherPem.existingSecret }} + - name: launcher-pem-secret + mountPath: "/mnt/secret-configmap/rstudio/launcher.pem" + subPath: "launcher.pem" + {{- end }} + {{- if .Values.secureCookieKey.existingSecret }} + - name: secure-cookie-key-secret + mountPath: "/mnt/secret-configmap/rstudio/secure-cookie-key" + subPath: "secure-cookie-key" + {{- end }} + {{- if .Values.config.database.conf.existingSecret }} + - name: database-conf-secret + mountPath: "/mnt/secret-configmap/rstudio/database.conf" + subPath: "database.conf" + {{- end }} {{- if .Values.config.userProvisioning }} - name: rstudio-user mountPath: "/etc/sssd/conf.d/" @@ -303,10 +320,30 @@ volumes: name: {{ include "rstudio-workbench.fullname" . }}-pam defaultMode: {{ .Values.config.defaultMode.pam }} {{- end }} +{{- if or (not .Values.launcherPem.existingSecret) (not .Values.secureCookieKey.existingSecret) (not .Values.config.database.conf.existingSecret) }} - name: rstudio-secret secret: secretName: {{ include "rstudio-workbench.fullname" . }}-secret defaultMode: {{ .Values.config.defaultMode.secret }} +{{- end }} +{{- if .Values.launcherPem.existingSecret }} +- name: launcher-pem-secret + secret: + secretName: {{ .Values.launcherPem.existingSecret }} + defaultMode: {{ .Values.config.defaultMode.secret }} +{{- end }} +{{- if .Values.secureCookieKey.existingSecret }} +- name: secure-cookie-key-secret + secret: + secretName: {{ .Values.secureCookieKey.existingSecret }} + defaultMode: {{ .Values.config.defaultMode.secret }} +{{- end }} +{{- if .Values.config.database.conf.existingSecret }} +- name: database-conf-secret + secret: + secretName: {{ .Values.config.database.conf.existingSecret }} + defaultMode: {{ .Values.config.defaultMode.secret }} +{{- end }} {{- if .Values.config.userProvisioning }} - name: rstudio-user secret: @@ -462,7 +499,7 @@ app.kubernetes.io/instance: {{ .Release.Name }} - if it is, we warn and leave it alone */}} {{- define "rstudio-workbench.secureCookieKey" -}} -{{- $cookieVar := default .Values.secureCookieKey .Values.global.secureCookieKey -}} +{{- $cookieVar := default .Values.secureCookieKey.value .Values.global.secureCookieKey.value -}} {{- if eq ($cookieVar) ("") -}} {{- $secretName := print (include "rstudio-workbench.fullname" .) "-secret" }} {{- $currentSecret := lookup "v1" "Secret" $.Release.Namespace $secretName }} diff --git a/charts/rstudio-workbench/templates/configmap-secret.yaml b/charts/rstudio-workbench/templates/configmap-secret.yaml index f821694a..2a907ebe 100644 --- a/charts/rstudio-workbench/templates/configmap-secret.yaml +++ b/charts/rstudio-workbench/templates/configmap-secret.yaml @@ -25,7 +25,7 @@ spec: {{- end }} {{- /* do not auto-generate value as the secret will not be encrypted */}} secure-cookie-key: | - {{- default .Values.secureCookieKey .Values.global.secureCookieKey | nindent 6 }} + {{- default .Values.secureCookieKey.value .Values.global.secureCookieKey.value | nindent 6 }} template: data: {{- if .Values.launcherPub }} diff --git a/charts/rstudio-workbench/values.yaml b/charts/rstudio-workbench/values.yaml index daf34069..517f5392 100644 --- a/charts/rstudio-workbench/values.yaml +++ b/charts/rstudio-workbench/values.yaml @@ -382,12 +382,16 @@ launcherPem: # -- An inline launcher.pub key to pair with launcher.pem. If `false` (the default), we will try to generate a `launcher.pub` from the provided `launcher.pem` launcherPub: false -secureCookieKey: "" +secureCookieKey: + value: "" + existingSecret: "" dangerRegenerateAutomatedValues: false global: - secureCookieKey: "" + secureCookieKey: + value: "" + existingSecret: "" config: defaultMode: @@ -419,6 +423,11 @@ config: # @default -- 0644 pam: 0644 + database: + conf: + value: "" + existingSecret: "" + # -- a map of session-scoped config files. Mounted to `/mnt/session-configmap/rstudio/` on both server and session, by default. session: repos.conf: From c36a73ccf372982482c3d9d88081aee05d509b39 Mon Sep 17 00:00:00 2001 From: pat-s Date: Fri, 19 Jul 2024 17:04:17 +0200 Subject: [PATCH 3/7] also add secret for userPassword --- charts/rstudio-workbench/templates/_helpers.tpl | 11 ++++++++++- charts/rstudio-workbench/values.yaml | 4 +++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/charts/rstudio-workbench/templates/_helpers.tpl b/charts/rstudio-workbench/templates/_helpers.tpl index 808871a5..bf967bd6 100644 --- a/charts/rstudio-workbench/templates/_helpers.tpl +++ b/charts/rstudio-workbench/templates/_helpers.tpl @@ -62,8 +62,17 @@ containers: value: "{{ .Values.userName }}" - name: RSW_TESTUSER_UID value: "{{ .Values.userUid }}" + {{- if .Values.userPassword.existingSecret }} - name: RSW_TESTUSER_PASSWD - value: "{{ .Values.userPassword }}" + valueFrom: + secretKeyRef: + key: password + name: {{ .Values.userPassword.existingSecret }} + {{- end }} + {{- if .Values.userPassword.value }} + - name: RSW_TESTUSER_PASSWD + value: {{ .Values.userPassword.value }} + {{- end }} {{- else }} - name: RSW_TESTUSER value: "" diff --git a/charts/rstudio-workbench/values.yaml b/charts/rstudio-workbench/values.yaml index 517f5392..8a4ac56b 100644 --- a/charts/rstudio-workbench/values.yaml +++ b/charts/rstudio-workbench/values.yaml @@ -273,7 +273,9 @@ userName: "rstudio" # -- userUid determines the UID of the created user userUid: "10000" # -- userPassword determines the password of the created user -userPassword: "rstudio" +userPassword: + value: "rstudio" + existingSecret: "" # -- The XDG config dirs (directories where configuration will be read from). Do not change without good reason. xdgConfigDirs: "/mnt/dynamic:/mnt/session-configmap:/mnt/secret-configmap:/mnt/configmap:/mnt/load-balancer/" From 248f6cdb99ef5dd88aee45cc38bf506141bd8b1a Mon Sep 17 00:00:00 2001 From: pat-s Date: Fri, 19 Jul 2024 17:13:31 +0200 Subject: [PATCH 4/7] document --- charts/rstudio-workbench/README.md | 16 +++++++++++----- charts/rstudio-workbench/values.yaml | 5 +++++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/charts/rstudio-workbench/README.md b/charts/rstudio-workbench/README.md index f79e701d..5577d486 100644 --- a/charts/rstudio-workbench/README.md +++ b/charts/rstudio-workbench/README.md @@ -14,7 +14,7 @@ To ensure a stable production deployment: * "Pin" the version of the Helm chart that you are using. You can do this using the: * `helm dependency` command *and* the associated "Chart.lock" files *or* * the `--version` flag. - + ::: {.callout-important} This protects you from breaking changes. ::: @@ -452,6 +452,8 @@ Use of [Sealed secrets](https://github.com/bitnami-labs/sealed-secrets) disables | affinity | object | `{}` | A map used verbatim as the pod's "affinity" definition | | args | list | `[]` | args is the pod container's run arguments. | | command | list | `[]` | command is the pod container's run command. By default, it uses the container's default. However, the chart expects a container using `supervisord` for startup | +| config.database.conf.value | string | 0644 | Database connection config | +| config.database.conf.existingSecret | string | `""` | Secret for database connection config | | config.defaultMode.jobJsonOverrides | int | 0644 | default mode for jobJsonOverrides config | | config.defaultMode.pam | int | 0644 | default mode for pam scripts | | config.defaultMode.prestart | int | 0755 | default mode for prestart config | @@ -475,7 +477,8 @@ Use of [Sealed secrets](https://github.com/bitnami-labs/sealed-secrets) disables | diagnostics | object | `{"directory":"/var/log/rstudio","enabled":false}` | Settings for enabling server diagnostics | | extraObjects | list | `[]` | Extra objects to deploy (value evaluated as a template) | | fullnameOverride | string | `""` | the full name of the release (can be overridden) | -| global.secureCookieKey | string | `""` | | +| global.secureCookieKey.value | string | `""` | | +| global.secureCookieKey.existingSecret | string | `""` | Secret containing secureCookieKey | | homeStorage.accessModes | list | `["ReadWriteMany"]` | accessModes defined for the storage PVC (represented as YAML) | | homeStorage.create | bool | `false` | whether to create the persistentVolumeClaim for homeStorage | | homeStorage.mount | bool | `false` | Whether the persistentVolumeClaim should be mounted (even if not created) | @@ -507,7 +510,8 @@ Use of [Sealed secrets](https://github.com/bitnami-labs/sealed-secrets) disables | launcher.templateValues | object | `{"job":{"annotations":{},"labels":{},"ttlSecondsAfterFinished":null},"pod":{"affinity":{},"annotations":{},"command":[],"containerSecurityContext":{},"defaultSecurityContext":{},"env":[],"extraContainers":[],"imagePullPolicy":"","imagePullSecrets":[],"initContainers":[],"labels":{},"nodeSelector":{},"securityContext":{},"serviceAccountName":"","tolerations":[],"volumeMounts":[],"volumes":[]},"service":{"annotations":{},"labels":{},"type":"ClusterIP"}}` | values that are passed along to the launcher job rendering process as a data object (in JSON). These values are then used within session templates. | | launcher.templateValues.pod.command | list | `[]` | command for all pods. This is really not something we should expose and will be removed once we have a better option | | launcher.useTemplates | bool | `false` | whether to render and use templates in the job launching process | -| launcherPem | string | `""` | An inline launcher.pem key. If not provided, one will be auto-generated. See README for more details. | +| launcherPem.value | string | `""` | An inline launcher.pem key. If not provided, one will be auto-generated. See README for more details. | +| launcherPem.existingSecret | string | `""` | Existing Secret for launcherPem | | launcherPub | bool | `false` | An inline launcher.pub key to pair with launcher.pem. If `false` (the default), we will try to generate a `launcher.pub` from the provided `launcher.pem` | | license.file | object | `{"contents":false,"mountPath":"/etc/rstudio-licensing","mountSubPath":false,"secret":false,"secretKey":"license.lic"}` | the file section is used for licensing with a license file | | license.file.contents | bool | `false` | contents is an in-line license file | @@ -552,7 +556,8 @@ Use of [Sealed secrets](https://github.com/bitnami-labs/sealed-secrets) disables | revisionHistoryLimit | int | `10` | The revisionHistoryLimit to use for the pod deployment. Do not set to 0 | | sealedSecret.annotations | object | `{}` | annotations for SealedSecret resources | | sealedSecret.enabled | bool | `false` | use SealedSecret instead of Secret to deploy secrets | -| secureCookieKey | string | `""` | | +| secureCookieKey.value | string | `""` | | +| secureCookieKey.existingSecret | string | `""` | Secret containing secureCookieKey | | securityContext | object | `{}` | | | service.annotations | object | `{}` | Annotations for the service, for example to specify [an internal load balancer](https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer) | | service.clusterIP | string | `""` | The cluster-internal IP to use with `service.type` ClusterIP | @@ -587,7 +592,8 @@ Use of [Sealed secrets](https://github.com/bitnami-labs/sealed-secrets) disables | topologySpreadConstraints | list | `[]` | An array used verbatim as the pod's "topologySpreadConstraints" definition | | userCreate | bool | `false` | userCreate determines whether a user should be created at startup (if true) | | userName | string | `"rstudio"` | userName determines the username of the created user | -| userPassword | string | `"rstudio"` | userPassword determines the password of the created user | +| userPassword.value | string | `"rstudio"` | userPassword determines the password of the created user | +| userPassword.existingSecret | string | `""` | Existing Secret for userPassword | | userUid | string | `"10000"` | userUid determines the UID of the created user | | versionOverride | string | `""` | A Workbench version to override the "tag" for the RStudio Workbench image and the session images. Necessary until https://github.com/helm/helm/issues/8194 | | xdgConfigDirs | string | `"/mnt/dynamic:/mnt/session-configmap:/mnt/secret-configmap:/mnt/configmap:/mnt/load-balancer/"` | The XDG config dirs (directories where configuration will be read from). Do not change without good reason. | diff --git a/charts/rstudio-workbench/values.yaml b/charts/rstudio-workbench/values.yaml index 8a4ac56b..56c22d9e 100644 --- a/charts/rstudio-workbench/values.yaml +++ b/charts/rstudio-workbench/values.yaml @@ -275,6 +275,7 @@ userUid: "10000" # -- userPassword determines the password of the created user userPassword: value: "rstudio" + # key 'password' existingSecret: "" # -- The XDG config dirs (directories where configuration will be read from). Do not change without good reason. @@ -380,12 +381,14 @@ jobJsonOverridesFiles: {} # -- An inline launcher.pem key. If not provided, one will be auto-generated. See README for more details. launcherPem: value: "" + # key 'launcher.pem' existingSecret: "" # -- An inline launcher.pub key to pair with launcher.pem. If `false` (the default), we will try to generate a `launcher.pub` from the provided `launcher.pem` launcherPub: false secureCookieKey: value: "" + # key 'secure-cookie-key' existingSecret: "" dangerRegenerateAutomatedValues: false @@ -393,6 +396,7 @@ dangerRegenerateAutomatedValues: false global: secureCookieKey: value: "" + # key 'secure-cookie-key' existingSecret: "" config: @@ -428,6 +432,7 @@ config: database: conf: value: "" + # key 'database.conf' existingSecret: "" # -- a map of session-scoped config files. Mounted to `/mnt/session-configmap/rstudio/` on both server and session, by default. From de66db119e9b7f1c3b3c5a9f4bbdff4ed96c42b5 Mon Sep 17 00:00:00 2001 From: pat-s Date: Fri, 19 Jul 2024 17:22:46 +0200 Subject: [PATCH 5/7] clean --- charts/rstudio-workbench/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/charts/rstudio-workbench/README.md b/charts/rstudio-workbench/README.md index 5577d486..4df72cf9 100644 --- a/charts/rstudio-workbench/README.md +++ b/charts/rstudio-workbench/README.md @@ -14,7 +14,6 @@ To ensure a stable production deployment: * "Pin" the version of the Helm chart that you are using. You can do this using the: * `helm dependency` command *and* the associated "Chart.lock" files *or* * the `--version` flag. - ::: {.callout-important} This protects you from breaking changes. ::: From a60473d59f62ad8d9cb509c34c41ce5f7a4ed679 Mon Sep 17 00:00:00 2001 From: pat-s Date: Fri, 19 Jul 2024 17:24:50 +0200 Subject: [PATCH 6/7] bump chart version --- charts/rstudio-workbench/Chart.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/rstudio-workbench/Chart.yaml b/charts/rstudio-workbench/Chart.yaml index 46d386ef..b3740f13 100644 --- a/charts/rstudio-workbench/Chart.yaml +++ b/charts/rstudio-workbench/Chart.yaml @@ -1,6 +1,6 @@ name: rstudio-workbench description: Official Helm chart for Posit Workbench -version: 0.8.7 +version: 1.0.0 apiVersion: v2 appVersion: 2024.09.1 icon: https://rstudio.com/wp-content/uploads/2018/10/RStudio-Logo-Flat.png From d2254acc9d103c774ac5226f4d4214dc3b165cb2 Mon Sep 17 00:00:00 2001 From: Patrick Schratz Date: Mon, 11 Nov 2024 18:49:20 +0100 Subject: [PATCH 7/7] Update charts/rstudio-workbench/README.md Co-authored-by: Graham Held --- charts/rstudio-workbench/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/rstudio-workbench/README.md b/charts/rstudio-workbench/README.md index 4df72cf9..07a2bfc0 100644 --- a/charts/rstudio-workbench/README.md +++ b/charts/rstudio-workbench/README.md @@ -510,7 +510,7 @@ Use of [Sealed secrets](https://github.com/bitnami-labs/sealed-secrets) disables | launcher.templateValues.pod.command | list | `[]` | command for all pods. This is really not something we should expose and will be removed once we have a better option | | launcher.useTemplates | bool | `false` | whether to render and use templates in the job launching process | | launcherPem.value | string | `""` | An inline launcher.pem key. If not provided, one will be auto-generated. See README for more details. | -| launcherPem.existingSecret | string | `""` | Existing Secret for launcherPem | +| launcherPem.existingSecret | string | `""` | Existing secret containing launcherPem contents | | launcherPub | bool | `false` | An inline launcher.pub key to pair with launcher.pem. If `false` (the default), we will try to generate a `launcher.pub` from the provided `launcher.pem` | | license.file | object | `{"contents":false,"mountPath":"/etc/rstudio-licensing","mountSubPath":false,"secret":false,"secretKey":"license.lic"}` | the file section is used for licensing with a license file | | license.file.contents | bool | `false` | contents is an in-line license file |