{"id":18497847,"url":"https://github.com/containers/validator","last_synced_at":"2025-04-09T00:30:46.721Z","repository":{"id":201197536,"uuid":"707176589","full_name":"containers/validator","owner":"containers","description":null,"archived":false,"fork":false,"pushed_at":"2023-11-28T10:18:23.000Z","size":115,"stargazers_count":7,"open_issues_count":1,"forks_count":5,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-03-23T19:44:41.971Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-2.1","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/containers.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"COPYING","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":"2023-10-19T11:24:13.000Z","updated_at":"2024-04-11T13:04:58.000Z","dependencies_parsed_at":null,"dependency_job_id":"a51dbba7-625f-4ee3-8d99-7455c721846a","html_url":"https://github.com/containers/validator","commit_stats":null,"previous_names":["alexlarsson/validate-generator","alexlarsson/validator","containers/validator"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/containers%2Fvalidator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/containers%2Fvalidator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/containers%2Fvalidator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/containers%2Fvalidator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/containers","download_url":"https://codeload.github.com/containers/validator/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247949694,"owners_count":21023368,"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-11-06T13:36:16.488Z","updated_at":"2025-04-09T00:30:45.299Z","avatar_url":"https://github.com/containers.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Validator\n\nValidator is a tool that allows you to sign a file, or a set of files,\nusing a private (Ed25519) key, and then later install these files on\nanother system (if the signatures are valid). You can also validate\nthe files directly.\n\nValidator also ships with a dracut module that makes it very easy to\ninstall additional files from the initramfs. You can use this to , for\nexample, add signed systemd units files to an otherwise read-only\nrootfs.\n\n# Trivial example\n\nLets start with some very simple examples. First generate a\npublic/secret key-pair to sign the files:\n\n```\n$ openssl genpkey -algorithm ed25519 -outform PEM -out secret.pem\n$ openssl pkey -in secret.pem -pubout -out public.pem\n```\n\nThen generate and sign a file:\n\n```\n$ echo foobar \u003e a-file.txt\n$ validator sign --key=secret.pem a-file.txt\n$ ls  a-file.txt*\na-file.txt  a-file.txt.sig\n```\n\nThis generated a signature (a-file.txt.sig) which we can validate:\n\n```\n$ validator validate --key=public.pem a-file.txt\n```\n\nIf the file changes content this is detected:\n\n```\n$ validator validate --key=public.pem a-file.txt\nSignature of './a-file.txt' is invalid (as a-file.txt)\n```\n\nOr if the signature is missing:\n\n```\n$ validator validate --key=public.pem a-file.txt\nNo signature for './a-file.txt'\n```\n\nOr if the file has changed name:\n\n```\n$ validator validate --key=public.pem renamed-file.txt\nSignature of './renamed-file.txt' is invalid (as renamed-file.txt)\n```\n\nThis is important, because filenames often are important for\nconfiguration files, not just the content.\n\nSuppose you have a file like this, you can now distribute it (with the\nsignature files) to another machine and install it, while validating\nthe data:\n\n```\n$ validator install --key=public.pem source/dir/a-file.txt dest/dir\n```\n\nOr you can recursively copy-and-validate all the files in a source\ndirectory:\n\n```\n$ validator install --key=public.pem -r source/dir dest/dir\n```\n\nValidator also supports signing and validating symlinks, which is\ncommonly used for configuration:\n\n```\n$ ln -s source_file a-symlink\n$ validator sign --key=secret.pem a-symlink\n$ ls  a-symlink*\na-symlink  a-symlink.sig\n$ ln -sf wrong-source_file a-symlink\n$ validator validate --key=public.pem a-symlink\nSignature of './a-symlink' is invalid (as a-symlink)\n```\n\n# Read-only system usecase\n\nA common usecase for Validator is when you have a machine with a\nread-only system partition (including /etc), and on top of this you\nwant to install extra configuration files that are individual to each\nmachine. However you don't want to allow *any* such configuration file\nto be installable, just those from a trusted source.\n\nA simple example is when you have a read-only, signed, system image,\nand then install containers at runtime to /var. For this to work you\nthen need to install a systemd service file into /etc to have them\nautomatically start at boot. But, if you allow any files to persist in\n/etc then you open yourself up for a malicious actor to e.g. persist a\nrootkit to next boot.\n\nSo, instead you install the file in e.g `/var/extra-etc`, and have\nValidator validate-and-copy the files into `/etc` the next boot using\na trusted public key in the read-only system partition.\n\nFor such a setup to work at all, the system must be configured to\nallow the locations to be writable in a non-persistent way. A common\nway to achieve this is to use\n[systemd-volatile-root.service](https://www.freedesktop.org/software/systemd/man/latest/systemd-volatile-root.service.html),\nor configure ostree with [transient /etc](https://ostreedev.github.io/ostree/man/ostree-prepare-root.html).\n\n# Dracut module\n\nValidator ships with the 'validator' dracut module. If this is enabled\nwhen building an initramfs, then all the install config files from\n`/usr/lib/validator/boot.d` and `/etc/validator/boot.d` will be copied\ninto the initramfs, and applied by a custom systemd unit file during\nthe initramfs at boot. Additionally, the module will copy any keys\nfrom `/usr/lib/validator/keys` and `/etc/validator/keys`, which\nthe config file can reference.\n\nFor example, if you put this in in the `boot.d` directory:\n```\n[install]\nkeys=/usr/lib/validator/keys/etc.key\nsources=/sysroot/opt/extra-etc\ndestination=/sysroot/etc\n```\nThen any correctly signed files in /opt/extra-etc will be copied\ninto /etc during the initramfs. This can include systemd units\nor any other kind of file in /etc.\n\n# Comparison to other tools\n\nThere are many tools available to sign content (and validate\nsignatures). For example:\n\n * GnuPG (https://www.gnupg.org/gph/en/manual/x135.html)\n * Signify (https://github.com/aperezdc/signify)\n * Ssh (https://www.agwa.name/blog/post/ssh_signatures)\n * OpenSSL commandline (https://www.zimuel.it/blog/sign-and-verify-a-file-using-openssl)\n\nMany of these are actually very similar to validator internally. For\nexample, Validator calls the same OpenSSL library API as the OpenSSL\ncommandline tools, and Signify uses exactly the same algorithm for the\nsignatures. The main difference between Validator and these tools is\nthe primary usecase.\n\nIn general the workflow for all the above tools is that you have some\nsort of data, be it an email or a file and then a signature for it\n(either separate or the two could be combined). You trigger validation\nof the file and then you continue using the data. For example reading\nthe mail or compiling a tarball. There is no particular workflow\ndefined after validation, or any code to support it.\n\nFor Validator, however the primary usecase is installing a (validated)\nfile into the system, in a particular location (often /etc), with a\nparticular name (filenames are critical to config files). To support\nthis, Validator adds some extra functionality (on top of the basic\nvalidation). First of all, it signs not just the content, but also the\nfilename, as well as the file type (regular file vs\nsymlink). Secondly, the primary operation is not \"validate\", but\n\"install\" which combines the validation of a source file with the\noperation that copies it into place. Third, Validator ships with extra\ntools (such as the dracut module) to make it very easy to integrate\nfile integration with system boot.\n\nAnother area that differ is the trust model. In some of the systems\nabove, a key represent a real-world individual or organization, and\nthere are key distribution and trust mechanisms to help you understand\nwho a key represents so you can trust a message from them. However, in\nthe typical Validator usecase the key represents the target system (or\nclass of systems) running validator and that single key is hard coded\ninto those systems.\n\nSo, if your usecase does not primarily involve installing validated\nfiles with a statically known trust model, you should probably look at\nthese other tools. They are fantastic.\n\n# Signature details\n\nThe data signed is a blob comprised of the type, the relative path of\nthe file, and the sha512 content of the file, or the symlink\ntarget. The Ed25519 signature of this blob is then put next to the\noriginal file with the suffix `.sig`.  In addition, the signature\nfiles have an 8 byte header containing the bytes \"VALIDTR\\001\".\n\nSignatures can be generated using `validator sign`, such as:\n```\n$ validator sign --key=secret.pem path/to/the/file.txt\n```\n\nBy default this will create a signature for just the basename of the\nfile (`file.txt` here). However, sometimes it is useful to validate a\nlonger relative path.\n\nFor example, you might have a file called\n`path-to/extra-etc/subdir/file.txt` and you want to validate this\nrelative to `extra-etc`. This way you can recursively install from\n`extra-etc` into `/etc` and and trust that the destination file ends\nup in the `/etc/subdir` directory.\n\nIf you want to validate a longer path you have\nseveral options.\n\nOption 1 is to recursively sign, starting at `extra-etc`:\n```\n$ validator sign --key=secret.pem -r path-to/extra-etc\n```\nOption 2 is to specify a relative path:\n```\n$ validator sign --key=secret.pem --relative-to=path-to/extra-etc  path-to/extra-etc/subdir/file.txt\n```\n\nOption 3 is to supply the prefix separately (for example, if the signed file is in some other location).\n```\n$ validator sign --key=secret.pem --path-prefix=subdir other-path/file.txt\n```\n\nApplying signatures is sometimes complicated and has to be done in a\ncontrolled environment. For this reason validator can output (using\nthe `validator blob` command) a raw file with the exact data that\nwould be signed. This allows the signature can be done using any\nexternal tool that supports standard RFC 8032 Ed25519 signatures.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcontainers%2Fvalidator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcontainers%2Fvalidator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcontainers%2Fvalidator/lists"}