This documentation is part of the "Projects with Books" initiative at zenOSmosis.
The source code for this project is available on GitHub.
User and Permissions
Relevant source files
Purpose and Scope
This page documents the user account and permission model used within the docker-sshfs container. It explains how the sshuser account is configured, why the /samba-share directory has world-writable permissions (777), and how FUSE's user_allow_other option enables cross-service filesystem access between SSHFS and Samba processes.
For information about SSHFS mount options that interact with these permissions, see 5.3. For details about the Samba configuration that enforces user identity, see 5.1).
The sshuser Account
The container creates a dedicated non-root user account specifically for running SSHFS mount operations. This account is created during the Docker image build process.
Account Specifications
| Property | Value | Location |
|---|---|---|
| Username | sshuser | Dockerfile9 |
| Password | sshpass | Dockerfile9 |
| User Type | Non-root with home directory | Dockerfile9 |
| UID | 1000 (default for first non-root user) | Assigned by useradd |
| GID | 1000 (default primary group) | Assigned by useradd |
The account is created using the useradd command with the -m flag to create a home directory:
useradd -m sshuser && echo "sshuser:sshpass" | chpasswd
Sources : Dockerfile9
Role in the System
The sshuser account serves three critical functions:
- SSHFS Mount Owner : When users manually execute
sshfscommands inside the container, they typically do so assshuserviadocker exec - File Operation Identity : All files accessed through Samba are forced to use
sshuseras the effective user (viaforce user = sshuserin smb.conf19) - Permission Boundary : This account provides a consistent identity layer between the guest-authenticated SMB clients and the remote SSH server
Sources : Dockerfile9 smb.conf19
Directory Permissions
The container's filesystem uses deliberately permissive settings to enable cross-service access between SSHFS mounts and Samba shares.
/samba-share Directory Permissions
The /samba-share directory is configured with 777 permissions (read, write, execute for all users):
chmod -R 777 /samba-share
Permission Breakdown :
| Octal | Binary | Owner | Group | Other |
|---|---|---|---|---|
| 777 | 111 111 111 | rwx | rwx | rwx |
This configuration is set at Dockerfile21 Notably, line 20 contains a commented-out alternative approach:
# RUN chown -R sshuser:sshuser /samba-share
This indicates that the design evolved from ownership-based access control to permission-based access control, choosing broad permissions over restricted ownership.
Sources : Dockerfile:20-21
Why 777 Permissions Are Used
The 777 permission mode is necessary because:
- Multiple Process Access : Both the
smbddaemon and SSHFS mount processes need write access to directories under/samba-share - Symbolic Link Traversal : The symbolic link at
/samba-share/remote(created at Dockerfile30) points to/remote, and both services must traverse this link - Unknown Client UIDs : macOS clients connecting as "guest" might have their requests mapped to various internal UIDs by Samba
- Write-Through Requirements : Files created by macOS clients must be writable through the SSHFS mount to the remote SSH server
Sources : Dockerfile21 Dockerfile30
FUSE user_allow_other Configuration
The most critical permission setting for cross-service integration is the FUSE user_allow_other option, enabled in /etc/fuse.conf.
Configuration Line
The Dockerfile appends this setting to the FUSE configuration:
echo "user_allow_other" >> /etc/fuse.conf
This occurs at Dockerfile24
Sources : Dockerfile24
What user_allow_other Does
By default, FUSE mounts are only accessible by the user who performed the mount operation. When sshuser mounts a remote filesystem via SSHFS to /remote, only sshuser can read or write files at that mount point.
graph TD
subgraph "Without user_allow_other"
SSHFS1["sshfs mount by sshuser\nMounted at: /remote"]
SambaProc1["smbd process\nRunning as: root or other user"]
Access1["File Access Denied"]
SSHFS1 -->|Access check| Access1
SambaProc1 -->|Attempts to read /remote| SSHFS1
end
subgraph "With user_allow_other"
SSHFS2["sshfs mount by sshuser\nOptions: allow_other\nMounted at: /remote"]
SambaProc2["smbd process\nRunning as: root or other user"]
Access2["File Access Granted"]
SSHFS2 -->|Access check allow_other active| Access2
SambaProc2 -->|Attempts to read /remote| SSHFS2
end
The user_allow_other setting changes this behavior:
Permission Flow :
- Without
user_allow_other: FUSE kernel module checks if requesting process UID matches mount owner UID - With
user_allow_other+allow_othermount option: FUSE allows access from any user, delegating permission checks to the underlying filesystem
Sources : Dockerfile24
Interaction with SSHFS Mount Options
The /etc/fuse.conf setting enables the capability , but users must also specify -o allow_other when mounting with SSHFS:
Without the system-level user_allow_other configuration in /etc/fuse.conf, the allow_other mount option would be rejected with an error like:
fusermount: option allow_other only allowed if 'user_allow_other' is set in /etc/fuse.conf
Sources : Dockerfile24
Samba Force User Mechanism
The Samba configuration enforces a consistent user identity for all file operations, regardless of how clients authenticate.
Configuration Settings
The [SSHFS Share] section in smb.conf contains:
This appears at smb.conf19 alongside guest access settings:
Sources : smb.conf:13-14 smb.conf19
graph LR
subgraph "macOS Client Request Flow"
MacOS["macOS Finder\nConnects as: Guest"]
SMBAuth["Samba Authentication\nmap to guest = bad user"]
ForceUser["Force User Transform\nforce user = sshuser"]
FileOp["Filesystem Operation\nEffective UID: 1000 (sshuser)"]
end
MacOS -->|SMB connection| SMBAuth
SMBAuth -->|Guest credentials| ForceUser
ForceUser -->|All operations as sshuser| FileOp
Force User Behavior
The force user directive overrides the authenticated user identity for all filesystem operations:
Effective Result : Whether the macOS client connects as "Guest" (which it must, given guest only = yes), or even if future configurations allowed authenticated users, all file operations would execute as sshuser (UID 1000).
Sources : smb.conf4 smb.conf:13-14 smb.conf19
flowchart TB
subgraph "macOS Client Layer"
Finder["macOS Finder\nUser identity: Varies"]
end
subgraph "Samba Layer (Container)"
SMB["smbd process\nConfiguration applies"]
GuestMap["map to guest = bad user\nGuest authentication"]
ForceUser["force user = sshuser\nUID override to 1000"]
end
subgraph "Filesystem Layer (Container)"
SambaShare["/samba-share\nPermissions: 777\nAccessible by all"]
SymLink["/samba-share/remote\nSymbolic link"]
RemoteMount["/remote\nSSHFS mount point"]
end
subgraph "FUSE Layer (Container)"
FUSEConf["user_allow_other\nin /etc/fuse.conf"]
MountOpts["SSHFS mount options:\nallow_other\nuid=1000\ngid=1000"]
end
subgraph "Remote Layer"
SSH["SSH connection\nAuthenticated as sshuser"]
RemoteFS["Remote filesystem\nFiles owned by remote user"]
end
Finder -->|SMB protocol| SMB
SMB --> GuestMap
GuestMap --> ForceUser
ForceUser -->|UID: 1000| SambaShare
SambaShare --> SymLink
SymLink --> RemoteMount
RemoteMount --> FUSEConf
FUSEConf -->|Allows cross-user access| MountOpts
MountOpts -->|Files appear as UID 1000| SSH
SSH --> RemoteFS
Complete Permission Model
The following diagram maps the complete permission flow from macOS client through Samba and SSHFS to the remote server:
Cross-Service Permission Flow
Sources : smb.conf4 smb.conf19 Dockerfile21 Dockerfile24 Dockerfile30
Permission Requirements by Operation
Different operations in the system have specific permission requirements:
| Operation | Required Permissions | Configuration Source |
|---|---|---|
| Samba reads /samba-share | World-readable (r--) | Dockerfile21 |
| Samba writes to /samba-share | World-writable (-w-) | Dockerfile21 |
| Samba traverses symlink | World-executable (--x) | Dockerfile21 |
| Samba accesses /remote | user_allow_other + allow_other | Dockerfile24 |
| SSHFS mounts remote files | User sshuser credentials | Manual sshfs command |
| Files created via Samba | Owned by UID 1000 (forced) | smb.conf19 |
| File permission on creation | 0777 (create_mask) | smb.conf17 |
| Directory permission on creation | 0777 (directory_mask) | smb.conf18 |
Sources : Dockerfile21 Dockerfile24 smb.conf:17-19
graph TD
subgraph "Identity Layers"
Layer1["Layer 1: macOS Client\nIdentity: Guest (varies)"]
Layer2["Layer 2: Samba Process\nForced Identity: sshuser (UID 1000)"]
Layer3["Layer 3: SSHFS Mount\nFile Owner: UID 1000"]
Layer4["Layer 4: Remote SSH Server\nIdentity: SSH user (varies)"]
end
Layer1 -->|force user = sshuser| Layer2
Layer2 -->|Filesystem operations| Layer3
Layer3 -->|uid=1000 mount option| Layer4
UID/GID Mapping
The system uses consistent UID/GID values to maintain identity across service boundaries:
Identity Mapping Table
Key Points :
- UID 1000 : The numeric user ID for
sshuser, used consistently across Samba and SSHFS - GID 1000 : The primary group ID for
sshuser - SSHFS uid/gid options : When mounting with
uid=1000,gid=1000, files on the remote server appear to be owned by UID 1000 locally, enabling write access
Sources : Dockerfile9 smb.conf19
Why This Permission Model Works
The permission architecture solves a complex cross-service access problem:
The Core Challenge
Two separate processes with different identities need to access the same mounted filesystem:
- The
smbddaemon (running as root or dedicated samba user) - The SSHFS mount (owned by
sshuser)
The Solution Components
| Component | Purpose | Why It's Necessary |
|---|---|---|
sshuser account | Consistent identity | Provides a known UID (1000) for both Samba and SSHFS |
777 on /samba-share | Permissive directory access | Allows any process to traverse and write |
user_allow_other in fuse.conf | Enable cross-user FUSE access | Allows smbd to read sshuser's mounts |
allow_other mount option | Activate cross-user access | Must be specified when mounting |
force user = sshuser | Identity enforcement | Ensures Samba operations use UID 1000 |
uid=1000,gid=1000 mount options | File ownership mapping | Makes remote files appear owned by sshuser |
Sources : Dockerfile9 Dockerfile21 Dockerfile24 smb.conf19
Security Implications
The permission model prioritizes functionality over strict security , which is appropriate given the container's isolation:
Relaxed Security Elements
- World-Writable Directories : The
777permissions on/samba-shareallow any process in the container to modify files - Guest-Only Access : No authentication required to connect via SMB (smb.conf:13-14)
- Hardcoded Password : The
sshuserpassword issshpass, visible in the Dockerfile - Privileged Container : The container typically runs with
--privilegedflag to enable FUSE
Mitigating Factors
- Container Isolation : Permissions are isolated within the container namespace
- Localhost Port Binding : SMB ports are bound to
127.0.0.1only (see 3.3) - Single-Purpose Container : No other services or users exist in the container
- Controlled Environment : Users explicitly choose to run this container and trust its purpose
Sources : Dockerfile9 Dockerfile21 smb.conf:13-14
Code-to-System Entity Mapping
The following table maps permission-related identifiers in code to their system-level meanings:
| Code Identifier | File | Line(s) | System Entity | Purpose |
|---|---|---|---|---|
sshuser | Dockerfile | 9 | Linux user account | SSHFS mount owner |
sshpass | Dockerfile | 9 | Password string | Authentication credential |
useradd -m | Dockerfile | 9 | Command | User creation with home dir |
777 | Dockerfile | 21 | Octal permission | World-readable/writable/executable |
user_allow_other | Dockerfile | 24 | FUSE config option | Enable cross-user mount access |
/etc/fuse.conf | Dockerfile | 24 | Config file path | FUSE system configuration |
force user | smb.conf | 19 | Samba directive | Override client user identity |
guest ok | smb.conf | 13 | Samba directive | Allow guest connections |
guest only | smb.conf | 14 | Samba directive | Enforce guest authentication |
map to guest | smb.conf | 4 | Samba directive | Guest authentication trigger |
create mask | smb.conf | 17 | Samba directive | New file permissions |
directory mask | smb.conf | 18 | Samba directive | New directory permissions |
Sources : Dockerfile9 Dockerfile21 Dockerfile24 smb.conf4 smb.conf:13-14 smb.conf:17-19
Summary
The docker-sshfs container implements a permission model that uses:
- A dedicated
sshuseraccount (UID 1000) as the consistent identity layer - World-writable permissions (
777) on/samba-sharefor cross-process access - FUSE's
user_allow_otherconfiguration to enable Samba access to SSHFS mounts - Samba's
force userdirective to normalize all client operations tosshuser - Consistent UID/GID mapping (1000:1000) across SSHFS mount options
This architecture trades strict security controls for operational simplicity, relying on Docker's container isolation to maintain security boundaries. The result is a system where macOS clients can seamlessly access remote SSH filesystems through Samba without encountering permission-denied errors.
Sources : Dockerfile9 Dockerfile21 Dockerfile24 smb.conf4 smb.conf:13-14 smb.conf:17-19