Skip to content

Protecting the GitHub private key

Github Apps make authenticated API calls by generating a JWT from a private key issued for the app. This private key is an extremely sensitive credential, as it can be used to access the full scope of actions assigned to the GitHub App.

Chinmina Bridge supports signing JWTs using AWS KMS, ensuring that key material cannot be extracted from the executing process or from the account configuration.

Uploading the private key to AWS KMS

  1. Follow GitHub’s instructions to generate a private key for the GitHub application in use.

  2. The key spec for your GitHub key should be RSA 2048. If you’re curious, this can be checked by examining the output of the following openssl command.

    Show details of private key
    openssl rsa -text -noout -in yourkey.pem
  3. Convert the downloaded GitHub private key file from PEM format to DER format. DER is required by AWS KMS when uploading key matter.

    Convert from PEM to DER
    openssl rsa -inform PEM -outform DER -in ./private-key.pem -out private-key.cer
  4. Follow the AWS KMS key import instructions for importing the application private key into GitHub.

    The instructions include how to create an RSA 2048 key of type EXTERNAL, how to encrypt the key material so that it can be imported, and how to upload it.

    The steps of this process individually are not difficult, but it does have a number of them and the details matter. Follow the instructions carefully.

  5. Create an alias for the KMS key to allow for easy manual key rotation.

    This might seem like an optional step, but a key alias is essential to allow for key rotation. Unless you’re stopped by your organizational policy, use the alias. The private key will be able to be rotated without any service downtime.

  6. Ensure that the key policy has a statement allowing Chinmina to access the key. The specified role should be the role that the Chinmina process has access to at runtime.

    {
    "Sid": "Allow Chinmina to sign using the key",
    "Effect": "Allow",
    "Principal": {
    "AWS": ["arn:aws:iam::226140413739:role/full-task-role-name"]
    },
    "Action": ["kms:Sign"],
    "Resource": "*"
    }

Configuring the Chinmina service

  1. Set the environment variable GITHUB_APP_PRIVATE_KEY_ARN to the ARN of the alias that has just been created.

  2. Update the key resource policy. The KMS key resource policy needs to allow the service to use the key for signing only.

    Allowing the Chinmina service to use the key can be done by specifying the ARN of the role principal (see highlight below), or by using AWS condition keys in a Condition element. The global condition key aws:PrincipalArn can be useful if it’s necessary to employ a wildcard on the role name.

    example-resource-policy.json
    {
    "Sid": "ChinminaServiceUsage",
    "Effect": "Allow",
    "Principal": {
    "AWS": ["arn:aws:iam::123456789012:role/chinmina-process-role"]
    },
    "Action": "kms:Sign",
    "Resource": "*"
    }
  3. The IAM policy for the Chinmina process (i.e. the AWS role available to Chinmina when it runs) needs to be able to use the alias created for the private key. This is done with a condition in the policy element:

    example-iam-policy.json
    {
    "Action": "kms:Sign",
    "Effect": "Allow",
    "Resource": "*",
    "Condition": {
    "StringEquals": {
    "kms:RequestAlias": "alias/chinmina-signing"
    }
    }
    }

    Using the kms:RequestAlias condition instead of the fully qualified key ARN in the resource attribute allows for transparent key rotation without service interruption.