Docker CIFS – How to Mount CIFS as a Docker Volume
In my environment I’m using a drobo CIFS NAS storage device. Data on the NAS is exported over CIFS to various servers. I have a few docker containers that need read/write access to the data stored on CIFS. However, when attempting to use the docker -v option to bind mount the cifs share into the docker container I ran into “permission denied” issues caused by SELinux and the CIFS mount UID/GID mapping. Here’s how I solved them.
In this article we will
The docker container will not be permitted to access your CIFS mount point unless you or mount the share with the appropriate SELinux security context.
The context used to make this work on my CentOS 7 host is:
Here’s an example of the fstab entry to mount the CIFS share on /mnt/cifs_share:
#/etc/fstab //10.0.0.200/cifs_share /mnt/cifs_share cifs defaults,username=USER,password=PASS,context=system_u:object_r:svirt_sandbox_file_t:s0 0 0
Mapping Local User Permissions to CIFS Share Permissions
Unlike NFS, a CIFS mount handles user authentication at mount time. This means that all files and directories at our CIFS mount point will be owned by the same user/group. This may be a problem if the user of the process running in your container and the user of the CIFS mount are not the same. I worked around this by mounting the same CIFS share multiple times with different uid and gid arguments.
To mount a CIFS share as a particular user use the uid, gid, forceuid and forcegid mount.cifs options.
# from 'man mount.cifs' uid=arg - sets the uid that will own all files or directories on the mounted filesystem when the server does not provide ownership information. It may be specified as either a username or a numeric uid. When not specified, the default is uid 0. The mount.cifs helper must be at version 1.10 or higher to support specifying the uid in non-numeric form. See the section on FILE AND DIRECTORY OWNERSHIP AND PERMISSIONS below for more information. forceuid -instructs the client to ignore any uid provided by the server for files and directories and to always assign the owner to be the value of the uid= option. gid=arg - sets the gid that will own all files or directories on the mounted filesystem when the server does not provide ownership information. It may be specified as either a groupname or a numeric gid. When not specified, the default is gid 0. The mount.cifs helper must be at version 1.10 or higher to support specifying the gid in non-numeric form. forcegid - instructs the client to ignore any gid provided by the server for files and directories and to always assign the owner to be the value of the gid= option.
Here’s an example FSTAB entry to mount CIFS share as local user “nobody” at path /mnt/cifs_share-nobody
#/etc/fstab #mount CIFS share as local user "nobody" at path /mnt/cifs_share-nobody //10.0.0.200/cifs_share /mnt/cifs_share-nobody cifs username=USER,password=PASS,uid=nobody,forceuid,gid=nobody,forcegid,context=system_u:object_r:svirt_sandbox_file_t:s0
Creating the Docker CIFS enabled container
Now that we have the CIFS share mounted as the appropriate user with the necessary SELinux context on the host OS we can use it in our Docker container as a data volume with the “docker run -v” option.
#from 'man docker-run' -v, --volume=volume[:ro|:rw] Bind mount a volume to the container. The -v option can be used one or more times to add one or more mounts to a container. These mounts can then be used in other containers using the --volumes-from option. The volume may be optionally suffixed with :ro or :rw to mount the volumes in read-only or read-write mode, respectively. By default, the volumes are mounted read-write. See examples.
Now, let’s mount our “nobody” CIFS share as /data in an example ubuntu Docker container that runs bash.
docker run -it -v /mnt/cifs_share-nobody:/data # Create a test file from the Host OS [root@dockerbox ~]# touch /mnt/cifs_share-nobody/testfile # Run an ubuntu:trusty container mounting our CIFS volume as /data inside [root@dockerbox ~]# docker run -it -v /mnt/cifs_share-nobody:/data ubuntu:trusty /bin/bash # Access our CIFS share from inside the container root@c90e78c4f38e:/# ls /data testfile
And there you have it. Access to a CIFS share from inside a Docker container.
More about CIFS Permissions from the mount.cifs man page:
File And Directory Ownership And Permissions The core CIFS protocol does not provide unix ownership information or mode for files and directories. Because of this, files and directories will generally appear to be owned by whatever values the uid= or gid= options are set, and will have permissions set to the default file_mode and dir_mode for the mount. Attempting to change these values via chmod/chown will return success but have no effect. When the client and server negotiate unix extensions, files and directories will be assigned the uid, gid, and mode provided by the server. Because CIFS mounts are generally single-user, and the same credentials are used no matter what user accesses the mount, newly created files and directories will generally be given ownership corresponding to whatever credentials were used to mount the share. If the uid's and gid's being used do not match on the client and server, the forceuid and forcegid options may be helpful. Note however, that there is no corresponding option to override the mode. Permissions assigned to a file when forceuid or forcegid are in effect may not reflect the the real permissions. When unix extensions are not negotiated, it's also possible to emulate them locally on the server using the "dynperm" mount option. When this mount option is in effect, newly created files and directories will receive what appear to be proper permissions. These permissions are not stored on the server however and can disappear at any time in the future (subject to the whims of the kernel flushing out the inode cache). In general, this mount option is discouraged. It's also possible to override permission checking on the client altogether via the noperm option. Server-side permission checks cannot be overriden. The permission checks done by the server will always correspond to the credentials used to mount the share, and not necessarily to the user who is accessing the share.