Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 155 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# Changelog

All notable changes to the RustFS NixOS module will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Recent Improvements (March 2026)

Following community feedback on Issue #9, additional improvements aligned with Nix best practices:

#### Removed Manual Binary Stripping

- Removed redundant manual `strip` command and `binutils` dependency
- Nix automatically strips binaries by default
- Allows packages to use `dontStrip` for debugging when needed

#### Clarified sourceProvenance

- Added clear documentation explaining pre-compiled binaries from GitHub releases
- Makes it obvious why `sourceProvenance = [ sourceTypes.binaryNativeCode ]` is declared

#### Migrated to Environment Attribute Set

- Changed from `serviceConfig.Environment` list to `environment` attribute set
- More idiomatic Nix style following nixpkgs conventions
- Better integration with override system
- Follows patterns from minio and other modules

#### Replaced Shell Script with %d Placeholder

- Eliminated `pkgs.writeShellScript` wrapper for credential loading
- Uses systemd's `%d` placeholder for credentials directory
- Cleaner implementation: `RUSTFS_ACCESS_KEY = "file:%d/access-key"`
- Direct binary execution without wrapper script

#### Default to Systemd Journal Logging

- Changed `logDirectory` default from `"/var/log/rustfs"` to `null`
- Logs written to systemd journal by default
- View logs with: `journalctl -u rustfs -f`
- File logging still available when explicitly configured
- Automatic log rotation and unified log management

### Added

- Comprehensive security documentation in `docs/SECURITY.md`
- Migration guide for users upgrading from insecure configuration in `docs/MIGRATION.md`
- Example configurations with sops-nix integration
- Support for both file-based and sops-nix/agenix secret management
- Systemd LoadCredential for secure secret passing
- Extensive systemd security hardening:
- `CapabilityBoundingSet = ""`
- `PrivateDevices = true`
- `PrivateTmp = true`
- `PrivateUsers = true`
- `ProtectSystem = "strict"`
- `ProtectHome = true`
- `ProtectKernelTunables = true`
- `ProtectKernelModules = true`
- `ProtectKernelLogs = true`
- `ProtectClock = true`
- `ProtectControlGroups = true`
- `ProtectHostname = true`
- `ProtectProc = "invisible"`
- `ProcSubset = "pid"`
- `RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ]`
- `RestrictNamespaces = true`
- `RestrictRealtime = true`
- `RestrictSUIDSGID = true`
- `SystemCallArchitectures = "native"`
- `SystemCallFilter = [ "@system-service" "~@privileged" "~@resources" ]`
- `MemoryDenyWriteExecute = true`
- `LockPersonality = true`
- `NoNewPrivileges = true`
- `UMask = "0077"`
- `ReadWritePaths` configuration for explicit write access
- Resource limits: `LimitNOFILE = 1048576`, `LimitNPROC = 32768`
- Improved restart configuration with `RestartSec = "10s"`
- Timeout configurations: `TimeoutStartSec = "60s"`, `TimeoutStopSec = "30s"`
- Automatic directory creation with secure permissions via `systemd.tmpfiles.rules`
- Detailed option descriptions with examples
- Security checklist in documentation
- Log rotation example configuration

### Changed

- **BREAKING**: Removed `services.rustfs.accessKey` option (security risk)
- **BREAKING**: Removed `services.rustfs.secretKey` option (security risk)
- **BREAKING**: `accessKeyFile` is now required instead of optional
- **BREAKING**: `secretKeyFile` is now required instead of optional
- Default `volumes` changed from `"/tmp/rustfs"` to `"/var/lib/rustfs"` (persistent storage)
Comment on lines +88 to +92
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description says there are no breaking changes, but this changelog section explicitly marks multiple BREAKING changes (removal of services.rustfs.accessKey/secretKey and making accessKeyFile/secretKeyFile required). Please reconcile this: either update the PR description (and release notes) to acknowledge the breaking change, or adjust the module/docs if it is intended to remain backward compatible.

Copilot uses AI. Check for mistakes.
- Console now defaults to localhost-only binding (`127.0.0.1:9001`)
- Improved logging output to separate stdout and stderr streams
- Enhanced documentation with security focus
- Updated examples to demonstrate secure configurations
- Service now explicitly grants write access only to required directories

### Deprecated

- `accessKey` option (removed, use `accessKeyFile`)
- `secretKey` option (removed, use `secretKeyFile`)

### Removed

- Direct secret configuration options (must use file-based secrets)

### Fixed

- Secrets no longer stored in Nix store (world-readable)
- Secrets no longer passed via environment variables
- Service can no longer access user home directories
- Service can no longer modify system files outside designated paths
- Service cannot spawn arbitrary processes or modify system configuration
- Console no longer exposed to public network by default

### Security

- Secrets are now passed via systemd LoadCredential (never in Nix store)
- Service runs as unprivileged `rustfs` user (not root)
- Comprehensive systemd sandboxing enabled
- System calls restricted to safe subset
- All capabilities dropped
- Prevents privilege escalation
- Memory execution protection
- Network address family restrictions
- Filesystem isolation with explicit write paths

## Migration Notes

Users upgrading from previous versions must:

1. Move secrets from `accessKey`/`secretKey` to file-based configuration
2. Update to use `accessKeyFile` and `secretKeyFile` options
3. Consider using sops-nix or agenix for secret management
4. Review firewall rules (console now localhost-only by default)
5. Update volume paths from `/tmp` to persistent storage

See [docs/MIGRATION.md](./docs/MIGRATION.md) for detailed migration instructions.

## Version Compatibility

- **NixOS**: 23.11 or later recommended
- **Systemd**: 252 or later (for all security features)
- **RustFS**: Compatible with current RustFS binary

## References

- [Issue #9](https://github.com/rustfs/rustfs-flake/issues/9) - Original security concerns
- [docs/SECURITY.md](./docs/SECURITY.md) - Complete security documentation
- [docs/MIGRATION.md](./docs/MIGRATION.md) - Migration guide
- [docs/IMPROVEMENTS.md](./docs/IMPROVEMENTS.md) - Technical implementation details

165 changes: 148 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,26 @@
# RustFS Flake

RustFS NixOS module.
RustFS NixOS module with secure secret management and systemd hardening.

> **⚠️ SECURITY NOTICE**: Never use plain-text secrets in your NixOS configuration! Always use `accessKeyFile` and
`secretKeyFile` with a secret management tool like sops-nix or agenix. See [docs/SECURITY.md](./docs/SECURITY.md) for
> details.

## Documentation

- **[docs/SECURITY.md](./docs/SECURITY.md)** - Security best practices and secret management
- **[docs/MIGRATION.md](./docs/MIGRATION.md)** - Migrating from old insecure configuration
- **[docs/IMPROVEMENTS.md](./docs/IMPROVEMENTS.md)** - Technical implementation details
- **[examples/nixos-configuration.nix](./examples/nixos-configuration.nix)** - Example secure configuration

## Features

- 🔒 **Secure by default**: File-based secrets with systemd LoadCredential
- 🛡️ **Systemd hardening**: Comprehensive security restrictions
- 🔐 **Secret management**: Integration with sops-nix, agenix, etc.
- 📝 **Non-root**: Runs as dedicated unprivileged user
- 🔥 **Firewall-ready**: Minimal port exposure
- 📊 **Production-ready**: Log rotation, monitoring, TLS support

## Usage

Expand Down Expand Up @@ -30,15 +50,54 @@ Then, add the flake to your `configuration.nix`:
rustfs = {
enable = true;
package = inputs.rustfs.packages.${pkgs.stdenv.hostPlatform.system}.default;
accessKey = "rustfsadmin";
secretKey = "rustfsadmin";
volumes = "/tmp/rustfs";
# SECURITY NOTE: Never use plain text secrets in configuration.nix!
# Use accessKeyFile and secretKeyFile instead:
accessKeyFile = "/run/secrets/rustfs-access-key"; # or use sops-nix, agenix, etc.
secretKeyFile = "/run/secrets/rustfs-secret-key";
volumes = "/var/lib/rustfs"; # Use a persistent location
address = ":9000";
consoleEnable = true;
consoleAddress = ":9001";
};
};
```

**For example with sops-nix:**

```nix
# In your flake inputs
inputs.sops-nix.url = "github:Mic92/sops-nix";

# In your configuration
imports = [
inputs.sops-nix.nixosModules.sops
];

sops.secrets.rustfs-access-key = {
sopsFile = ./secrets.yaml;
owner = config.services.rustfs.user;
group = config.services.rustfs.group;
mode = "0400";
};

sops.secrets.rustfs-secret-key = {
sopsFile = ./secrets.yaml;
owner = config.services.rustfs.user;
group = config.services.rustfs.group;
mode = "0400";
};

services.rustfs = {
enable = true;
package = inputs.rustfs.packages.${pkgs.stdenv.hostPlatform.system}.default;
accessKeyFile = config.sops.secrets.rustfs-access-key.path;
secretKeyFile = config.sops.secrets.rustfs-secret-key.path;
volumes = "/var/lib/rustfs";
address = ":9000";
consoleEnable = true;
};
```

You can also install the rustfs itself (Just binary):

just install following as a package:
Expand All @@ -57,40 +116,112 @@ Enables the rustfs service.

The rustfs package providing the rustfs binary.

### services.rustfs.accessKey
### services.rustfs.accessKeyFile

**Type:** `path`

**Example:** `/run/secrets/rustfs-access-key`

Path to a file containing the access key for client authentication. Use a runtime path (e.g. /run/secrets/…) to prevent
the secret from being copied into the Nix store. The file should be readable by the rustfs service user and contain only
the access key without any trailing whitespace.

For security best practices, use secret management tools like sops-nix, agenix, or NixOps keys.

**Note:** The deprecated `accessKey` option has been removed for security reasons.

### services.rustfs.secretKeyFile

**Type:** `path`

**Example:** `/run/secrets/rustfs-secret-key`

The access key for the rustfs server.
Path to a file containing the secret key for client authentication. Use a runtime path (e.g. /run/secrets/…) to prevent
the secret from being copied into the Nix store. The file should be readable by the rustfs service user and contain only
the secret key without any trailing whitespace.

### services.rustfs.secretKey
For security best practices, use secret management tools like sops-nix, agenix, or NixOps keys.

The secret key for the rustfs server.
**Note:** The deprecated `secretKey` option has been removed for security reasons.

### services.rustfs.user

**Type:** `string`

**Default:** `"rustfs"`

User account under which RustFS runs. The service runs as a dedicated non-root user for security.

### services.rustfs.group

**Type:** `string`

**Default:** `"rustfs"`

Group under which RustFS runs.

### services.rustfs.volumes

The volumes to mount.
**Type:** `string` or `list of strings`

**Default:** `["/var/lib/rustfs"]`

List of paths or comma-separated string where RustFS stores data. Use persistent locations, not /tmp.

### services.rustfs.address

The address to listen on.
**Type:** `string`

**Default:** `":9000"`

The network address for the API server (e.g., :9000).

### services.rustfs.consoleEnable

Whether to enable the console.
**Type:** `bool`

**Default:** `true`

Whether to enable the RustFS management console.

### services.rustfs.consoleAddress

**Type:** `string`

**Default:** `":9001"`

The network address for the management console (e.g., :9001).

### services.rustfs.logLevel

The log level.
**Type:** `string`

**Default:** `"info"`

The log level (error, warn, info, debug, trace).

### services.rustfs.logDirectory

The log directory.
**Type:** `null or path`

**Default:** `null`

Directory where RustFS service logs are written to files. If `null` (default), logs are written to systemd journal only.
Use `journalctl -u rustfs` to view logs. Set to a path (e.g., `"/var/log/rustfs"`) to enable file logging.

### services.rustfs.tlsDirectory

The TLS directory.
**Type:** `path`

**Default:** `"/etc/rustfs/tls"`

The directory containing TLS certificates.

### services.rustfs.extraEnvironmentVariables

Additional environment variables to set for the RustFS service.
These will be appended to the environment file at /etc/default/rustfs.
Used for advanced configuration not covered by other options. (e.g. `RUST_BACKTRACE`)
**Type:** `attribute set of strings`

**Default:** `{}`

Additional environment variables to set for the RustFS service. Used for advanced configuration not covered by other
options (e.g. `RUST_BACKTRACE`).
Loading