We would like to use gpg signatures to verify some aspects of our system configuration management tools. Additionally, we would like to use a "trust" model where individual sysadmin keys are signed with a master signing key, and then our systems trust that master key (and use the "web of trust" to validate signatures by our sysadmins).
This gives us a lot of flexibility, such as the ability to easily
revoke the trust on a key when someone leaves, but we've run into a
problem. While the gpg
command will tell you if a key is
untrusted, it doesn't appear to return an exit code indicating this
fact. For example:
# gpg -v < foo.asc
Version: GnuPG v1.4.11 (GNU/Linux)
gpg: armor header:
gpg: original file name=''
this is a test
gpg: Signature made Fri 22 Jul 2011 11:34:02 AM EDT using RSA key ID ABCD00B0
gpg: using PGP trust model
gpg: Good signature from "Testing Key <[email protected]>"
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: ABCD 1234 0527 9D0C 3C4A CAFE BABE DEAD BEEF 00B0
gpg: binary signature, digest algorithm SHA1
The part we care about is this:
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
The exit code returned by gpg in this case is 0, despite the trust failure:
# echo $?
0
How do we get gpg to fail in the event that something is signed with an untrusted signature?
I've seen some suggestions that the gpgv
command will return a proper exit code, but unfortunately gpgv
doesn't know how to fetch keys from keyservers. I guess we can parse the status output (using --status-fd) from gpg
, but is there a better way?
This is what ended up with:
This looks for the trust information that
gpg
outputs on--status-fd
. The script exits with an error in the presence of an untrusted signature (or invalid/no signature):The script exits with no error in the presence of a valid, trusted signature:
So let me try to split the issue:
First issue seems that the key your are testing against is untrusted.
I assumed this is intentional... but before we get to how to fix, let me suggest you use gpgv instead of gpg -v? You will se why in a minute:
No key, no trust... No we import the key into trustedkeys.gpg
Hope it helps
Two options come to mind (other than parsing the output).
A quick and dirty way would be to run both
gpg
andgpgv
. The first run ofgpg
would ensure the key was fetched from the keyserver, and thengpgv
will give you the return code you want.A more elegant, controlled way (though it would involve more work) would be to use the gpgme library to verify the signature. It is a C library, though there are wrappers for Perl, PHP, Python and Ruby. (The Python one is quite low level, while the Ruby one has some higher level abstractions, not sure about Perl or PHP).
The GPGME library appears to talk to keyservers when I've used it, though you'd want to confirm that. I've written a bit of code that uses the ruby gpgme library (search for
verify
andverified_ok?
for code that verifies a signature, and forsig_output_lines
for some code that works out whether a signature is trusted).What about migrating your system configuration to a tool like Puppet or Chef?
While a non-trivial amount of work, Chef (I have not used Puppet) you must create user accounts (and pub/private keys are generated). While this doesn't prevent people from modifying the files local on the server, chef-client runs periodically, and will overwrite their changes on the next run. (Periodic recurring runs occurs by default.)