Skip to content

Commit be14484

Browse files
authored
Merge pull request #726 from rstudio/workbench-k8s-secrets-for-sensitive-configs
Copy of the PR from pat-s:existingSecret so it can run tests properly
2 parents 68b14a8 + ed7d692 commit be14484

19 files changed

+585
-34
lines changed

.github/workflows/chart-test.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,16 @@ jobs:
173173
kubectl create secret generic ppm-license --from-file=ppm.lic --namespace posit-test
174174
rm ppm.lic
175175
176+
- name: Create Workbench Secrets to test existingSecrets
177+
run: |
178+
echo "Generating a fake launcher.pem file"
179+
openssl genrsa -out launcher.pem 4096
180+
kubectl create secret generic launcherpem-secret --from-file=launcher.pem=launcher.pem --namespace posit-test
181+
kubectl create secret generic userpassword-secret --from-literal=password="testpassword" --namespace posit-test
182+
kubectl create secret generic securecookiekey-secret --from-literal=secure-cookie-key="ec44ae41-5b74-44a4-915b-3b0ac8ef72b6" --namespace posit-test
183+
kubectl create secret generic globalsecurecookiekey-secret --from-literal=secure-cookie-key="ec44ae41-5b74-44a4-915b-3b0ac8ef72b6" --namespace posit-test
184+
kubectl create secret generic databaseconf-secret --from-literal=database.conf="testdatabaseconf" --namespace posit-test
185+
176186
# no allow-failure until https://github.com/actions/toolkit/issues/399
177187
- name: Run chart-testing (install changed)
178188
id: ct-install

charts/rstudio-workbench/Chart.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: rstudio-workbench
22
description: Official Helm chart for Posit Workbench
3-
version: 0.9.16
3+
version: 0.10.0
44
apiVersion: v2
55
appVersion: 2025.09.2
66
icon: https://rstudio.com/wp-content/uploads/2018/10/RStudio-Logo-Flat.png

charts/rstudio-workbench/NEWS.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,26 @@
11
# Changelog
22

3+
## 0.10.0
4+
5+
- BREAKING: `userPassword` has been replaced by `userPassword.value` or `userPassword.existingSecret`
6+
- This allows for better secret management and avoids putting passwords in plaintext in `values.yaml`
7+
- If you were using `userPassword`, you can migrate by setting `userPassword.value` to the same value
8+
- Alternatively, you can create a Kubernetes secret with the password and set `userPassword.existingSecret` to the name of the secret
9+
- BREAKING: `launcherPem` has been replaced by `launcherPem.value` or `launcherPem.existingSecret`
10+
- This allows for better secret management and avoids putting PEM keys in plaintext in `values.yaml`
11+
- If you were using `launcherPem`, you can migrate by setting `launcherPem.value` to the same value
12+
- Alternatively, you can create a Kubernetes secret with the PEM key and set `launcherPem.existingSecret` to the name of the secret
13+
- BREAKING: `secureCookieKey` has been replaced by `secureCookieKey.value` or `secureCookieKey.existingSecret`
14+
- This allows for better secret management and avoids putting secure cookie keys in plaintext in `values.yaml`
15+
- If you were using `secureCookieKey`, you can migrate by setting `secureCookieKey.value` to the same value
16+
- Alternatively, you can create a Kubernetes secret with the secure cookie key and set `secureCookieKey.existingSecret` to the name of the secret
17+
- BREAKING `global.secureCookieKey` has been replaced by `global.secureCookieKey.value` or `global.secureCookieKey.existingSecret`
18+
- This allows for better secret management and avoids putting secure cookie keys in plaintext in `values.yaml`
19+
- If you were using `global.secureCookieKey`, you can migrate by setting `global.secureCookieKey.value` to the same value
20+
- Alternatively, you can create a Kubernetes secret with the secure cookie key and set `global.secureCookieKey.existingSecret` to the name of the secret
21+
- Add `config.database.conf` section can be used to configure database settings. Either `config.database.conf.value` or `config.database.conf.existingSecret` can be used to set the database configuration.
22+
- This can be used instead of specifying the database config values in plain text in `config.secret.database.conf`
23+
324
## 0.9.16
425

526
- Bump Workbench version to 2025.09.2

charts/rstudio-workbench/README.md

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Posit Workbench
22

3-
![Version: 0.9.16](https://img.shields.io/badge/Version-0.9.16-informational?style=flat-square) ![AppVersion: 2025.09.2](https://img.shields.io/badge/AppVersion-2025.09.2-informational?style=flat-square)
3+
![Version: 0.10.0](https://img.shields.io/badge/Version-0.10.0-informational?style=flat-square) ![AppVersion: 2025.09.2](https://img.shields.io/badge/AppVersion-2025.09.2-informational?style=flat-square)
44

55
#### _Official Helm chart for Posit Workbench_
66

@@ -24,11 +24,11 @@ To ensure a stable production deployment:
2424

2525
## Installing the chart
2626

27-
To install the chart with the release name `my-release` at version 0.9.16:
27+
To install the chart with the release name `my-release` at version 0.10.0:
2828

2929
```{.bash}
3030
helm repo add rstudio https://helm.rstudio.com
31-
helm upgrade --install my-release rstudio/rstudio-workbench --version=0.9.16
31+
helm upgrade --install my-release rstudio/rstudio-workbench --version=0.10.0
3232
```
3333

3434
To explore other chart versions, look at:
@@ -109,7 +109,25 @@ Alternatively, license files can be set during `helm install` with the following
109109

110110
Workbench requires a PostgreSQL database when running in Kubernetes. You must configure a [valid connection URI and a password](https://docs.posit.co/ide/server-pro/database/configuration.html#postgresql) for the product to function correctly. Both the connection URI and password may be specified in the `config` section of `values.yaml`. However, we recommend only adding the connection URI and putting the database password in a Kubernetes `Secret`, which can be [automatically set as an environment variable](#database-password).
111111

112-
### Database configuration
112+
### Database configuration the new way:
113+
You can now specify your database connection details in `config.database.conf` as follows:
114+
```yaml
115+
config:
116+
database:
117+
conf:
118+
value: |
119+
provider=postgresql
120+
connection-uri=postgres://<USERNAME>@<HOST>:<PORT>/<DATABASE>?sslmode=allow
121+
```
122+
123+
or you can use an existing `Secret` that contains the database configuration file:
124+
```yaml
125+
config:
126+
database:
127+
conf:
128+
existingSecret:
129+
130+
### Database configuration the old way:
113131
114132
Add the following to your `values.yaml`, replacing the `connection-uri` with your database details.
115133

@@ -129,6 +147,12 @@ First, create a `Secret` declaratively with YAML or imperatively using the follo
129147
kubectl create secret generic rstudio-workbench-database --from-literal=password=YOURPASSWORDHERE
130148
```
131149

150+
To avoid storing the password in your shell history, use:
151+
```bash
152+
kubectl create secret generic rstudio-workbench-database --from-file=password=/path/to/password-file
153+
```
154+
the file at `/path/to/password-file` should contain only the password.
155+
132156
Second, specify the following in your `values.yaml`:
133157

134158
```yaml
@@ -508,6 +532,9 @@ Use of [Sealed secrets](https://github.com/bitnami-labs/sealed-secrets) disables
508532
| chronicleAgent.workbenchApiKey.value | string | `""` | Workbench API key as a raw string to set as the `CHRONICLE_WORKBENCH_APIKEY` environment variable (not recommended) |
509533
| chronicleAgent.workbenchApiKey.valueFrom | object | `{}` | Workbench API key as a `valueFrom` reference (ex. a Kubernetes Secret reference) to set as the `CHRONICLE_WORKBENCH_APIKEY` environment variable (recommended) |
510534
| 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 |
535+
| config.database | object | `{"conf":{"existingSecret":"","value":""}}` | a map of database connection config files. Mounted to `/mnt/secret-configmap/rstudio/database.conf` with 0600 permissions |
536+
| config.database.conf.existingSecret | string | `""` | Secret for database connection config. Will take precedence over `config.database.conf.value`. Key: 'database.conf' |
537+
| config.database.conf.value | string | `""` | Database connection config. Will only be used if `config.database.conf.existingSecret` is not set. |
511538
| config.defaultMode.jobJsonOverrides | int | 0644 | default mode for jobJsonOverrides config |
512539
| config.defaultMode.pam | int | 0644 | default mode for pam scripts |
513540
| config.defaultMode.prestart | int | 0755 | default mode for prestart config |
@@ -531,7 +558,9 @@ Use of [Sealed secrets](https://github.com/bitnami-labs/sealed-secrets) disables
531558
| diagnostics | object | `{"directory":"/var/log/rstudio","enabled":false}` | Settings for enabling server diagnostics |
532559
| extraObjects | list | `[]` | Extra objects to deploy (value evaluated as a template) |
533560
| fullnameOverride | string | `""` | the full name of the release (can be overridden) |
534-
| global.secureCookieKey | string | `""` | |
561+
| global.secureCookieKey | object | `{"existingSecret":"","value":""}` | global.secureCookieKey takes precedence over secureCookieKey |
562+
| global.secureCookieKey.existingSecret | string | `""` | Secret containing secureCookieKey. Will take precedence over `global.secureCookieKey.value`. Key: 'secure-cookie-key' |
563+
| global.secureCookieKey.value | string | `""` | Will only be used if `global.secureCookieKey.existingSecret` is not set |
535564
| homeStorage.accessModes | list | `["ReadWriteMany"]` | accessModes defined for the storage PVC (represented as YAML) |
536565
| homeStorage.create | bool | `false` | whether to create the persistentVolumeClaim for homeStorage |
537566
| homeStorage.mount | bool | `false` | Whether the persistentVolumeClaim should be mounted (even if not created) |
@@ -563,7 +592,9 @@ Use of [Sealed secrets](https://github.com/bitnami-labs/sealed-secrets) disables
563592
| launcher.templateValues | object | `{"job":{"annotations":{},"labels":{},"ttlSecondsAfterFinished":null},"pod":{"affinity":{},"annotations":{},"command":[],"containerSecurityContext":{},"defaultSecurityContext":{},"env":[],"ephemeralStorage":{"limit":"","request":""},"extraContainers":[],"hostAliases":[],"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. |
564593
| 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 |
565594
| launcher.useTemplates | bool | `true` | whether to render and use templates in the job launching process |
566-
| launcherPem | string | `""` | An inline launcher.pem key. If not provided, one will be auto-generated. See README for more details. |
595+
| launcherPem | object | `{"existingSecret":"","value":""}` | An inline launcher.pem key. If not provided, one will be auto-generated. See README for more details. |
596+
| launcherPem.existingSecret | string | `""` | Existing secret containing launcherPem contents. Will take precedence over `launcherPem.value`. Key: 'launcher.pem' |
597+
| launcherPem.value | string | `""` | An inline launcher.pem key. If not provided, one will be auto-generated. See README for more details. Will only be used if `launcherPem.existingSecret` is not set. |
567598
| 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` |
568599
| 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 |
569600
| license.file.contents | bool | `false` | contents is an in-line license file, generally requiring the use of multi-line yaml notation |
@@ -609,7 +640,9 @@ Use of [Sealed secrets](https://github.com/bitnami-labs/sealed-secrets) disables
609640
| revisionHistoryLimit | int | `10` | The revisionHistoryLimit to use for the pod deployment. Do not set to 0 |
610641
| sealedSecret.annotations | object | `{}` | annotations for SealedSecret resources |
611642
| sealedSecret.enabled | bool | `false` | use SealedSecret instead of Secret to deploy secrets |
612-
| secureCookieKey | string | `""` | |
643+
| secureCookieKey | object | `{"existingSecret":"","value":""}` | global.secureCookieKey takes precedence over secureCookieKey |
644+
| secureCookieKey.existingSecret | string | `""` | Secret containing secureCookieKey. Will take precedence over `secureCookieKey.value`. Key: 'secure-cookie-key' |
645+
| secureCookieKey.value | string | `""` | Will only be used if `secureCookieKey.existingSecret` is not set. |
613646
| securityContext | object | `{}` | |
614647
| 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) |
615648
| service.clusterIP | string | `""` | The cluster-internal IP to use with `service.type` ClusterIP |
@@ -646,7 +679,9 @@ Use of [Sealed secrets](https://github.com/bitnami-labs/sealed-secrets) disables
646679
| topologySpreadConstraints | list | `[]` | An array used verbatim as the pod's "topologySpreadConstraints" definition |
647680
| userCreate | bool | `false` | userCreate determines whether a user should be created at startup (if true) |
648681
| userName | string | `"rstudio"` | userName determines the username of the created user |
649-
| userPassword | string | `"rstudio"` | userPassword determines the password of the created user |
682+
| userPassword | object | `{"existingSecret":"","value":"rstudio"}` | userPassword determines the password of the created user |
683+
| userPassword.existingSecret | string | `""` | Existing Secret for userPassword. Will take precedence over `userPassword.value`. Key: 'password' |
684+
| userPassword.value | string | `"rstudio"` | userPassword determines the password of the created user. Will only be used if `userPassword.existingSecret` is not set. |
650685
| userUid | string | `"10000"` | userUid determines the UID of the created user |
651686
| 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 |
652687
| 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. |

charts/rstudio-workbench/README.md.gotmpl

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,25 @@ To function, this chart requires the following:
5454

5555
Workbench requires a PostgreSQL database when running in Kubernetes. You must configure a [valid connection URI and a password](https://docs.posit.co/ide/server-pro/database/configuration.html#postgresql) for the product to function correctly. Both the connection URI and password may be specified in the `config` section of `values.yaml`. However, we recommend only adding the connection URI and putting the database password in a Kubernetes `Secret`, which can be [automatically set as an environment variable](#database-password).
5656

57-
### Database configuration
57+
### Database configuration the new way:
58+
You can now specify your database connection details in `config.database.conf` as follows:
59+
```yaml
60+
config:
61+
database:
62+
conf:
63+
value: |
64+
provider=postgresql
65+
connection-uri=postgres://<USERNAME>@<HOST>:<PORT>/<DATABASE>?sslmode=allow
66+
```
67+
68+
or you can use an existing `Secret` that contains the database configuration file:
69+
```yaml
70+
config:
71+
database:
72+
conf:
73+
existingSecret:
74+
75+
### Database configuration the old way:
5876
5977
Add the following to your `values.yaml`, replacing the `connection-uri` with your database details.
6078
@@ -74,6 +92,12 @@ First, create a `Secret` declaratively with YAML or imperatively using the follo
7492
kubectl create secret generic {{ .Name }}-database --from-literal=password=YOURPASSWORDHERE
7593
```
7694
95+
To avoid storing the password in your shell history, use:
96+
```bash
97+
kubectl create secret generic {{ .Name }}-database --from-file=password=/path/to/password-file
98+
```
99+
the file at `/path/to/password-file` should contain only the password.
100+
77101
Second, specify the following in your `values.yaml`:
78102
79103
```yaml
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
license:
2+
file:
3+
secret: pwb-license
4+
secretKey: pwb.lic
5+
6+
global:
7+
secureCookieKey:
8+
existingSecret: "globalsecurecookiekey-secret"
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
license:
2+
file:
3+
secret: pwb-license
4+
secretKey: pwb.lic
5+
6+
global:
7+
secureCookieKey:
8+
value: "testsecurecookiekey"
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
license:
2+
file:
3+
secret: pwb-license
4+
secretKey: pwb.lic
5+
6+
launcherPem:
7+
existingSecret: launcherpem-secret
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
license:
2+
file:
3+
secret: pwb-license
4+
secretKey: pwb.lic
5+
6+
launcherPem:
7+
value: "TESTDATA"
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
license:
2+
file:
3+
secret: pwb-license
4+
secretKey: pwb.lic
5+
6+
secureCookieKey:
7+
existingSecret: "securecookiekey-secret"

0 commit comments

Comments
 (0)