Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
26 changes: 26 additions & 0 deletions assets/basic-auth-bucket/adapters.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { SecretsManager } from "@aws-sdk/client-secrets-manager"
import { GetParameterCommand, SSMClient } from "@aws-sdk/client-ssm"
import type { ICache, ISecretStore } from "./ports"

export class SecretStore implements ISecretStore {
Expand Down Expand Up @@ -30,6 +31,31 @@ export class InMemorySecretStore implements ISecretStore {
}
}

export class ParameterStore implements ISecretStore {
private client: SSMClient
constructor() {
this.client = new SSMClient({
// To avoid the need for cross region replication of parameters
region: "us-east-1",
})
}
async getSecret(secretName: string): Promise<string | undefined> {
let secret
try {
const result = await this.client.send(
new GetParameterCommand({
Name: secretName,
WithDecryption: true,
}),
)
secret = result.Parameter?.Value
} catch (e) {
console.error(e)
}
return secret
}
}

export class InMemoryCache implements ICache {
private cache: Record<string, unknown>
constructor() {
Expand Down
7 changes: 5 additions & 2 deletions assets/basic-auth-bucket/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import type * as lambdaTypes from "aws-lambda"
import { InMemoryCache, SecretStore } from "./adapters"
import { InMemoryCache, ParameterStore, SecretStore } from "./adapters"
import { AuthorizeRequest } from "./core"

const secretStore = new SecretStore()
const secretStore =
process.env.SECRET_TYPE === "parameter-store"
? new ParameterStore()
: new SecretStore()
const cache = new InMemoryCache()

export const handler: lambdaTypes.CloudFrontRequestHandler = async (event) => {
Expand Down
29 changes: 22 additions & 7 deletions assets/github-cookie-auth/authorizer.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,30 @@
import { DynamoDB } from "@aws-sdk/client-dynamodb"
import { KMS } from "@aws-sdk/client-kms"
import { SecretsManager } from "@aws-sdk/client-secrets-manager"
import { GetParameterCommand, SSMClient } from "@aws-sdk/client-ssm"
import { DynamoDBDocument } from "@aws-sdk/lib-dynamodb"
import type * as octokitTypes from "@octokit/types"
import type * as lambdaTypes from "aws-lambda"
import { getCookieValue, httpRequest } from "./lib"

const secretsManager = new SecretsManager()
const ssmClient = new SSMClient({})
const kms = new KMS()

async function getSecretValue(
name: string,
type: string,
): Promise<string | undefined> {
if (type === "parameter-store") {
const result = await ssmClient.send(
new GetParameterCommand({ Name: name, WithDecryption: true }),
)
return result.Parameter?.Value
}
const result = await secretsManager.getSecretValue({ SecretId: name })
return result.SecretString
}

const dynamodb = DynamoDBDocument.from(new DynamoDB())

const getGitHubAppInstallationsForUser = async (
Expand Down Expand Up @@ -57,6 +73,7 @@ export const handler = async (
accessControl,
allowedOrigin,
secretName,
secretType,
authCookieEncryptionKeyArn,
authCookieName,
gitHubAppId,
Expand All @@ -71,6 +88,7 @@ export const handler = async (
: undefined,
process.env.ALLOWED_ORIGIN,
process.env.SECRET_NAME,
process.env.SECRET_TYPE || "secrets-manager",
process.env.AUTH_COOKIE_ENCRYPTION_KEY_ARN,
process.env.AUTH_COOKIE_NAME,
process.env.GITHUB_APP_ID,
Expand Down Expand Up @@ -143,19 +161,16 @@ export const handler = async (
throw new Error("Unauthenticated")
}

const secret = await secretsManager.getSecretValue({
SecretId: secretName,
})

const secrets = secret.SecretString
? (JSON.parse(secret.SecretString) as {
const secretString = await getSecretValue(secretName, secretType)
const secrets = secretString
? (JSON.parse(secretString) as {
clientId: string
clientSecret: string
})
: null

if (!secrets || !secrets.clientId || !secrets.clientSecret) {
console.error("Could not properly read secrets from Secrets Manager")
console.error("Could not properly read secret")
throw new Error("Unauthenticated")
}

Expand Down
29 changes: 22 additions & 7 deletions assets/github-cookie-auth/oauth-flow-callback.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,28 @@
import { createHash } from "node:crypto"
import { KMS } from "@aws-sdk/client-kms"
import { SecretsManager } from "@aws-sdk/client-secrets-manager"
import { GetParameterCommand, SSMClient } from "@aws-sdk/client-ssm"
import type * as lambdaTypes from "aws-lambda"
import { getCookieValue, httpRequest } from "./lib"

const secretsManager = new SecretsManager()
const ssmClient = new SSMClient({})
const kms = new KMS()

async function getSecretValue(
name: string,
type: string,
): Promise<string | undefined> {
if (type === "parameter-store") {
const result = await ssmClient.send(
new GetParameterCommand({ Name: name, WithDecryption: true }),
)
return result.Parameter?.Value
}
const result = await secretsManager.getSecretValue({ SecretId: name })
return result.SecretString
}

export const handler = async (event: lambdaTypes.APIGatewayProxyEvent) => {
const [
nonceCookieName,
Expand All @@ -15,6 +31,7 @@ export const handler = async (event: lambdaTypes.APIGatewayProxyEvent) => {
authCookieEncryptionKeyArn,
responseHeaders,
secretName,
secretType,
redirectUrl,
] = [
process.env.NONCE_COOKIE_NAME,
Expand All @@ -25,6 +42,7 @@ export const handler = async (event: lambdaTypes.APIGatewayProxyEvent) => {
? (JSON.parse(process.env.RESPONSE_HEADERS) as Record<string, string>)
: undefined,
process.env.SECRET_NAME,
process.env.SECRET_TYPE || "secrets-manager",
process.env.REDIRECT_URL,
]
if (
Expand Down Expand Up @@ -80,18 +98,15 @@ export const handler = async (event: lambdaTypes.APIGatewayProxyEvent) => {
}

// Perform code exchange
const secret = await secretsManager.getSecretValue({
SecretId: secretName,
})

const secrets = secret.SecretString
? (JSON.parse(secret.SecretString) as {
const secretString = await getSecretValue(secretName, secretType)
const secrets = secretString
? (JSON.parse(secretString) as {
clientId: string
clientSecret: string
})
: null
if (!secrets || !secrets.clientId || !secrets.clientSecret) {
console.error("Could not properly read secrets from Secrets Manager")
console.error("Could not properly read secret")
return {
headers: {
...responseHeaders,
Expand Down
29 changes: 22 additions & 7 deletions assets/github-cookie-auth/oauth-flow-request.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
import { createHash } from "node:crypto"
import { SecretsManager } from "@aws-sdk/client-secrets-manager"
import { GetParameterCommand, SSMClient } from "@aws-sdk/client-ssm"
import type * as lambdaTypes from "aws-lambda"
import { generateRandomString, getUrlWithEncodedQueryParams } from "./lib"

const secretsManager = new SecretsManager()
const ssmClient = new SSMClient({})

async function getSecretValue(
name: string,
type: string,
): Promise<string | undefined> {
if (type === "parameter-store") {
const result = await ssmClient.send(
new GetParameterCommand({ Name: name, WithDecryption: true }),
)
return result.Parameter?.Value
}
const result = await secretsManager.getSecretValue({ SecretId: name })
return result.SecretString
}

export const handler = async (_event: lambdaTypes.APIGatewayProxyEvent) => {
const [
Expand All @@ -12,6 +28,7 @@ export const handler = async (_event: lambdaTypes.APIGatewayProxyEvent) => {
callbackUrl,
responseHeaders,
secretName,
secretType,
] = [
process.env.NONCE_COOKIE_NAME,
process.env.NONCE_COOKIE_ATTRIBUTES,
Expand All @@ -20,6 +37,7 @@ export const handler = async (_event: lambdaTypes.APIGatewayProxyEvent) => {
? (JSON.parse(process.env.RESPONSE_HEADERS) as Record<string, string>)
: undefined,
process.env.SECRET_NAME,
process.env.SECRET_TYPE || "secrets-manager",
]
if (!nonceCookieName || !secretName || !callbackUrl) {
console.error("Missing required environment variables")
Expand All @@ -31,18 +49,15 @@ export const handler = async (_event: lambdaTypes.APIGatewayProxyEvent) => {
}
}

const secret = await secretsManager.getSecretValue({
SecretId: secretName,
})

const secrets = secret.SecretString
? (JSON.parse(secret.SecretString) as {
const secretString = await getSecretValue(secretName, secretType)
const secrets = secretString
? (JSON.parse(secretString) as {
clientId: string
clientSecret: string
})
: null
if (!secrets || !secrets.clientId || !secrets.clientSecret) {
console.error("Could not properly read secrets from Secrets Manager")
console.error("Could not properly read secret")
return {
headers: {
...responseHeaders,
Expand Down
25 changes: 19 additions & 6 deletions assets/github-push-webhook/webhook-receiver.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
import { createHmac, timingSafeEqual } from "node:crypto"
import { DynamoDB } from "@aws-sdk/client-dynamodb"
import { SecretsManager } from "@aws-sdk/client-secrets-manager"
import { GetParameterCommand, SSMClient } from "@aws-sdk/client-ssm"
import { DynamoDBDocument } from "@aws-sdk/lib-dynamodb"
import type * as lambdaTypes from "aws-lambda"
import type { DbPushEvent } from "./types"

const secretsManager = new SecretsManager()
const ssmClient = new SSMClient({})

async function getSecretValue(
name: string,
type: string,
): Promise<string | undefined> {
if (type === "parameter-store") {
const result = await ssmClient.send(
new GetParameterCommand({ Name: name, WithDecryption: true }),
)
return result.Parameter?.Value
}
const result = await secretsManager.getSecretValue({ SecretId: name })
return result.SecretString
}

const dynamodb = DynamoDBDocument.from(new DynamoDB())

Expand All @@ -24,6 +40,7 @@ export const handler = async (event: lambdaTypes.APIGatewayProxyEvent) => {

const tableName = process.env.TABLE_NAME
const secretName = process.env.SECRET_NAME
const secretType = process.env.SECRET_TYPE || "secrets-manager"

if (!tableName || !secretName) {
console.error("Missing required environment variables")
Expand All @@ -47,13 +64,9 @@ export const handler = async (event: lambdaTypes.APIGatewayProxyEvent) => {
}
}

const secret = await secretsManager.getSecretValue({
SecretId: secretName,
})

const secretToken = secret.SecretString || null
const secretToken = await getSecretValue(secretName, secretType)
if (!secretToken) {
console.error("Could not properly read secret from Secrets Manager")
console.error("Could not properly read secret")
return {
statusCode: 500,
}
Expand Down
25 changes: 19 additions & 6 deletions assets/github-workflow-run-webhook-receiver/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,30 @@ import { createHmac } from "node:crypto"
import { timingSafeEqual } from "node:crypto"
import { DynamoDB } from "@aws-sdk/client-dynamodb"
import { SecretsManager } from "@aws-sdk/client-secrets-manager"
import { GetParameterCommand, SSMClient } from "@aws-sdk/client-ssm"
import { DynamoDBDocument } from "@aws-sdk/lib-dynamodb"
import type * as octokitWebhooksTypes from "@octokit/webhooks-types"
import type { ServiceException } from "@smithy/smithy-client"
import type * as lambdaTypes from "aws-lambda"

const secretsManager = new SecretsManager()
const ssmClient = new SSMClient({})
const dynamodb = DynamoDBDocument.from(new DynamoDB())

async function getSecretValue(
name: string,
type: string,
): Promise<string | undefined> {
if (type === "parameter-store") {
const result = await ssmClient.send(
new GetParameterCommand({ Name: name, WithDecryption: true }),
)
return result.Parameter?.Value
}
const result = await secretsManager.getSecretValue({ SecretId: name })
return result.SecretString
}

export const timingSafeStringComparison = (a: string, b: string) => {
try {
return timingSafeEqual(Buffer.from(a, "utf8"), Buffer.from(b, "utf8"))
Expand All @@ -32,6 +48,7 @@ export const isAWSError = (arg: unknown): arg is ServiceException => {
export const handler = async (event: lambdaTypes.APIGatewayProxyEvent) => {
const tableName = process.env.TABLE_NAME
const secretName = process.env.SECRET_NAME
const secretType = process.env.SECRET_TYPE || "secrets-manager"
const gitHubAppId = process.env.GITHUB_APP_ID

if (!tableName || !secretName || !gitHubAppId) {
Expand All @@ -56,13 +73,9 @@ export const handler = async (event: lambdaTypes.APIGatewayProxyEvent) => {
}
}

const secret = await secretsManager.getSecretValue({
SecretId: secretName,
})

const secretToken = secret.SecretString || null
const secretToken = await getSecretValue(secretName, secretType)
if (!secretToken) {
console.error("Could not properly read secret from Secrets Manager")
console.error("Could not properly read secret")
return {
statusCode: 500,
}
Expand Down
Loading