From 6dff0e915623a8d93a927d6405d2495727349af5 Mon Sep 17 00:00:00 2001 From: Stijn Seghers Date: Thu, 22 Apr 2021 14:44:52 +1200 Subject: [PATCH] feat: use SSM Parameter Store to store secrets --- modules/runners/encrypt.tf | 24 ---- modules/runners/lambdas/runners/src/lambda.ts | 16 +-- .../runners/src/scale-runners/gh-auth.test.ts | 106 +++++++++++------- .../runners/src/scale-runners/gh-auth.ts | 33 +++--- .../runners/src/scale-runners/kms/index.ts | 25 ----- .../src/scale-runners/scale-down.test.ts | 20 ++-- .../src/scale-runners/scale-up.test.ts | 12 +- .../lambdas/runners/src/scale-runners/ssm.ts | 20 ++++ .../instance-ssm-parameters-policy.json | 6 +- modules/runners/scale-down.tf | 35 +++--- modules/runners/scale-up.tf | 41 +++---- modules/runners/variables.tf | 10 +- variables.tf | 12 +- 13 files changed, 180 insertions(+), 180 deletions(-) delete mode 100644 modules/runners/encrypt.tf delete mode 100644 modules/runners/lambdas/runners/src/scale-runners/kms/index.ts create mode 100644 modules/runners/lambdas/runners/src/scale-runners/ssm.ts diff --git a/modules/runners/encrypt.tf b/modules/runners/encrypt.tf deleted file mode 100644 index e4cad100e1..0000000000 --- a/modules/runners/encrypt.tf +++ /dev/null @@ -1,24 +0,0 @@ -locals { - github_app_key_base64 = var.encryption.encrypt ? aws_kms_ciphertext.github_app_key_base64[0].ciphertext_blob : var.github_app.key_base64 - github_app_client_secret = var.encryption.encrypt ? aws_kms_ciphertext.github_app_client_secret[0].ciphertext_blob : var.github_app.client_secret -} - -resource "aws_kms_ciphertext" "github_app_key_base64" { - count = var.encryption.encrypt ? 1 : 0 - key_id = var.encryption.kms_key_id - plaintext = var.github_app.key_base64 - - context = { - Environment = var.environment - } -} - -resource "aws_kms_ciphertext" "github_app_client_secret" { - count = var.encryption.encrypt ? 1 : 0 - key_id = var.encryption.kms_key_id - plaintext = var.github_app.client_secret - - context = { - Environment = var.environment - } -} diff --git a/modules/runners/lambdas/runners/src/lambda.ts b/modules/runners/lambdas/runners/src/lambda.ts index 576daafce2..6a27653d27 100644 --- a/modules/runners/lambdas/runners/src/lambda.ts +++ b/modules/runners/lambdas/runners/src/lambda.ts @@ -1,26 +1,26 @@ -import { scaleUp } from './scale-runners/scale-up'; -import { scaleDown } from './scale-runners/scale-down'; +import { scaleUp as scaleUp_ } from './scale-runners/scale-up'; +import { scaleDown as scaleDown_ } from './scale-runners/scale-down'; import { SQSEvent, ScheduledEvent, Context } from 'aws-lambda'; -module.exports.scaleUp = async (event: SQSEvent, context: Context, callback: any) => { +export async function scaleUp(event: SQSEvent, context: Context, callback: any) { console.dir(event, { depth: 5 }); try { for (const e of event.Records) { - await scaleUp(e.eventSource, JSON.parse(e.body)); + await scaleUp_(e.eventSource, JSON.parse(e.body)); } return callback(null); } catch (e) { console.error(e); return callback('Failed handling SQS event'); } -}; +} -module.exports.scaleDown = async (event: ScheduledEvent, context: Context, callback: any) => { +export async function scaleDown(event: ScheduledEvent, context: Context, callback: any) { try { - scaleDown(); + scaleDown_(); return callback(null); } catch (e) { console.error(e); return callback('Failed'); } -}; +} diff --git a/modules/runners/lambdas/runners/src/scale-runners/gh-auth.test.ts b/modules/runners/lambdas/runners/src/scale-runners/gh-auth.test.ts index 64737fbfff..b089f8cafb 100644 --- a/modules/runners/lambdas/runners/src/scale-runners/gh-auth.test.ts +++ b/modules/runners/lambdas/runners/src/scale-runners/gh-auth.test.ts @@ -2,13 +2,13 @@ import { createOctoClient, createGithubAuth } from './gh-auth'; import nock from 'nock'; import { createAppAuth } from '@octokit/auth-app'; import { StrategyOptions } from '@octokit/auth-app/dist-types/types'; -import { decrypt } from './kms'; +import SSM from './ssm'; import { RequestInterface } from '@octokit/types'; import { mock, MockProxy } from 'jest-mock-extended'; import { request } from '@octokit/request'; -jest.mock('./kms'); jest.mock('@octokit/auth-app'); +jest.mock('./ssm'); const cleanEnv = process.env; @@ -19,7 +19,7 @@ beforeEach(() => { nock.disableNetConnect(); }); -describe('Test createGithubAuth', () => { +describe('Test createOctoClient', () => { test('Creates app client to GitHub public', async () => { // Arrange const token = '123456'; @@ -46,7 +46,7 @@ describe('Test createGithubAuth', () => { }); describe('Test createGithubAuth', () => { - const mockedDecrypt = (decrypt as unknown) as jest.Mock; + const mockedSSM = SSM as jest.MockedClass; const mockedCreatAppAuth = (createAppAuth as unknown) as jest.Mock; const mockedDefaults = jest.spyOn(request, 'defaults'); let mockedRequestInterface: MockProxy; @@ -54,48 +54,59 @@ describe('Test createGithubAuth', () => { const installationId = 1; const authType = 'app'; const token = '123456'; - const decryptedValue = 'decryptedValue'; - const b64 = Buffer.from(decryptedValue, 'binary').toString('base64'); + const privateKey = 'my-private-key'; + const privateKeyBase64 = Buffer.from(privateKey, 'binary').toString('base64'); + const appId = '123'; + const clientId = 'abc'; + const clientSecret = 'abcdef123456'; beforeEach(() => { - process.env.GITHUB_APP_ID = '1'; - process.env.GITHUB_APP_CLIENT_SECRET = 'client_secret'; - process.env.GITHUB_APP_KEY_BASE64 = 'base64'; - process.env.KMS_KEY_ID = 'key_id'; + process.env.GITHUB_APP_KEY_BASE64_PARAMETER_NAME = 'private-key'; + process.env.GITHUB_APP_ID_PARAMETER_NAME = 'app-id'; + process.env.GITHUB_APP_CLIENT_ID_PARAMETER_NAME = 'client-id'; + process.env.GITHUB_APP_CLIENT_SECRET_PARAMETER_NAME = 'client-secret'; process.env.ENVIRONMENT = 'dev'; - process.env.GITHUB_APP_CLIENT_ID = '1'; }); test('Creates auth object for public GitHub', async () => { // Arrange const authOptions = { - appId: parseInt(process.env.GITHUB_APP_ID as string), - privateKey: 'decryptedValue', + appId: parseInt(appId), + privateKey, installationId, - clientId: process.env.GITHUB_APP_CLIENT_ID, - clientSecret: 'decryptedValue', + clientId, + clientSecret, }; - mockedDecrypt.mockResolvedValueOnce(decryptedValue).mockResolvedValueOnce(b64); + const mockedGetParameter = jest.fn() + .mockResolvedValueOnce(privateKeyBase64) + .mockResolvedValueOnce(appId) + .mockResolvedValueOnce(clientId) + .mockResolvedValueOnce(clientSecret); + mockedSSM.mockImplementation(() => ({ + ssm: null as any, + getParameter: mockedGetParameter, + })); + const mockedAuth = jest.fn(); mockedAuth.mockResolvedValue({ token }); - mockedCreatAppAuth.mockImplementation((authOptions: StrategyOptions) => { - return mockedAuth; - }); + mockedCreatAppAuth.mockImplementation(() => mockedAuth); // Act const result = await createGithubAuth(installationId, authType); // Assert - expect(mockedDecrypt).toBeCalledWith( - process.env.GITHUB_APP_CLIENT_SECRET, - process.env.KMS_KEY_ID, - process.env.ENVIRONMENT, + expect(mockedGetParameter).toBeCalledWith( + process.env.GITHUB_APP_KEY_BASE64_PARAMETER_NAME + ); + expect(mockedGetParameter).toBeCalledWith( + process.env.GITHUB_APP_ID_PARAMETER_NAME + ); + expect(mockedGetParameter).toBeCalledWith( + process.env.GITHUB_APP_CLIENT_ID_PARAMETER_NAME ); - expect(mockedDecrypt).toBeCalledWith( - process.env.GITHUB_APP_KEY_BASE64, - process.env.KMS_KEY_ID, - process.env.ENVIRONMENT, + expect(mockedGetParameter).toBeCalledWith( + process.env.GITHUB_APP_CLIENT_SECRET_PARAMETER_NAME ); expect(mockedCreatAppAuth).toBeCalledTimes(1); expect(mockedCreatAppAuth).toBeCalledWith(authOptions); @@ -113,34 +124,43 @@ describe('Test createGithubAuth', () => { }); const authOptions = { - appId: parseInt(process.env.GITHUB_APP_ID as string), - privateKey: 'decryptedValue', + appId: parseInt(appId), + privateKey, installationId, - clientId: process.env.GITHUB_APP_CLIENT_ID, - clientSecret: 'decryptedValue', + clientId, + clientSecret, request: mockedRequestInterface.defaults({ baseUrl: githubServerUrl }), }; - mockedDecrypt.mockResolvedValueOnce(decryptedValue).mockResolvedValueOnce(b64); + const mockedGetParameter = jest.fn() + .mockResolvedValueOnce(privateKeyBase64) + .mockResolvedValueOnce(appId) + .mockResolvedValueOnce(clientId) + .mockResolvedValueOnce(clientSecret); + mockedSSM.mockImplementation(() => ({ + ssm: null as any, + getParameter: mockedGetParameter, + })); + const mockedAuth = jest.fn(); mockedAuth.mockResolvedValue({ token }); - mockedCreatAppAuth.mockImplementation((authOptions: StrategyOptions) => { - return mockedAuth; - }); + mockedCreatAppAuth.mockImplementation(() => mockedAuth); // Act const result = await createGithubAuth(installationId, authType, githubServerUrl); // Assert - expect(mockedDecrypt).toBeCalledWith( - process.env.GITHUB_APP_CLIENT_SECRET, - process.env.KMS_KEY_ID, - process.env.ENVIRONMENT, + expect(mockedGetParameter).toBeCalledWith( + process.env.GITHUB_APP_KEY_BASE64_PARAMETER_NAME + ); + expect(mockedGetParameter).toBeCalledWith( + process.env.GITHUB_APP_ID_PARAMETER_NAME + ); + expect(mockedGetParameter).toBeCalledWith( + process.env.GITHUB_APP_CLIENT_ID_PARAMETER_NAME ); - expect(mockedDecrypt).toBeCalledWith( - process.env.GITHUB_APP_KEY_BASE64, - process.env.KMS_KEY_ID, - process.env.ENVIRONMENT, + expect(mockedGetParameter).toBeCalledWith( + process.env.GITHUB_APP_CLIENT_SECRET_PARAMETER_NAME ); expect(mockedCreatAppAuth).toBeCalledTimes(1); expect(mockedCreatAppAuth).toBeCalledWith(authOptions); diff --git a/modules/runners/lambdas/runners/src/scale-runners/gh-auth.ts b/modules/runners/lambdas/runners/src/scale-runners/gh-auth.ts index dda1e5cbf1..05ad081383 100644 --- a/modules/runners/lambdas/runners/src/scale-runners/gh-auth.ts +++ b/modules/runners/lambdas/runners/src/scale-runners/gh-auth.ts @@ -3,7 +3,7 @@ import { request } from '@octokit/request'; import { createAppAuth } from '@octokit/auth-app'; import { Authentication, StrategyOptions } from '@octokit/auth-app/dist-types/types'; import { OctokitOptions } from '@octokit/core/dist-types/types'; -import { decrypt } from './kms'; +import SSM from './ssm'; export async function createOctoClient(token: string, ghesApiUrl = ''): Promise { const ocktokitOptions: OctokitOptions = { @@ -21,25 +21,28 @@ export async function createGithubAuth( authType: 'app' | 'installation', ghesApiUrl = '', ): Promise { - const clientSecret = await decrypt( - process.env.GITHUB_APP_CLIENT_SECRET as string, - process.env.KMS_KEY_ID as string, - process.env.ENVIRONMENT as string, + const ssm = new SSM(); + const privateKeyBase64 = await ssm.getParameter( + process.env.GITHUB_APP_KEY_BASE64_PARAMETER_NAME as string ); - const privateKeyBase64 = await decrypt( - process.env.GITHUB_APP_KEY_BASE64 as string, - process.env.KMS_KEY_ID as string, - process.env.ENVIRONMENT as string, + const appIdString = await ssm.getParameter( + process.env.GITHUB_APP_ID_PARAMETER_NAME as string ); - - if (clientSecret === undefined || privateKeyBase64 === undefined) { - throw Error('Cannot decrypt.'); + const clientId = await ssm.getParameter( + process.env.GITHUB_APP_CLIENT_ID_PARAMETER_NAME as string + ); + const clientSecret = await ssm.getParameter( + process.env.GITHUB_APP_CLIENT_SECRET_PARAMETER_NAME as string + ); + if (privateKeyBase64 === undefined + || appIdString === undefined + || clientId === undefined + || clientSecret === undefined) { + throw Error('Cannot decrypt GitHub App parameters.'); } const privateKey = Buffer.from(privateKeyBase64, 'base64').toString(); - - const appId: number = parseInt(process.env.GITHUB_APP_ID as string); - const clientId = process.env.GITHUB_APP_CLIENT_ID as string; + const appId = parseInt(appIdString); const authOptions: StrategyOptions = { appId, diff --git a/modules/runners/lambdas/runners/src/scale-runners/kms/index.ts b/modules/runners/lambdas/runners/src/scale-runners/kms/index.ts deleted file mode 100644 index 12c719a527..0000000000 --- a/modules/runners/lambdas/runners/src/scale-runners/kms/index.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { KMS } from 'aws-sdk'; -import AWS from 'aws-sdk'; - -AWS.config.update({ - region: process.env.AWS_REGION, -}); - -const kms = new KMS(); - -export async function decrypt(encrypted: string, key: string, environmentName: string): Promise { - let result: string | undefined = encrypted; - if (key != undefined) { - const decrypted = await kms - .decrypt({ - CiphertextBlob: Buffer.from(encrypted, 'base64'), - KeyId: key, - EncryptionContext: { - ['Environment']: environmentName, - }, - }) - .promise(); - result = decrypted.Plaintext?.toString(); - } - return result; -} diff --git a/modules/runners/lambdas/runners/src/scale-runners/scale-down.test.ts b/modules/runners/lambdas/runners/src/scale-runners/scale-down.test.ts index f34565653b..f0c5e6c41a 100644 --- a/modules/runners/lambdas/runners/src/scale-runners/scale-down.test.ts +++ b/modules/runners/lambdas/runners/src/scale-runners/scale-down.test.ts @@ -25,6 +25,10 @@ jest.mock('@octokit/rest', () => ({ jest.mock('./runners'); +jest.mock('./ssm', () => jest.fn().mockImplementation(() => ({ + getParameter: jest.fn().mockImplementation(() => ''), +}))); + export interface TestData { repositoryName: string; repositoryOwner: string; @@ -105,10 +109,10 @@ const DEFAULT_REGISTERED_RUNNERS = [ describe('scaleDown', () => { beforeEach(() => { - process.env.GITHUB_APP_KEY_BASE64 = 'TEST_CERTIFICATE_DATA'; - process.env.GITHUB_APP_ID = '1337'; - process.env.GITHUB_APP_CLIENT_ID = 'TEST_CLIENT_ID'; - process.env.GITHUB_APP_CLIENT_SECRET = 'TEST_CLIENT_SECRET'; + process.env.GITHUB_APP_KEY_BASE64_PARAMETER_NAME = 'private-key'; + process.env.GITHUB_APP_ID_PARAMETER_NAME = 'app-id'; + process.env.GITHUB_APP_CLIENT_ID_PARAMETER_NAME = 'client-id'; + process.env.GITHUB_APP_CLIENT_SECRET_PARAMETER_NAME = 'client-secret'; process.env.RUNNERS_MAXIMUM_COUNT = '3'; process.env.ENVIRONMENT = environment; process.env.MINIMUM_RUNNING_TIME_IN_MINUTES = minimumRunningTimeInMinutes.toString(); @@ -319,10 +323,10 @@ describe('scaleDown', () => { describe('scaleDown ghes', () => { beforeEach(() => { - process.env.GITHUB_APP_KEY_BASE64 = 'TEST_CERTIFICATE_DATA'; - process.env.GITHUB_APP_ID = '1337'; - process.env.GITHUB_APP_CLIENT_ID = 'TEST_CLIENT_ID'; - process.env.GITHUB_APP_CLIENT_SECRET = 'TEST_CLIENT_SECRET'; + process.env.GITHUB_APP_KEY_BASE64_PARAMETER_NAME = 'private-key'; + process.env.GITHUB_APP_ID_PARAMETER_NAME = 'app-id'; + process.env.GITHUB_APP_CLIENT_ID_PARAMETER_NAME = 'client-id'; + process.env.GITHUB_APP_CLIENT_SECRET_PARAMETER_NAME = 'client-secret'; process.env.RUNNERS_MAXIMUM_COUNT = '3'; process.env.ENVIRONMENT = environment; process.env.MINIMUM_RUNNING_TIME_IN_MINUTES = minimumRunningTimeInMinutes.toString(); diff --git a/modules/runners/lambdas/runners/src/scale-runners/scale-up.test.ts b/modules/runners/lambdas/runners/src/scale-runners/scale-up.test.ts index f3bc78b633..cd14ad49a3 100644 --- a/modules/runners/lambdas/runners/src/scale-runners/scale-up.test.ts +++ b/modules/runners/lambdas/runners/src/scale-runners/scale-up.test.ts @@ -24,6 +24,10 @@ jest.mock('@octokit/rest', () => ({ jest.mock('./runners'); +jest.mock('./ssm', () => jest.fn().mockImplementation(() => ({ + getParameter: jest.fn().mockImplementation(() => ''), +}))); + const TEST_DATA: ActionRequestMessage = { id: 1, eventType: 'check_run', @@ -47,10 +51,10 @@ beforeEach(() => { jest.resetModules(); jest.clearAllMocks(); process.env = { ...cleanEnv }; - process.env.GITHUB_APP_KEY_BASE64 = 'TEST_CERTIFICATE_DATA'; - process.env.GITHUB_APP_ID = '1337'; - process.env.GITHUB_APP_CLIENT_ID = 'TEST_CLIENT_ID'; - process.env.GITHUB_APP_CLIENT_SECRET = 'TEST_CLIENT_SECRET'; + process.env.GITHUB_APP_KEY_BASE64_PARAMETER_NAME = 'private-key'; + process.env.GITHUB_APP_ID_PARAMETER_NAME = 'app-id'; + process.env.GITHUB_APP_CLIENT_ID_PARAMETER_NAME = 'client-id'; + process.env.GITHUB_APP_CLIENT_SECRET_PARAMETER_NAME = 'client-secret'; process.env.RUNNERS_MAXIMUM_COUNT = '3'; process.env.ENVIRONMENT = 'unit-test-environment'; diff --git a/modules/runners/lambdas/runners/src/scale-runners/ssm.ts b/modules/runners/lambdas/runners/src/scale-runners/ssm.ts new file mode 100644 index 0000000000..5962b83eda --- /dev/null +++ b/modules/runners/lambdas/runners/src/scale-runners/ssm.ts @@ -0,0 +1,20 @@ +import AWS from 'aws-sdk'; + +export default class SSM { + ssm: AWS.SSM + + constructor() { + this.ssm = new AWS.SSM({ + apiVersion: '2014-11-06', + region: process.env.AWS_REGION, + }); + } + + public async getParameter(name: string): Promise { + const data = await this.ssm.getParameter({ + Name: name, + WithDecryption: true, + }).promise(); + return data.Parameter?.Value; + } +} diff --git a/modules/runners/policies/instance-ssm-parameters-policy.json b/modules/runners/policies/instance-ssm-parameters-policy.json index f2f4f11718..7d1b616be5 100644 --- a/modules/runners/policies/instance-ssm-parameters-policy.json +++ b/modules/runners/policies/instance-ssm-parameters-policy.json @@ -1,14 +1,10 @@ { "Version": "2012-10-17", "Statement": [ - { - "Effect": "Allow", - "Action": ["ssm:DeleteParameter"], - "Resource": "${arn_ssm_parameters}" - }, { "Effect": "Allow", "Action": [ + "ssm:DeleteParameter", "ssm:GetParameters", "ssm:GetParameter" ], diff --git a/modules/runners/scale-down.tf b/modules/runners/scale-down.tf index d82e3d5b0f..fcb91b043a 100644 --- a/modules/runners/scale-down.tf +++ b/modules/runners/scale-down.tf @@ -4,12 +4,6 @@ resource "aws_kms_grant" "scale_down" { key_id = var.encryption.kms_key_id grantee_principal = aws_iam_role.scale_down.arn operations = ["Decrypt"] - - constraints { - encryption_context_equals = { - Environment = var.environment - } - } } resource "aws_lambda_function" "scale_down" { @@ -27,16 +21,15 @@ resource "aws_lambda_function" "scale_down" { environment { variables = { - ENVIRONMENT = var.environment - KMS_KEY_ID = var.encryption.kms_key_id - ENABLE_ORGANIZATION_RUNNERS = var.enable_organization_runners - MINIMUM_RUNNING_TIME_IN_MINUTES = var.minimum_running_time_in_minutes - GITHUB_APP_KEY_BASE64 = local.github_app_key_base64 - GITHUB_APP_ID = var.github_app.id - GITHUB_APP_CLIENT_ID = var.github_app.client_id - GITHUB_APP_CLIENT_SECRET = local.github_app_client_secret - SCALE_DOWN_CONFIG = jsonencode(var.idle_config) - GHES_URL = var.ghes_url + ENVIRONMENT = var.environment + ENABLE_ORGANIZATION_RUNNERS = var.enable_organization_runners + MINIMUM_RUNNING_TIME_IN_MINUTES = var.minimum_running_time_in_minutes + GITHUB_APP_KEY_BASE64_PARAMETER_NAME = var.github_app.key_base64_parameter_name + GITHUB_APP_ID_PARAMETER_NAME = var.github_app.id_parameter_name + GITHUB_APP_CLIENT_ID_PARAMETER_NAME = var.github_app.client_id_parameter_name + GITHUB_APP_CLIENT_SECRET_PARAMETER_NAME = var.github_app.client_secret_parameter_name + SCALE_DOWN_CONFIG = jsonencode(var.idle_config) + GHES_URL = var.ghes_url } } @@ -88,6 +81,14 @@ resource "aws_iam_role_policy" "scale_down" { policy = templatefile("${path.module}/policies/lambda-scale-down.json", {}) } +resource "aws_iam_role_policy" "scale_down_ssm_parameters" { + name = "${var.environment}-lambda-scale-down-ssm-parameters" + role = aws_iam_role.scale_down.name + policy = templatefile("${path.module}/policies/instance-ssm-parameters-policy.json", { + arn_ssm_parameters = "arn:aws:ssm:${var.aws_region}:${data.aws_caller_identity.current.account_id}:parameter/${var.environment}-*" + }) +} + resource "aws_iam_role_policy" "scale_down_logging" { name = "${var.environment}-lambda-logging" role = aws_iam_role.scale_down.name @@ -100,4 +101,4 @@ resource "aws_iam_role_policy_attachment" "scale_down_vpc_execution_role" { count = length(var.lambda_subnet_ids) > 0 ? 1 : 0 role = aws_iam_role.scale_down.name policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole" -} \ No newline at end of file +} diff --git a/modules/runners/scale-up.tf b/modules/runners/scale-up.tf index 5418880662..adb32b111e 100644 --- a/modules/runners/scale-up.tf +++ b/modules/runners/scale-up.tf @@ -4,12 +4,6 @@ resource "aws_kms_grant" "scale_up" { key_id = var.encryption.kms_key_id grantee_principal = aws_iam_role.scale_up.arn operations = ["Decrypt"] - - constraints { - encryption_context_equals = { - Environment = var.environment - } - } } resource "aws_lambda_function" "scale_up" { @@ -28,20 +22,19 @@ resource "aws_lambda_function" "scale_up" { environment { variables = { - ENABLE_ORGANIZATION_RUNNERS = var.enable_organization_runners - ENVIRONMENT = var.environment - GHES_URL = var.ghes_url - GITHUB_APP_CLIENT_ID = var.github_app.client_id - GITHUB_APP_CLIENT_SECRET = local.github_app_client_secret - GITHUB_APP_ID = var.github_app.id - GITHUB_APP_KEY_BASE64 = local.github_app_key_base64 - KMS_KEY_ID = var.encryption.kms_key_id - RUNNER_EXTRA_LABELS = var.runner_extra_labels - RUNNER_GROUP_NAME = var.runner_group_name - RUNNERS_MAXIMUM_COUNT = var.runners_maximum_count - LAUNCH_TEMPLATE_NAME = aws_launch_template.runner.name - LAUNCH_TEMPLATE_VERSION = aws_launch_template.runner.latest_version - SUBNET_IDS = join(",", var.subnet_ids) + ENABLE_ORGANIZATION_RUNNERS = var.enable_organization_runners + ENVIRONMENT = var.environment + GHES_URL = var.ghes_url + GITHUB_APP_KEY_BASE64_PARAMETER_NAME = var.github_app.key_base64_parameter_name + GITHUB_APP_ID_PARAMETER_NAME = var.github_app.id_parameter_name + GITHUB_APP_CLIENT_ID_PARAMETER_NAME = var.github_app.client_id_parameter_name + GITHUB_APP_CLIENT_SECRET_PARAMETER_NAME = var.github_app.client_secret_parameter_name + RUNNER_EXTRA_LABELS = var.runner_extra_labels + RUNNER_GROUP_NAME = var.runner_group_name + RUNNERS_MAXIMUM_COUNT = var.runners_maximum_count + LAUNCH_TEMPLATE_NAME = aws_launch_template.runner.name + LAUNCH_TEMPLATE_VERSION = aws_launch_template.runner.latest_version + SUBNET_IDS = join(",", var.subnet_ids) } } @@ -91,6 +84,14 @@ resource "aws_iam_role_policy" "scale_up" { }) } +resource "aws_iam_role_policy" "scale_up_ssm_parameters" { + name = "${var.environment}-lambda-scale-up-ssm-parameters" + role = aws_iam_role.scale_up.name + policy = templatefile("${path.module}/policies/instance-ssm-parameters-policy.json", { + arn_ssm_parameters = "arn:aws:ssm:${var.aws_region}:${data.aws_caller_identity.current.account_id}:parameter/${var.environment}-*" + }) +} + resource "aws_iam_role_policy" "scale_up_logging" { name = "${var.environment}-lambda-logging" role = aws_iam_role.scale_up.name diff --git a/modules/runners/variables.tf b/modules/runners/variables.tf index 0abd518684..c1a752248d 100644 --- a/modules/runners/variables.tf +++ b/modules/runners/variables.tf @@ -108,12 +108,12 @@ variable "enable_organization_runners" { } variable "github_app" { - description = "GitHub app parameters, see your github app. Ensure the key is the base64-encoded `.pem` file (the output of `base64 app.private-key.pem`, not the content of `private-key.pem`)." + description = "GitHub App parameters. See your GitHub App. All values are expected to be valid SSM Parameter names, referring to existing SSM Parameters. Ensure the private key is the base64-encoding of the `.pem` file (the output of `base64 app.private-key.pem`, not the content of `private-key.pem` itself)." type = object({ - key_base64 = string - id = string - client_id = string - client_secret = string + key_base64_parameter_name = string + id_parameter_name = string + client_id_parameter_name = string + client_secret_parameter_name = string }) } diff --git a/variables.tf b/variables.tf index aeb991a192..b31b5fb6b9 100644 --- a/variables.tf +++ b/variables.tf @@ -29,13 +29,13 @@ variable "enable_organization_runners" { } variable "github_app" { - description = "GitHub app parameters, see your github app. Ensure the key is the base64-encoded `.pem` file (the output of `base64 app.private-key.pem`, not the content of `private-key.pem`)." + description = "GitHub App parameters. See your GitHub App. All values except the webhook secret are expected to be valid SSM Parameter names, referring to existing SSM Parameters. Ensure the private key is the base64-encoding of the `.pem` file (the output of `base64 app.private-key.pem`, not the content of `private-key.pem` itself)." type = object({ - key_base64 = string - id = string - client_id = string - client_secret = string - webhook_secret = string + key_base64_parameter_name = string + id_parameter_name = string + client_id_parameter_name = string + client_secret_parameter_name = string + webhook_secret = string }) }