Fork me on GitHub

One image,
every protocol.

Which protocol carries a file is a property of the client at the other end. macOS and Windows reach for SMB, a Linux fleet already has NFS, a browser or a phone has HTTP. Running four servers, each with its own configuration and its own idea of who alice is, is a way to get three of them subtly wrong. Pure Go, CGO_ENABLED=0. BSD-3-Clause.

5 protocols, one configuration8 filesystems, plus 4 by partitionCGO=0 one static binary
fileshare โ€” zsh
# which protocols this binary actually has โ€” ask it
$ fileshare --protocol nope -i photos.img -u alice -p pw
fileshare: --protocol names none this binary has:
it has nfs, s3, sftp, smb and webdav

# what it would serve, and to whom, before a restart
$ fileshare check -c fileshare.hcl
this configuration can be served
5 protocols โ€” one directory answers all of them, and not with the same people
Before anything is restarted

It says what it would do, and why it would refuse.

fileshare check opens every image and prints every share against every protocol, and every person against every protocol. The matrix below is real output, with nothing edited but the width of this page.

fileshare check โ€” zsh
FILESHARE

SHARE   IMAGE                FILESYSTEM  WHO MAY CONNECT           WHO MAY WRITE             SMB  NFS  WEBDAV  SFTP  S3
photos  /tmp/srv/photos.img  fat32       alice                     alice                     yes  NO   yes     yes   yes
public  /tmp/srv/pub.img     fat32       anyone who authenticates  anyone who authenticates  yes  yes  yes     yes   yes

photos is not served over nfs: it is restricted to alice, and NFSv3 on its own has no authentication: AUTH_UNIX is a claim the client makes about itself and the wire cannot disagree with it. A kerberos block lifts this: sec=krb5 carries a principal a ticket proves; so does identity = "certificate" on the nfs serve block: RPC-over-TLS with a client certificate naming the person

USER   FROM                    AUTHENTICATES WITH           SMB  WEBDAV  SFTP  S3
alice  the configuration file  a password from /tmp/srv/pw  yes  yes     -     yes
bob    the configuration file  1 key                        -    -       yes   -

this configuration can be served
Why go-fileshare

The protocols do not agree about who is asking.

That is a fact about the protocols, not a limitation here. What a person can be served over depends on what the directory holds for them โ€” so the honest thing is to compute that matrix and print it, rather than leave it to be discovered at a mount.

๐Ÿ”

What proves somebody differs by protocol

SMB needs NTLMv2, so it needs the password or its MD4(UTF16LE(password)). S3 needs the password itself, because SigV4 is an HMAC computed from it. SFTP takes a public key or a certificate. A person holding only a key reaches SFTP and nothing else.

๐Ÿšซ

A refusal, not a warning

A share that names who may use it is not exported over NFS. A configuration saying photos belongs to alice and a protocol handing photos to whoever connects cannot both be honoured, and quietly widening access is the worse of the two failures.

๐ŸŽซ

Kerberos, or a certificate, lifts that refusal

A kerberos block gives NFS something to check: sec=krb5 carries a principal a ticket proves, rather than a uid the client asserts. The realm is compared, not just the name before the @ โ€” two realms can each have an alice. Or identity = "certificate": RPC-over-TLS, and the person named in the client certificate, checked against its CRL at every call.

๐Ÿ“‹

Said before it is served

fileshare check opens every image and prints every share against every protocol and every person against every protocol. A name that belongs to no user block is refused at startup rather than locking Alice out of her own share.

๐Ÿ’ฝ

One image, opened once

fat32, exfat, ext4, ntfs, ufs, iso9660, squashfs and hfs+, with apfs, btrfs, xfs and zfs by partition โ€” read by go-filesystems. Every protocol shares that one open image behind one lock. A block device works the same way, and a directory is served through an os.Root, so a link out of it is refused by the kernel.

๐Ÿ—„๏ธ

Storage it creates, under a quota

Through the admin API, a privileged fileshare provisioner creates volumes โ€” ZFS datasets, btrfs subvolumes, XFS and ext4 directories under a project quota, by go-fsctl โ€” and the server, which holds no privilege, serves shares from them. It refuses to serve one as root or with CAP_SYS_RESOURCE, which ext4 lets past the quota. Linux only; no Ceph yet.

๐ŸŽ“

Your institution's login

An oidc block admits the people an identity provider vouches for โ€” such as go-authn/bridge in front of a SAML federation: a token over WebDAV, the provider's SSH certificate or an opkssh one over SFTP, a client certificate over NFS. Shares name its groups and domains. Certificates from the EuroHPC SSH CA can be filtered too. With ssh_domains, a certificate is accepted only where its domain grant names this host, and only from the addresses it is pinned to. That covers the CA itself and bridge issuing in its profile.

โ›”

Taken back everywhere, failing closed

The provider's KRL and CRL are fetched, their signatures and expiry verified, never taken older than the one held โ€” across a restart too. A CAEP session-revoked over shared signals voids what no list can name. A list that cannot be had refuses, rather than lets everyone through.

โš–๏ธ

Judged by other people's clients

Samba's smbclient, macOS's Finder, Windows' own redirector, OpenSSH's sftp, mount_nfs. A fixture built from one reading of a protocol can only confirm that reading โ€” which is how the one defect only Windows could find was found.

What each protocol needs

Five answers to who is asking.

smb

NTLMv2. Needs the password, or its MD4(UTF16LE(password)) โ€” an NT hash is enough, and is what a directory should hold if SMB is all it serves.

nfs

Nothing, on its own. AUTH_UNIX is a claim the client makes about itself and the wire cannot disagree with it โ€” so a restricted share is not exported here at all, unless a kerberos block gives it sec=krb5, or identity = "certificate" takes the person from a client certificate over RPC-over-TLS (RFC 9289).

webdav

HTTP Basic, or a bearer token an identity provider signed. The most forgiving of the five: a verifier the directory can only check is enough.

sftp

A public key or a certificate: one a trusted CA signed, the identity provider’s own, or an OpenPubkey (opkssh) one. Somebody with only authorized_keys reaches SFTP and none of the others โ€” and somebody with only a password does not reach it.

s3

A SigV4 signature: an HMAC computed from the secret, which therefore has to be the password itself and not a hash of it. A share is a bucket.

In a browser, or natively

Many servers, one login.

Written once in Go with go-widgets: the same code is a page served by the portal and a native window. The console and the explorer are each tested in headless Chrome, behind the real portal binary, in front of real fileshare binaries.

portal v0.3.1

The server behind the UIs. It logs a person in (OIDC), keeps the session in encrypted cookies, holds a token per fileshare server, and passes the admin API (Connect) and WebDAV through. The page never sees a token. Files are served inert: a document on a share cannot run as the portal.

console v0.3.2

The admin console: shares, grants, volumes and server state on every fileshare server a portal knows, from one page. It runs in a browser behind the portal, or as a native window that logs in through the system browser.

explorer v0.3.0

The file explorer: browse, upload, download, rename, copy and delete. Uploads go in pieces, so a browser never holds a whole file, and one that fails resumes where it stopped – by the same file only. A rename never replaces a file already there, and a delete takes two presses. In a browser behind the portal, or as a native window that logs in through the system browser.

5
protocols from one configuration file
1
image, opened once, behind one lock
โ‰ฅ70%
coverage the CI gate enforces on fileshare
6
Linux architectures, four of them under qemu โ€” plus macOS and Windows on their own

File sharing that ships like Go.

No cgo, no frameworks, no runtime to install. A build tag leaves a protocol out of the binary entirely, and --isolate gives each one its own process, opening only the images it may serve. The people can come from a user block, a database or LDAP โ€” the same users block authnd reads, so a site describes its directory once โ€” or from an identity provider. Shares can be changed live through a gRPC admin API, and TLS comes from files or ACME.

Read the source on GitHub โ†’