Open sgibson91 opened 11 months ago
I've started looking into this and can and it doesn't look like its a security issue at least, its just a bad UX presenting an seeminlgy empty folder.
I tried starting a non-admin user's server and saw this:
The pod created by KubeSpawner revealed:
# pod spec snippet
volumes:
- name: home
persistentVolumeClaim:
claimName: home-nfs
# main container spec snippet
volumeMounts:
- mountPath: /home/jovyan
name: home
subPath: redacted-username
- mountPath: /home/jovyan/shared
name: home
readOnly: true
subPath: _shared
# init container spec snippet
volumeMounts:
- mountPath: /home/jovyan
name: home
subPath: redacted-username
- mountPath: /home/jovyan/shared-readwrite
name: home
subPath: _shared
# init container's command
- command:
- sh
- -c
- 'id && chown 1000:1000 /home/jovyan && chown 1000:1000 /home/jovyan/shared-readwrite
&& ls -lhd /home/jovyan '
This UX bug is seen in other clusters as well, not just the 2i2c cluster's ohw hub with GKE v1.26, such as openscapes on EKS k8s 1.24.
Running the mount
command from a terminal as a non-admin user showed this.
10.234.45.250:/homes/homes/ohw/_shared on /home/jovyan/shared type nfs (ro,noatime,vers=3,rsize=1048576,wsize=1048576,namlen=255,soft,proto=tcp,timeo=600,retrans=2,sec=sys,mountaddr=10.234.45.250,mountvers=3,mountport=2050,mountproto=tcp,local_lock=none,addr=10.234.45.250)
10.234.45.250:/homes/homes/ohw/_shared on /home/jovyan/shared-readwrite type nfs (rw,noatime,vers=3,rsize=1048576,wsize=1048576,namlen=255,soft,proto=tcp,timeo=600,retrans=2,sec=sys,mountaddr=10.234.45.250,mountvers=3,mountport=2050,mountproto=tcp,local_lock=none,addr=10.234.45.250)
fs-b25253b5.efs.us-west-2.amazonaws.com:/prod/_shared on /home/jovyan/shared type nfs4 (rw,relatime,vers=4.1,rsize=1048576,wsize=1048576,namlen=255,soft,noresvport,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=192.168.43.179,local_lock=none,addr=192.168.63.243)
jupyterhub:
custom:
auth:
anonymizeUsername: false
singleuser:
extraPVCs: []
singleuserAdmin:
extraEnv: {}
extraVolumeMounts:
- name: home
mountPath: /home/jovyan/shared-readwrite
subPath: _shared
singleuser:
# Need to explicitly fix ownership here, as otherwise these directories will be owned
# by root on most NFS filesystems - neither EFS nor Google Filestore support anonuid
initContainers:
- name: volume-mount-ownership-fix
image: busybox
command:
[
"sh",
"-c",
"id && chown 1000:1000 /home/jovyan && chown 1000:1000 /home/jovyan/shared-readwrite && ls -lhd /home/jovyan ",
]
securityContext:
runAsUser: 0
volumeMounts:
- name: home
mountPath: /home/jovyan
subPath: "{username}"
# Here so we can chown it appropriately
- name: home
mountPath: /home/jovyan/shared-readwrite
subPath: _shared
I think I understand this well enough now, but I'm not sure on the resolution.
It seems that when we've mounted something inside another mount, like we how we mount a users home folder to /home/jovyan
and then mounted the shared folder to /home/jovyan/shared-readwrite
, we end up with an empty directory in the users volume.
So in practice, the non-admin users see the shared-readwrite
directory because its part of their home directory, as a remnant of just having declared the mount to /home/jovyan/shared-readwrite
inside /home/jovyan
once in an init container. I've verified it wasn't part of the chown
step.
initContainers:
- name: volume-mount-ownership-fix
image: busybox
command:
[
"sh",
"-c",
"id && chown 1000:1000 /home/jovyan && chown 1000:1000 /home/jovyan/shared-readwrite && ls -lhd /home/jovyan ",
]
securityContext:
runAsUser: 0
volumeMounts:
- name: home
mountPath: /home/jovyan
subPath: "{username}"
# Here so we can chown it appropriately
- name: home
mountPath: /home/jovyan/shared-readwrite
subPath: _shared
I think by an update like below, we should be fine. I've tested this manually on staging.2i2c.cloud from a state of having cleaned up the folders and started an admin and a non-admin user, where the admin user saw staging
and staging-readwrite
with the correct permissions to the folders, and the non-admin saw staging
only with the correct permissions to the folder.
command:
[
"sh",
"-c",
- "id && chown 1000:1000 /home/jovyan && chown 1000:1000 /home/jovyan/shared-readwrite && ls -lhd /home/jovyan ",
+ "id && chown 1000:1000 /home/jovyan && chown 1000:1000 /home/jovyan/shared && ls -lhd /home/jovyan
",
]
volumeMounts:
- name: home
mountPath: /home/jovyan
subPath: "{username}"
# Here so we can chown it appropriately
- name: home
- mountPath: /home/jovyan/shared-readwrite
+ mountPath: /home/jovyan/shared
subPath: _shared
I think what needs to be done is to visit all clusters hubs storage and iterate across all users to remove all empty shared-readwrite folders we find in their home directories.
Here is how we can empty shared-readwrite
folders put inside users home directories using a script. Note that for admin users, this empty folder won't matter since they are hidden by getting a proper folder mounted on top of it, but non-admin users will be confused by seeing an empty folder in their home directory.
deployer exec homes <cluster name>
cd home
# the command below is quite safe to run I htink,
# because `rm -d` is used, it will only delete empty folders
ls -d */shared-readwrite | xargs -t -L1 -I {} rm -d {}
shared-readwrite
folders that have been created before https://github.com/2i2c-org/infrastructure/pull/2954 was merged. https://github.com/2i2c-org/infrastructure/issues/2946#issuecomment-1968894102 can be used to cleanup an individual hub.I made this a "High" priority because its a good time save to get it solved before more complaints come in about it - as each complaint leads to notable amount of communication work for us etc.
Context
ref: https://2i2c.freshdesk.com/a/tickets/870
There seems to be a bug on the OHW hub where non-admin users can see the shared-readwrite folder which is supposed to be admin only. We know at least one non-admin who can see it cannot write to it, so if that is true across the board, damage is limited and we are just dealing with confused users. We establish "who is an admin" via some custom Kubespawner code. I think a lot of work has been going on over there recently, and I'm wondering if something could have broken/modified this functionality a bit? But I'm not sure how to go about digging into this one.
Proposal
No response
Updates and actions
No response