{"id":22412402,"url":"https://github.com/mandx/privie","last_synced_at":"2025-07-31T23:30:56.775Z","repository":{"id":38334560,"uuid":"405244103","full_name":"mandx/privie","owner":"mandx","description":null,"archived":false,"fork":false,"pushed_at":"2023-02-13T16:40:00.000Z","size":56,"stargazers_count":6,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-04-15T15:26:24.554Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","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/mandx.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}},"created_at":"2021-09-11T00:19:43.000Z","updated_at":"2021-11-14T20:26:39.000Z","dependencies_parsed_at":"2022-07-25T20:31:03.215Z","dependency_job_id":null,"html_url":"https://github.com/mandx/privie","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mandx%2Fprivie","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mandx%2Fprivie/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mandx%2Fprivie/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mandx%2Fprivie/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mandx","download_url":"https://codeload.github.com/mandx/privie/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228312180,"owners_count":17900217,"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":[],"created_at":"2024-12-05T14:08:41.352Z","updated_at":"2024-12-05T14:08:42.005Z","avatar_url":"https://github.com/mandx.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🔐 Privie 🔐\n\nAn experimental (and opinionated, and probably over-engineered) CLI utility to manage secrets as part of code, managed with your source control system. This utility is heavily inspired by [`ejson`](https://github.com/Shopify/ejson), and so, it strives to keep all of its benefits, which are:\n\n\u003e * Secrets can be safely stored in a git repo.\n\u003e * Changes to secrets are auditable on a line-by-line basis with git blame.\n\u003e * Anyone with git commit access has access to write new secrets.\n\u003e * Decryption access can easily be locked down to production servers only.\n\u003e * Secrets change synchronously with application source (as opposed to secrets provisioned by Configuration Management).\n\nThere are also a couple more (opinionated) improvements:\n\n* Keyrings are a single JSON file, instead of files named with random hashes. Now there's a single file with an explicit name to be added to `.gitignore`.\n* By default keyrings are looked up in the current directory, so no need to modify your own system using `sudo` on  `/opt/` or whatever.\n* Full support for `stdin`/`stdout`, plus explicit CLI flags to specify the input and output files.\n* Handy subcommand to add and encrypt secrets to an existing secrets file; less hand editing files.\n* Public keys are embedded in the encrypted secrets themselves, instead of a single public key shared for all the secrets in the document. This allows for two things:\n * JSON documents can now have an arbitrary structure, now there's no requirement for them to be an object. We could have a JSON document containing an array of strings, the individual strings inside the array can be encrypted too.\n * We can construct an encrypted secrets file in which each secret can have independent public keys, so, when decoding, only the keys in the keyring with a corresponding secret key will be decrypted; the rest of the secrets (those that couldn't be decrypted) will be left as-is in the output.\n\n## Caveats (or, why you shouldn't use this)\nUnfortunately, at this moment, Privie can not be recommended for production environments, mainly because:\n* I'm not cryptography expert! (Help is welcomed)\n* The [cryptographic libraries used](https://github.com/RustCrypto) provide a good API, however they haven't been (yet) properly audited.\n\n## Usage\n\n### Keyrings\n\nA keyring is a JSON document with a mapping of public keys and (optionally) their corresponding secret keys. We only need a public key to encrypt a secret, but we do need its corresponding secret key to decrypt that encrypted secret.\n\nA keyring can be generated like this:\n```\n$ privie generate-keyring \u003e my-keyring.json\n# or\n$ privie generate-keyring --output=my-keyring.json\n```\nBy default generated keyrings are dumped to `stdout`, so we can use shell redirections (`\u003e`) or the explicit `--output` parameter.\n\nNow we have a keyring file that looks like this:\n```\ncat my-keyring.json\n{\"17EV2Rohy...Th0tJF36qfAw=\":\"hy9ZzHBn...8dpiqdIBxck8=\"}\n```\n\nKeyrings contain the secret keys required for decryption, so it's very important we keep these safe. *DO NOT commit these to any code repository!*.\n\n### Encrypting\n\nAssuming we have a file called `my-secrets.json` with this content:\n\n```json\n{\n   \"mongodb\": \"mongodb://m-user:m-pass@some-server.mlab.com:23022/someDb\",\n   \"redis\": \"redis://r-user:r-pass@some-server.cloud.redislab.com:12345/1\"\n}\n```\n\nWe can encrypt it using the keyring from the previous example:\n\n```\n$ privie encrypt --keyring=my-keyring.json --input=my-secrets.json --output=my-encrypted-secrets.json\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eWe can also use `stdin` and/or `stdout` instead of `--input` and/or `--ouput`\u003c/summary\u003e\n\nFor example, this command is equivalent to the previous one:\n\n```\n$ privie encrypt --keyring=my-keyring.json \u003c my-secrets.json \u003e my-encrypted-secrets.json\n```\n\n\u003c/details\u003e\n\nNow we have a `my-encrypted-secrets.json` file that looks something like this:\n\n```\n$ cat my-encrypted-secrets.json\n{\n  \"mongodb\": \"17EV2Rohy...Th0tJF36qfAw=:qeGq09vNaBoDda8RWnmnT2zxF/B5jIeEtQ894Uy4...g9zBE2BPa08DVzt1sjHJxe\",\n  \"redis\": \"17EV2Rohy...Th0tJF36qfAw=:cDbrdgVu446IA475Hq8HTDJb7FMKGXtlG8YAgGCbr1...7Cq0FXl+O41kKRSfEix3f70pJDK1K\"\n}\n```\n\nNow our secrets are encrypted and can be committed to our repository:\n\n```\n$ git add my-encrypted-secrets.json\n$ git commit -m 'Add encrypted secrets file'\n```\n\n### Decrypting\n\n```\n$ privie decrypt --keyring=my-keyring.json --input=my-encrypted-secrets.json --output=my-decrypted-secrets.json\n```\n\nSimilar to when decrypting; we use the `decrypt` subcommand instead of `encrypt` and reverse the `--input` and `--output` params. Now we have a `my-decrypted-secrets.json` file which is \"equivalent\" to the initial `my-secrets.json` file we had at the beginning. (They won't be exactly equal, since most formatting will be lost every time a JSON document is read and written).\n\n### Sharing the keyring\n\nThis is where is up to the team to decide where to keep this file, and also, how to make it available in CI. For example, its possible to paste the content of the keyring as a Github secret, and write it to a file just before invoking `privie`:\n\n```yaml\n      - name: Decrypt the secrets file\n        env:\n          KEYRING_CONTENTS: ${{ secrets.KEYRING_CONTENTS }}\n        run: |\n          echo $KEYRING_CONTENTS \u003e my-keyring.json\n          privie decrypt --keyring=my-keyring.json --input=my-encrypted-secrets.json --output=my-decrypted-secrets.json\n```\n\nYou can also have the keyring's content piped in via `stdin`, like so:\n\n```\n$ echo $KEYRING_CONTENTS | privie decrypt --keyring=- --input=my-encrypted-secrets.json --output=my-decrypted-secrets.json\n```\nMost commands with a `--keyring` argument will allow using `-` to denote to read from `stdin`, the limitation being that it won't be possible then to use `stdin` for the `--input` argument.\n\n// TODO: Add more examples\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmandx%2Fprivie","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmandx%2Fprivie","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmandx%2Fprivie/lists"}