Distributed cache
Single-instance deployments cache GitHub access tokens in process memory. With multiple instances, each independently requests tokens from GitHub, increasing API usage and latency. A shared Valkey cache eliminates this redundancy by allowing all instances to read and write from the same token store.
Chinmina supports Valkey (or any Redis-compatible server) as a distributed cache backend. When configured, Chinmina uses a multi-level caching strategy: a fast local in-memory cache backed by the shared Valkey instance.
As you go
Section titled “As you go”Values to save for configuration are marked in the instructions below like this: 📝 ENV_VAR_NAME.
Collect these values as you proceed through the infrastructure setup sections. They are used in the “Configure Chinmina” steps that follow each section.
Create the Valkey instance
Section titled “Create the Valkey instance”-
Create an ElastiCache Serverless Valkey cache (or replication group) by following the ElastiCache getting started guide. Place the cache in the same VPC as your Chinmina instances, or ensure network connectivity via VPC peering or security group rules.
Save the cache endpoint as 📝 VALKEY_ADDRESS and cache name (replication group ID or serverless cache name) as 📝 VALKEY_IAM_CACHE_NAME.
-
Enable in-transit encryption (TLS) on the cache. TLS is required for IAM authentication and is strongly recommended in all cases.
-
Create an ElastiCache IAM-enabled user for Chinmina to authenticate with.
Save the user ID as 📝 VALKEY_USERNAME.
Configure Chinmina for the Valkey cache
Section titled “Configure Chinmina for the Valkey cache”-
Set
CACHE_TYPE=valkeyandVALKEY_ADDRESSto the cache endpoint inhost:portformat:Terminal window CACHE_TYPE=valkeyVALKEY_ADDRESS=chinmina-cache-abcdef.serverless.use1.cache.amazonaws.com:6379 -
Enable IAM authentication and identify the cache:
Terminal window VALKEY_IAM_ENABLED=trueVALKEY_IAM_CACHE_NAME=chinmina-cacheVALKEY_IAM_SERVERLESS=trueSet
VALKEY_IAM_SERVERLESS=truefor ElastiCache Serverless caches, orfalsefor replication groups. -
Set
VALKEY_USERNAMEto the IAM user ID created in the previous section:Terminal window VALKEY_USERNAME=chinmina-cache-user -
Grant the Chinmina execution role
elasticache:Connectpermission, scoped to the cache and user:example-elasticache-iam-policy.json {"Version": "2012-10-17","Statement": [{"Effect": "Allow","Action": "elasticache:Connect","Resource": ["arn:aws:elasticache:us-east-1:123456789012:serverlesscache:chinmina-cache","arn:aws:elasticache:us-east-1:123456789012:user:chinmina-cache-user"]}]}
Configure cache encryption
Section titled “Configure cache encryption”Cache encryption uses Tink for AEAD (Authenticated Encryption with Associated Data) with AES-256-GCM. An encrypted Tink keyset is stored in AWS Secrets Manager, protected by an AWS KMS envelope encryption key. At runtime, Chinmina decrypts the keyset and uses it to encrypt and decrypt cached tokens.
Create the KMS key and Secrets Manager secret
Section titled “Create the KMS key and Secrets Manager secret”-
Create a symmetric encryption KMS key (AES-256). Enable automatic annual rotation and set the deletion window to 30 days. Follow the KMS key creation guide for detailed instructions.
Save the key ARN as 📝 CACHE_ENCRYPTION_KMS_ENVELOPE_KEY_URI.
-
Create an alias for the key, for example
alias/chinmina-cache-encryption. A key alias simplifies key rotation and policy management. -
Update the key policy to allow the Chinmina execution role to decrypt:
example-kms-key-policy-statement.json {"Sid": "Allow Chinmina to decrypt the cache encryption keyset","Effect": "Allow","Principal": {"AWS": ["arn:aws:iam::123456789012:role/chinmina-task-role"]},"Action": ["kms:Decrypt", "kms:DescribeKey"],"Resource": "*"} -
Create a Secrets Manager secret to hold the encrypted Tink keyset. Use a naming convention such as
/chinmina-bridge/{environment}/tink-keyset:Create the Secrets Manager secret aws secretsmanager create-secret \--name /chinmina-bridge/production/tink-keyset \--description "Encrypted Tink AEAD keyset for Chinmina cache encryption"Save the secret name as 📝 CACHE_ENCRYPTION_KEYSET_URI. The keyset content will be uploaded in the next section.
-
Grant the Chinmina execution role access to read the secret:
example-secrets-manager-iam-policy.json {"Version": "2012-10-17","Statement": [{"Effect": "Allow","Action": "secretsmanager:GetSecretValue","Resource": "arn:aws:secretsmanager:us-east-1:123456789012:secret:/chinmina-bridge/*/tink-keyset-*"}]}The trailing wildcard on the resource ARN accounts for the random suffix that Secrets Manager appends to secret names.
Create and upload the Tink keyset
Section titled “Create and upload the Tink keyset”-
Install the
tinkeyCLI by following the Tink installation instructions. -
Generate an AEAD keyset:
Generate a new Tink keyset tinkey create-keyset \--key-template AES256_GCM \--out-format json \--out plaintext-keyset.json -
Encrypt the keyset with the KMS key:
Encrypt the keyset tinkey encrypt-keyset \--in plaintext-keyset.json \--out encrypted-keyset.json \--master-key-uri aws-kms://arn:aws:kms:us-east-1:123456789012:key/abcd1234-a123-456a-a12b-a123b4cd56ef -
Delete the plaintext keyset:
Delete the plaintext keyset shred -u plaintext-keyset.json -
Upload the encrypted keyset to the Secrets Manager secret:
Upload the encrypted keyset aws secretsmanager put-secret-value \--secret-id /chinmina-bridge/production/tink-keyset \--secret-string file://encrypted-keyset.jsonDelete the local encrypted keyset file after uploading.
Configure Chinmina to use the keyset
Section titled “Configure Chinmina to use the keyset”-
Enable cache encryption:
Terminal window CACHE_ENCRYPTION_ENABLED=true -
Set the Secrets Manager URI for the keyset. Use the
aws-secretsmanager://scheme followed by the secret name:Terminal window CACHE_ENCRYPTION_KEYSET_URI=aws-secretsmanager://chinmina-bridge/production/tink-keyset -
Set the KMS key URI for envelope decryption. Use the
aws-kms://scheme followed by the full key ARN:Terminal window CACHE_ENCRYPTION_KMS_ENVELOPE_KEY_URI=aws-kms://arn:aws:kms:us-east-1:123456789012:key/abcd1234-a123-456a-a12b-a123b4cd56ef -
On startup, Chinmina performs a test encrypt/decrypt cycle. If the keyset or KMS key is misconfigured, the service will fail to start with a clear error message.
Key rotation
Section titled “Key rotation”Tink keysets hold multiple keys simultaneously. Only the primary key encrypts, but all keys decrypt. This allows zero-downtime rotation: add a new key, wait for all instances to load it, then promote to primary.
Chinmina refreshes its keyset from Secrets Manager every 15 minutes. The rotation procedure accounts for this interval and the cache TTL (tokens expire after 45 minutes).
Timeline
Section titled “Timeline”T+0min Stage 1 — Upload keyset with new key (non-primary)T+15min All instances can decrypt with both keysT+75min Stage 2 — Promote new key to primaryT+90min All instances encrypting with new keyT+150min Stage 3 (optional) — Disable old keyStage 1: Add a new key
Section titled “Stage 1: Add a new key”-
Download the current encrypted keyset from Secrets Manager:
Download the current keyset aws secretsmanager get-secret-value \--secret-id /chinmina-bridge/production/tink-keyset \--query SecretString --output text > current-keyset.json -
Add a new key to the keyset. The
add-keycommand adds a new key without promoting it to primary — the existing primary key continues to be used for encryption:Add a new key to the keyset tinkey add-key \--in current-keyset.json \--out stage1-keyset.json \--key-template AES256_GCM \--master-key-uri aws-kms://arn:aws:kms:REGION:ACCOUNT:key/KEY-ID -
Upload the updated keyset:
Upload the keyset with the new key aws secretsmanager update-secret \--secret-id /chinmina-bridge/production/tink-keyset \--secret-string file://stage1-keyset.json -
Wait at least 15 minutes for all instances to refresh. After this point, all instances can decrypt with both keys.
Stage 2: Promote the new key
Section titled “Stage 2: Promote the new key”Wait an additional 60 minutes after stage 1 completes (75 minutes from the start). This ensures all tokens encrypted with the old primary key have expired from the cache.
-
Promote the new key to primary. Find the new key’s ID from the keyset metadata:
Promote the new key to primary tinkey promote-key \--in stage1-keyset.json \--out stage2-keyset.json \--key-id <NEW_KEY_ID> \--master-key-uri aws-kms://arn:aws:kms:REGION:ACCOUNT:key/KEY-ID -
Upload the updated keyset:
Upload the keyset with the promoted key aws secretsmanager update-secret \--secret-id /chinmina-bridge/production/tink-keyset \--secret-string file://stage2-keyset.json -
After another 15 minutes, all instances will encrypt new tokens with the new primary key.
Stage 3: Disable the old key (optional)
Section titled “Stage 3: Disable the old key (optional)”After another cache TTL cycle (at least 60 minutes after stage 2), all tokens encrypted with the old key have expired. The old key can be safely disabled.
tinkey disable-key \ --in stage2-keyset.json \ --out final-keyset.json \ --key-id <OLD_KEY_ID> \ --master-key-uri aws-kms://arn:aws:kms:REGION:ACCOUNT:key/KEY-IDUpload the final keyset using the same aws secretsmanager update-secret command. Delete any local keyset files after uploading.