Introduction:
This guide explains how to rotate Tink encryption keys in CircleCI Server. Tink key rotation lets you introduce a new encryption key for fresh data while retaining old keys for decrypting previously stored information.
This process involves adding a new key to your keyset JSON, making it the primary key, and keeping the old key(s) until they are no longer needed.
This process is useful if your Tink key is leaked or otherwise compromised and needs to be replaced to ensure the security of your context vars.
Prerequisites:
Access to the CircleCI Server Helm values (
values.yaml)Access to the Tink keyset (JSON), either from tink.keyset in values.yaml or via the tink Kubernetes secret
Administrative access to the deployment environment.
Familiarity with base64 encoding/decoding and JSON editing.
Instructions:
-
Locate the current keyset
Retrieve your current Tink keyset from
values.yamlor thetinksecret-
If retreiving from the K8S secret, it'll need to be base64 decoded:
kubectl -n <circle-ns> get secret tink -o jsonpath='{.data.keyset}'|base64 -d|jq > keyset.json
-
Generate a new key
Use Tink CLI or library to generate a key for the same primitive (e.g., AES-GCM).
-
Example (CLI, pseudo-code):
./tinkey create-keyset --key-template XCHACHA20_POLY1305 > new_keyset.json
-
Merge the new key into the existing keyset
Open both
keyset.json(existing) andnew_keyset.json(new key).-
Copy the new
keyobject fromnew_keyset.jsoninto thekeyarray ofkeyset.json.{ "primaryKeyId": 3921291120, "key": [ { "keyData": { "typeUrl": "type.googleapis.com/google.crypto.tink.XChaCha20Poly1305Key", "value": "GiD7e53Wz1SE71MZ8twnancdqS+48lYJFMwoLkHcZQX65g==", "keyMaterialType": "SYMMETRIC" }, "status": "ENABLED", "keyId": 3921291120, "outputPrefixType": "TINK" }, { "keyData": { "typeUrl": "type.googleapis.com/google.crypto.tink.XChaCha20Poly1305Key", "value": "GiARW2q2hwUqOMIAeL7T2R/+NKDIiaOYchhIIMLLVG6HMw==", "keyMaterialType": "SYMMETRIC" }, "status": "ENABLED", "keyId": 2483191459, "outputPrefixType": "TINK" } ] }Tip: You can pipe the single line json into jq with no args to get the "pretty" formatted version for editing then run it through
jq -cpost editing to obtain the oneline compact form.
-
Make the new key the primary
Update the
primaryKeyIdinkeyset.jsonto match thekeyIdof the new key.Keep the old key’s
statusas"ENABLED"to ensure old data can still be decrypted.
-
Update CircleCI Server with the rotated keyset
-
Encode the updated JSON as base64 and create the new tink secret:
kubectl create secret generic tink --from-file=keyset=keyset.json
OR
-
Update
values.yaml, encapsulating the full json blob in single quotes under tink.keysethelm upgrade
-
-
Phase out old keys (optional)
Once all data encrypted with the old key has been re-encrypted or is no longer needed, change its
statusto"DISABLED"or"DESTROYED".Apply the updated keyset to CircleCI Server again.
Outcome:
After following these steps, CircleCI Server will encrypt all new data with the newly created key while still being able to decrypt old data using the previous keys. Over time, old keys can be disabled or destroyed to complete the rotation process.
Additional Notes:
Tink stores the key ID in the ciphertext prefix, allowing it to automatically select the correct key during decryption.
Key rotation does not automatically re-encrypt existing data — you must handle that manually if required.
Comments
Article is closed for comments.