Key signing party for small teams

To make key signings as efficient as possible it’s important that all participants comes prepared. We avoid using Key Servers, since they are flakey, slow and might publish more information than you want. Before the event all users should have received a list of keys that will be signed, and imported them into their own keyring.

Most people don’t carry around their master key, or prefer to keep it air-gapped. These people will provide their signature later. During the signing party everyone will take a secure note of KeyID and fingerprints that they have checked.

To speed up the process and help for those with offline keys a list of KeyID and fingerprints can be prepared as a hardcopy, where the participants can take notes.

The benefit of GPG in the workplace

Most companies do a decent job with background checks and general vetting of people before hiring them. And physical security in buildings is often more than good enough, someone will notice if you go around pretending to be me at the office. On the Internet however that is a lot harder, so you need to have some kind of digital proof, something that cannot be copied or easily stolen.

And that’s GPG. Users store the private keys (or signing keys) on security tokens, like YubiKey, which cannot be copied without being destroyed, and when lost, is easily noticed. The token is protected by a PIN-number, and the private key stored on the devices is protected by a passphrase. So you need three things, a PIN, passphrase and token to impersonate someone.

A very typical scenario is that someone needs to reset or unlink MFA device from their account or something similar. It could be anyone requesting that you do that - unless they sign the request with their key, a key you know only they can (within reason) hold, that you or enough people you already trust approve off. And since we also can encrypt any data we need to send them, we don’t have to worry too much about how we’re sending it.

You also get the added benefit of a second vetting. Security works best in layers, it’s best to not assume anything. If the user loses their key or doesn’t have it you just have to do another Key Signing. At least if you want to do anything online for this user.

Lets do the Key Signing Dance

To check that the key holder is who they say they are, we meet up face-to-face, and do the key signing dance:

  1. The other participants import the key holders public key into their local keyring, using either of these alternatives:
    • gpg --import foobar.gpg
    • gpg --locate
    • gpg --recv-keys [--keyserver <|>]
    • curl | gpg --import
  2. The key holder confirms their KeyID and fingerprint by reading it out loud
  3. The other participants verify the key holders valid ID, like a drivers license or passport
  4. The other participants takes a note that they’ve verified this key

When all keys are verified the participants either sign and export the signature at the venue and hand them over to the key holder, or wait until they have access to their master key and do it then. Out of curtesy it’s common to not publish key signatures to public key servers, but rather export the signature and send it via email to the key holder. Then they can import the signatures and publish it key servers and web key directory at their own will.

  1. Sign the key holders public key, using the KeyID
    • gpg --sign-key KeyID
  2. Encrypt the key and send to key holder via email
    • gpg --export --armor KeyID > KeyID.key
    • gpg --encrypt --recipient KeyID KeyID.key (creates KeyID.key.gpg)

Why shouldn’t you publish signatures to Key Servers on other users behalf?

I was a little puzzled by this myself, as it seems strange that key servers allow a usage pattern that is not recommended. Apparently there are two primary reasons, most notably that you’ve likely only verified their name and identity, not the ownership of the e-mail account used as their UID. When you send the signature to the key holder via e-mail only the holder of that e-mail account would be able to publish the signature, proving that they own that account. And last but not least, there is a privacy concern. The Key Holder might not want the world to know that you two know each other. So we make it up to them to decide.

Cheat sheet

  1. Listing keys and fingerprint
    • gpg --list-keys [UID|KeyID]
    • gpg --list-keys --fingerprint [UID|KeyID]
  2. Exporting keys
    • gpg --export --armor <UID|KeyID>
    • gpg --export --armor SUBKEYID! [SUBKEYID! ..]
  3. Importing key signature
    • gpg --import --import-options merge-only foobar.gpg

Configuring Web Key Directory for GPG

Web Key Directory (WKD) is a proposal for a new way to discover other users keys, using HTTP and TLS. In short it looks up the UID on the users host. This works since all UIDs are email address, and all email addresses are built up of two parts, the username and host part.

When we need to look up a new key, we can just query the server, establish a secure connection using TLS, and ask it to provide the users public key. Boom! Now you don’t need to rely on flakey key servers that are abused by people for nefarious purposes, given their immutable nature.

Technical details

The documentation for WKD leaves much to be desired, and seems mostly focused on setting up more advanced systems for larger organizations to let users manage their WKD identity. For personal use it’s pretty straight forward to generate and publish.

Show me, show me!

If you’re too lazy, just export the UID hash directly, like so:

vegardx@yondu:~ $ gpg --list-keys --with-wkd-hash
pub   rsa4096/0xBBF808963354ED16 2019-08-06 [SC]
      Key fingerprint = 4770 5635 6BEF A6F0 FBE7  BB21 BBF8 0896 3354 ED16
uid                   [ultimate] Vegard Hansen <>
sub   rsa4096/0xCE7C14C99AB0CF0C 2019-08-06 [E]
sub   rsa4096/0x47C0E0BD11845008 2019-08-06 [S]
sub   rsa4096/0x9BCCE335DC440E2A 2019-08-06 [S]
sub   ed25519/0xB9FAAEC4B0E92228 2019-08-06 [A]

So when you’ve put the file in the correct place with the correct content you should be able to look yourself up, without using a key server, like so:

vegardx@bork:~ $ gpg --locate
gpg: key BBF808963354ED16: public key "Vegard Hansen <>" imported
gpg: Total number processed: 1
gpg:               imported: 1
pub   rsa4096 2019-08-06 [SC]
uid           [ unknown] Vegard Hansen <>
sub   rsa4096 2019-08-06 [E]
sub   rsa4096 2019-08-06 [S]
sub   rsa4096 2019-08-06 [S]
sub   ed25519 2019-08-06 [A]

Invalidate CloudFront with Lambda and S3 events

Bla bla bla… You’re here for the solution, not to hear me talk about it. See code example. Improvise, adapt and overcome.

One thing though, unless you have a shit metric ton of objects that you want to keep all hot and sizzling in cache I suggest you just invalidate the entire path, and not per object. Amazon has this weird pricing model where wildcard invalidations are priced as a single path.

Parking a domain on S3

You might want to “park” a domain to notify people that they’re no longer in use or whatever. Since we’re using Terraform you can update a ton of parked domains at the same time. Which is nice when business decides to rebrand everything. Like they do.

Notice that we’re using a bucket policy and not ACLs to make the contents of the bucket public. This gives us more fine grained control over access to the bucket, and while it doesn’t really matter in this case, it’s a good habit to get into.

Using Terraform to manage redirects

S3 has a few neat features, like letting you publish your webpage or store backups. But one of my favorite features is the ability to set up more or less maintenance-free redirects. This is super useful when you’re in a corporate environment where domain name changes are quite frequent, either due to rebranding or similar.

So, say you want to redirect all traffic on to, then a simple configuration like this is enough.

This only works when you want to redirect regular HTTP traffic, if the endpoint you’re redirecting from was using TLS you have to put CloudFront with certificates from Certificate Manager in front.

Salted sha-512 hashes on macOS

This has been a recurring issue for me. I often need (for some weird reason) to send a sha-512 hashed password to someone. This seems like such a trivial task, but since you’ve landed here I guess you’ve also figured out that this is non-trivial without pulling out Python or something similar. And that takes a lot of time.

In comes Docker and Alpine Linux. You can always pass the password and copy the output directly, but then you also have that password in your shell history. Probably not what you want.