file-server
Secure file server with the following characteristics.
- Public key cryptography is used for authentication
- User information is stored in a PostgreSQL database
- No shell file access
⚠ This is a work in progress and not ready for production yet ⚠
Implementation Status
Working
- SSH public key authentication against keys stored in PostgreSQL; keys added
through the API take effect without a restart
- SFTP access confined to each user's own directory
- SFTP operations
- upload, download and opening files for both reading and writing
- list directories and stat files
- create and remove directories (non-empty directories are not removed)
- remove files
- rename files and directories without overwriting an existing target
- set size (truncate), permissions, and access and modification times
- Interactive shell sessions are rejected with a message
- SSH idle timeout and a cap on concurrent SSH connections
- HTTP API to create, list and delete users and their public keys, with
Swagger documentation
- Graceful shutdown of both the SSH and HTTP servers on
SIGINT/SIGTERM
To be implemented
- Authentication and authorisation of the HTTP API;
administrative_users is
validated at startup but not used yet
- SFTP operations that currently return an error
- symbolic and hard links (
Symlink, Link, Lstat, Readlink)
posix-rename@openssh.com and statvfs@openssh.com extensions
- changing file ownership
- Removal of a user's directory when the user is deleted (it is currently left
on disk)
Storage
- Files of each user are stored in
<path_users_directory>/<username>, which
is created on the first SFTP session. SFTP clients cannot reach anything
outside this directory.
- Users and their public keys are stored in PostgreSQL tables
users and
user_credentials. The schema is migrated automatically at startup. A user
cannot be deleted while it still has credentials.
Configuration
Configuration is loaded via viper. Environment
variables take precedence over the configuration file.
Command-line flags
The server accepts no command-line flags or arguments.
Configuration file
A configuration file named .file-server.<ext> in the user's home directory is
loaded automatically if it exists. Supported extensions include yaml, yml,
json, toml, properties, and ini. Keys are the environment variables
without the FILESERVER_ prefix.
host_key: ./keys/ecdsa.key
ssh_port: 8822
api_port: 8880
path_users_directory: ./data/files
path_database_connection_string: ./keys/database_connection_string
ssh_idle_timeout: 5m
ssh_max_connections: 100
administrative_users:
- alex
Environment variables
All environment variables are prefixed with FILESERVER_.
| Variable |
Description |
FILESERVER_PATH_DATABASE_CONNECTION_STRING |
File path to a text file containing the PostgreSQL connection string on its first line |
FILESERVER_HOST_KEY |
File path to the SSH host private key |
FILESERVER_SSH_PORT |
Port of the SSH/SFTP server |
FILESERVER_API_PORT |
Port of the HTTP API server |
FILESERVER_PATH_USERS_DIRECTORY |
Directory path for data storage, must exist |
FILESERVER_ADMINISTRATIVE_USERS |
Space-separated list of administrative usernames, must not be empty |
FILESERVER_SSH_IDLE_TIMEOUT |
Idle timeout for SSH connections in Go duration format (e.g. 90s, 5m); defaults to 5m; malformed values fail startup |
FILESERVER_SSH_MAX_CONNECTIONS |
Maximum concurrently open SSH connections; defaults to 100; 0 disables the cap |
task run sets all of the above with development defaults, except
FILESERVER_SSH_IDLE_TIMEOUT and FILESERVER_SSH_MAX_CONNECTIONS, which use
their defaults.
HTTP API
The API manages users and their SSH public keys. It is currently
unauthenticated; do not expose the API port publicly.
| Method |
Path |
Description |
GET |
/users |
List usernames |
POST |
/users |
Create a user |
DELETE |
/users/{username} |
Delete a user (fails with 409 while credentials exist) |
GET |
/users/{username}/credentials |
List credentials of a user |
POST |
/users/{username}/credentials |
Add a public key in authorized_keys format |
DELETE |
/users/{username}/credentials/{credential_id} |
Delete a credential |
Swagger UI is served at /docs/index.html.
Development
- Create the files under
keys/ (gitignored):
ecdsa.key — SSH host key, generated by task gen-key
database_password — password of the Postgres container
database_connection_string — connection string for task run
database_connection_string_docker — connection string used by the
file-server container in docker-compose.yml
- Create
data/files.
task run starts Postgres and the server.
Tests:
task test runs all tests; API tests are skipped without a test database.
task test-api creates the file_server_test database in the Postgres
container and runs the API tests against it.
References