use delegated zfs permissions without sudo access
bjornbouetsmith opened this issue · 86 comments
Hi,
I really like this project - but would it be possible that the driver uses its required credentials from a secret that is stored inside the kubernetes cluster?
Right now credentials are stored in plain text inside the values, and that seems like a really bad idea.
Edit: Also I seem to not be able to get a non-root user to work at all.
System info:
- TrueNas 12
- Raw Kubernetes (k8s)
If I use username/password for httpConnection like this:
httpConnection:
protocol: http
host: 192.168.0.201
port: 80
allowInsecure: true
username: k8s
password: xys
Then I get a 401 from the API - my guess is that non-root users are not allowed to use the API.
With the apiKey present instead
httpConnection:
protocol: http
host: 192.168.0.201
port: 80
allowInsecure: true
apiKey: "2-qEjchKvqI7QimbvONfM4vbNopomKuHpNC0ffnNY8QOPdXlyr0gxPDhSv1BgzXC05"
I get errors from the ssh connection
failed to provision volume with StorageClass "freenas-nfs-csi": rpc error: code = Internal desc = Error: cannot create 'fast/k8s/nfs/vols/pvc-5e7afe1e-b3c2-4118-a413-5c6c17f92193': permission denied
if I add:
zfs:
cli:
sudoEnabled: true
The error becomes different:
failed to provision volume with StorageClass "freenas-nfs-csi": rpc error: code = Internal desc = Error: sudo: a terminal is required to read the password; either use the -S option to read from standard input or configure an askpass helper sudo: a password is required
Thanks for any hints - or even a message stating that its not supported properly without root.
Can you send over the full values files (cleansed of secrets of course)? Generally you can run as non-root for ssh connection/operations but the api is root only. The apiKey setup you’re currently using is ideal for the api atm.
The values file does turn the config data into a k8s secret so it is stored as a secret in k8s. If that’s troublesome you can either create the secret manually without using the chart or you can use a project like helm secrets
to encrypt your values file(s).
Also what version of TrueNAS are you currently running?
Thanks - I am using version:
FreeBSD vmnas.root.dom 12.2-RELEASE-p6 FreeBSD 12.2-RELEASE-p6 df578562304(HEAD) TRUENAS amd6
And if I ssh to the TrueNas server - try to create a dataset, i.e.
zfs create fast/k8s/nfs/vols/test
truenas ask me to authenticate via its "sudo" functionality and when I type in the password - the dataset is created.
In regards to storing the values file inside k8s - I did not realise it was stored as a secret - I just saw the values stored and it looked like it was stored in plain text to me - but that might just have been my "ui" that decrypted it.
csiDriver:
# should be globally unique for a given cluster
name: "org.democratic-csi.freenas-nfs"
storageClasses:
- name: freenas-nfs-csi
defaultClass: true
reclaimPolicy: Retain
volumeBindingMode: Immediate
allowVolumeExpansion: true
parameters:
fsType: nfs
mountOptions:
- noatime
secrets:
provisioner-secret:
controller-publish-secret:
node-stage-secret:
node-publish-secret:
controller-expand-secret:
driver:
config:
driver: freenas-nfs
instance_id:
httpConnection:
protocol: http
host: 192.168.0.201
port: 80
allowInsecure: true
apiKey: "2-qEjchKvqI7QimbvONfM4vbNopomKuHpNC0ffnNY8QOPdXlyr0gxPDhSv1BgzXC05"
apiVersion: 2
sshConnection:
host: 192.168.0.201
port: 22
username: k8s
password: "<masked>"
zfs:
cli:
sudoEnabled: true
datasetParentName: fast/k8s/nfs/vols
detachedSnapshotsDatasetParentName: fast/k8s/nfs/snaps
datasetEnableQuotas: true
datasetEnableReservation: false
datasetPermissionsMode: "0777"
datasetPermissionsUser: k8s
datasetPermissionsGroup: wheel
nfs:
shareHost: 192.168.0.201
shareAlldirs: false
shareAllowedHosts: []
shareAllowedNetworks: []
shareMaprootUser: ""
shareMaprootGroup: ""
shareMapallUser: k8s
shareMapallGroup: wheel
I guess helm itself stores the full values in the cluster as secrets as well yes (unless you've configured helm to use configmaps which I wouldn't recommend).
My guess is you haven't enabled passwordless sudo for the k8s
user. This bit from the README may help:
# if on CORE 12.0-u3+ you should be able to do the following
# which will ensure it does not get reset during reboots etc
# at the command prompt
cli
# after you enter the truenas cli and are at that prompt
account user query select=id,username,uid,sudo_nopasswd
# find the `id` of the user you want to update (note, this is distinct from the `uid`)
account user update id=<id> sudo=true
account user update id=<id> sudo_nopasswd=true
# optional if you want to disable password
#account user update id=<id> password_disabled=true
# exit cli by hitting ctrl-d
# confirm sudoers file is appropriate
cat /usr/local/etc/sudoers
I guess helm itself stores the full values in the cluster as secrets as well yes (unless you've configured helm to use configmaps which I wouldn't recommend).
My guess is you haven't enabled passwordless sudo for the
k8s
user. This bit from the README may help:
True - I did not notice that - it would be nice to have as a comment in the "values.yaml" example - so people know its a hard requirement that passwordless sudo is set up.
But it seems like it does not change a thing - at least not for me:
From my "cli"
{'id': 35, 'sudo': True, 'sudo_nopasswd': True, 'username': 'k8s'}]
From my sudoers
k8s ALL=(ALL) NOPASSWD: ALL
%k8s ALL=(ALL) ALL
But still my k8s cluster logs:
failed to provision volume with StorageClass "truenas-nfs": rpc error: code = Internal desc = Error: sudo: a terminal is required to read the password; either use the -S option to read from standard input or configure an askpass helper sudo: a password is required
But to make it fair - even though it seems like its set up correctly on the truenas server - I cannot even do it passwordless when ssh'ing to the server manually and logging on.
So it seems like the passwordless sudo on truenas is not working as expected.
I will dig into this further - but at least I got a bit further.
Thanks
The issue is the group...sudo has strange behavior in this regard. If you're going to enable sudo on the group as well do the following:
- remove the
sudo_nopasswd
from the user - add the
sudo_nopasswd
to the group
It should then work as desired.
EDIT: alternatively, just remove sudo access from the group and you should also get the behavior you are after
Its very strange - now I can ssh in manually and do:
sudo zfs create fast/k8s/nfs/vols/test
Without getting asked for password - but still I get the same error from k8s.
I will try your suggestion to only give it on the group or client.
That is strange yeah :( let me know how it goes.
That is strange yeah :( let me know how it goes.
It works now - when I removed the sudo from the group.
Now I just need to figure out if I can limit my k8s user from destroying my entire pool - just in case there is a bug in the csi framework.
But that is more a question for the truenas/zfs forum.
Thanks a lot for your support.
That's a very fair concern. The short answer is you can't really (not with how the driver works currently). When using sudo the commands are invoked with root privs anyway so limiting the k8s
user's access won't really help anyway.
At some point I may look into leveraging the zfs delegation but nothing is in place yet :(
I have asked the question on the TrueNAS forum - whether or not its possible to limit access to datasets - so a configured user gets full access to a certain dataset and nothing else.
And looking at that link you sent it seems like ZFS at least supports it - so perhaps its possible if I do not use sudo, and simply use the access control things in TrueNAS so its only on the explicit dataset that it can get access.
Fingers crossed - and if it turns out its possible already - if I stop using sudo, then I will report back here - and it should probably be used as a "best practice" - just like not using the root user :-)
Yeah. There are a couple scenarios where sudo is still required but please do test and see how far you get.
Without sudo enabled it will fail to change the ownership and permissions on the share dir (for nfs) and will fail some volume expansion operations (for iscsi). For testing nfs you’ll want to disable the datasetPermission config options to avoid those failures. It’s mostly due to these reasons that I haven’t fully explored the delegated deployment yet…it’s certainly feasible to not use sudo for zfs but use it for the other scenarios but it simply hasn’t been developed yet.
I just tried with delegated permissions - and now I can fully control what the k8s user can do - but it does not have permissions to mount the dataset, which is required I assume to expose it via nfs.
So I am kind of back to square one.
Perhaps one solution - although it requires changes in the codebase is to "document" that any dataset that is set up for this should use delegated permissions (with documentation of which csi require) - and then only do the ZFS commands via ssh, and the remaining via the api, i.e.
If csi needs to create a dataset - it happens via ssh, but the mounting, sharing via nfs etc happens via the API - then it might work with a regular user without sudo access and with delegated permissions to its own dataset?
Does it make sense what I propose?
I am fully aware that having "root" API access is just a capable of messing up the entire system/pools/datasets etc - but if we limit "root" access to the non zfs things - it should make the integration more secure in the sense if a bug creeps in that would potentially destroy something it should not destroy when the code cleans up datasets, then it would only affect the delegated dataset.
Also if bugs sneak in the API integration code, then it would only affect the more "innocent" things, like sharing, mounting etc.
Of course this "split" responsibility will only work for truenas installations - but if you can make one implementation more "secure" from potential bugs, I think it could be worth it - if its possible..
Alternatively - on the TrueNAS forums, they also suggested to use a jail for the dataset - I am not sure if that would make it easier on permissions, or if its even possible to interact with the jail from a ssh session in any decent way - but perhaps a jail, with a dataset inside that - it could be managed with the "generic " zfs-generic-nfs implementation, since everything could be done with ssh towards the jail, with full "su" access, and even if bugs come up, it will only affect the jail and the dataset that got mounted to that jail.
So basically run a NFS server in a jail, with the dataset mounted to that jail, with full delegation - then whatever runs in the jail can do whatever to the dataset, can mount datasets, share them via ssh - but obviously it would all happen via ssh, since there are probably no api access to jails in truenas.
The mount should happen automatically inheriting the mount point logic from the parent no?
I’m with you on making it secure as possible. It just hasn’t been done and requires some thought to make it as robust as possible.
The mount should happen automatically inheriting the mount point logic from the parent no?
Unfortunately it does not happen - at least not on truenas.
The unpriveleged user is allowed to create a sub dataset in the delegated dataset, but the mount does not happen as far as I see - it even emits a message about this.
Can you get all the properties on the dataset and send it here?
I have solved it:
zfs allow -u k8s clone,create,destroy,mount,promote,receive,rename,rollback,send,share,snapshot,sharenfs,mountpoint fast/k8s
Add sysctl setting:
vfs.usermount=1
So now when I ssh in with my k8s user - I can do whatever i want with the dataset fast/k8s and below - including mounting it - which happens automatically when I do:
zfs create fast/k8s/test
Then it gets mounted to /mnt/fast/k8s/test
So I think it might be possible to do with just using "generic zfs csi" - and by using this way.
I can probably remove many of the delegations - I just delegated all of them that I thought the csi might use.
So I definately think this might be the way forward - so a pure SSH solution is possible and just by using delegation and allowing non-root mounts.
I will definately try it out :-)
Pure ssh is not possible as http is required to manage the shares (ie: insert stuff into the TrueNAS db, etc). Also note that sudo will still be required for some non-zfs operations (such as reloading some services, etc). However all zfs operations could be done over ssh in an underprivileged (non-sudo) fashion however so that is great news!
Regarding the specific permissions there are actually quite a few required to cover the full breadth of what the driver does so I think that above list is probably a great start. If anything fails we can add from there.
I see - but I think that is a decent compromise - since then the driver only needs root access to the API - and not directly to the Zfs commands.
Of course that still allow a bug in the api code to somehow destroy something, but at least it will not impact the zfs pools - which should be the most precious part of a truenas installation, since thats where the data is stored.
Everything else can be recreated - data is harder to recreate - unless you have a very good backup strategy and take snapshots very often.
P.S. I just tested - with sudo=false in my values.yaml - and it does not work:
failed to provision volume with StorageClass "truenas-nfs": rpc error: code = Internal desc = Error: cannot create 'fast/k8s/vols/pvc-e3061070-b0b1-4af2-9bd3-f85e8f813495': permission denied
Which is strange, since I can just ssh as the k8s user and do:
zfs create fast/k8s/vols/pvc-e3061070-b0b1-4af2-9bd3-f85e8f813495
Is that because the driver assumes something, like using sudo is required?
Even though my values contains:
zfs:
cli:
sudoEnabled: false
What is even more strange is that it did manage to create the dataset:
fast/k8s/vols
It was just the last one with the guid it failed to create.
Perhaps its quotas or something else it fails on - let me try to delegate more :-)
I agree 100% it's a decent compromise. While not ideal to still require sudo for some of the other purposes there's not really any ways around that, and having protection/insurance at the zfs level is indeed highly desirable.
Any where I can see what zfs properties that gets set when the dataset gets created?
I have tried with:
zfs allow -u k8s clone,create,destroy,mount,promote,receive,rename,rollback,send,share,snapshot,sharenfs,mountpoint,quota,volsize,snapdir,reservation,readonly,exec,copies,compression fast/k8s
And still it fails.
I even removed the "vols" dataset beneath fast/k8s - and that got created again - so I am thinking its some property or setting the drives tries to set, that it gets the permission denied from.
Progress - I added more delegations and now the pvc dataset gets created, but then it fails when it tries to set some properties:
failed to provision volume with StorageClass "truenas-nfs": rpc error: code = AlreadyExists desc = volume has already been created with a different size, existing size: 0, required_bytes: 10737418240, limit_bytes: 0
And
failed to provision volume with StorageClass "truenas-nfs": rpc error: code = Internal desc = Error: cannot set property for 'fast/k8s/vols/pvc-8c417bd8-f729-47c5-853e-06aa27dcc3be': permission denied
output from zfs get all fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114
.
So properties are getting set by the driver - I wonder where it fails to do something.
I have looked into the code - but javascript is not my strong side - I am more of a c++/c/c# kind of guy.
vmnas# zfs get all fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114
NAME PROPERTY VALUE SOURCE
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 type filesystem -
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 creation Tue Feb 22 20:04 2022 -
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 used 96K -
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 available 6.51T -
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 referenced 96K -
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 compressratio 1.00x -
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 mounted yes -
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 quota none default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 reservation none default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 recordsize 16K inherited from fast
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 mountpoint /mnt/fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 sharenfs off default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 checksum on default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 compression lz4 inherited from fast
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 atime off inherited from fast
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 devices on default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 exec on default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 setuid on default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 readonly off default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 jailed off default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 snapdir hidden default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 aclmode passthrough inherited from fast/k8s
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 aclinherit passthrough inherited from fast
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 createtxg 57196865 -
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 canmount on default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 xattr sa inherited from fast/k8s
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 copies 1 inherited from fast/k8s
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 version 5 -
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 utf8only off -
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 normalization none -
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 casesensitivity sensitive -
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 vscan off default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 nbmand off default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 sharesmb off default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 refquota none default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 refreservation none default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 guid 12125938536443656666 -
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 primarycache all default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 secondarycache all default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 usedbysnapshots 0B -
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 usedbydataset 96K -
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 usedbychildren 0B -
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 usedbyrefreservation 0B -
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 logbias latency default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 objsetid 35688 -
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 dedup off default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 mlslabel none default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 sync standard default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 dnodesize legacy default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 refcompressratio 1.00x -
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 written 96K -
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 logicalused 42.5K -
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 logicalreferenced 42.5K -
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 volmode default default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 filesystem_limit none default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 snapshot_limit none default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 filesystem_count none default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 snapshot_count none default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 snapdev hidden default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 acltype nfsv4 default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 context none default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 fscontext none default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 defcontext none default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 rootcontext none default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 relatime off default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 redundant_metadata all default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 overlay on default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 encryption off default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 keylocation none default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 keyformat none default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 pbkdf2iters 0 default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 special_small_blocks 0 default
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 democratic-csi:volume_context_provisioner_driver freenas-nfs local
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 democratic-csi:csi_volume_name pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 local
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 democratic-csi:managed_resource true local
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 org.truenas:managedby 192.168.17.200 inherited from fast/k8s
fast/k8s/vols/pvc-e3561ccf-05e6-4db3-ac92-901656c1a114 org.freebsd.ioc:active yes inherited from fast
These are my current delegations:
zfs allow -u k8s clone,create,destroy,mount,promote,receive,rename,rollback,send,share,snapshot,sharenfs,mountpoint,quota,volsize,snapdir,reservation,readonly,exec,copies,compression,userquota,aclmode,exec,readonly,groupquota,groupused,userprop,userquota,userused,atime,canmount,checksum,compression,devices,nbmand,normalization,readonly,recordsize,refreservation,reservation,setuid,utf8only,version,volsize,volblocksize,vscan,xattr fast/k8s
Any way I can turn on debug logging of some kind - so it logs more what commands it tries to run?
# values.yaml
controller:
driver:
logLevel: debug
node:
driver:
logLevel: debug
Regarding the error perhaps what happened is the driver tried to set the refuota
when you first deployed and the user didn't have permissions (but it failed silently). Try to delete it entirely and start fresh with the new set of permissions and see how it does.
# values.yaml controller: driver: logLevel: debug node: driver: logLevel: debug
Can I do this in my values.yaml that I give to helm? I have tried editing via kubectl - but it does not seem to give more logging output.
Regarding the error perhaps what happened is the driver tried to set the
refuota
when you first deployed and the user didn't have permissions (but it failed silently). Try to delete it entirely and start fresh with the new set of permissions and see how it does.
I already did that - I have removed the dataset, reapplied delegations, uninstalled the helm chart - reinstalled it - but still I get this permission error after it creates the dataset.
Edit:
I have now added refquota to the list of delegations and it works now with my non-root user.
So my full delegation command is:
zfs allow -u k8s clone,create,destroy,mount,promote,receive,rename,rollback,send,share,snapshot,sharenfs,mountpoint,quota,volsize,snapdir,reservation,readonly,exec,copies,compression,userquota,aclmode,exec,readonly,groupquota,groupused,userprop,userquota,userused,atime,canmount,checksum,compression,devices,nbmand,normalization,readonly,recordsize,refreservation,reservation,setuid,utf8only,version,volsize,volblocksize,vscan,xattr,refquota fast/k8s
And the most important bit I think that it requires the sysctl setting:
systctl vfs.usermount=1
Which can be added via the TrueNAS gui - this allows non-root users to mount filesystems.
So success - sudo is no longer needed for the ssh connction :-)
Thank you for the help.
For future reference it would be awesome if it could be documented, what delegations is required precisely, so users only need to delegate the required bits and not do trial and error like I have done.
The debugging must be added to your helm values yes. I would appreciate any contributions to the documentation to get the delegated setup properly documented and explained for easy use.
I think in the meantime, I'll go rework some bits of the code to unconditionally use sudo
if the user is not root
. Doing so will ensure those things that require sudo
will continue to work while also disabling sudo
for zfs
operations.
The debugging must be added to your helm values yes. I would appreciate any contributions to the documentation to get the delegated setup properly documented and explained for easy use.
Sure - I don't mind helping with the documentation part - if you can just tell me what delegations I should include :-)
I think in the meantime, I'll go rework some bits of the code to unconditionally use
sudo
if the user is notroot
. Doing so will ensure those things that requiresudo
will continue to work while also disablingsudo
forzfs
operations.
I am not sure what you mean by this - will this not be counter-intuitive to what I have been trying to achieve?
With my recipy the SSH connection does not require sudo - if you have set up proper delegation and the correct sysctl setting.
So perhaps add a setting instead of sudo?
i.e.
driver:
config:
driver: freenas-nfs
sshConnection:
host: 192.168.0.201
port: 22
delegation: true
sudo: false
And then in the driver you check whether or not delegation or sudo is in use.
If you have not set up correct delegation, then obviously it requires passwordless sudo to be set up correctly - unless you run as root. But even running as root, in theory it does not guarantee that root has the required permissions - root is just a username - although root usually is the "super user" with all access.
Unless I misunderstand you?
Right now, my user is not allowed to do any sudo, so if you change the code to always require sudo if the username is not root, then my work would be in vain - and I am back to being a possible "victim" of bugs that can destroy my pool.
I honestly don't have a comprehensive list of which delegations are required to cover the feature set. I suspect you've probably given enough at this point. The project has the potential to change as the driver evolves over time as well. I think we'll just need to run it for a bit and see if we run into any situations where something fails due to lack of permissions.
Regarding sudo
here are a few points to consider:
sudo
is always required in the broad sense (executingchmod
,chown
, etc) to properly run the driver- if using delegated
zfs
permissionssudo
may not be required forzfs
operations
I'm updating the code to decouple the scenarios in point 1 from point 2. The situations in point 1 require the use of sudo
when the user is not root
. You cannot delegate chmod
, etc (unless you do some really really really stupid stuff).
I honestly don't have a comprehensive list of which delegations are required to cover the feature set. I suspect you've probably given enough at this point. The project has the potential to change as the driver evolves over time as well. I think we'll just need to run it for a bit and see if we run into any situations where something fails due to lack of permissions.
Ok - no worries - I can just try this out for a bit.
Regarding
sudo
here are a few points to consider:
sudo
is always required in the broad sense (executingchmod
,chown
, etc) to properly run the driver- if using delegated
zfs
permissionssudo
may not be required forzfs
operations
To be honest I don't see why chmod
, chown
etc. should require sudo
- surely all operations will happen within the delegated dataset and is fully within the users control.
And if the initial "root" dataset is created with ownership to the user/group, then even the commands you listed will just work right?
Obviously I don't know much about what the driver does - but in broad sense as I understand it:
- It uses the ssh connection to run zfs commands
- It uses the API connection to export the zfs mounts via NFS (plus other stuff that I don't know about)
Any other operations it needs to do, should hopefully only be relevant to the delegated dataset?
And if so, then no sudo
should be required, since as far as I know - if a user "owns" a folder, then that user can do anything inside that folder. And also with the correct delegations in place, no sudo should be required.
And so far for me it just works with my "plain" user - as long as I delegated all permissions to the user on the "parent" dataset and have allowuser mount, then any dataset is automatically mounted by that user, and seems to be exported just fine.
When I have reclaimPolicy: Delete
is also just removed the dataset as expected.
So from my extremely narrow point of view - delegation is the solution to "all" permission issues and should remove the requirement for sudo - unless you do other stuff on the ssh connection except the zfs command?
EDIT: Just tested - I can do chmod
but not chown
on a folder I created in the delegated dataset - so if the driver really needs to do chown on the datasets that it creates, then yes - sudo
is required - but I did not see any errors of any kind without sudo
, so perhaps its special cases that require sudo
that I have not been using?
I'm not sure who owns the mounted dataset when created by another user and it may be owned by the user. However, if a user (maybe you will not, but others will) set any of the following config options sudo
must be used (if using non-root):
datasetPermissionsMode: "0777"
datasetPermissionsUser: root
datasetPermissionsGroup: wheel
#datasetPermissionsAcls:
#- "-m everyone@:full_set:allow"
#- "-m u:kube:full_set:allow"
Even if the user already owns the directory, chmod
will probably work, but chown
cannot be invoked in this way as non-root users.
For nfs
you should be covered if you don't enable the above options (just comment them out). For iscsi
when a volume resize happens I have to reload the iscsi daemon (ctld
) to make the new size recognized by ctld
(or execute echo 1 > /sys/kernel/scst_tgt/devices/${iscsiName}/resync_size
on scale).
To summarize, for you specifically you may get away with no sudo
access while using nfs
...others may not. If running iscsi
eventually the user will need sudo
access regardless of configuration.
To summarize, for you specifically you may get away with no
sudo
access while usingnfs
...others may not. If runningiscsi
eventually the user will needsudo
access regardless of configuration.
Yes - I was aware that delegation might only fix the issues when being used in the very narrow use case as I have it configured - but I think it would be worth to document as perhaps "best practice" - unless you have very special requirements.
But anyway, thank you very much for your time.
Thank you for all the testing! It will take a couple hours for all the tests to run and to get images built, but here is the fixes: #155
I anticipate to have them ready today and have v1.5.1
snapped. After that I'd love for you to test your setup for a bit with that version and see how things go. We'll leave this issue open and let it settle for a bit and assuming everything works out nicely we'll get the docs updated with all our findings.
OK, v1.5.1
snapped and images built. It should cover the use-case of delegated zfs
permissions but still use sudo
when appropriate (or attempt to) for misc activities as needed.
Hi,
As I wrote earlier I am no js expert, but have you not changed the code so instead of explicitly only using sudo
when configured, to always use it if the username is not root?
Or is that only for special cases you have changed that?
if its a general fix so all ssh commands now require sudo it will break my now "working" solution, since I have turned off sudo for my user.
I am aware that certain options require the use of sudo, but if you can live with a very shallow usecase like mine, where you have set up delegation - uses no special permissions, then sudo=false should be respected?
It only uses it unconditionally when it must (effectively tied to the config options mentioned above datasetPermission*
). The location of the config parameter (sudoEnabled
) is purposely scoped to just the zfs cli configuration, so zfs operations will strictly adhere to the value of the setting (it technically always did, so nothing has changed in this regard).
In short, you should be able to disable sudo
for the user entirely when using nfs
without any adverse effects. Just make sure to not set the datasetPermission*
config options and you should be good to go.
cool - I will give it a go and let you know if it behaves differently from before.
Fantastic thread, was just trying to crack this nut and came here looking for help. I'll sit back and wait a bit until need some testing.
The underlying code behind the zfs operations is quite robust and stable so I think testing now is appropriate. Use v1.5.2
and try with the delegated permissions mentioned above (along with the sysctl parameter).
The delegated permissions is really the aspect we need to nail down so the more testing on that front the better.
I did this a bunch of times, and had great success building on the work done above!
The key items are:
- zfs delegation
- The
chown k8s:k8s /mnt/main/k8s/iscsi
to make that non-root - The tunable to allow non-root to mount
Seems to be working with no root access at all to API nor sudo
with ssh. The delegation probably should be trimmed down to only what is relevant, but at least this is limited to just this dataset and its descendants.
Here's a breakdown of what I did on TrueNAS (12.0-U8), in the GUI:
Create non-root User:
Note that sudo
& password
have been disabled.
- Username: k8s
- Home directory:
/mnt/main/users/k8s
- Shell:
/usr/local/bin/bash
- Email: N/A
- Password Disabled: true
- Lock User: false
- Permit Sudo: false
- Microsoft Account: false
- Samba Authentication: false
Created Two Datasets:
Created "k8s" and "iscsi" under pool main (main/k8s/iscsi
), using the following defaults:
- Sync: Inherit (standard)
- Compression: Inherit (lz4)
- Enable Atime: Inherit (off)
- Encryption: Inherit (encrypted)
- Record Size: Inherit (129Kib)
- ACL Mode: Passthrough
Create Tunable to allow non-root to mount
- System > Tunables:
- Variable:
vfs.usermount
- Value:
1
- Type:
sysctl
- Description: Allows non-root users to mount filesystems.
- Enabled: (checked)
Delegate ZFS Permissions to non-root account "k8s" for dataset "main/k8s"
On the TrueNAS CLI as root:
# zfs allow -u k8s clone,create,destroy,mount,promote,receive,rename,rollback,send,share,snapshot,sharenfs,mountpoint,quota,volsize,snapdir,reservation,readonly,exec,copies,compression,userquota,aclmode,exec,readonly,groupquota,groupused,userprop,userquota,userused,atime,canmount,checksum,compression,devices,nbmand,normalization,readonly,recordsize,refreservation,reservation,setuid,utf8only,version,volsize,volblocksize,vscan,xattr,refquota main/k8s
Set non-root as owner of iscsi
directory
On TrueNAS side must chown
directory to the non-root account or you will get permission denied as root would own the mountpoint. Skipping this step gives "failed to provision volume with StorageClass "freenas-iscsi-csi": rpc error: code = Internal desc = Error: cannot mount '/mnt/main/k8s/iscsi/v': failed to create mountpoint: Permission denied"
.
# chown k8s:k8s /mnt/main/k8s/iscsi
Relevant part of freenas-iscsi.yaml
for HTTP/s API and SSH:
(I use SSL Port 443 for API)
httpConnection:
protocol: https
host: truenas.[REDACTED]
port: 443
apiKey: [REDACTED]
allowInsecure: False
#apiVersion: 2
sshConnection:
host: truenas.[REDACTED]
port: 22
username: k8s
privateKey: |
-----BEGIN OPENSSH PRIVATE KEY-----
b [REDACTED] =
-----END OPENSSH PRIVATE KEY-----
Clean Install of democratic-csi
:
I did not see anything specific showing that csi v1.5.2
was used, but I just did:
$ helm upgrade --install --create-namespace --values freenas-iscsi.yaml --namespace democratic-csi zfs-iscsi democratic-csi/democratic-csi
Release "zfs-iscsi" does not exist. Installing it now.
NAME: zfs-iscsi
LAST DEPLOYED: Sat Feb 26 15:36:29 2022
NAMESPACE: democratic-csi
STATUS: deployed
REVISION: 1
TEST SUITE: None
$ helm list -n democratic-csi
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
zfs-iscsi democratic-csi 1 2022-02-26 15:36:29.704596387 -0500 EST deployed democratic-csi-0.10.1 1.0
Create PVC:
$ kubectl -n democratic-csi create -f test-claim-iscsi.yaml
Validation Steps:
$ kubectl -n democratic-csi get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
test-claim-iscsi Bound pvc-fe4d439f-c5a5-48bc-8dec-19f79f8044dc 1Gi RWO freenas-iscsi-csi 4m1
$ kubectl describe pvc/test-claim-iscsi -n democratic-csi
Name: test-claim-iscsi
Namespace: democratic-csi
StorageClass: freenas-iscsi-csi
Status: Bound
Volume: pvc-fe4d439f-c5a5-48bc-8dec-19f79f8044dc
Labels: <none>
Annotations: pv.kubernetes.io/bind-completed: yes
pv.kubernetes.io/bound-by-controller: yes
volume.beta.kubernetes.io/storage-class: freenas-iscsi-csi
volume.beta.kubernetes.io/storage-provisioner: org.democratic-csi.iscsi
volume.kubernetes.io/storage-provisioner: org.democratic-csi.iscsi
Finalizers: [kubernetes.io/pvc-protection]
Capacity: 1Gi
Access Modes: RWO
VolumeMode: Filesystem
Used By: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Provisioning 10s org.democratic-csi.iscsi_zfs-iscsi-democratic-csi-controller-7d7c7868b5-h2kx8_26442678-03fb-4d3f-83ce-4b7f3dcb7ef9 External provisioner is provisioning volume for claim "democratic-csi/test-claim-iscsi"
Normal ExternalProvisioning 10s (x2 over 10s) persistentvolume-controller waiting for a volume to be created, either by external provisioner "org.democratic-csi.iscsi" or manually created by system administrator
Normal ProvisioningSucceeded 6s org.democratic-csi.iscsi_zfs-iscsi-democratic-csi-controller-7d7c7868b5-h2kx8_26442678-03fb-4d3f-83ce-4b7f3dcb7ef9 Successfully provisioned volume pvc-fe4d439f-c5a5-48bc-8dec-19f79f8044dc
Back on the TrueNAS Side:
root@truenas[/]# zfs list -r main/k8s
NAME USED AVAIL REFER MOUNTPOINT
main/k8s 704K 24.5T 208K /mnt/main/k8s
main/k8s/iscsi 496K 24.5T 208K /mnt/main/k8s/iscsi
main/k8s/iscsi/v 288K 24.5T 200K /mnt/main/k8s/iscsi/v
main/k8s/iscsi/v/pvc-05257700-96dd-46bc-a389-5adaee4f1499 88K 24.5T 88K -
zfs get -o property,value,source all main/k8s/iscsi/v/pvc-05257700-96dd-46bc-a389-5adaee4f1499 | grep democratic
democratic-csi:freenas_iscsi_extent_id 1 local
democratic-csi:managed_resource true local
democratic-csi:freenas_iscsi_target_id 1 local
democratic-csi:freenas_iscsi_targettoextent_id 5 local
democratic-csi:provision_success true local
democratic-csi:volume_context_provisioner_driver freenas-iscsi local
democratic-csi:freenas_iscsi_assets_name csi-pvc-defb89f7-fad5-4344-a325-414052f2c771-clustera local
democratic-csi:csi_share_volume_context {"node_attach_driver":"iscsi","portal":"truenas.[REDACTED]:3260","portals":"","interface":"","iqn":"iqn.2005-10.org.freenas.ctl:csi-pvc-defb89f7-fad5-4344-a325-414052f2c771-clustera","lun":0} local
democratic-csi:csi_volume_name pvc-defb89f7-fad5-4344-a325-414052f2c771 local
- Some of the captures above were collected at different attempts, so if volumes name and generated numbers don't match, that's why.
I don't have anything deployed yet to make use of this, however I think that looks clean. Please review.
That seems like a pretty good flow for nfs, but iscsi has some different needs:
- iscsi shouldn’t require mount access and chown’ing the parent dataset dir shouldn’t be necessary
- Nor should the user mount property be required for iscsi (although you may want it for nfs anyway)
- in order for resizing to properly work sudo is required so if you want that to work you must reenable (even if zfs is delegated and you don’t use sudo for zfs operations/commands)
- just a note, but access to the api is always/implicitly root access (even if using apiKey)
I should note here that currently the primary purpose of configuring delegation is to limit bad things should some bug make it’s way into the code specifically for zfs operations, not necessarily to mitigate the risks associated with a user having sudo access. As has been mentioned without sudo there are certain things that simply will not work at the moment:
- datasetPermission* operations for nfs driver (chown, chmod)
- iscsi resizing
If you’re on scale you can use the api only driver which eliminates the need for ssh access altogether, but the user/integration is still implicitly super user in that case.
iscsi does require mount and chowning the parent dataset in order for the "v" dataset to be mounted. The non-root user can not mount "v" into "iscsi" if that is root owned. I tried many times, I could not get passed:
"failed to provision volume with StorageClass "freenas-iscsi-csi": rpc error: code = Internal desc = Error: cannot mount '/mnt/main/k8s/iscsi/v': failed to create mountpoint: Permission denied"
Ah I see. You could create that in advance but I see the issue now if you have not pre-created the datasets yes.
So taking your advice above, I deleted everything and disabled the TrueNAS tunable (Should not be needed for iscsi if you create datasets in advance). I did not do any chown or assigning permissions to non-root this time.
I created main/k8s/iscsi/v
and main/k8s/iscsi/s
in advance
zfs create -o org.freenas:description="Persistent Storage for Kubernetes" main/k8s
zfs create -o org.freenas:description="Container to hold iSCSI zvols and snapshots" main/k8s/iscsi
zfs create -o org.freenas:description="Storage Container to hold zvols" main/k8s/iscsi/v
zfs create -o org.freenas:description="Storage Container to hold detached snapshots" main/k8s/iscsi/s
I reduced some of the delegation which was used above in previous steps, I cleaned up the duplicates. Still plenty of ones I don't know what they do so I left them in only because they were included above. Perhaps the list can be reduced more by someone more knowledgeable. NOTE: I applied it to the main/k8s/iscsi
dataset instead since nfs
delegation would be different.
Above @travisghansen stated "Nor should the user mount property be required for iscsi", which I assume meant the mount
delegation was not needed, so I left it out:
zfs allow -u k8s aclmode,canmount,checksum,clone,create,destroy,devices,exec,groupquota,groupused,mountpoint,nbmand,normalization,promote,quota,readonly,recordsize,refquota,refreservation,receive,rename,reservation,rollback,send,setuid,share,snapdir,snapshot,userprop,userquota,userused,utf8only,version,volblocksize,volsize,vscan,xattr main/k8s/iscsi
Claim Failed:
Warning ProvisioningFailed 8s (x4 over 15s) org.democratic-csi.iscsi_zfs-iscsi-democratic-csi-controller-7d7c7868b5-hdgqs_ebf6ea51-ce6e-42f3-bfb8-d80cb20430cb failed to provision volume with StorageClass "freenas-iscsi-csi": rpc error: code = Internal desc = Error: cannot create 'main/k8s/iscsi/v/pvc-be16a758-db4a-4ca7-8458-42ff2a738985': permission denied
I added mount delegation back:
zfs allow -u k8s mount main/k8s/iscsi
Then claim works:
Normal ProvisioningSucceeded 2s org.democratic-csi.iscsi_zfs-iscsi-democratic-csi-controller-7d7c7868b5-hdgqs_ebf6ea51-ce6e-42f3-bfb8-d80cb20430cb Successfully provisioned volume pvc-e0a96fac-1584-4af2-adf0-dd7b77745d9c
So mount is required for iSCSI.
Thanks for all the research! I wasn’t very clear about what I meant. I was referring to the sysctl for user mounts not the delegated mount property on the zfs dataset.
I’m surprised the zfs property is needed as well frankly, but that’s why we’re testing so we can lock it all down and get it sanely documented :)
Looking at your comment about zvol resize, I've never tried to resize before so this was good learning for me as well.
TrueNAS side, started with:
root@truenas[~]# zfs get volsize main/k8s/iscsi/v/pvc-e0a96fac-1584-4af2-adf0-dd7b77745d9c
NAME PROPERTY VALUE SOURCE
main/k8s/iscsi/v/pvc-e0a96fac-1584-4af2-adf0-dd7b77745d9c volsize 1G local
I edited the claim test:
$ sudo kubectl edit pvc test-claim-iscsi -n democratic-csi
persistentvolumeclaim/test-claim-iscsi edited
Where I bumped 1Gi to 2Gi:
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi
TrueNAS side picks it up:
root@truenas[~]# zfs get volsize main/k8s/iscsi/v/pvc-e0a96fac-1584-4af2-adf0-dd7b77745d9c
NAME PROPERTY VALUE SOURCE
main/k8s/iscsi/v/pvc-e0a96fac-1584-4af2-adf0-dd7b77745d9c volsize 2G local
TruneNAS > Sharing > iSCSI > Extents:
Device: main/k8s/iscsi/v/pvc-e0a96fac-1584-4af2-adf0-dd7b77745d9c (2G)
Sure enough, I see where sudo was attempted in the status of the claim:
volume "pvc-e0a96fac-1584-4af2-adf0-dd7b77745d9c" by resizer "org.democratic-csi.iscsi" failed: rpc error: code = Unknown desc = error reloading iscsi daemon: {"stderr":"\nWe trust you have received the usual lecture from the local System\nAdministrator. It usually boils down to these three things:\n\n #1) Respect the privacy of others.\n #2) Think before you type.\n #3) With great power comes great responsibility.\n\nsudo: a terminal is required to read the password; either use the -S option to read from standard input or configure an askpass helper\nsudo: a password is required\n","code":1}
So when I look at the API DOCS on my TrueNAS Core install (just place /api/docs
at the end of your instance hostname).
I see a reference to restart service via API:
service.restart
Arguments:
{
"title": "service",
"type": "string"
}
{
"type": "object",
"properties": {
"ha_propagate": {
"type": "boolean"
}
},
"additionalProperties": false,
"title": "service-control",
"default": {}
}
Can that be used instead of sudo
?
Perhaps. A reload is needed not a restart however…a restart will drop existing connections and generally cause chaos. Do you see a reload method by chance?
Perhaps. A reload is needed not a restart however…a restart will drop existing connections and generally cause chaos. Do you see a reload method by chance?
Here ya go:
service.reload
Arguments:
{
"title": "service",
"type": "string"
}
{
"type": "object",
"properties": {
"ha_propagate": {
"type": "boolean"
}
},
"additionalProperties": false,
"title": "service-control",
"default": {}
}
Yeah that works. I've got it prototyped. I should probably figure in which version of TN/FN that was introduced and only use it as appropriate. Now to use the api for the permissions/chmod/chown activities and then you can use a completely sudo-less user for both nfs and iscsi :)
These help?
filesystem.setacl
{
"type": "object",
"properties": {
"path": {
"type": "string"
},
"uid": {
"type": [
"integer",
"null"
]
},
"gid": {
"type": [
"integer",
"null"
]
},
"dacl": {
"type": "array",
"items": [
{
"type": "object"
},
{
"type": "object"
}
]
},
"nfs41_flags": {
"type": "object",
"properties": {
"autoinherit": {
"type": "boolean"
},
"protected": {
"type": "boolean"
}
},
"additionalProperties": false
},
"acltype": {
"type": "string",
"enum": [
"NFS4",
"POSIX1E",
"RICH"
]
},
"options": {
"type": "object",
"properties": {
"stripacl": {
"type": "boolean"
},
"recursive": {
"type": "boolean"
},
"traverse": {
"type": "boolean"
},
"canonicalize": {
"type": "boolean"
}
},
"additionalProperties": false
}
},
"additionalProperties": false,
"title": "filesystem_acl",
"default": {}
}
Set ACL of a given path. Takes the following parameters: path
full path to directory or file.
dacl
"simplified" ACL here or a full ACL.
uid
the desired UID of the file user. If set to None (the default), then user is not changed.
gid
the desired GID of the file group. If set to None (the default), then group is not changed.
recursive
apply the ACL recursively
traverse
traverse filestem boundaries (ZFS datasets)
strip
convert ACL to trivial. ACL is trivial if it can be expressed as a file mode without losing any access rules.
canonicalize
reorder ACL entries so that they are in concanical form as described in the Microsoft documentation MS-DTYP 2.4.5 (ACL)
In all cases we replace USER_OBJ, GROUP_OBJ, and EVERYONE with owner@, group@, everyone@ for consistency with getfacl and setfacl. If one of aforementioned special tags is used, 'id' must be set to None.
An inheriting empty everyone@ ACE is appended to non-trivial ACLs in order to enforce Windows expectations regarding permissions inheritance. This entry is removed from NT ACL returned to SMB clients when 'ixnas' samba VFS module is enabled.
filesystem.setperm
{
"type": "object",
"properties": {
"path": {
"type": "string"
},
"mode": {
"type": [
"string",
"null"
]
},
"uid": {
"type": [
"integer",
"null"
]
},
"gid": {
"type": [
"integer",
"null"
]
},
"options": {
"type": "object",
"properties": {
"stripacl": {
"type": "boolean"
},
"recursive": {
"type": "boolean"
},
"traverse": {
"type": "boolean"
}
},
"additionalProperties": false
}
},
"additionalProperties": false,
"title": "filesystem_permission",
"default": {}
}
Remove extended ACL from specified path.
If mode
is specified then the mode will be applied to the path and files and subdirectories depending on which options
are selected. Mode should be formatted as string representation of octal permissions bits.
uid
the desired UID of the file user. If set to None (the default), then user is not changed.
gid
the desired GID of the file group. If set to None (the default), then group is not changed.
stripacl
setperm will fail if an extended ACL is present on path, unless stripacl is set to True.
recursive
remove ACLs recursively, but do not traverse dataset boundaries.
traverse
remove ACLs from child datasets.
If no mode
is set, and stripacl
is True, then non-trivial ACLs will be converted to trivial ACLs. An ACL is trivial if it can be expressed as a file mode without losing any access rules.
It’s actually setperm that I need but I’m already using it for the pure api scale driver so should be easy to leverage that code. Will take me a little bit to rework everything but should be doable.
Reworked code to use the api for resize / permissions operations here: d275ecc
You can test it out using the next
images. The only TrueNAS scenario that doesn't currently work is iscsi resizing in SCALE when using the ssh-based driver (there is no working api method to do this atm). If using the api-only driver with SCALE resizing works fine because the call to resize the volume automatically handles the lun resize operation transparently through the api.
I uninstalled everything thinking I'd use a clean install of your "next" image, but I'm not sure how to consume that image via helm
. What's the right way to do this? I thought it would just be some combination of democratic-csi/democratic-csi/next
or democratic-csi/democratic-csi:next
values.yaml
for helm
controller:
driver:
image: democraticcsi/democratic-csi:next
imagePullPolicy: Always
logLevel: debug
node:
driver:
image: democraticcsi/democratic-csi:next
imagePullPolicy: Always
logLevel: debug
And then use the values.yaml
like this?
helm upgrade --install --create-namespace --values values.yaml --values freenas-iscsi.yaml --namespace democratic-csi zfs-iscsi democratic-csi/democratic-csi
Was trying to confirm it was using the next image...
$ kubectl get pods -n democratic-csi -o jsonpath="{.items[*].spec.containers[*].image}" | tr -s '[[:space:]]' '\n' | grep next | uniq
democraticcsi/democratic-csi:next
I'll do some testing on it tomorrow, thanks for the assistance.
I should note that when using the api for chown you must set the values to numeric values and cannot use user and group names.
I reviewed the freenas-iscsi.yaml
and didn't see where to set numeric values, I don't have any user or group names defined.
I completely removed the ssh
section, just left the API section:
driver:
config:
driver: freenas-iscsi
instance_id:
httpConnection:
protocol: https
host: truenas.rich-durso.us
port: 443
apiKey: [ REDACTED ]
allowInsecure: False
#apiVersion: 2
Test claim went fine:
$ kubectl -n democratic-csi create -f test-claim-iscsi.yaml
persistentvolumeclaim/test-claim-iscsi created
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Provisioning 35s org.democratic-csi.iscsi_zfs-iscsi-democratic-csi-controller-7cf8c844f-wh89s_cc168fe8-c63e-42f6-9859-3ae2ae823530 External provisioner is provisioning volume for claim "democratic-csi/test-claim-iscsi"
Normal ExternalProvisioning 32s (x3 over 35s) persistentvolume-controller waiting for a volume to be created, either by external provisioner "org.democratic-csi.iscsi" or manually created by system administrator
Normal ProvisioningSucceeded 31s org.democratic-csi.iscsi_zfs-iscsi-democratic-csi-controller-7cf8c844f-wh89s_cc168fe8-c63e-42f6-9859-3ae2ae823530 Successfully provisioned volume pvc-12e8d579-5e2f-4004-9841-8db4f0ab8309
Tried to edit the claim:
$ kubectl edit pvc test-claim-iscsi -n democratic-csi
persistentvolumeclaim/test-claim-iscsi edited
Conditions:
Type Status LastProbeTime LastTransitionTime Reason Message
---- ------ ----------------- ------------------ ------ -------
FileSystemResizePending True Mon, 01 Jan 0001 00:00:00 +0000 Tue, 01 Mar 2022 09:21:24 -0500 Waiting for user to (re-)start a pod to finish file system resize of volume on node.
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Provisioning 7m1s org.democratic-csi.iscsi_zfs-iscsi-democratic-csi-controller-7cf8c844f-wh89s_cc168fe8-c63e-42f6-9859-3ae2ae823530 External provisioner is provisioning volume for claim "democratic-csi/test-claim-iscsi"
Normal ExternalProvisioning 6m58s (x3 over 7m1s) persistentvolume-controller waiting for a volume to be created, either by external provisioner "org.democratic-csi.iscsi" or manually created by system administrator
Normal ProvisioningSucceeded 6m57s org.democratic-csi.iscsi_zfs-iscsi-democratic-csi-controller-7cf8c844f-wh89s_cc168fe8-c63e-42f6-9859-3ae2ae823530 Successfully provisioned volume pvc-12e8d579-5e2f-4004-9841-8db4f0ab8309
Warning ExternalExpanding 47s volume_expand Ignoring the PVC: didn't find a plugin capable of expanding the volume; waiting for an external controller to process this PVC.
Normal Resizing 47s external-resizer org.democratic-csi.iscsi External resizer is resizing volume pvc-12e8d579-5e2f-4004-9841-8db4f0ab8309
Normal FileSystemResizeRequired 46s external-resizer org.democratic-csi.iscsi Require file system resize of volume on node
I noticed the condition to restart the node, so I tried this:
$ kubectl -n democratic-csi rollout restart daemonsets,deployment
daemonset.apps/zfs-iscsi-democratic-csi-node restarted
deployment.apps/zfs-iscsi-democratic-csi-controller restarted
But the condition remains...
Conditions:
Type Status LastProbeTime LastTransitionTime Reason Message
---- ------ ----------------- ------------------ ------ -------
FileSystemResizePending True Mon, 01 Jan 0001 00:00:00 +0000 Tue, 01 Mar 2022 09:21:24 -0500 Waiting for user to (re-)start a pod to finish file system resize of volume on node.
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Provisioning 32m org.democratic-csi.iscsi_zfs-iscsi-democratic-csi-controller-7cf8c844f-wh89s_cc168fe8-c63e-42f6-9859-3ae2ae823530 External provisioner is provisioning volume for claim "democratic-csi/test-claim-iscsi"
Normal ExternalProvisioning 32m (x3 over 32m) persistentvolume-controller waiting for a volume to be created, either by external provisioner "org.democratic-csi.iscsi" or manually created by system administrator
Normal ProvisioningSucceeded 32m org.democratic-csi.iscsi_zfs-iscsi-democratic-csi-controller-7cf8c844f-wh89s_cc168fe8-c63e-42f6-9859-3ae2ae823530 Successfully provisioned volume pvc-12e8d579-5e2f-4004-9841-8db4f0ab8309
Warning ExternalExpanding 26m volume_expand Ignoring the PVC: didn't find a plugin capable of expanding the volume; waiting for an external controller to process this PVC.
Normal Resizing 26m external-resizer org.democratic-csi.iscsi External resizer is resizing volume pvc-12e8d579-5e2f-4004-9841-8db4f0ab8309
Normal FileSystemResizeRequired 26m external-resizer org.democratic-csi.iscsi Require file system resize of volume on node
I don't see any obvious errors.... suggestions?
You can't remove the ssh
section. All zfs
operations still run over ssh. The FileSystemResizePending
does not mean you need to restart the csi pods, it simply means a pod must be using the volume and the node resize process will happen (it will resize the filesystem on the lun). When that condition appears (despite the message) just sit and exercise patience...it will resize on it's own (assuming a pod is actively using the volume).
Regarding the user/group those settings are only applicable to nfs so not an issue with iscsi. I'm referring to these config options:
...
datasetPermissionsMode: "0777"
datasetPermissionsUser: root # must be numeric when using api to set permissions
datasetPermissionsGroup: wheel # must be numeric when using api to set permissions
Went back over my notes, while I removed the SSH section from the yaml, I did not reinstall the helm chart.. so that edit didn't do anything.
After some more testing, created a new claim, created a nginx pod to use the claim, and then resized the claim with the nginix pod running and just waited a few seconds and I think everything worked as expected.
The 2nd claim bumped to 2Gi
kubectl get pvc -A
NAMESPACE NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
democratic-csi test-claim-iscsi Bound pvc-12e8d579-5e2f-4004-9841-8db4f0ab8309 1Gi RWO freenas-iscsi-csi 132m
default test-claim-iscsi Bound pvc-1c25c12a-b338-49eb-81c4-e413417e0627 2Gi RWO freenas-iscsi-csi 10m
Capacity: 2Gi
Access Modes: RWO
VolumeMode: Filesystem
Used By: task-pv-pod
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ExternalProvisioning 7m26s persistentvolume-controller waiting for a volume to be created, either by external provisioner "org.democratic-csi.iscsi" or manually created by system administrator
Normal Provisioning 7m26s org.democratic-csi.iscsi_zfs-iscsi-democratic-csi-controller-59f5f77864-fqj29_5ddcb17a-4c73-4dd8-b616-c6d60fa405b5 External provisioner is provisioning volume for claim "default/test-claim-iscsi"
Normal ProvisioningSucceeded 7m22s org.democratic-csi.iscsi_zfs-iscsi-democratic-csi-controller-59f5f77864-fqj29_5ddcb17a-4c73-4dd8-b616-c6d60fa405b5 Successfully provisioned volume pvc-1c25c12a-b338-49eb-81c4-e413417e0627
Warning ExternalExpanding 43s volume_expand Ignoring the PVC: didn't find a plugin capable of expanding the volume; waiting for an external controller to process this PVC.
Normal Resizing 43s external-resizer org.democratic-csi.iscsi External resizer is resizing volume pvc-1c25c12a-b338-49eb-81c4-e413417e0627
Normal FileSystemResizeRequired 42s external-resizer org.democratic-csi.iscsi Require file system resize of volume on node
Normal FileSystemResizeSuccessful 15s kubelet MountVolume.NodeExpandVolume succeeded for volume "pvc-1c25c12a-b338-49eb-81c4-e413417e0627"
Inside the pod:
# df -h /usr/share/nginx/html
Filesystem Size Used Avail Use% Mounted on
/dev/sdd 2.0G 35M 2.0G 2% /usr/share/nginx/html
Anything else to check?
Great! Not really other than to make sure the api call was used to reload ctld vs a command over ssh. If the user does not have sudo
then that's pretty well a given that it worked so we're probably good.
If you wish to confirm with certainty you would need to review the logs of the controller pod (csi-driver
container) and look for the reload
service api request.
I see this on the TrueNAS side, I assume that isn't important?
Mar 1 11:17:39 truenas 1 2022-03-01T11:17:39.677313-05:00 truenas.[REDACTED] ctld 91366 - - no LUNs defined for target "iqn.2005-10.org.freenas.ctl:csi-pvc-1c25c12a-b338-49eb-81c4-e413417e0627-clustera"
Found in the csi-driver
logs:
{"level":"verbose","message":"FreeNAS reloading iscsi daemon using api","service":"democratic-csi"}
{"level":"debug","message":"FREENAS HTTP REQUEST: {\"method\":\"POST\",\"url\":\"https://truenas.[REDACTED]/api/v2.0/service/reload\",\"headers\":{\"Accept\":\"application/json\",\"User-Agent\":\"democratic-csi-driver\",\"Content-Type\":\"application/json\"},\"json\":true,\"body\":{\"service\":\"iscsitarget\",\"service-control\":{\"ha_propagate\":true}},\"agentOptions\":{\"rejectUnauthorized\":true}}","service":"democratic-csi"}
Details:
{"level":"info","message":"new response - driver: FreeNASSshDriver method: ControllerGetCapabilities response: {\"capabilities\":[{\"rpc\":{\"type\":\"CREATE_DELETE_VOLUME\"}},{\"rpc\":{\"type\":\"LIST_VOLUMES\"}},{\"rpc\":{\"type\":\"GET_CAPACITY\"}},{\"rpc\":{\"type\":\"CREATE_DELETE_SNAPSHOT\"}},{\"rpc\":{\"type\":\"LIST_SNAPSHOTS\"}},{\"rpc\":{\"type\":\"CLONE_VOLUME\"}},{\"rpc\":{\"type\":\"EXPAND_VOLUME\"}},{\"rpc\":{\"type\":\"GET_VOLUME\"}},{\"rpc\":{\"type\":\"SINGLE_NODE_MULTI_WRITER\"}}]}","service":"democratic-csi"}
{"level":"info","message":"new request - driver: FreeNASSshDriver method: ControllerExpandVolume call: {\"_events\":{},\"_eventsCount\":1,\"call\":{},\"cancelled\":false,\"metadata\":{\"_internal_repr\":{\"user-agent\":[\"grpc-go/1.40.0\"]},\"flags\":0},\"request\":{\"secrets\":\"redacted\",\"volume_id\":\"pvc-1c25c12a-b338-49eb-81c4-e413417e0627\",\"capacity_range\":{\"required_bytes\":\"2147483648\",\"limit_bytes\":\"0\"},\"volume_capability\":{\"access_mode\":{\"mode\":\"SINGLE_NODE_MULTI_WRITER\"},\"mount\":{\"mount_flags\":[],\"fs_type\":\"xfs\",\"volume_mount_group\":\"\"},\"access_type\":\"mount\"}}}","service":"democratic-csi"}
{"level":"debug","message":"operation lock keys: [\"volume_id_pvc-1c25c12a-b338-49eb-81c4-e413417e0627\"]","service":"democratic-csi"}
{"level":"verbose","message":"ZfsProcessManager command: /usr/local/sbin/zfs get -Hp -o name,property,value,received,source volblocksize main/k8s/iscsi/v/pvc-1c25c12a-b338-49eb-81c4-e413417e0627","service":"democratic-csi"}
{"level":"verbose","message":"ZfsProcessManager command: /usr/local/sbin/zfs set volsize=\"2147483648\" main/k8s/iscsi/v/pvc-1c25c12a-b338-49eb-81c4-e413417e0627","service":"democratic-csi"}
{"level":"verbose","message":"FreeNAS reloading iscsi daemon using api","service":"democratic-csi"}
{"level":"debug","message":"FREENAS HTTP REQUEST: {\"method\":\"POST\",\"url\":\"https://truenas.[REDACTED]/api/v2.0/service/reload\",\"headers\":{\"Accept\":\"application/json\",\"User-Agent\":\"democratic-csi-driver\",\"Content-Type\":\"application/json\"},\"json\":true,\"body\":{\"service\":\"iscsitarget\",\"service-control\":{\"ha_propagate\":true}},\"agentOptions\":{\"rejectUnauthorized\":true}}","service":"democratic-csi"}
{"level":"debug","message":"FREENAS HTTP ERROR: null","service":"democratic-csi"}
{"level":"debug","message":"FREENAS HTTP STATUS: 200","service":"democratic-csi"}
{"level":"debug","message":"FREENAS HTTP HEADERS: {\"server\":\"nginx\",\"date\":\"Tue, 01 Mar 2022 16:24:21 GMT\",\"content-type\":\"text/plain; charset=utf-8\",\"content-length\":\"4\",\"connection\":\"close\",\"strict-transport-security\":\"max-age=63072000; includeSubDomains; preload\",\"x-content-type-options\":\"nosniff\",\"x-xss-protection\":\"1; mode=block\",\"permissions-policy\":\"geolocation=(),midi=(),sync-xhr=(),microphone=(),camera=(),magnetometer=(),gyroscope=(),fullscreen=(self),payment=()\",\"referrer-policy\":\"strict-origin\",\"x-frame-options\":\"SAMEORIGIN\"}","service":"democratic-csi"}
{"level":"debug","message":"FREENAS HTTP BODY: true","service":"democratic-csi"}
{"level":"info","message":"new response - driver: FreeNASSshDriver method: ControllerExpandVolume response: {\"capacity_bytes\":2147483648,\"node_expansion_required\":true}","service":"democratic-csi"}
{"level":"info","message":"new request - driver: FreeNASSshDriver method: Probe call: {\"_events\":{},\"_eventsCount\":1,\"call\":{},\"cancelled\":false,\"metadata\":{\"_internal_repr\":{\"user-agent\":[\"grpc-node/1.24.0-pre1 grpc-c/8.0.0 (linux; chttp2; game)\"]},\"flags\":0},\"request\":{}}","service":"democratic-csi"}
{"level":"debug","message":"performing exec sanity check..","service":"democratic-csi"}
{"level":"info","message":"new response - driver: FreeNASSshDriver method: Probe response: {\"ready\":{\"value\":true}}","service":"democratic-csi"}
I don't know why you would see that warning...I'm assuming there is indeed a lun defined for the target otherwise you wouldn't be able to attach to it and use the volume.
In any case, the logs look exactly like what we're after so that part is good.
It shows lun 0
-- perhaps it assigns 0
if one is not specified?
I just did:
$ kubectl apply -f pv-pod.yaml
persistentvolumeclaim/test-claim-iscsi created
pod/task-pv-pod created
TrueNAS Console then shows:
Mar 1 12:57:19 truenas 1 2022-03-01T12:57:19.778710-05:00 truenas ctld 91366 - - no LUNs defined for target "iqn.2005-10.org.freenas.ctl:csi-pvc-914daf4b-2c59-4fe6-913b-f107198f12e8-clustera"
Is there an annotation (or something else) which can be used in the claim to populate the extent's "Description" field?
Well, was that error from when the volume was provisioned? You should only see that during initial creation of the volume as the target gets created and then later the lun assigned (never to be removed unless/until the volume is deleted).
comment: "", // TODO: allow this to be templated
I guess I never allowed for setting the comment on the extent field..
comment: "", // TODO: allow this to be templated
I guess I never allowed for setting the comment on the extent field..
Should I open an issue to request this?
Sure.
Has someone been able to get rootless NFS shares working on Linux?
Can you elaborate more on what you want to achieve?
I want to avoid having to give root access to the CSI driver on the storage box. The problems seems to be that new NFS exports cannot be created by non-root users on Linux. Unable to create temporary file: Permission deniedcannot share 'tank/k8s/ds: system error': NFS share creation failed property may be set but unable to reshare filesystem
Which driver are you using? Can you send over the logs?
This is before even using the driver, just manually settings the sharenfs property as a non-root user. I can reproduce this on different hosts. I just wanted to confirm that this is expected and that no workaround exists.
I see so you're using delegated permissions and trying to set the sharenfs
property on the dataset as a non-root user and that failure is what you see?
Correct. Environment is Ubuntu 22.04.
Do you have all the deps installed? openzfs/zfs#4534
Yes of course. I'm perfectly able to create the export as root. Are you able to create it as non-root on Linux?
I've never actually tried to run a fully delegated setup no. Just wanted to make sure it was specific to delegation and not a general issue.
Honestly that behavior seems odd to me but I don't exactly how the internals of it are handled by zfsd or whatever it is that handles those. Do the exports generally show up in /etc/exports
or similar when run successfully as root?
Zfs doesn't use /etc/exports
to create the share. Instead it alters /var/lib/nfs/etab
and calls exportfs
. I tried changing owners of the directory and files, but that doesn't help. The error seems to come from https://github.com/openzfs/zfs/blob/master/lib/libshare/nfs.c#L102 however I don't know where it's trying to create the temp file.
Well you certainly know more than me about the matter! I've just asked in the irc channel to see if anyone has some input they can provide.
Can you possibly run the zfs command with strace to figure out what folder etc it's trying to create etc?
Thanks for the hint. With strace I found that it was trying to write to /etc/exports.d/zfs.exports. Giving permissions on this file (and directory) setting the sharenfs property did not err anymore, however the share was still not created. I additionally had to give permissions to /var/lib/nfs/etab (and containing directory), then it works.! :)
We definitely need to get that documented!
It would be great to test the same for sharesmb as well and document what is needed there. The upcoming release will debut support for windows nodes/clusters and so smb has far greater test coverage etc than previously.
I managed to get non-root sharesmb going, too:
Apart from the zfs allow permissions, it also requires write access to /etc/exports.d/zfs.exports
. Additionally, smb.conf needs usershare allow guests = yes
and the user must be part of the sambashare
group.