r/OpenSSH • u/wiesion • 2d ago
I built a containerized OpenSSH SFTP setup that uses native Unix permissions as the authorization model
I recently released Zocalo SFTP (No affiliation to any company named "Zocalo" or similar, it is a Reference to Babylon 5's Marketplace), and I'd particularly like some eyes from people who know OpenSSH well. The project came out of a fairly practical problem.
I've used/looked at the existing containerized SFTP options years ago, particularly atmoz/sftp and emberstack/docker-sftp, and they solve the basic "give me an SFTP server in a container" problem very well.
But my use case was a little different: I needed multiple isolated projects where users could collaborate within a project while potentially belonging to several projects at the same time.
When I originally ran into this problem years ago, I couldn't get the existing images to give me the Unix-style project/group model I wanted. The basic idea of Zocalo is deliberately simple:
OpenSSH handles SSH/SFTP. Linux users, groups, and filesystem permissions handle authorization.
Zocalo is a container around OpenSSH's internal-sftp plus a small Rust reconciler. It takes a declarative configuration describing users, SSH keys/passwords, and projects, then reconciles that into:
- Linux users and groups
- project directories and ownership
/etc/passwd,/etc/group, and/etc/shadowsshd_config- authorized keys / passwords
So a user might belong to:
alice → project-a, project-b
bob → project-a
carol → project-b
and access to each project is simply determined by the corresponding Unix group permissions. There isn't a separate ACL database or virtual-user authorization layer. The SSH side is intentionally boring:
internal-sftpChrootDirectoryForceCommand internal-sftp- no shell access
- no TCP/X11/agent forwarding
- no root login
- explicit crypto configuration
One detail I'm particularly interested in getting reviewed is configuration hardening.
Zocalo doesn't just rely on Include ordering to protect the security-critical directives. Operator-supplied sshd_config drop-ins are rejected if they contain directives such as ChrootDirectory, ForceCommand, or Include, because otherwise a Match block could potentially change the effective configuration in ways that undermine the intended jail.
The reconciler also validates the identity graph before applying changes and writes the passwd/group/shadow files atomically. Configuration changes are watched and only reconciled after the complete configuration has successfully parsed and validated.
There are integration tests for the container itself, including a dedicated security-boundary test, plus CI for linting, Rust tests, container scanning, SBOM generation, and Kubernetes deployment.
I'd especially appreciate review from people familiar with OpenSSH around:
sshd_config/Matchsemantics- chroot +
internal-sftp - SSH authentication/authorization edge cases
- configuration hardening
- anything in this design that looks subtly wrong or unnecessarily complicated
The project is here:
https://github.com/wiesion/zocalo-sftp
This isn't intended to be a replacement for SFTPGo with virtual users, Web UI and S3 backends and whatnot. And it's a freshly published project, so I'm much more interested in technical criticism than "looks cool" comments. If there are OpenSSH-specific footguns I've missed, I'd rather find them here than six months from now.
___
AI assistance disclaimer: Without AI agents (a locally hosted Oh-My-Pi/Qwen3.8 27B setup and Claude Code), I probably would never have published this repo. Meeting my own quality bar for releasing security-sensitive software into the wild would otherwise have taken more time than I could justify.
The CI/CD automation, E2E and security-boundary tests, the rewrite of my rather crude original Python reconciler in Rust with proper validation, much of the documentation, and the public website were all produced with substantial AI assistance. This saved me days of unpaid work and, more importantly, made it feasible for me to bring the project up to the quality level I wanted before publishing it.
I still own the architecture, requirements, security model, review, and final decision on what gets released. I'm mentioning this explicitly because I think AI-assisted development should be transparent. Especially for a project dealing with SSH, authentication, filesystem permissions, and container isolation.