{"id":16138006,"url":"https://github.com/glehmann/yage","last_synced_at":"2025-03-16T09:33:12.817Z","repository":{"id":220154366,"uuid":"750867809","full_name":"glehmann/yage","owner":"glehmann","description":"A simple tool to manage encrypted secrets in YAML files with age encryption 🔑","archived":false,"fork":false,"pushed_at":"2025-03-10T10:40:58.000Z","size":422,"stargazers_count":22,"open_issues_count":4,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-10T11:35:07.223Z","etag":null,"topics":["age-encryption","secret-distribution","secret-management","yaml"],"latest_commit_sha":null,"homepage":"","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/glehmann.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-01-31T13:37:21.000Z","updated_at":"2025-03-10T10:40:55.000Z","dependencies_parsed_at":"2024-03-02T14:30:19.620Z","dependency_job_id":"a3463c59-b4ff-483f-a8f7-6923b0ecf6b7","html_url":"https://github.com/glehmann/yage","commit_stats":null,"previous_names":["glehmann/yage"],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/glehmann%2Fyage","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/glehmann%2Fyage/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/glehmann%2Fyage/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/glehmann%2Fyage/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/glehmann","download_url":"https://codeload.github.com/glehmann/yage/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243809844,"owners_count":20351406,"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":["age-encryption","secret-distribution","secret-management","yaml"],"created_at":"2024-10-09T23:31:16.429Z","updated_at":"2025-03-16T09:33:12.420Z","avatar_url":"https://github.com/glehmann.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# yage: yaml age\n\nA simple tool to manage encrypted secrets in YAML files with age encryption.\n\n`yage` is using [age encryption](https://github.com/FiloSottile/age) to encrypt the *values*\nin a [YAML](https://yaml.org/) file while keeping the *keys* unchanged.\n\nA simple yaml file like this one:\n\n```yaml\nbackend:\n  url: https://example.com\n  username: gaspard\n  password: api_s3cr3t_k3y\n```\n\nis encrypted by `yage` to:\n\n```yaml\nbackend:\n  url: yage[YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1KzZiNVVvTThaQ0dSbVZBMElRUEpZRlVxb1VaamU3SGtWRWxseFBHMkVNClBsUGJMWFJ0MnA0czA0MEE0VnRjY3Q3VnE4NElpUHQ2aTNKUlVMOUJnbEUKLT4gZGVVYFRQcVwtZ3JlYXNlIHR+OSVVZyMhCituclJ0ZTZJU1grSmpxaTZvb2hMYlBvMnpIbGFja0ltRm9BdE9sTVJ5RG14RkhNaXNsc0xUbUViT1lyRVh6dWYKdHRsVU10SHJ1YytaY2hhdWdjQ0lJVnFkczJFcHBMMXl3QTNEQUc1SW9YM0hscGZVbEdPdWZWTQotLS0gcTVIZzZrdnVJNGNoNm51UEE1alJHVmJsQnRMdStuVXU0Q1pJSzFzVlU1QQqH64hS0UV4JI6CtYHpSCEslxLqi3764zaxF/VJy67gQOBrj2TV1z6NwJaBmlUPBQB2zROq|r:age15eesfkh778yljxzgwdq5vaqmmchg5py480vplsymzzqf0dwe5gnqrexdq6]\n  username: yage[YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBVU2tuOWFpV2NDT05DSC9FbHNadzVVTTJmSFQwekRjRjZiOERDVTZ0aGdnCnhKTGpQcGY1SUw0bFd2cFhudC9yY1I0VTJxWklBYUkvYlhzNHhUeCtIVmsKLT4gTGJ+LWdyZWFzZSAhClJlTU5TZ3NldGRaRzRGQThOZmMrdkFnS0NzUnBpMmFpRTM4d0hGQXEKLS0tIGQvSXIxcXpDYk9yTU9ERDlEMHV1d0VmTGovWU9SVkJ5TkswYS9rMmdGbHMK3GehcWJL1GUKFGLJXQFGUQLhs56mgHRYpBIsFgYpyW818dG27bz1jQ==|r:age15eesfkh778yljxzgwdq5vaqmmchg5py480vplsymzzqf0dwe5gnqrexdq6]\n  password: yage[YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAyRVUyTHpmQnZuTlc5MGJhODFuSE5WMmdzalNid0ExamliNDREbWlJUXdvClFhS3JGSGV2cjlnL0dWUnNwSDNvWGVHUDVDendkNzFWWXJCcTNDTVJNLzgKLT4geW0tZ3JlYXNlIF8zJ3MpXksKeXRwMW9aeitydwotLS0gWVNjbnZsUmNRWTdtM0pjVjNKQjBDZ1k2cVNhcWkwMnAxREwwMXptREhLZwrpCkrMFiq/XWfAyFRrLuLkkEPhnZ9Kt68pg5ENgDTV9+3iRcy6XKYdkqnEBRidMg==|r:age15eesfkh778yljxzgwdq5vaqmmchg5py480vplsymzzqf0dwe5gnqrexdq6]\n```\n\nHaving the keys unencrypted allows to easily manage the file in a version control system, like git,\nand to use this file in a CI/CD pipeline or in a [gitops](https://en.wikipedia.org/wiki/DevOps#GitOps)\nworkflows.\n\nIf you think this looks a lot like [SOPS](https://getsops.io/), you're right! This is basically what\nSOPS is doing, but we some key differences:\n* `yage` doesn't include any metadata in the encrypted file, in particular no [MAC](https://en.wikipedia.org/wiki/Message_authentication_code).\n* `yage` is focused on age encryption, and include everything required in a single binary.\n\nThe lack of MAC, while it could be seen as a missed opportunity to add some security, actually allows\nsome interesting use cases:\n  * the encrypted file can modified by someone that only has the public key, while still preserving\n    the encrypted values.\n  * the encrypted file can modified by multiple persons and merged in a version control system without\n    having to decrypt it first.\n  * the encrypted file only contains the original keys and the encrypted values, so it can be used\n    to verify that it is usable for a specific task without having to decrypt it or remove the metadata.\n\n## Installation\n\n### From binaries\n\nGo to the [releases page](https://github.com/glehmann/yage/releases), download the binary for your\nplatform, extract it and put the `yage` binary in a directory in your `PATH`.\n\nFor example on linux with an intel/amd64 processor, you can run the following commands to install `yage` in `~/.local/bin`:\n\n```sh\ncurl -ssL https://github.com/glehmann/yage/releases/download/0.5.0/yage-0.5.0-linux-amd64.tar.gz | tar xzf - -C ~/.local/bin --strip-components=1\n```\n\n### Docker\n\n`yage` is also available as a [docker image](https://github.com/glehmann/yage/pkgs/container/yage).\n\nHere is how you can use it to encrypt a file in place:\n\n~~~sh\ndocker run --rm -t -v $(pwd):/src ghcr.io/glehmann/yage:0.5.0 encrypt -iR prod.pub secrets.yaml\n~~~\n\n### From source\n\nJust run\n\n```sh\n$ cargo install --path .\n```\n\nin this repository\n\n## Command line reference\n\n`yage` comes with a full description of its commands and options. Just run `yage --help` to get it.\n\n```sh\n$ yage --help\nA simple tool to manage encrypted secrets in YAML files with age encryption\n\nUsage: yage [OPTIONS] [COMMAND]\n\nCommands:\n  check       Check the encryption status of a YAML file\n  decrypt     Decrypt the values in a YAML file\n  edit        Edit an encrypted YAML file\n  encrypt     Encrypt the values in a YAML file\n  env         Execute a command with the environment from the encrypted YAML file\n  keygen      Generate a new age key\n  pubkey      Convert private age keys to their public key\n  recipients  List the recipients of the encrypted data\n  re-encrypt  Re-encrypt the values in a YAML file\n  help        Print this message or the help of the given subcommand(s)\n\nOptions:\n      --completion \u003cSHELL\u003e  Generate the completion code for this shell [possible values:\n                            bash, elvish, fish, powershell, zsh]\n  -v, --verbose...          Increase logging verbosity\n  -q, --quiet...            Decrease logging verbosity\n  -h, --help                Print help\n  -V, --version             Print version\n```\n\nSee also the [markdown version of the command line reference](doc/CommandLineHelp.md).\n\nYou may also find convenient to install the completion for your shell. For example for fish:\n\n```sh\n$ yage --completion fish \u003e ~/.config/fish/completions/yage.fish\n```\n\n## Usage\n\nFirst generate a new age key pair:\n\n```sh\n$ yage keygen -o prod.key -p prod.pub\nPublic key: age15eesfkh778yljxzgwdq5vaqmmchg5py480vplsymzzqf0dwe5gnqrexdq6\n```\n\nThe public key can be shared with anyone. It allows everybody that has that key to encrypt a secret that\ncan be decrypted only by someone who has access to the private key. The private key must be kept secret.\n\nBoth keys are just text:\n\n```sh\n$ cat prod.key\nAGE-SECRET-KEY-1EZEU9RUTW3K5GV98ER6RHMS73QJNQ37ARWG6MWHXM4JP8FVD3A9QK2DD70\n```\n\nThe public key could be committed to a git repository:\n\n```sh\n$ git add prod.pub\n$ git commit -m \"Add prod public key\"\n```\n\nMake sure that the private key won't be committed by mistake in the repository, for example by adding it\nto the `.gitignore` file, and by using a tool like [gitleaks](https://github.com/gitleaks/gitleaks).\n\n```\n$ echo \"*.key\" \u003e .gitignore\n```\n\nThe private key should be kept in a secure place, for example in a password manager. It may also\nbe added to a CI/CD pipeline as [a secret](https://docs.github.com/actions/security-guides/encrypted-secrets).\n\nOnce you have a private and a public key, you can encrypt a YAML file. The `--recipient-file` or `-R`\noption is used to specify a file containing the public keys to use for encryption. The recipients\ncan also be specified directly on the command line with the `--recipient` or `-r` option.\n\n```sh\n$ yage encrypt --recipient-file prod.pub secrets.yaml --output secrets.enc.yaml\n```\n\nIf you prefer you can encrypt the file in place wit the `--in-place` or `-i` option:\n\n```sh\n$ yage encrypt -iR prod.pub secrets.yaml\n```\n\nYou need the private key to have access to the decrypted values, so if you don't have it,\nthe encrypted file is showing you what is encrypted, for example `backend.password`, but not the values.\n\n```yaml\nbackend:\n  password: yage[YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBRVW9wTXo0dG9lWTRyd1gxdm8yTGNOb1VuQWZSajBETzF4YThMbVVGM21FCjBTQXZxVDIvTWxGd1N6YXlUTHpoVlMzbTVURDZHcXBYaVc5NitYaE1LSW8KLT4gayMtZ3JlYXNlIFwganwhJUcyS1QgTT5sWTMzblYKCi0tLSBLUnREbytjalY3Rm45aEdVVnIzWG8yWC9RUVdlK1A4Mm9BSFdtamg5N2RNCm38HthiQvHqtUIu6+wKOyOH0WShltaeTGk2Qilym+9WFFb0n8g5Eb/6|r:age15eesfkh778yljxzgwdq5vaqmmchg5py480vplsymzzqf0dwe5gnqrexdq6]\n```\n\nBut with just the public key, you can still modify the file, for example to add a new secret:\n\n```yaml\nmail:\n  apiKey: my_secret_key_to_send_emails\nbackend:\n  password: yage[YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBRVW9wTXo0dG9lWTRyd1gxdm8yTGNOb1VuQWZSajBETzF4YThMbVVGM21FCjBTQXZxVDIvTWxGd1N6YXlUTHpoVlMzbTVURDZHcXBYaVc5NitYaE1LSW8KLT4gayMtZ3JlYXNlIFwganwhJUcyS1QgTT5sWTMzblYKCi0tLSBLUnREbytjalY3Rm45aEdVVnIzWG8yWC9RUVdlK1A4Mm9BSFdtamg5N2RNCm38HthiQvHqtUIu6+wKOyOH0WShltaeTGk2Qilym+9WFFb0n8g5Eb/6|r:age15eesfkh778yljxzgwdq5vaqmmchg5py480vplsymzzqf0dwe5gnqrexdq6]\n```\n\nYou can encrypt the new secrets by just using the same command as before:\n\n```sh\n$ yage encrypt -iR prod.pub secrets.yaml\n```\n\nOr you can omit the recipients, and `yage` will use the recipients from the encrypted file:\n\n```sh\n$ yage encrypt -i secrets.yaml\n```\n\n`secrets.yaml` now contains the encrypted values:\n\n```yaml\nmail:\n  apiKey: yage[YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBPTmRHcGhPUnJQa2ZjbTVEUEtyT3g1bFd5REdnckF6Z0ZLQzlTekV5THdJCkoybXY3SEI2N3FTcXlHenByRHJOVGFtR2VRUWFBWGhEOGphbkd2ekV3bVkKLT4geUt2b0I2Ly1ncmVhc2UKODVocmxxODlZME1Sa1UvV2RnQkNPcjhvTWpZZFlKYzNkQmsKLS0tIHhsNEpvYzNwT1FMd1c2bmxLQmxOeGZxWnlXbDJUUmVsTklxZVIweUxSQXcK51Wf0RiFIAXYfsbmyMsyQRON5rhQxver8PUU8PDAMIm0XeBSKOzL3ngCmOKGeacahMOY5tWC6DgP20MrtQ==|r:age15eesfkh778yljxzgwdq5vaqmmchg5py480vplsymzzqf0dwe5gnqrexdq6]\nbackend:\n  password: yage[YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBRVW9wTXo0dG9lWTRyd1gxdm8yTGNOb1VuQWZSajBETzF4YThMbVVGM21FCjBTQXZxVDIvTWxGd1N6YXlUTHpoVlMzbTVURDZHcXBYaVc5NitYaE1LSW8KLT4gayMtZ3JlYXNlIFwganwhJUcyS1QgTT5sWTMzblYKCi0tLSBLUnREbytjalY3Rm45aEdVVnIzWG8yWC9RUVdlK1A4Mm9BSFdtamg5N2RNCm38HthiQvHqtUIu6+wKOyOH0WShltaeTGk2Qilym+9WFFb0n8g5Eb/6|r:age15eesfkh778yljxzgwdq5vaqmmchg5py480vplsymzzqf0dwe5gnqrexdq6]\n```\n\nNote that `backend.password` has not been re-encrypted, so you can easily track the changes in your\nversion control system.\n\nTo decrypt the file, you need the private key:\n\n```sh\n$ yage decrypt --key-file prod.key secrets.enc.yaml --output secrets.yaml\n```\n\nOr just do it in place:\n\n```sh\n$ yage decrypt -iK prod.key secrets.yaml\n```\n\nIf your decrypting in a CI/CD pipeline, you may find convenient to put the private key in the\n`YAGE_KEY` environment variable. This way you can just use `yage decrypt -i secrets.yaml`.\n\nYou may also find convenient to pass the private key on the standard input, for example to avoid\nstoring the private key on disk:\n\n```sh\n$ vault-get-key | yage decrypt --key-file - secrets.yaml\n```\n\nIf you have the private key, you can edit the file in place with your favorite text editor\nconfigured in the `EDITOR` environment variable:\n\n```sh\n$ export EDITOR=micro\n$ yage edit -K prod.key secrets.yaml\n```\n\nThe file is edited in clear in the editor and re-encrypted when you save and quit. Here again only\nthe modified values are re-encrypted. The others are left unchanged to allow easy tracking of changes.\n\nFinally, with the private key, you can use the secrets in the encrypted file to run a command\nwith the environment variables set to the decrypted values in a single command:\n\n```sh\n$ yage run -K prod.key secrets.yaml env terraform apply\n```\n\n## Pre-commit hook\n\n`yage` can be used in a [pre-commit hook](https://pre-commit.com/) to make sure that the secrets are always encrypted before\ncommitting them to the repository. Here is an example of a `.pre-commit-config.yaml` file that\nuses `yage` to detect the non-encrypted secrets in a YAML file before committing them:\n\n```yaml\nrepos:\n  - repo: https://github.com/glehmann/yage\n    rev: 0.5.0\n    hooks:\n      - id: yage-detect\n        files: \"secrets-.+\\\\.yaml\"\n```\n\nThe `files` option is a regular expression that matches the files that should be checked by `yage`.\n\nIf your public key is in the repository, you can also add a hook to encrypt the secrets before\ncommitting them:\n\n```yaml\nrepos:\n  - repo: https://github.com/glehmann/yage\n    rev: 0.5.0\n    hooks:\n      - id: yage-encrypt\n        files: \"secrets-prod-.+\\\\.yaml\"\n        args: [\"--in-place\", \"--recipient-file=prod.pub\"]\n```\n\n`yage-detect` and `yage-encrypt` hooks require the `yage` binary to be installed in the environment where the hook is\nrunning.\n\nThe `yage-detect-rust` and `yage-encrypt-rust` hooks are other available variants that\nbuild yage from source.\n\nIf you're already using docker in your project, the easiest alternatives are the `yage-detect-docker` and\n`yage-encrypt-docker` hooks. They only require docker to be installed in the environment where the hook is running.\nThe `yage` image is downloaded automatically when the hook is run for the first time.\n\n## Why?\n\nMostly to unlock the ability to add values to an encrypted file without having to decrypt it,\nthing that is not possible with SOPS. Something I've not been the only one frustrated with, see\n[here](https://github.com/getsops/sops/discussions/1081),\n[here](https://stackoverflow.com/questions/74103453/is-it-possible-to-update-a-sops-encrypted-file-without-decrypting-it-first),\n[here](https://github.com/getsops/sops/issues/1117), [here](https://github.com/getsops/sops/issues/833), …\n\nAnd because writing command line tools in rust is fun!\n\n## Still to be done\n\n* [ ] Support comments. Sadly no YAML library that I know of supports comments, so this will be a bit tricky.\n* [ ] Support age plugins. age has a plugin system that could be used to add support for other encryption methods.\n* [ ] Support multi-document YAML files. This could help to make the CLI more consistent between in place and\n      standard output operations.\n\n## License\n\n`yage` is distributed under the terms of the MIT license.\n\nSee [LICENSE](LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fglehmann%2Fyage","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fglehmann%2Fyage","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fglehmann%2Fyage/lists"}