Conversation
- Run Workbench as non-root by default via serviceAccountUser - Invoke supervisord with -u "" when running Workbench non-root - Fix supervisord non-root workaround: pass -u <serviceAccountUser> instead of -u "" - Fix non-root supervisord startup: emptyDir, path rewriting, fsGroup - Simplify prestart-launcher.bash for non-root operation - Simplify prestart-workbench.bash for non-root operation - Update secrets test mode assertions for non-root default (0640) - Document rootless prestart script simplification - Drop supervisord non-root workaround, use image default command - Add explicit config.sssd toggle, off by default - Add non-root config defaults for launcher auth, PAM, provisioning - Default serviceAccountUser to root, keep non-root opt-in - Avoid contradictory root securityContext on user override
Previously sssd.enabled defaulted to false with a hard render failure if set to true while running non-root. Now sssd.enabled defaults to true and is silently skipped when serviceAccountUser is not root, preserving existing root behavior with no BREAKING change. Introduce rstudio-workbench.sssd.active helper to centralize the effective-SSSD gate (enabled AND root) used across helpers, configmaps, and NOTES.txt warnings.
…tUser Add top-level runAsRoot: true (default) as the single binary control for pod privilege. Previously, serviceAccountUser == "root" was the implicit trigger for all root-vs-non-root behavior (securityContext, SSSD, secret file modes, rserver.conf defaults), conflating the OS application user with the Kubernetes security concept. serviceAccountUser now solely controls server-user in rserver.conf. All privilege-gating logic switches from eq serviceAccountUser "root" to .Values.runAsRoot / not .Values.runAsRoot.
| pod: | ||
| securityContext: | ||
| runAsUser: 4242 | ||
| fsGroup: 4242 |
There was a problem hiding this comment.
Recommend making this unique, even if that's unrealistic, just to be sure these values end up where they are supposed to.
| fsGroup: 4242 | |
| fsGroup: 4243 |
| value: 4242 | ||
| - equal: | ||
| path: spec.template.spec.securityContext.fsGroup | ||
| value: 4242 |
There was a problem hiding this comment.
| value: 4242 | |
| value: 4243 |
GCRev
left a comment
There was a problem hiding this comment.
If there are any problems with this, then I didn't spot them.
When load balancing is active (replicas > 1 or loadBalancer.forceEnabled), prestart-workbench.bash writes the load-balancer config under /mnt/load-balancer. With no volume mounted there the path lives on the container root fs, which a non-root pod (pod.runAsRoot: false) cannot write to, causing CrashLoopBackOff on mkdir. Mount an emptyDir at /mnt/load-balancer under the same condition that sets RSW_LOAD_BALANCING, mirroring the /mnt/dynamic pattern. fsGroup makes it writable for the unprivileged user.
| - A new `config.sssd` block controls the bundled SSSD daemon (replaces the deprecated `config.userProvisioning`). | ||
| - `config.userProvisioning` is deprecated; use `config.sssd.conf`. A warning is emitted when it is set. |
There was a problem hiding this comment.
Consider rewriting these two lines into a single bullet point; they feel kind of redundant. I'm also confused by config.sssd vs config.sssd.conf.
| ## 0.21.1 | ||
|
|
||
| - Workbench pods can now run as a non-root user. Set `pod.runAsRoot: false` (new value, default `true`) to run unprivileged. | ||
| - When running unprivelaged SCIM must be used for user management. |
There was a problem hiding this comment.
| - When running unprivelaged SCIM must be used for user management. | |
| - Use SCIM for user management when running unprivileged. |
| - When running unprivelaged SCIM must be used for user management. | ||
| - A new `config.sssd` block controls the bundled SSSD daemon (replaces the deprecated `config.userProvisioning`). | ||
| - `config.userProvisioning` is deprecated; use `config.sssd.conf`. A warning is emitted when it is set. | ||
| - The Workbench and launcher prestart scripts (`prestart-workbench.bash`, `prestart-launcher.bash`) no longer perform root-only operations. |
There was a problem hiding this comment.
How relevant is this to the end admin? I'm not familiar enough to know if this is important to call out or if it could be dropped.
| - A new `config.sssd` block controls the bundled SSSD daemon (replaces the deprecated `config.userProvisioning`). | ||
| - `config.userProvisioning` is deprecated; use `config.sssd.conf`. A warning is emitted when it is set. | ||
| - The Workbench and launcher prestart scripts (`prestart-workbench.bash`, `prestart-launcher.bash`) no longer perform root-only operations. | ||
| - A writable `emptyDir` is now mounted at `/mnt/load-balancer` when load balancing is active (`replicas > 1` or `loadBalancer.forceEnabled: true`), so the prestart script can write the load-balancer config when the pod runs unprivileged (`pod.runAsRoot: false`). |
There was a problem hiding this comment.
| - A writable `emptyDir` is now mounted at `/mnt/load-balancer` when load balancing is active (`replicas > 1` or `loadBalancer.forceEnabled: true`), so the prestart script can write the load-balancer config when the pod runs unprivileged (`pod.runAsRoot: false`). | |
| - A writable `emptyDir` is now mounted at `/mnt/load-balancer` when load balancing is active (`replicas > 1` or `loadBalancer.forceEnabled: true`). The prestart script writes the load-balancer config in this directory when the pod runs unprivileged (`pod.runAsRoot: false`). |
(Or perhaps "can write" instead of "writes"; I don't know the details.)
| - Located at:<br> `config.userProvisioning.<< name of file >>` Helm values | ||
| - SSSD Configuration: | ||
| - These configuration files configure the bundled `sssd` daemon (legacy LDAP/AD provisioning), which is started only when `config.sssd.enabled=true`. | ||
| - Located at:<br> `config.sssd.conf.<< name of file >>` Helm values (the deprecated `config.userProvisioning` is honored as a fallback) |
There was a problem hiding this comment.
This line seems really awkward... I'm not sure what you mean.
| The [latest Workbench container](https://github.com/rstudio/rstudio-docker-products/tree/main/workbench#user-provisioning) | ||
| has `sssd` included and running by default (see `userProvisioning` configuration files above). | ||
| Posit Workbench's native user provisioning (SCIM / just-in-time) is the recommended approach and does not require SSSD. | ||
| The legacy approach is `sssd`: the [latest Workbench container](https://github.com/rstudio/rstudio-docker-products/tree/main/workbench#user-provisioning) |
There was a problem hiding this comment.
| The legacy approach is `sssd`: the [latest Workbench container](https://github.com/rstudio/rstudio-docker-products/tree/main/workbench#user-provisioning) | |
| `sssd` is the legacy approach: the [latest Workbench container](https://github.com/rstudio/rstudio-docker-products/tree/main/workbench#user-provisioning) |
| |-----|------|---------|-------------| | ||
| | affinity | object | `{}` | A map used verbatim as the pod's "affinity" definition | | ||
| | args | list | `[]` | args is the pod container's run arguments. | | ||
| | args | list | `[]` | args is the pod container's run arguments. When unset, the container's default arguments are used. | |
There was a problem hiding this comment.
Consider changing the content of the "default" column. Not sure what to suggest though.
| * A method to join the deployed `rstudio-workbench` container to your auth domain. The `posit/workbench` image ships `sssd` for legacy LDAP/Active Directory provisioning. SSSD must run as root, so the bundled daemon starts by default only on root deployments (`config.sssd.enabled: true`, `pod.runAsRoot: true`) and is automatically skipped when `pod.runAsRoot: false`. Modern provisioning (SCIM / native) does not require SSSD. | ||
| Provide its configuration in `config.sssd.conf` like so (set `config.sssd.enabled: false` to disable the daemon entirely): |
There was a problem hiding this comment.
I wonder if this is too much information?
|
I'm going to recuse myself from this PR beyond basic documentation style. I don't really know much about this subject matter and I'm heading out of town tomorrow. |
On the rootless path (pod.runAsRoot: false) the launcher session pods were left with the default launcher-sessions-create-container-user=1, which needs the session container to start as root to useradd + setuid into the requesting user. An unprivileged container cannot, so sessions crashed with EPERM. Disabling it makes rserver stamp the session pod securityContext with the user's UID/GID instead (the runAsUserId branch in ServerJobLauncher), so the session runs directly as the user with no privilege.
The Kubernetes launcher runs as the non-root serviceAccountUser even in a root pod, so several root-mode paths broke once it stopped running as root: - Set fsGroup (and fsGroupChangePolicy: OnRootMismatch) in root mode when launcher.enabled, so the projected ServiceAccount token is group-readable (root:rstudio-server 0640) to the launcher (rstudio-pro#11349). - Project the autogenerated secure-cookie-key into /mnt/secret-configmap/rstudio in rootless mode so the launcher shares rserver's cookie key instead of reading a missing file. - Create the launcher scratch dirs (Local, Kubernetes) setgid + group-writable so the non-root launcher can write to them without a root-only chown.
| - The launcher prestart script now creates its scratch dirs (`/var/lib/rstudio-launcher/Local`, `/Kubernetes`) setgid and group-writable, so the launcher (which runs as the non-root `serviceAccountUser`) can write to them in root-mode pods without a privileged ownership change. | ||
|
|
||
| - Workbench pods can now run as a non-root user. Set `pod.runAsRoot: false` (new value, default `true`) to run unprivileged. | ||
| - When running unprivelaged SCIM must be used for user management. |
There was a problem hiding this comment.
I still don't fully understand how SCIM works here but JIT doesn't. Fundamentally it seems like the requirement is that Workbench native user provisioning must be used, not necessarily the exact provisioning method?
There was a problem hiding this comment.
Ah! Yeah I'm conflating the two here. I'll be clearer. This work with SCIM as well as JIT. You need to use openid/saml or some other auth provider - local auth basically doesn't work because that leans on pam.
| # `false` runs unprivileged: pod sets `runAsNonRoot: true` and `runAsUser`/`fsGroup` to | ||
| # `pod.serviceAccountUserId`, SSSD is skipped, secrets mount 0640, and non-root | ||
| # `rserver.conf`/`launcher.conf` defaults are applied. | ||
| runAsRoot: true |
There was a problem hiding this comment.
Is making this true by default a breaking change?
There was a problem hiding this comment.
By default we currently run as root - flipping this to false will enabled the rootless mode. Which is beaking.
So idea here is to wire up a rootless version of workbench in the helm charts,
There's a simple high level flag (
pod. runAsRoot) this defaults to true (for now). But you can set it to false to basically wire in a pretty separate mode for workbench. Where,a.
sssdis disabled - you need to use SCIM instead.b. Workbench and pods that it launches will use the service account instead.
c. There's some other toggling which is more minor.
If you're in the rootless mode you can also specify the service account user and uid. For this to really work though I think you would need to build your own version of the workbench image. The user + uid is baked into there with my other changes.
Closes https://github.com/rstudio/rstudio-pro/issues/10847