Skip to content

Allow multiple keys to be used for decrypting messages#11

Merged
armon merged 25 commits intohashicorp:masterfrom
ryanuber:multikey
Apr 7, 2014
Merged

Allow multiple keys to be used for decrypting messages#11
armon merged 25 commits intohashicorp:masterfrom
ryanuber:multikey

Conversation

@ryanuber
Copy link
Member

@ryanuber ryanuber commented Apr 3, 2014

For reliable key rotation to work, we need to support adding in encryption keys and then switching to them without removing the origin key. This would allow some time for all members to perform their key cut-over, and then remove the old key later on.

Here I have added a config.SecretKeys list, which tracks all keys memberlist currently knows about. We still have the original config.SecretKey, which is the key that is used for encrypting messages.

When a new key is installed, it is not immediately activated. This is to allow time for the new key to be distributed to all members. Once it is safe to start encrypting messages with the new key, a call to UseSecretKey can be made, passing in the key which should become the "active" key.

When a message is received, we first try to decode it using the "active" key. Failing that, we iterate through each of our config.SecretKeys (excluding the active key), and attempt to decrypt with each one until we get a success. If no keys work, then an error message is returned.

The original interfaces are all still intact.

@armon
Copy link
Member

armon commented Apr 3, 2014

This looks great! The only suggestion I have is to add an "internal" version of m.config.GetSecretKeys that caches the list of keys, just so that we are allocating a new slice every time we get a message. Should be a minor change. Thanks!

@ryanuber
Copy link
Member Author

ryanuber commented Apr 3, 2014

@armon Thanks, and good point. Maybe something like the updates I just pushed? Now whenever keys get modified using AddSecretKey, RemoveSecretKey, or UseSecretKey, we just order SecretKeys at that time and store it in the config structure so we can use it directly without allocating a new ordered slice.

@armon
Copy link
Member

armon commented Apr 3, 2014

@ryanuber I think this is going in the right approach, but there are some questionable thread safety issues in here. I think there should honestly be a private member installedKeys or something, that is protected by a mutex. Add/Remove/Install key should grab the lock, build the new slice, and just do a pointer swap on installedKeys. Internally we should only ever read the installedKeys. Otherwise we are changing the slice around while another goroutine is reading from it. Its okay for us to do the slice allocation on key changes (very rare), as long as its not in the hot loop of decoding.

@armon
Copy link
Member

armon commented Apr 3, 2014

Sorry to nitpick on this!

@ryanuber
Copy link
Member Author

ryanuber commented Apr 3, 2014

@armon no problem! You're right, I'll take another look tonight when I have more time. Thanks!

@ryanuber
Copy link
Member Author

ryanuber commented Apr 4, 2014

@armon, I added a mutex to the operations that read/write key data. I overhauled it a little and broke all of this stuff out into a Keyring structure which seemed more fitting than shoving it all into Config. One thing I haven't really done is test the Mutex, and I'm not sure what the right way to go about doing that is since the calls are blocking.

I also added an EncryptionEnabled bool to Config, rather than checking config.SecretKey != nil. This isn't really necessary now that I think about it so if you'd rather not have that we can just axe it.

@ryanuber
Copy link
Member Author

ryanuber commented Apr 4, 2014

Ok, I think I've got a decent amount of tests. @armon Maybe let's let this soak over the weekend. Let me know your thoughts whenever you have a few minutes. Thanks!

@armon
Copy link
Member

armon commented Apr 4, 2014

Sorry things have been busy! This is definitely the right direction. I think we can kill SecretKeys and EncryptionEnabled. We must keep SecretKey for backwards compatibility. If the secret key OR keychain is provided, encryption is enabled. Thanks! I will try to review more closely soon.

@ryanuber
Copy link
Member Author

ryanuber commented Apr 5, 2014

@armon no problem, how often are things not busy? No rush at all, just let me know what you think whenever you have time to do a code review on this.

I killed SecretKeys and EncryptionEnabled. So this would leave memberlist with 4 options for instantiation:

  • Omitting encryption entirely
  • Passing only SecretKey, which automatically gets installed as the primary key on the Keyring
  • Passing only Keyring, which simply installs the provided keyring
  • Passing both SecretKey and Keyring, which installs the keyring and sets the primary key to SecretKey.

@armon
Copy link
Member

armon commented Apr 7, 2014

Awesome work! LGTM! Thanks @ryanuber

armon added a commit that referenced this pull request Apr 7, 2014
Allow multiple keys to be used for decrypting messages
@armon armon merged commit fb5619c into hashicorp:master Apr 7, 2014
@ryanuber ryanuber deleted the multikey branch April 9, 2014 08:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants