#!/usr/bin/env node import { DynamoDBClient } from '@aws-sdk/client-dynamodb'; import { KMSClient } from '@aws-sdk/client-kms'; export declare const kms: KMSClient; export declare const dynamoDB: DynamoDBClient; export type ImportPrivateKey = ({ pemFilePath, appId, tableName, validateInputs, convertPemToDer, createKmsKey, encryptKeyMaterial, importKeyMaterialAndValidate, updateAppsTable, tagKeyAsFailed, }: { pemFilePath: string; appId: number; tableName: string; validateInputs?: ValidateInputs; convertPemToDer?: ConvertPemToDer; createKmsKey?: CreateKmsKey; getKmsImportParameters?: GetKmsImportParameters; encryptKeyMaterial?: EncryptKeyMaterial; importKeyMaterialAndValidate?: ImportKeyMaterialAndValidate; updateAppsTable?: UpdateAppsTable; tagKeyAsFailed?: TagKeyAsFailed; }) => Promise; /** * Function that imports private key from a PEM file into AWS KMS for a GitHub App * and deletes the PEM file from path after successful import. * * This function performs the following steps: * 1. Validates the input PEM file, App ID and TableName * 2. Converts the PEM file to DER format * 3. Creates a new KMS key and tagged as active * 4. Retrieves KMS import parameters * 5. Encrypts the key material * 6. Imports the encrypted key material into KMS and validates it * 7. Updates the DynamoDB table with the KMS key ARN * 8. Upon rotation, old key is tagged as inactive. * 9. PEM file is permanently deleted from the local path provided. * 10. Tags failed imports created KMS keys as status "Failed" * * --- * dependency injection parameters: * @param pemFilePath Path to the PEM file containing the private key * @param appId GitHub App ID * @param validateInputs Function that checks if the provided PEM file and AppId belongs to the same GitHub App and validates if the Table exists. * @param convertPemToDer Function that converts PKCS#1 PEM format file to PKCS#8 DER format file. * @param createKmsKey Function that creates a KMS key for the imported private key and tags key as 'active'. * @param encryptKeyMaterial Function that encrypts the key material using public key from AWS KMS. * @param importKeyMaterialAndValidate Function that uses importToken to import the private key and validate JWT Auth. * @param updateAppsTable Function that updates the DynamoDB table with imported key ARN. * @param tagKeyAsFailed Function that tags failed imports created KMS keys as Failed * */ export declare const importPrivateKey: ImportPrivateKey; type ValidateInputs = ({ pemFile, appId, tableName, listTables, validateJWt, pemSign, }: { pemFile: string; appId: number; tableName: string; listTables?: () => Promise; validateJWt?: ValidateJWT; pemSign?: PemSign; }) => Promise; /** * Function that checks the validation of GitHub App ID, PEM file, and DynamoDB table. * This function performs the following validations: * 1. Checks if the PEM file exists at the specified path * 2. Validates the private key and App ID combination by: * - Using the private key to sign JWT tokens * - Authenticating with GitHub API * - Verifying the App ID matches * 3. Validates the existence of Table provided. * * --- * dependency injection parameters: * @param pemFile Path to the PEM file containing private key * @param appId GitHub App ID * @param tableName Table to update the KMSKey ARN. * @param validateJWT Function to validate JWT authentication. * @param pemSign Function that helps to sign messages with private key. * @returns Returns if GitHub authentication is successful, throws error otherwise. */ export declare const validateInputsImpl: ValidateInputs; type ConvertPemToDer = ({ pemFile }: { pemFile: string; }) => Buffer; /** * Function that does conversion of PKCS#1 PEM format private key to PKCS#8 DER format private key. * GitHub private keys are of PKCS#1 format * Docs for GitHub: https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/managing-private-keys-for-github-apps#generating-private-keys * AWS KMS expects RSA private keys of PKCS#8 format * Docs for AWS KMS: https://docs.aws.amazon.com/kms/latest/developerguide/importing-keys-conceptual.html * * @param pemFile Path to the PEM file containing private key * @returns Private key in DER format as a Buffer */ export declare const convertPemToDerImpl: ConvertPemToDer; type CreateKmsKey = ({ appId }: { appId: number; }) => Promise; /** * Function that creates an external AWS KMS key configured for GitHub App signing. * Configurations: * - KeySpec: Specified by CREATE_KEY_SPEC constant * - KeyUsage: SIGN_VERIFY * - Origin: EXTERNAL * - Tags: Status, CreatedOn, AppId, and FrameworkForGitHubAppOnAwsManaged * * @param appId GitHub App ID to associate with the KMS key * @returns The ARN of the created KMS key */ export declare const createKmsKeyImpl: CreateKmsKey; type GetKmsImportParameters = ({ appKeyArn, }: { appKeyArn: string; }) => Promise<{ publicKey: Uint8Array; importToken: Uint8Array; }>; /** * Function that retrieves KMS import parameters public key and import token * using RSA AES key wrapping. * * @param appKeyArn ARN of the KMS key * @returns Object containing: * - publicKey: The public key to use for wrapping the import material * - importToken: The import token required for the import operation */ export declare const getKmsImportParametersImpl: GetKmsImportParameters; type EncryptKeyMaterial = ({ privateKeyDer, importParams, wrapKeyMaterial, }: { privateKeyDer: Buffer; importParams: { publicKey: Uint8Array; importToken: Uint8Array; }; wrapKeyMaterial?: WrapKeyMaterial; }) => Promise; /** * Function that encrypts key material for import into AWS KMS * * --- * dependency injection parameters: * * @param privateKeyDer Private key in DER format. * @param importParams Import parameters from KMS. * @param wrapKeyMaterial Function to wrap key material. * @returns Encrypted key material ready for import. */ export declare const encryptKeyMaterialImpl: EncryptKeyMaterial; export type WrapKeyMaterial = ({ keyMaterial, aesKey, }: { keyMaterial: Buffer; aesKey: Buffer; }) => Buffer; /** * Implements the AES key wrap with padding algorithm for wrapping key material. * * This function performs the following steps: * 1. Validates that the key material is not empty * 2. Creates a cipher using AES-256 key wrap with padding (id-aes256-wrap-pad) * 3. Uses a static IV of 'A65959A6' as per the AES key wrap algorithm specification * Docs: https://www.rfc-editor.org/rfc/rfc5649.html * 4. Wraps the key material using the cipher * * --- * dependency injection parameters: * * @param keyMaterial The key material to be wrapped. * @param aesKey The AES key used for wrapping. * @returns Wrapped Key Material. */ export declare const wrapKeyMaterialImpl: WrapKeyMaterial; type ImportKeyMaterialAndValidate = ({ appKeyArn, appId, wrappedMaterial, importToken, kmsSign, validateJWT, }: { appKeyArn: string; appId: number; wrappedMaterial: Buffer; importToken: Uint8Array; kmsSign?: KmsSign; validateJWT?: ValidateJWT; }) => Promise; /** * Function that imports key material into KMS and validates JWT Auth. * * --- * dependency injection parameters: * * @param appKeyArn ARN of the KMS key * @param appId GitHub App ID * @param wrappedMaterial Encrypted key material to import * @param importToken Import token from KMS * @param kmsSign Function for KMS signing * @param validateJWT Function for JWT validation */ export declare const importKeyMaterialAndValidateImpl: ImportKeyMaterialAndValidate; type UpdateAppsTable = ({ appKeyArn, appId, tableName, tagOldKeyArn, }: { appKeyArn: string; appId: number; tableName: string; tagOldKeyArn?: TagOldKeyArn; }) => Promise; /** * Function that updates DynamoDB table with appId and AWS key ARN, * also includes tagging of old key as Inactive upon rotation. * * --- * dependency injection parameters: * * @param appKeyArn ARN of the new KMS key * @param appId GitHub App ID * @param tableName Table to update the KMSKey ARN and App ID * @param tagOldKeyArn Function to tag the old key as Inactive if rotation */ export declare const updateAppsTableImpl: UpdateAppsTable; export type TagOldKeyArn = ({ oldKeyArn, appKeyArn, appId, }: { oldKeyArn: string; appKeyArn: string; appId: number; }) => Promise; /** * Function that tags old KMS key with replacement information. * * --- * @param oldKeyArn ARN of the old key being replaced * @param appKeyArn ARN of the new key * @param appId GitHub App ID */ export declare const tagOldKeyArnImpl: TagOldKeyArn; export type TagKeyAsFailed = ({ appKeyArn, }: { appKeyArn: string; }) => Promise; /** * Function that tags failed imports created KMS keys as Failed. * * --- * @param appKeyArn ARN of the new key created */ export declare const tagKeyAsFailedImpl: TagKeyAsFailed; export type ValidateJWT = ({ appId, signFunction, }: { appId: number; signFunction: (message: string) => Promise; }) => Promise; /** * Function that validates JWT authentication with GitHub API using provided signing function. * Docs: https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-json-web-token-jwt-for-a-github-app * * The signFunction parameter is abstracted to support below signing methods: * - signing with a private key from PEM file * - signing with a private key from AWS KMS * * --- * @param appId GitHub App ID * @param signFunction Function to sign JWT with private key from both PEM file and AWS KMS . * @returns True if validation succeeds, false otherwise. */ export declare const validateJWTImpl: ValidateJWT; export type KmsSign = ({ appKeyArn, message, }: { appKeyArn: string; message: string; }) => Promise; /** * Function that signs a message using key that was imported in AWS KMS. * * Note: This function uses the RSASSA-PKCS1-v1_5 signing algorithm with SHA-256. * * --- * @param appKeyArn ARN of the new key. * @param message The message to be signed. * @returns The signature as a Buffer */ export declare const kmsSignImpl: KmsSign; export type PemSign = ({ pemFile, message, }: { pemFile: string; message: string; }) => Promise; /** * Function that does message signing using a private key from a PEM file. * * Note: Uses Node.js crypto module's sign function with SHA-256 algorithm * * --- * @param pemFile Path to the PEM file containing private key. * @param message Message to be signed. * @returns The signature as a Buffer */ export declare const pemSignImpl: PemSign; export {};