Rotate Encryption Keys
GoodData.CN encrypts data source credentials and organization OIDC client secrets with a Google Tink keyset that you supply to the metadata-api service. Rotating that keyset periodically is a standard security practice. For the initial keyset and the Helm values that enable encryption, see Encrypt Metadata and Data Source Credentials.
Rotation is prone to race conditions, because every metadata-api pod must know a key before anything is encrypted with it. Perform the steps in order and do not skip the restarts.
All commands use Tinkey, the Tink key management tool:
curl -fsL https://storage.googleapis.com/tinkey/tinkey-1.9.0.tar.gz | tar xzvf -Keep every keyset version
Keep the keyset in a secure location and back it up alongside your database backups. Data encrypted with a key that no longer exists in any backup of the keyset cannot be decrypted.
Add a New Key
Add a new key to the keyset and propagate the change to all metadata-api services before you promote it.
Steps:
Identify all existing keys in the keyset:
tinkey list-keyset --in live_keyset.json |grep ' key_id:'The output may look something like this:
key_id: 1088398113 key_id: 343627806Add a new key to the keyset:
tinkey add-key --key-template AES256_GCM --in live_keyset.json --out added_key_keyset.jsonVerify by listing the keys again:
tinkey list-keyset --in added_key_keyset.json |grep ' key_id:'The output may look something like this:
key_id: 1088398113 key_id: 343627806 key_id: 1292234114where
key_id: 1292234114is the new key.Distribute
added_key_keyset.jsonto your GoodData.CN deployments by updating the Secret referenced bymetadataApi.encryptor.existingSecret, and make sure allmetadata-apipods restart afterwards.
Promote the New Key
Promoting a key makes it the primary key used for encryption. Do this only after every metadata-api pod has restarted with the new key present.
tinkey promote-key --key-id <RECENTLY_ADDED_KEY_ID> --in added_key_keyset.json --out rotated_keyset.jsonReplace <RECENTLY_ADDED_KEY_ID> with the ID of the key you just added (for example, 1292234114).
Distribute rotated_keyset.json the same way and restart all metadata-api pods again.
Re-encrypt Existing Secrets
With the new primary key in place, secrets stored earlier are still encrypted with the previous key. Re-encrypt them by calling the reencrypt actuator endpoint on the metadata-api pod:
kubectl exec <pod> -n <namespace> -- /bin/bash -c "curl -X POST -v http://localhost:9008/actuator/reencrypt"For example:
kubectl -n gooddata-cn exec -c metadata-api deployments/gooddata-cn-metadata-api -- curl -X POST -v http://localhost:9008/actuator/reencrypt(Optional) Remove the Oldest Key
The keyset grows with every rotation, so you may want to drop keys you no longer need. Before you do:
- Confirm the key does not encrypt any secret, which means the re-encryption in the previous step completed.
- Remember that SQL-level database backups taken while the key was in use become unusable once the key is gone.
tinkey delete-key --key-id <OLDEST_KEY_ID> --in rotated_keyset.json --out removed_old_key_keyset.jsonDistribute the resulting keyset and restart the metadata-api pods.
Inspect a Keyset
To review the keys in a keyset and see which one is primary:
tinkey list-keyset --in keyset.jsonprimary_key_id: 343627806
key_info {
type_url: "type.googleapis.com/google.crypto.tink.AesGcmKey"
status: ENABLED
key_id: 1088398113
output_prefix_type: TINK
}
key_info {
type_url: "type.googleapis.com/google.crypto.tink.AesGcmKey"
status: ENABLED
key_id: 343627806
output_prefix_type: TINK
}