{"id":14967898,"url":"https://github.com/mrjones2014/opnix","last_synced_at":"2025-10-27T17:31:31.925Z","repository":{"id":252826059,"uuid":"841414260","full_name":"mrjones2014/opnix","owner":"mrjones2014","description":"❄️ Native secret management for NixOS using 1Password.","archived":false,"fork":false,"pushed_at":"2024-11-26T00:02:31.000Z","size":105,"stargazers_count":106,"open_issues_count":3,"forks_count":8,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-02-05T09:13:42.193Z","etag":null,"topics":["1password","1password-cli","nix","nixos","secret-management","secrets"],"latest_commit_sha":null,"homepage":"","language":"Nix","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mrjones2014.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-08-12T11:08:20.000Z","updated_at":"2025-02-02T23:41:32.000Z","dependencies_parsed_at":"2025-01-14T11:09:30.093Z","dependency_job_id":"dadbc54e-b680-4dfb-bd4b-541812dbdfaf","html_url":"https://github.com/mrjones2014/opnix","commit_stats":{"total_commits":93,"total_committers":3,"mean_commits":31.0,"dds":"0.12903225806451613","last_synced_commit":"5a2f62ceba69f03d7bba791bb21dd316d3da2454"},"previous_names":["mrjones2014/op-nix","mrjones2014/opnix"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrjones2014%2Fopnix","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrjones2014%2Fopnix/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrjones2014%2Fopnix/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrjones2014%2Fopnix/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mrjones2014","download_url":"https://codeload.github.com/mrjones2014/opnix/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238533277,"owners_count":19488160,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["1password","1password-cli","nix","nixos","secret-management","secrets"],"created_at":"2024-09-24T13:38:50.500Z","updated_at":"2025-10-27T17:31:26.615Z","avatar_url":"https://github.com/mrjones2014.png","language":"Nix","funding_links":[],"categories":["Security","Nix"],"sub_categories":[],"readme":"![check-flake workflow](https://github.com/mrjones2014/opnix/actions/workflows/check-flake.yml/badge.svg) [![1Password CLI](https://img.shields.io/badge/1Password-CLI-blue?logo=1password\u0026label=1Password)](https://developer.1password.com/docs/cli/) [![1Password Service Accounts](https://img.shields.io/badge/1Password-Service%20Accounts-blue?logo=1password\u0026label=1Password)](https://developer.1password.com/docs/service-accounts)\n\n# opnix\n\n\u003e [!IMPORTANT]\n\u003e This project was built for a hackathon. [brizzbuzz/opnix](https://github.com/brizzbuzz/opnix) is probably a better solution for most users.\n\nManage secrets for NixOS with 1Password natively with a NixOS module.\n\n\u003e [!NOTE]\n\u003e This is _beta software._ There may be breaking changes in the future, and some things may not work.\n\u003e Please try it out and report any issues that may come up!\n\n## Security\n\nWith this setup, you should only need one unencrypted secret on your machine; your [1Password Service Account](https://developer.1password.com/docs/service-accounts/) token.\nYou should set your Service Account token to have the _absolute minimum required permissions._ Usually this means read-only\naccess to only a single vault in which your server secrets are kept. You should set an expiration on the token and\n[rotate it regularly](https://developer.1password.com/docs/service-accounts/manage-service-accounts/#rotate-token).\n\nThe Service Account token is provided to the `systemd` jobs via an `EnvironmentFile` so that the token will not appear in `systemd` logs.\n\nYour `source` text (e.g. `opnix.secrets.my-secret.source = \"{{ op://SomeVault/SomeItem/token }}\";`) _**does appear**_ in the Nix store, in plaintext.\nYour **actual secrets _do NOT_** appear in the Nix store at all; however they are mounted in plaintext to a temporary `ramfs` during runtime, with\nstrict UNIX file permissions. These files go away when the machine is powered off, and are recreated during system activation.\n\n## Usage\n\nAdd the `opnix` module as a Flake input:\n\n```nix\n{\n  inputs = {\n    nixpkgs.url = \"github:NixOS/nixpkgs/nixpkgs-unstable\";\n    opnix = {\n      url = \"github:mrjones2014/opnix\";\n      inputs.nixpkgs.follows = \"nixpkgs\";\n    };\n  };\n\n  outputs = { nixpkgs, opnix, ... }:\n    let system = \"x86_64-linux\";\n    in {\n      nixosConfigurations.nixos-pc = nixpkgs.lib.nixosSystem {\n        inherit system;\n        modules = [\n          # import the opnix NixOS module\n          opnix.nixosModules.default\n          ./configuration.nix\n        ];\n      };\n    };\n}\n```\n\nThen, in your configuration:\n\n```nix\n{ config, ... }: {\n  opnix = {\n    # This is where you put your Service Account token in .env file format, e.g.\n    # OP_SERVICE_ACCOUNT_TOKEN=\"{your token here}\"\n    # See: https://developer.1password.com/docs/service-accounts/use-with-1password-cli/#get-started\n    # This file should have permissions 400 (file owner read only) or 600 (file owner read-write)\n    # The systemd script will print a warning for you if it's not\n    environmentFile = \"/etc/opnix.env\";\n    # Set the systemd services that will use 1Password secrets; this makes them wait until\n    # secrets are deployed before attempting to start the service.\n    systemdWantedBy = [ \"my-systemd-service\" \"homepage-dashboard\" ];\n    # Specify the secrets you need\n    secrets = {\n      # The 1Password Secret Reference in here (the `op://` URI)\n      # will get replaced with the actual secret at runtime\n      some-secret.source = ''\n        # You can put arbitrary config markup in here, for example, TOML config\n        [ConfigRoot]\n        SomeSecretValue=\"{{ op://MyVault/MySecretItem/token }}\"\n      '';\n      # you can also specify the UNIX file owner, group, and mode\n      some-secret.user = \"SomeServiceUser\";\n      some-secret.group = \"SomeServiceGroup\";\n      some-secret.mode = \"0600\";\n      # If you need to, you can even customize the path that the secret gets installed to\n      some-secret.path = \"/some/other/path/some-secret\";\n      # You can also disable symlinking the secret into the installation destination\n      some-secret.symlink = false;\n    };\n  };\n\n  # run a systemd service\n  systemd.services.my-systemd-service = {\n    enable = true;\n    # here, `config.opnix.secrets.some-secret.path` is the ramfs path\n    # of the file with the actual secret injected\n    script = ''\n      some-script --env-file ${config.opnix.secrets.some-secret.path}\n    '';\n    wantedBy = [ \"multi-user.target\" ];\n  };\n\n  # or if there's a NixOS module and it has an `environmentFile` option,\n  # you can provide your secrets that way\n  services.homepage-dashboard = {\n    enable = true;\n    environmentFile = config.opnix.secrets.some-secret.path;\n    # ... the rest of your homepage config here\n  };\n}\n```\n\n## Tradeoffs vs. `agenix`\n\n`agenix` had a few major pain points for me that we attempted to solve with this project. Those pain points are:\n\n- `age` does not support SSH agents, so I can't use the 1Password SSH agent and have to have separate SSH keys that are only on my server, on disk, although encrypted with a passphrase\n- I have to duplicate the secrets; one copy in 1Password and one copy in `my-secret.age` file in my dotfiles repo.\n\n`opnix` solves both of these pain points; SSH keys are taken out of the equation entirely, and pulls your secrets directly from your 1Password Vault(s)\nusing a [Service Account token](https://developer.1password.com/docs/service-accounts/). This does, however, come with the tradeoff that\n_a network connection is now required to provide secrets._\n\nFor my use-case (just a simple home media server and WireGuard VPN server) this is a totally fine thing for me to accept,\nhowever you'll need to use your own judgement to decide if this project is a good fit for you.\n\n## Acknowledgements/Prior Art\n\nMuch of the logic in this project is very similar to that of [agenix](https://github.com/ryantm/agenix); thanks for all the hard work you've put into that project!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrjones2014%2Fopnix","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmrjones2014%2Fopnix","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrjones2014%2Fopnix/lists"}