age-encrypted secrets for NixOS; drop-in replacement for agenix

Overview

ragenix

ragenix provides age-encrypted secrets for NixOS systems which live in the Nix store and are decrypted on system activation. Using ragenix to create, edit and rekey secrets is possible on any system which has Nix installed—with particular support for NixOS and macOS.

ragenix is a drop-in replacement for @ryantm's agenix written in Rust. It aims at being fully compatible with its flake while offering more robust command line parsing, additional validation logic and solid tests.

As opposed to agenix, ragenix only strives for supporting Nix Flakes.

Installation

As ragenix seeks to replace agenix without breaking compatability, getting started with age-encrypted secrets or switching from agenix to ragenix is easy: just follow the original instructions from agenix while replacing references to github.com/ryantm/agenix with github.com/yaxitech/ragenix. Everything else should remain the same as the ragenix package provides aliases for a) an agenix package and b) the agenix binary. The flake also exposes a NixOS module which is passed through from the agenix flake.

Create, edit and rekey secrets

ragenix resembles the command line options and behavior of agenix:

  • By default, ragenix looks for a Nix rules file in ./secrets.nix. You may change this path by setting the RULES environment variable accordingly. As a ragenix addon, you may also use the --rules command line option.
  • The Nix rules reference age-encrypted files relative to the rules file. For example, a ./secrets/secrets.nix file with the following content would instruct ragenix to look for mysecret.age in ./secrets/: { "mysecret.age".publicKeys = "age1hunh4g..."; }.
  • If a file given in the secrets rules does not exist:
    • --edit: the file is created prior to opening it for editing.
    • --rekey: the file is ignored.
  • ragenix opens a file for editing using $EDITOR. Again, you may use --editor instead of the environment variable.
  • Prior to editing/rekeying, ragenix verifies the validity of the rules file using this JSON schema. The schema is also available to third party applications with the --schema command line switch. For an example rules file, please refer to the agenix README or take a look at the files in the example directory of this repository.

The ragenix package also provides shell completions for bash, zsh, and fish. Make sure to install the package with either nix profile install github:yaxitech/ragenix, environment.systemPackages on NixOS or home.packages for home-manager.

Contributions

We'd love to see PRs from you! Please consider the following guidelines:

  • ragenix stays compatible to agenix. Please make sure your contributions don't introduce breaking changes.
  • The secrets configuration happens through a Nix configuration.
  • New features should support both NixOS and macOS, if applicable.

The CI invokes nix flake check. Some of the checks invoke nix itself. To allow those tests to run nix, you have to enable the recursive-nix feature. On NixOS, you can put the following snippet into your configuration.nix:

{
  nix = {
    extraOptions = ''
      experimental-features = nix-command flakes recursive-nix
    '';
    systemFeatures = [ "recursive-nix" ];
  };
}

Similar projects / acknowledgements

The agenix-cli project is quite similar to ragenix. In fact, it served as an inspiration (thanks!). Both projects have in common that they aim at replacing the fragile shell script with a version written in Rust. In contrast to ragenix, however, agenix-cli is not compatible to the original agenix. It uses a TOML configuration file to declare rules on a repository level (similar to .sops.yaml). While having a global rules file might be useful for some (particularly if you're looking to switch from sops-nix), we wanted to continue to define our rules using Nix expressions which reside in different directories.

Comments
  • Tooling: replace naersk with nixpkgs

    Tooling: replace naersk with nixpkgs

    • change the tooling
    • adapt check phase & execute checks before the build phase
    • especially run the fmt check first to avoid building everything (twice) only to fail the build on format checks

    closes #61

    opened by blaggacao 7
  • decrypt-with-age check fails on macOS

    decrypt-with-age check fails on macOS

    error: builder for '/nix/store/kjzpnhknd26670201m9lvbwzhxxrwhkg-decrypt-with-age.drv' failed with exit code 101;
           last 2 log lines:
           > thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: NotWellFormed', /private/tmp/nix-build-rage-0.7.0.drv-0/rage-0.7.0-vendor.tar.gz/locale_config/src/macos.rs:16:76
           > note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
           For full logs, run 'nix log /nix/store/kjzpnhknd26670201m9lvbwzhxxrwhkg-decrypt-with-age.drv'.
    error: build of '/nix/store/4574nc3jkm74pmbld8akw8b8kx5hvhd3-check-agenix-symlink.drv', '/nix/store/8fb3b4yyc71h403i421njbb9ng16d7p8-emit-schema.drv', '/nix/store/dl0mqvayp04jhggi7z4y14l33m62mbw4-check-shell-completions.drv', '/nix/store/kjzpnhknd26670201m9lvbwzhxxrwhkg-decrypt-with-age.drv' failed
    

    This problem is this call in locale_config, which rage depends on for localizations. rage works in every other context but this check on my machine.

    bug help wanted 
    opened by winterqt 3
  • Build without `recursive-nix`

    Build without `recursive-nix`

    Refactor the code to allow building without recursive-nix:

    • The Rust integration tests which require recursive-nix are guarded by a feature flag which is enabled by default (to still run them by just executing cargo test).
    • nix build disables the recursive-nix feature flag. This allows using ragenix without a system with recursive-nix support. nix flake check will build ragenix (again) and run all tests.
    • Building and checking are two separate CI workflows now. The former uses a Nix without recursive-nix while the latter uses a Nix installation with the recursive-nix feature enabled. Only the check workflow requires recursive-nix.
    • macOS fails to run the recursive-nix checks. I'm not sure what's the reason but it is probably an upstream bug. Therefore, I moved the respective checks to the Linux check outputs. We can revert the commit as soon as this is addressed.

    Fixes #65

    opened by veehaitch 2
  • recursive-nix needed for simple install

    recursive-nix needed for simple install

    In the README we get the impression that the recursive-nix feature is only needed if we want to contribute but for me, simply putting ragenix as an input in my flake.nix and having it as a command in my devshell gives me:

    error: a 'x86_64-linux' with features {recursive-nix} is required to build '/nix/store/dn03sf91527lndd0mj6s35qsd6v38a3b-ragenix.drv', but I am a 'x86_64-linux' with features {benchmark, big-parallel, kvm, nixos-test}
    

    Is recursive-nix needed to just use ragenix? In that case maybe it should be listed as a dependency or something.

    bug good first issue 
    opened by sweenu 2
  • Flake: workaround for hanging QEMU 6.1.0

    Flake: workaround for hanging QEMU 6.1.0

    For testing the agenix NixOS module, use QEMU 6.0.0 until upstream fixes a bug which causes QEMU 6.1.0 to hang indefinitely, at least for virtualized hosts.

    Closes #35

    opened by veehaitch 2
  • get rid of naersk

    get rid of naersk

    naersk has a track record of pulling in it's own nixpkgs and any follows constellations continuously cause problems (due to long lasting bugs in nix's follows implementation). This is why many repositories start switching to 21.11 upstream rust machinery (which can consume Cargo.lock files).

    Piling up uncontrolled nixpkgs versions in flake lock files is not necessarily bad, per se, but it makes it increasingly hard for an operator to manage & audit this core dependency for about everything.

    If my sentiment is mirrored I'd be happy to prepare a PR with a switch.

    question 
    opened by blaggacao 1
  • Update flake inputs

    Update flake inputs

    Resolved URL: git+file:///home/runner/work/ragenix/ragenix?shallow=1
    Locked URL: git+file:///home/runner/work/ragenix/ragenix?ref=main&rev=36679efd2f4818035e2d7db900db0f3010e6fb3c&shallow=1
    Description: A rust drop-in replacement for agenix
    Path: /nix/store/6ilzzimnv33lqqldp9nna6ihsvb731i0-source
    Revision: 36679efd2f4818035e2d7db900db0f3010e6fb3c
    Last modified: 2021-12-05 02:38:46
    Inputs:
    ├───agenix: github:ryantm/agenix/52ea2f8c3231cc2b5302fa28c63588aacb77ea29
    │ └───nixpkgs follows input 'nixpkgs'
    ├───flake-utils: github:numtide/flake-utils/74f7e4319258e287b0f9cb95426c9853b282730b
    ├───naersk: github:nix-community/naersk/c3e56b8a4ffb6d906cdfcfee034581f9a8ece571
    │ └───nixpkgs follows input 'nixpkgs'
    ├───nixpkgs: github:nixos/nixpkgs/6daa4a5c045d40e6eae60a3b6e427e8700f1c07f
    ├───nixpkgs-nixos-test: github:nixos/nixpkgs/e1fc1a80a071c90ab65fb6eafae5520579163783
    └───rust-overlay: github:oxalica/rust-overlay/88ce9c458d9e4dedfd9eed85a3fe818730a2fac5
     ├───flake-utils follows input 'flake-utils'
     └───nixpkgs follows input 'nixpkgs'
    
    opened by wurzelpfropf 1
  • CI: use `wurzelpfropf` binary cache from cachix

    CI: use `wurzelpfropf` binary cache from cachix

    In an effort to reduce the build times, use a public binary cache from cachix.

    I've created the binary cache through @wurzelpfropf with the name wurzelpfropf and added an auth token as a secret with write access as CACHIX_AUTH_TOKEN_PUBLIC on the organization level.

    opened by veehaitch 1
  • Flake: use upstream naersk

    Flake: use upstream naersk

    Upstream naersk now has support for

    • aarch64-darwin: https://github.com/nix-community/naersk/pull/182
    • Stable Rust channel: https://github.com/nix-community/naersk/pull/191

    That means, we no longer have to use our fork.

    opened by veehaitch 1
  • Update flake inputs

    Update flake inputs

    Updated Flake dependencies through nix flake update.

    Resolved URL:  git+file:///home/runner/work/ragenix/ragenix?shallow=1
    Locked URL:    git+file:///home/runner/work/ragenix/ragenix?ref=refs%2fheads%2fmain&rev=bb31b2b70dfca44f08b0b7775b0702d7a9155885&shallow=1
    Description:   A rust drop-in replacement for agenix
    Path:          /nix/store/248zb3nybzj96fd52fva4rkdz29vf1jz-source
    Revision:      bb31b2b70dfca44f08b0b7775b0702d7a9155885
    Last modified: 2023-01-01 02:29:46
    Inputs:
    ├───agenix: github:ryantm/agenix/a630400067c6d03c9b3e0455347dc8559db14288
    │   └───nixpkgs follows input 'nixpkgs'
    ├───flake-utils: github:numtide/flake-utils/5aed5285a952e0b949eb3ba02c12fa4fcfef535f
    ├───nixpkgs: github:nixos/nixpkgs/677ed08a50931e38382dbef01cba08a8f7eac8f6
    └───rust-overlay: github:oxalica/rust-overlay/176b6fd3dd3d7cea8d22ab1131364a050228d94c
        ├───flake-utils follows input 'flake-utils'
        └───nixpkgs follows input 'nixpkgs'
    
    

    Updated Cargo dependencies through cargo update.

    Dependency status of main prior to this PR: dependency status

    opened by wurzelpfropf 0
  • Update flake inputs

    Update flake inputs

    Updated Flake dependencies through nix flake update.

    Resolved URL:  git+file:///home/runner/work/ragenix/ragenix?shallow=1
    Locked URL:    git+file:///home/runner/work/ragenix/ragenix?ref=refs%2fheads%2fmain&rev=468ba936f9205e5ed7bf4321dc2adaa09d9632c1&shallow=1
    Description:   A rust drop-in replacement for agenix
    Path:          /nix/store/vmpczdl8js7b76xnmx0zcgp7gj4a9816-source
    Revision:      468ba936f9205e5ed7bf4321dc2adaa09d9632c1
    Last modified: 2022-12-25 02:21:52
    Inputs:
    ├───agenix: github:ryantm/agenix/a630400067c6d03c9b3e0455347dc8559db14288
    │   └───nixpkgs follows input 'nixpkgs'
    ├───flake-utils: github:numtide/flake-utils/5aed5285a952e0b949eb3ba02c12fa4fcfef535f
    ├───nixpkgs: github:nixos/nixpkgs/652e92b8064949a11bc193b90b74cb727f2a1405
    └───rust-overlay: github:oxalica/rust-overlay/631e692192eeeea85cdfb2a9dccbbfce543478b1
        ├───flake-utils follows input 'flake-utils'
        └───nixpkgs follows input 'nixpkgs'
    
    

    Updated Cargo dependencies through cargo update.

    Dependency status of main prior to this PR: dependency status

    opened by wurzelpfropf 0
  • Error when trying to edit file

    Error when trying to edit file

    When I try to edit the file a12l_password.age I get an error message

    $ ragenix -e a12l_password.age
    error: secrets rules are invalid: './secrets.nix'
    Failed to read ./secrets.nix as JSON
    

    My expected result is that my $EDITOR starts with the decrypted file in a buffer.

    This is my secrets.nix file:

    let
      a12l = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH9yYBrcu2A7N5S93yOgK7J9wNcMUWMN2va2cd7srZ6m";
      users = [a12l];
      p-desktop1 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK1YN6HPXhnwhxr/qzvIstjLP70h+EXJ95/Ilsrl9W/0";
      systems = [p-desktop1];
    in {"a12l_password.age".publicKeys = [a12l p-desktop1];}
    

    I've looked at

    $ ragenix --schema
    {
      "$schema": "https://json-schema.org/draft/2020-12/schema",
      "description": "Agenix secrets rules schema",
      "type": "object",
      "properties": {},
      "additionalProperties": {
        "type": "object",
        "description": "An age-encrypted file",
        "required": [
          "publicKeys"
        ],
        "properties": {
          "publicKeys": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "string",
              "description": "An age-compatible recipient, e.g., an ed25519 SSH public key"
            },
            "uniqueItems": true
          }
        }
      }
    }
    

    but I don't know when the schema is checked in the evaluation process.

    bug 
    opened by a12l 6
  • `ragenix --generate`

    `ragenix --generate`

    • Tooling: change from naersk to nixpkgs+fenix
    • Tooling: avoid double building between codeStyleConformanceCheck & cargoCheckHook
    • Feature: add first implementation of secrets generate script
    enhancement ci-fails/needs-rework 
    opened by blaggacao 3
  • Support rules from flake outputs (nixosConfigurations)

    Support rules from flake outputs (nixosConfigurations)

    Just an idea I wanted to propose:

    Would it be possible to support reading rules from another flake's output instead of a separate secrets.nix file? E.g. If I have a flake defining my systems like this:

    {
      outputs = { self, nixpkgs }: {
    
        nixosConfigurations = {
          system1 = nixpkgs.lib.nixosSystem {
            system = "x86_64-linux";
            modules = [
              ({ pkgs, ... }:
                {
                  # Config ...
                  age.option-to-set-key = "ssh-ed25519 AAAAAAA...";
                  age.secrets.secret1.file = ./secrets/secret1.age;
                  age.secrets.secret2.file = ./secrets/secret2.age;
                })
            ];
          };
    
          system2 = nixpkgs.lib.nixosSystem {
            system = "x86_64-linux";
            modules = [
              ({ pkgs, ... }:
                {
                  # Config
                  age.option-to-set-key = "ssh-ed25519 AAAABBB...";
                  age.secrets.secret2.file = ./secrets/secret2.age;
                })
            ];
          };
        };
      };
    }
    
    

    nixosConfigurations could be used directly resulting in a rule set equivalent to:

    let
      system1 = "ssh-ed25519 AAAAAAA..";
      system2 = "ssh-ed25519 AAAABBB..";
    in
    {
      "secret1.age".publicKeys = [ system1 ];
      "secret2.age".publicKeys = [ system1 system2];
    }
    

    Since you only plan on supporting flakes it seems like an extra step to have to write a secrets.nix file, as the information is already present in an organized form. The --rules flag of ragenix could be expanded do accept a flake path or an additional flag (e.g. --flake) implemented the same way as other tools like nixos-rebuild have.

    I might have not considered something, let me know what you think or if this is a bad idea. This could even serve as an alternative for #48, as there would no longer be a reason to have globs since you don't need to define the rules at all.

    enhancement 
    opened by pinpox 2
  • Are glob/regex supported?

    Are glob/regex supported?

    I'm wondering how to organise my secrets without specifying every single one of them explicitly Is there some mechanism of how to specify glob patterns or regex's in the secrets.nix file?

    It would be nice to be able to specify something like this:

    let
      host1 = "ssh-ed25519 AAAAC3...";
      host2 = "ssh-ed25519 AAAAC3...";
      backup-admin = "ssh-ed25519 AAAAC3...";
    in
    {
      "hosts/host1/*".publicKeys = [ system1 ];
      "hosts/host2/*".publicKeys = [ system2 ];
      "hosts/*/backup-key".publicKeys = [ backup-admin ];
    }
    

    In this example every host should be able to access anything in his directory and the backup-admin should additionally be able to access the backup-keys for all hosts (but not the other files of all hosts).

    └── hosts
       ├── host1
       │  ├── backup-key   # Readable by 'host1' and 'backup-admin'
       │  └── ssh-key      # Readable by 'host1'
       └── host2
          ├── backup-key   # Readable by 'host2' and 'backup-admin'
          └── ssh-key      # Readable by 'host2'
    

    Is this possible?

    enhancement good first issue 
    opened by pinpox 3
Owner
YAXI
You'll be amazed.
YAXI
Show details about outdated packages in your NixOS system.

nix-olde is a tool to show details about outdated packages in your NixOS system using https://repology.org/ database. It can use both default <nixpkgs

Sergei Trofimovich 14 Jan 24, 2023
Run unpatched dynamic binaries on NixOS

nix-ld-rs Run unpatched dynamic binaries on NixOS. This is a rewrite of nix-ld in Rust, with extra functionalities. It's intended to be upstreamed at

Nix community projects 13 Jun 26, 2023
A Password Manager Using age for Encryption

A Password Manager Using age for Encryption Contents Features Usage Install Import from pass How It Works Features It is inspired by pass. senior's fe

Retirement Home 3 Nov 2, 2023
Secure storage for cryptographic secrets in Rust

secrets secrets is a library to help Rust programmers safely held cryptographic secrets in memory. It is mostly an ergonomic wrapper around the memory

Stephen Touset 165 Dec 22, 2022
Kubernetes controller written in Rust for automatically generating and updating secrets

Kubernetes controller written in Rust for automatically generating and updating secrets

Loc Mai 6 Nov 8, 2022
A mini CLI tool to detect secrets & credentials in source code

Fencer Fencer is a mini-CLI tool that can used to scan various kind of secrets/credentials that are hardcoded into a project source code files Feature

Naresh Balaji 17 Aug 23, 2022
Distributed Vault For Your Secrets

https://meta-secret.github.io Application Design Activity Diagram graph TD User --> |split password| MSS{MetaSecret} MSS --> |split| Hash1

Meta Secret 4 Nov 9, 2022
A simple command-line application to securely store secrets using encryption

rust-secret-vault A simple yet robust command-line tool designed to safely encrypt and store your sensitive information. Harnessing the power of AES-2

Luis Soares 4 Nov 22, 2023
a handy utility to work with encrypted DMGs

edmgutil edmgutil is a simple wrapper utility to hdiutil to help you work with disposable, encrypted DMGs. It can decompress an encrypted ZIP into a n

Sentry 9 Nov 29, 2022
Encrypted memories

Diary - Encrypted memories Diary is a TUI program written in Rust for GNU/Linux / *BSD / Android (It probably works on other platforms too, but who ca

Arun Sojan Parolikkal 44 Dec 23, 2022
An application for creating encrypted vaults for the GNOME desktop.

Vaults An application for creating encrypted vaults for the GNOME desktop. It currently uses gocryptfs and CryFS for encryption. Please always keep a

Martin Pobaschnig 51 Dec 17, 2022
Trustworthy encrypted command line authenticator app compatible with multiple backups.

cotp - command line totp authenticator I believe that security is of paramount importance, especially in this digital world. I created cotp because I

Reply 71 Dec 30, 2022
Drop-in Access Control via NFT Ownership

niftygate - Signature-Based Authenticating Proxy What is it? niftygate is a proxy for HTTP services, that validates signatures, providing an AuthN lay

Chris Olstrom 70 Jan 3, 2023
An encrypted multi client messaging system written in pure Rust

?? Preamble This is a pure Rust multi-client encrypted messaging system, also known as Edode's Secured Messaging System. It is an end-to-end(s) commun

Edode 3 Sep 16, 2022
Dione is an anonymize and encrypted messaging system build on top on a peer to peer layer.

Secure and Anonymous Messaging WARNING: Currently Dione is not ready to be used nor does it fulfill its goal of being an anonymous messenger. In order

Dione 41 Jan 5, 2023
NymDrive is a complete, end-to-end encrypted file syncing daemon that runs over the Nym network.

NymDrive NymDrive is a complete, end-to-end encrypted file syncing daemon that runs over the Nym network. Features Active file monitoring of changes i

Hans Bricks 16 Jul 12, 2022
An open source desktop wallet for nano and banano with end-to-end encrypted, on chain messaging using the dagchat protocol.

An open source wallet with end-to-end encrypted, on chain messaging for nano and banano using the dagchat protocol.

derfarctor 22 Nov 6, 2022
Smarter brute-force password searching for PKZIP encrypted files

Zip Blitz Motivation This program was created for a very specfic problem I had. I had a large encrypted zip file that I lost/forgot the password for.

Michael 4 Jul 29, 2022
DexiosGUI - Simple cross-platform drag-and-drop Dexios file encryption

DexiosGUI Simple cross-platform drag-and-drop Dexios file encryption. Latest Windows x64 release is here. DexiosGUI is a Qt/C++ app for encrypt and de

Fabrice Corraire 4 Jul 25, 2022