Skip to content

refactor: Issue #9 improvements and documentation reorganization#15

Merged
houseme merged 5 commits intomainfrom
feature/improve-security-1
Mar 3, 2026
Merged

refactor: Issue #9 improvements and documentation reorganization#15
houseme merged 5 commits intomainfrom
feature/improve-security-1

Conversation

@houseme
Copy link
Collaborator

@houseme houseme commented Mar 3, 2026

Summary

Implements all Issue #9 feedback for Nix best practices and reorganizes documentation by removing duplicates and improving structure.

Code Improvements

  • Remove Manual Binary Stripping - Nix does this automatically
  • Clarify sourceProvenance - Explicit documentation for pre-compiled binaries
  • Use Environment Attribute Set - Follows nixpkgs best practices
  • Replace Shell Script - Uses systemd %d placeholder instead
  • Default to Journal Logging - Logs go to systemd journal by default

Documentation Changes

  • Move detailed docs to docs/ directory (SECURITY.md, MIGRATION.md, IMPROVEMENTS.md)
  • Remove duplicates (SUMMARY.md, CHANGELOG_IMPROVEMENTS.md)
  • Create docs/README.md as index
  • Update all references throughout project

Breaking Changes

None - Fully backward compatible

Testing

  • ✅ No Nix syntax errors
  • ✅ Module evaluation successful
  • ✅ No broken documentation links
  • ✅ All examples working

Closes #9

- Remove manual binary stripping and binutils
- Clarify sourceProvenance for pre-compiled binaries
- Migrate to environment attribute set (nixpkgs best practice)
- Replace shell script with %d placeholder
- Default to systemd journal logging
- Move detailed docs to docs/, remove duplicates
- Update all documentation references
Copilot AI review requested due to automatic review settings March 3, 2026 03:44
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses Issue #9 by tightening the NixOS module’s secret handling and systemd hardening, and reorganizes project documentation into a dedicated docs/ directory.

Changes:

  • Refactors the NixOS module service definition (systemd environment attrset, LoadCredential usage, optional file logging with journal default, extended hardening).
  • Simplifies the flake packaging by removing manual binary stripping and clarifying binary provenance metadata.
  • Reorganizes and expands documentation (security, migration, improvements, changelog) and updates examples.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
nixos/rustfs.nix Updates option docs, makes logDirectory optional, refactors systemd env/logging/tmpfiles rules, expands hardening.
flake.nix Removes binutils/manual strip and clarifies sourceProvenance documentation for prebuilt binaries.
examples/nixos-configuration.nix Expands “secure production” example (file-based secrets, firewall, logging guidance).
examples/flake.nix Updates example to use file-based secrets paths and adds demo secret provisioning.
docs/SECURITY.md Adds comprehensive security guidance and configuration examples.
docs/MIGRATION.md Adds migration guide away from plain-text secrets to file-based secrets.
docs/IMPROVEMENTS.md Adds detailed explanation of the security/performance refactors and rationale.
docs/README.md Adds docs index/entrypoint.
docs/REORGANIZATION.md Documents the doc structure changes and moved/removed files.
README.md Updates top-level README with security notice and links to new docs.
CHANGELOG.md Adds changelog including security improvements and behavior changes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +78 to +82
description = ''
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.
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 option description says the secret file must be readable by the rustfs service user, but the module actually loads it via systemd LoadCredential (PID1 reads the source file and exposes a separate credential file to the service). This wording is misleading and may cause users to unnecessarily grant the service direct read access to the original secret file; consider updating it to reflect the real requirement (readable by systemd/root) and that the service reads from the credential directory instead.

Copilot uses AI. Check for mistakes.
Comment on lines +30 to +39
# Create secret files for demonstration purposes
# In production, use sops-nix, agenix, or other secret management
environment.etc."rustfs-secrets/access-key" = {
text = "admin-access-key";
mode = "0400";
};
environment.etc."rustfs-secrets/secret-key" = {
text = "secure-secret-key";
mode = "0400";
};
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.

This example writes secret values via environment.etc.<name>.text, which places the secret contents into the Nix store (defeating the purpose of moving to file-based secrets to keep them out of /nix/store). Even for a demo, this pattern is insecure/misleading; please switch the example to use an out-of-store path (e.g. /run/secrets/...) and document how to create/populate those secrets (or show a minimal sops-nix/agenix example).

Copilot uses AI. Check for mistakes.
docs/SECURITY.md Outdated
Comment on lines +126 to +130
systemd.tmpfiles.rules = [
"d ${cfg.logDirectory} 0750 ${cfg.user} ${cfg.group} -"
"d ${cfg.tlsDirectory} 0750 ${cfg.user} ${cfg.group} -"
"d ${volume} 0750 ${cfg.user} ${cfg.group} -" # For each volume
];
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.

This tmpfiles example uses ${cfg.logDirectory} unconditionally, but the module now defaults logDirectory = null and only adds the tmpfiles rule when it is non-null. Consider updating the snippet to match the current module behavior (make logDirectory optional in the example).

Suggested change
systemd.tmpfiles.rules = [
"d ${cfg.logDirectory} 0750 ${cfg.user} ${cfg.group} -"
"d ${cfg.tlsDirectory} 0750 ${cfg.user} ${cfg.group} -"
"d ${volume} 0750 ${cfg.user} ${cfg.group} -" # For each volume
];
systemd.tmpfiles.rules =
(lib.optional (cfg.logDirectory != null)
"d ${cfg.logDirectory} 0750 ${cfg.user} ${cfg.group} -")
++ [
"d ${cfg.tlsDirectory} 0750 ${cfg.user} ${cfg.group} -"
"d ${volume} 0750 ${cfg.user} ${cfg.group} -" # For each volume
];

Copilot uses AI. Check for mistakes.
Comment on lines +88 to +94
### 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)
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.
Comment on lines +89 to +93
description = ''
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.
For security best practices, use secret management tools like sops-nix, agenix, or NixOps keys.
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.

Same as accessKeyFile: the description currently states the file should be readable by the rustfs service user, but the module uses LoadCredential so systemd reads the source file and the service consumes the copied credential. Please align this description with how secrets are actually consumed to avoid encouraging overly broad file permissions.

Copilot uses AI. Check for mistakes.
docs/SECURITY.md Outdated
- **Memory protections**: `MemoryDenyWriteExecute = true`
- **Network restrictions**: Only AF_INET, AF_INET6, and AF_UNIX allowed

See the full list in [nixos/rustfs.nix](./nixos/rustfs.nix).
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.

This link is broken due to the docs being in docs/: ./nixos/rustfs.nix resolves to docs/nixos/rustfs.nix which doesn't exist. It should point to ../nixos/rustfs.nix (or another correct relative path).

Suggested change
See the full list in [nixos/rustfs.nix](./nixos/rustfs.nix).
See the full list in [nixos/rustfs.nix](../nixos/rustfs.nix).

Copilot uses AI. Check for mistakes.
Comment on lines +157 to +164
networking.firewall = {
enable = true;
allowedTCPPorts = [ 9000 ]; # API port
allowedTCPPorts = [ 9001 ]; # Console port (consider restricting to local only)

# Or use interfaces for more granular control
interfaces.eth0.allowedTCPPorts = [ 9000 9001 ];
};
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 firewall example sets allowedTCPPorts twice; in Nix this will overwrite the first assignment, so only one port would actually be opened. Please combine the ports into a single list (or show interface-specific rules) to make the example correct.

Copilot uses AI. Check for mistakes.
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@copilot open a new pull request to apply changes based on this feedback

If you encounter issues:

1. Check the [SECURITY.md](./SECURITY.md) documentation
2. Review the [example configuration](./examples/nixos-configuration.nix)
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.

This link is broken from within docs/MIGRATION.md: ./examples/nixos-configuration.nix resolves under docs/, but the examples directory is at the repo root. Update it to ../examples/nixos-configuration.nix (or another correct relative path).

Suggested change
2. Review the [example configuration](./examples/nixos-configuration.nix)
2. Review the [example configuration](../examples/nixos-configuration.nix)

Copilot uses AI. Check for mistakes.
Comment on lines +154 to +156
cfg.logDirectory
cfg.tlsDirectory
] ++ volumesList;
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.

This ReadWritePaths snippet includes cfg.logDirectory unconditionally, but the module now defaults logDirectory = null and only adds it when non-null. Please update the documentation snippet to reflect the current implementation (e.g., include tlsDirectory and volumes always, and only add logDirectory optionally).

Suggested change
cfg.logDirectory
cfg.tlsDirectory
] ++ volumesList;
cfg.tlsDirectory
] ++ lib.optional (cfg.logDirectory != null) cfg.logDirectory
++ volumesList;

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Copilot AI commented Mar 3, 2026

@houseme I've opened a new pull request, #16, to work on those changes. Once the pull request is ready, I'll request review from you.

…xample (#16)

* Initial plan

* fix: combine duplicate allowedTCPPorts into single list in firewall example

Co-authored-by: houseme <4829346+houseme@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: houseme <4829346+houseme@users.noreply.github.com>
@houseme
Copy link
Collaborator Author

houseme commented Mar 3, 2026

@copilot

Copy link
Contributor

Copilot AI commented Mar 3, 2026

@houseme I've opened a new pull request, #17, to work on those changes. Once the pull request is ready, I'll request review from you.

Copilot AI and others added 2 commits March 3, 2026 13:05
… optional logDirectory (#17)

* Initial plan

* fix: address remaining review comments - secrets handling, broken links, optional logDirectory

Co-authored-by: houseme <4829346+houseme@users.noreply.github.com>

* fix: clarify CHANGELOG deprecated accessKey/secretKey semantics and required file path

Co-authored-by: houseme <4829346+houseme@users.noreply.github.com>

* fix: remove hardcoded secrets from activation script example; align README with LoadCredential behavior

Co-authored-by: houseme <4829346+houseme@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: houseme <4829346+houseme@users.noreply.github.com>
@houseme
Copy link
Collaborator Author

houseme commented Mar 3, 2026

@copilot fix ci error

Copy link
Contributor

Copilot AI commented Mar 3, 2026

@houseme I've opened a new pull request, #18, to work on those changes. Once the pull request is ready, I'll request review from you.

… arity (#18)

* Initial plan

* fix: resolve CI errors — invalid checkout@v6 and mkRenamedOptionModule 3-arg call

Co-authored-by: houseme <4829346+houseme@users.noreply.github.com>

* fix: apply nixpkgs-fmt to all 3 failing files and restore checkout@v6

Co-authored-by: houseme <4829346+houseme@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: houseme <4829346+houseme@users.noreply.github.com>
@houseme houseme merged commit e09095d into main Mar 3, 2026
2 checks passed
@houseme houseme deleted the feature/improve-security-1 branch March 3, 2026 06:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unsecure: secret key is world-readable + service runs as root + no hardening

3 participants