You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The GitHub App private key is currently stored in SSM Parameter Store (encrypted at rest) and loaded into Lambda memory for every JWT signing operation. This means:
The plaintext private key is in Lambda memory during execution — any memory dump, debug log, or compromised dependency could exfiltrate it
No hardware security boundary — the key exists as a software secret, not in an HSM
Single App limitation — the module is hardwired to one App's credentials via global env vars, making multi-App deployments impossible without separate infrastructure stacks
Proposal
Move JWT signing to AWS KMS using an asymmetric RSA key (RSA_2048, SIGN_VERIFY, RSASSA_PKCS1_V1_5_SHA_256). The private key never leaves the HSM — Lambda calls kms:Sign and receives only the signature bytes.
Why this is a clean change
The codebase already has the perfect abstraction point. @octokit/auth-app accepts a custom createJwt callback (mutually exclusive with privateKey), and this repo already uses it:
The initial PR implements single-App KMS signing. Multi-App credential resolution (DynamoDB lookup by installation_id) is a follow-up.
Key import constraint
GitHub generates the RSA key pair when you create an App. The private key must be imported into KMS (EXTERNAL key material origin). This is a one-time setup operation.
Terraform: aws_kms_external_key resource handles the lifecycle.
KMS rate limits
Default KMS quota: 300 TPS for RSA signing (region-dependent). Combined with the token cache (#5132, ~1 JWT sign/hour/installation), this is never a bottleneck.
Terraform changes
Optional aws_kms_external_key resource (gated by variable)
IAM policy: kms:Sign scoped to the key
Lambda env var: GITHUB_APP_KMS_KEY_ARN
Documentation on importing the GitHub App PEM into KMS
Problem
The GitHub App private key is currently stored in SSM Parameter Store (encrypted at rest) and loaded into Lambda memory for every JWT signing operation. This means:
Proposal
Move JWT signing to AWS KMS using an asymmetric RSA key (
RSA_2048,SIGN_VERIFY,RSASSA_PKCS1_V1_5_SHA_256). The private key never leaves the HSM — Lambda callskms:Signand receives only the signature bytes.Why this is a clean change
The codebase already has the perfect abstraction point.
@octokit/auth-appaccepts a customcreateJwtcallback (mutually exclusive withprivateKey), and this repo already uses it:The change is swapping what happens inside
signJwt:Design
Guard: env var
GITHUB_APP_KMS_KEY_ARN— if set, use KMS signer. If unset, fall back to SSM PEM (100% backwards compatible).Multi-App foundation
This architecture naturally extends to multiple GitHub Apps:
installation.id→ already passed through to scale-up Lambdainstallation_id→ each App has its own KMS keyinstallation_id→ each App's tokens cached independentlyThe initial PR implements single-App KMS signing. Multi-App credential resolution (DynamoDB lookup by
installation_id) is a follow-up.Key import constraint
GitHub generates the RSA key pair when you create an App. The private key must be imported into KMS (EXTERNAL key material origin). This is a one-time setup operation.
Terraform:
aws_kms_external_keyresource handles the lifecycle.KMS rate limits
Default KMS quota: 300 TPS for RSA signing (region-dependent). Combined with the token cache (#5132, ~1 JWT sign/hour/installation), this is never a bottleneck.
Terraform changes
aws_kms_external_keyresource (gated by variable)kms:Signscoped to the keyGITHUB_APP_KMS_KEY_ARNBenefits
Related
I will provide a PR for this.