Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move Lambda Vars to Parameter Store #941

Merged
merged 36 commits into from
Aug 4, 2021
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
736a854
fix(scale): Refactor Runner Type and Owner (#871)
mcaulifn Jun 15, 2021
6e35845
feat: support multiple instance types (#898)
mcaulifn Jun 16, 2021
a768687
docs: fix lambda_security_group_ids incorrect description #738 (#902)
npalm Jun 17, 2021
5b5ee3b
fix: scale down runners (#905)
npalm Jun 17, 2021
8746249
chore: group upgrade lambda dependencies (#906)
npalm Jun 17, 2021
7bda880
feat(runner): Move Lambda Vars to Parameter Store
mcaulifn Jun 23, 2021
333eae7
Add test for ssm module (#1)
mcaulifn Jun 25, 2021
65535fb
Removing KMS/GH Auth from scale-down
mcaulifn Jun 25, 2021
b460a1a
Merge branch 'mcaulifn/ssm' of https://github.com/mcaulifn/terraform-…
mcaulifn Jun 25, 2021
aecc383
Add SSM permissions to runner policy
mcaulifn Jun 30, 2021
c84ae6c
Allow custom key_id
mcaulifn Jun 30, 2021
d2b61f1
Fixing for loop
mcaulifn Jun 30, 2021
8f34d71
Move SSM policy to Lambdas
mcaulifn Jul 1, 2021
7d44ac8
Fixing function call
mcaulifn Jul 1, 2021
66bd078
chore: Bump aws-sdk (#752) (#909)
dependabot[bot] Jun 18, 2021
77c8e13
chore: Bump aws-sdk (#752) (#908)
dependabot[bot] Jun 18, 2021
fe0a126
chore: Bump aws-sdk (#752) (#887)
dependabot[bot] Jun 18, 2021
174b4ca
chore: Bump aws-sdk (#752) (#885)
dependabot[bot] Jun 18, 2021
0f1493f
chore: Bump aws-sdk (#752) (#889)
dependabot[bot] Jun 18, 2021
5314469
chore: Bump aws-sdk (#752) (#892)
dependabot[bot] Jun 18, 2021
640ef5f
chore: Bump aws-sdk (#752) (#907)
dependabot[bot] Jun 18, 2021
1658635
chore: Bump aws-sdk (#752) (#864)
dependabot[bot] Jun 18, 2021
a401c0d
chore: Bump eslint in /modules/webhook/lambdas/webhook (#918)
dependabot[bot] Jun 24, 2021
870280b
chore: Bump typescript (#929)
dependabot[bot] Jun 24, 2021
0fdf8cf
chore: Bump @typescript-eslint/eslint-plugin (#928)
dependabot[bot] Jun 24, 2021
a6b9a29
chore: Bump typescript in /modules/webhook/lambdas/webhook (#926)
dependabot[bot] Jun 24, 2021
b5096bb
feat: Added support for white listing of repositories (#915)
ravenolf Jul 7, 2021
7ac1a25
Need `,` after list item
mcaulifn Jul 7, 2021
cbf7a70
Move Lambda Policy to data resource
mcaulifn Jul 7, 2021
d8e6fbd
Merge branch 'develop' into mcaulifn/ssm
mcaulifn Jul 7, 2021
d46f9e2
Merge branch 'develop' into mcaulifn/ssm
mcaulifn Jul 14, 2021
0c9aff5
Addressing PR comments, fixing lint
mcaulifn Jul 16, 2021
3104d34
Refactoring Parameters to SSM Module
mcaulifn Jul 27, 2021
7c09270
Merge branch 'develop' into mcaulifn/ssm
mcaulifn Jul 27, 2021
4ea2a17
Fixing rebase
mcaulifn Jul 27, 2021
19199e3
Using only key ARN as input value
mcaulifn Jul 29, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,6 @@ module "runners" {
subnet_ids = var.subnet_ids
environment = var.environment
tags = local.tags
encryption = {
kms_key_id = local.kms_key_id
encrypt = var.encrypt_secrets
}

s3_bucket_runner_binaries = module.runner_binaries.bucket
s3_location_runner_binaries = local.s3_action_runner_url
Expand Down Expand Up @@ -118,6 +114,8 @@ module "runners" {
runner_iam_role_managed_policy_arns = var.runner_iam_role_managed_policy_arns

ghes_url = var.ghes_url

kms_key_id = var.kms_key_id
}

module "runner_binaries" {
Expand Down
5 changes: 2 additions & 3 deletions modules/runners/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,6 @@ No Modules.
| [aws_iam_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) |
| [aws_iam_role_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) |
| [aws_iam_role_policy_attachment](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) |
| [aws_kms_ciphertext](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_ciphertext) |
| [aws_kms_grant](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_grant) |
| [aws_lambda_event_source_mapping](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_event_source_mapping) |
| [aws_lambda_function](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function) |
| [aws_lambda_permission](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) |
Expand All @@ -98,7 +96,6 @@ No Modules.
| enable\_cloudwatch\_agent | Enabling the cloudwatch agent on the ec2 runner instances, the runner contains default config. Configuration can be overridden via `cloudwatch_config`. | `bool` | `true` | no |
| enable\_organization\_runners | n/a | `bool` | n/a | yes |
| enable\_ssm\_on\_runners | Enable to allow access the runner instances for debugging purposes via SSM. Note that this adds additional permissions to the runner instances. | `bool` | n/a | yes |
| encryption | KMS key to encrypted lambda environment secrets. Either provide a key and `encrypt` set to `true`. Or set the key to `null` and encrypt to `false`. | <pre>object({<br> kms_key_id = string<br> encrypt = bool<br> })</pre> | n/a | yes |
| environment | A name that identifies the environment, used as prefix and for tagging. | `string` | n/a | yes |
| ghes\_url | GitHub Enterprise Server URL. DO NOT SET IF USING PUBLIC GITHUB | `string` | `null` | no |
| github\_app | 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`). | <pre>object({<br> key_base64 = string<br> id = string<br> client_id = string<br> client_secret = string<br> })</pre> | n/a | yes |
Expand All @@ -107,6 +104,7 @@ No Modules.
| instance\_type | [DEPRECATED] See instance\_types. | `string` | `"m5.large"` | no |
| instance\_types | List of instance types for the action runner. | `set(string)` | `null` | no |
| key\_name | Key pair name | `string` | `null` | no |
| kms\_key\_id | Optional CMK Key ID to be used for Parameter Store. | `string` | `null` | no |
| lambda\_s3\_bucket | S3 bucket from which to specify lambda functions. This is an alternative to providing local files directly. | `any` | `null` | no |
| lambda\_security\_group\_ids | List of security group IDs associated with the Lambda function. | `list(string)` | `[]` | no |
| lambda\_subnet\_ids | List of subnets in which the lambda will be launched, the subnets needs to be subnets in the `vpc_id`. | `list(string)` | `[]` | no |
Expand Down Expand Up @@ -148,6 +146,7 @@ No Modules.
| lambda\_scale\_down | n/a |
| lambda\_scale\_up | n/a |
| launch\_template | n/a |
| policy | n/a |
| role\_runner | n/a |
| role\_scale\_down | n/a |
| role\_scale\_up | n/a |
Expand Down
24 changes: 0 additions & 24 deletions modules/runners/encrypt.tf

This file was deleted.

6 changes: 5 additions & 1 deletion modules/runners/lambdas/runners/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"build": "ncc build src/lambda.ts -o dist",
"dist": "yarn build && cd dist && zip ../runners.zip index.js",
"format": "prettier --write \"**/*.ts\"",
"format-check": "prettier --check \"**/*.ts\""
"format-check": "prettier --check \"**/*.ts\"",
"all": "yarn build && yarn format && yarn lint && yarn test"
},
"devDependencies": {
"@types/aws-lambda": "^8.10.75",
Expand All @@ -22,14 +23,17 @@
"@typescript-eslint/parser": "^4.22.0",
"@vercel/ncc": "0.27.0",
"eslint": "^7.22.0",
"eslint-plugin-prettier": "3.4.0",
"jest": "^26.6.3",
"jest-mock-extended": "^1.0.13",
"moment-timezone": "^0.5.33",
"nock": "^13.0.11",
"prettier": "2.3.1",
"ts-jest": "^26.5.5",
"ts-node-dev": "^1.1.6"
},
"dependencies": {
"@aws-sdk/client-ssm": "^3.18.0",
"@octokit/auth-app": "3.4.0",
"@octokit/rest": "^18.3.5",
"@octokit/types": "^6.13.0",
Expand Down
2 changes: 2 additions & 0 deletions modules/runners/lambdas/runners/src/lambda.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { scaleUp } from './scale-runners/scale-up';
import { scaleDown } from './scale-runners/scale-down';
import { SQSEvent, ScheduledEvent, Context } from 'aws-lambda';

// eslint-disable-next-line @typescript-eslint/no-explicit-any
module.exports.scaleUp = async (event: SQSEvent, context: Context, callback: any) => {
console.dir(event, { depth: 5 });
try {
Expand All @@ -15,6 +16,7 @@ module.exports.scaleUp = async (event: SQSEvent, context: Context, callback: any
}
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
module.exports.scaleDown = async (event: ScheduledEvent, context: Context, callback: any) => {
try {
scaleDown();
Expand Down
128 changes: 88 additions & 40 deletions modules/runners/lambdas/runners/src/scale-runners/gh-auth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,20 @@ 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 { getParameterValue } from './ssm';
import { RequestInterface } from '@octokit/types';
import { mock, MockProxy } from 'jest-mock-extended';
import { request } from '@octokit/request';
import { mocked } from 'ts-jest/utils';

jest.mock('./kms');
jest.mock('./ssm');
jest.mock('@octokit/auth-app');

const cleanEnv = process.env;
const ENVIRONMENT = 'dev';
const GITHUB_APP_ID = '1';
const GITHUB_APP_CLIENT_ID = '1';
npalm marked this conversation as resolved.
Show resolved Hide resolved
const GITHUB_APP_CLIENT_SECRET = 'client_secret';

beforeEach(() => {
jest.resetModules();
Expand Down Expand Up @@ -46,8 +51,7 @@ describe('Test createGithubAuth', () => {
});

describe('Test createGithubAuth', () => {
const mockedDecrypt = (decrypt as unknown) as jest.Mock;
const mockedCreatAppAuth = (createAppAuth as unknown) as jest.Mock;
const mockedCreatAppAuth = createAppAuth as unknown as jest.Mock;
const mockedDefaults = jest.spyOn(request, 'defaults');
let mockedRequestInterface: MockProxy<RequestInterface>;

Expand All @@ -58,27 +62,28 @@ describe('Test createGithubAuth', () => {
const b64 = Buffer.from(decryptedValue, 'binary').toString('base64');

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.ENVIRONMENT = 'dev';
process.env.GITHUB_APP_CLIENT_ID = '1';
process.env.ENVIRONMENT = ENVIRONMENT;
});

test('Creates auth object for public GitHub', async () => {
// Arrange
const authOptions = {
appId: parseInt(process.env.GITHUB_APP_ID as string),
privateKey: 'decryptedValue',
appId: parseInt(GITHUB_APP_ID),
privateKey: decryptedValue,
installationId,
clientId: process.env.GITHUB_APP_CLIENT_ID,
clientSecret: 'decryptedValue',
clientId: GITHUB_APP_CLIENT_ID,
clientSecret: GITHUB_APP_CLIENT_SECRET,
};

mockedDecrypt.mockResolvedValueOnce(decryptedValue).mockResolvedValueOnce(b64);
const mockedGet = mocked(getParameterValue);
mockedGet
.mockResolvedValueOnce(GITHUB_APP_ID)
.mockResolvedValueOnce(b64)
.mockResolvedValueOnce(GITHUB_APP_CLIENT_ID)
.mockResolvedValueOnce(GITHUB_APP_CLIENT_SECRET);
const mockedAuth = jest.fn();
mockedAuth.mockResolvedValue({ token });
// eslint-disable-next-line @typescript-eslint/no-unused-vars
mockedCreatAppAuth.mockImplementation((authOptions: StrategyOptions) => {
return mockedAuth;
});
Expand All @@ -87,16 +92,11 @@ describe('Test createGithubAuth', () => {
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(mockedDecrypt).toBeCalledWith(
process.env.GITHUB_APP_KEY_BASE64,
process.env.KMS_KEY_ID,
process.env.ENVIRONMENT,
);
expect(getParameterValue).toBeCalledWith(ENVIRONMENT, 'github_app_id');
expect(getParameterValue).toBeCalledWith(ENVIRONMENT, 'github_app_key_base64');
expect(getParameterValue).toBeCalledWith(ENVIRONMENT, 'github_app_client_id');
expect(getParameterValue).toBeCalledWith(ENVIRONMENT, 'github_app_client_secret');

expect(mockedCreatAppAuth).toBeCalledTimes(1);
expect(mockedCreatAppAuth).toBeCalledWith(authOptions);
expect(mockedAuth).toBeCalledWith({ type: authType });
Expand All @@ -113,17 +113,70 @@ describe('Test createGithubAuth', () => {
});

const authOptions = {
appId: parseInt(process.env.GITHUB_APP_ID as string),
privateKey: 'decryptedValue',
appId: parseInt(GITHUB_APP_ID),
privateKey: decryptedValue,
installationId,
clientId: process.env.GITHUB_APP_CLIENT_ID,
clientSecret: 'decryptedValue',
clientId: GITHUB_APP_CLIENT_ID,
clientSecret: GITHUB_APP_CLIENT_SECRET,
request: mockedRequestInterface.defaults({ baseUrl: githubServerUrl }),
};

const mockedGet = mocked(getParameterValue);
mockedGet
.mockResolvedValueOnce(GITHUB_APP_ID)
.mockResolvedValueOnce(b64)
.mockResolvedValueOnce(GITHUB_APP_CLIENT_ID)
.mockResolvedValueOnce(GITHUB_APP_CLIENT_SECRET);
const mockedAuth = jest.fn();
mockedAuth.mockResolvedValue({ token });
// eslint-disable-next-line @typescript-eslint/no-unused-vars
mockedCreatAppAuth.mockImplementation((authOptions: StrategyOptions) => {
return mockedAuth;
});

// Act
const result = await createGithubAuth(installationId, authType, githubServerUrl);

// Assert
expect(getParameterValue).toBeCalledWith(ENVIRONMENT, 'github_app_id');
expect(getParameterValue).toBeCalledWith(ENVIRONMENT, 'github_app_key_base64');
expect(getParameterValue).toBeCalledWith(ENVIRONMENT, 'github_app_client_id');
expect(getParameterValue).toBeCalledWith(ENVIRONMENT, 'github_app_client_secret');

expect(mockedCreatAppAuth).toBeCalledTimes(1);
expect(mockedCreatAppAuth).toBeCalledWith(authOptions);
expect(mockedAuth).toBeCalledWith({ type: authType });
expect(result.token).toBe(token);
});

test('Creates auth object for Enterprise Server with no ID', async () => {
// Arrange
const githubServerUrl = 'https://github.enterprise.notgoingtowork';

mockedRequestInterface = mock<RequestInterface>();
mockedDefaults.mockImplementation(() => {
return mockedRequestInterface.defaults({ baseUrl: githubServerUrl });
});

const installationId = undefined;

const authOptions = {
appId: parseInt(GITHUB_APP_ID),
privateKey: decryptedValue,
clientId: GITHUB_APP_CLIENT_ID,
clientSecret: GITHUB_APP_CLIENT_SECRET,
request: mockedRequestInterface.defaults({ baseUrl: githubServerUrl }),
};

mockedDecrypt.mockResolvedValueOnce(decryptedValue).mockResolvedValueOnce(b64);
const mockedGet = mocked(getParameterValue);
mockedGet
.mockResolvedValueOnce(GITHUB_APP_ID)
.mockResolvedValueOnce(b64)
.mockResolvedValueOnce(GITHUB_APP_CLIENT_ID)
.mockResolvedValueOnce(GITHUB_APP_CLIENT_SECRET);
const mockedAuth = jest.fn();
mockedAuth.mockResolvedValue({ token });
// eslint-disable-next-line @typescript-eslint/no-unused-vars
mockedCreatAppAuth.mockImplementation((authOptions: StrategyOptions) => {
return mockedAuth;
});
Expand All @@ -132,16 +185,11 @@ describe('Test createGithubAuth', () => {
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(mockedDecrypt).toBeCalledWith(
process.env.GITHUB_APP_KEY_BASE64,
process.env.KMS_KEY_ID,
process.env.ENVIRONMENT,
);
expect(getParameterValue).toBeCalledWith(ENVIRONMENT, 'github_app_id');
expect(getParameterValue).toBeCalledWith(ENVIRONMENT, 'github_app_key_base64');
expect(getParameterValue).toBeCalledWith(ENVIRONMENT, 'github_app_client_id');
expect(getParameterValue).toBeCalledWith(ENVIRONMENT, 'github_app_client_secret');

expect(mockedCreatAppAuth).toBeCalledTimes(1);
expect(mockedCreatAppAuth).toBeCalledWith(authOptions);
expect(mockedAuth).toBeCalledWith({ type: authType });
Expand Down
37 changes: 7 additions & 30 deletions modules/runners/lambdas/runners/src/scale-runners/gh-auth.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import { Octokit } from '@octokit/rest';
import { request } from '@octokit/request';
import { createAppAuth } from '@octokit/auth-app';
import {
Authentication,
StrategyOptions,
AppAuthentication,
InstallationAccessTokenAuthentication,
} from '@octokit/auth-app/dist-types/types';
import { StrategyOptions, AppAuthentication } from '@octokit/auth-app/dist-types/types';
import { OctokitOptions } from '@octokit/core/dist-types/types';
import { decrypt } from './kms';
import { getParameterValue } from './ssm';

export async function createOctoClient(token: string, ghesApiUrl = ''): Promise<Octokit> {
const ocktokitOptions: OctokitOptions = {
Expand All @@ -26,31 +21,13 @@ export async function createGithubAuth(
authType: 'app' | 'installation',
ghesApiUrl = '',
): Promise<AppAuthentication> {
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 privateKeyBase64 = await decrypt(
process.env.GITHUB_APP_KEY_BASE64 as string,
process.env.KMS_KEY_ID as string,
process.env.ENVIRONMENT as string,
);

if (clientSecret === undefined || privateKeyBase64 === undefined) {
throw Error('Cannot decrypt.');
}

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 environment = process.env.ENVIRONMENT as string;

let authOptions: StrategyOptions = {
appId,
privateKey,
clientId,
clientSecret,
appId: parseInt(await getParameterValue(environment, 'github_app_id')),
privateKey: Buffer.from(await getParameterValue(environment, 'github_app_key_base64'), 'base64').toString(),
clientId: await getParameterValue(environment, 'github_app_client_id'),
clientSecret: await getParameterValue(environment, 'github_app_client_secret'),
};
if (installationId) authOptions = { ...authOptions, installationId };

Expand Down
25 changes: 0 additions & 25 deletions modules/runners/lambdas/runners/src/scale-runners/kms/index.ts

This file was deleted.

Loading