Jail And Container Configuration With Bind Mounts
Defining Bind Mounts
What are bind mounts?
Bind mounts are a mechanism to expose a file or directory on the host system into a chroot jail or Linux container. They allow sharing of configuration files, application code, and data between the host and isolated environments. Bind mounts map a path from the host file system hierarchy into the sandboxed filesystem namespace.
How bind mounts provide separation
Jails and containers provide process, networking, and filesystem isolation from the host system. However, some sharing between environments is often necessary. Bind mounts selectively bridge the gap to provide controlled access for sharing directories and files.
For example, application configuration may be managed on the host but needs to be exposed into containers. Or shared libraries on the host may need mounting into multiple jails. Bind mounts provide this bridge in a secure way.
Bind mount types and use cases
There are two main types of bind mounts:
- Read-only – Shared directories from host exposed read-only
- Read-write – Shared directories with read-write access
Read-only bind mounts are generally recommended as they prevent any state from being changed on the host. Some common use cases include:
- Application code/binaries – Mounted read-only
- Configuration – Mounted read-only
- Log directories – Mounted read-write
- Data directories – Mounted read-write
Configure bind mounts carefully based on the specific sharing needs between host and containers. Favor read-only wherever possible.
Configuring Bind Mounts for Jails
Enabling bind mounts in jail.conf
To use bind mounts in a FreeBSD jail, the admin must first enable the mount capability in the jail configuration. This is done in jail.conf by adding:
mount; mount.devfs;
The mount capability allows mounting filesystems in general. And mount.devfs specifically allows mounting devfs to expose host devices.
Mounting host directories into jails
With mounting enabled, host directories are exposed via fstab syntax. For example:
/usr/local/www /jails/web/usr/local/www nullfs ro 0 0
This will mount the host’s web root directory into the jail at the same path. The nullfs indicates it is bind mounted versus a discrete filesystem.
Read-only versus read-write mounts
Be default bind mounts are read-only. This prevents the jail from writing to or modifying the host system.
To mount a directory read-write instead, change the mount options to rw like:
/tmp /jails/web/tmp nullfs rw 0 0
This would allow full read-write access on /tmp between the host and jail.
Example jail.conf bind mount configurations
Some common examples include:
# Application code read-only /usr/local/www /jails/web/usr/local/www nullfs ro 0 0 # Writable log dir /var/log/web /jails/web/var/log nullfs rw 0 0
And for application dependencies:
# Binaries /usr/local/bin /jails/app/usr/local/bin nullfs ro 0 0 # Shared libs /usr/local/lib /jails/app/usr/local/lib nullfs ro 0 0
Always validate that the jail starts properly after making bind mount changes before deploying into production.
Leveraging Bind Mounts with Docker and Podman
Dockers built-in bind mount options
Docker natively supports bind mounting host directories into containers using the -v argument. For example:
docker run -v /host/directory:/container/directory image-name
This will expose /host/directory from the host into the container at /container/directory.
Sharing configuration via named volumes
Docker named volumes can also be used for sharing configuration:
docker volume create config docker run -v config:/container/config image-name
This creates a shared volume that can be mounted into multiple containers.
Read-only bind mounts for application code
Make use of the built-in :ro option to mount directories read-only:
docker run -v /host/code:/container/code:ro image-name
This is useful for mounting in shared application code read-only.
Example Podman container launch with bind mounts
Podman supports the same -v bind mount syntax as Docker. For example:
podman run -v /host/config:/container/config:ro -v /host/data:/container/data:rw image-name
This launches a Podman container with the host config directory mounted read-only, and a writable data directory mount.
Securing Bind Mounts Against Container Breakout
Mount namespaces and privilege requirements
There are potential security implications of bind mounts to consider. Containers use mount namespaces to establish independent filesystem views.
Privileged containers are able to mount over directories on the host system to “breakout” of the container namespace. Similar risks exist with read-write bind mounts.
Risks of writable mounts to the host system
If a container vulnerability allows executing code in the context of the container, read-write bind mounts pose further risk.
For example, if /host/logs is mounted into the container read-write an exploit could manipulate host log files. Or inject monitoring tools to gather data from the host system.
Recommendations for read-only mounts only
To limit exposure only mount directories read-only unless write access is absolutely required:
docker run -v /host/code:/container/code:ro image-name
This eliminates the possibility of container breakout risk from bind mounts.
Dropping privileges with user namespacing
Additional mitigations include running containers with a non-root user via Docker’s userns-remap option. This adds user namespacing:
docker run --userns=host -u 1000:1000 image-name
User namespaces provide additional privilege separation between the container and host system.