Created
April 24, 2021 01:27
-
-
Save medelman17/959ed7bd11d60b191a54c385ac686703 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as fs from 'fs'; | |
import * as path from 'path'; | |
import * as cdk from '@aws-cdk/core'; | |
import * as lambda from '@aws-cdk/aws-lambda-nodejs'; | |
import * as kms from '@aws-cdk/aws-kms'; | |
import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; | |
import * as acm from '@aws-cdk/aws-certificatemanager'; | |
import * as alias from '@aws-cdk/aws-route53-targets'; | |
import * as iam from '@aws-cdk/aws-iam'; | |
import * as api from '@aws-cdk/aws-apigatewayv2'; | |
import * as route53 from '@aws-cdk/aws-route53'; | |
import { Runtime, Tracing } from '@aws-cdk/aws-lambda'; | |
import { LambdaProxyIntegration } from '@aws-cdk/aws-apigatewayv2-integrations'; | |
export class CdkInfraStack extends cdk.Stack { | |
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) { | |
super(scope, id, props); | |
// Get existing parent hosted zone for `amplify.edelman.sh` by lookup | |
const parentZone = route53.HostedZone.fromHostedZoneAttributes( | |
this, | |
'ParentZone', | |
{ | |
zoneName: 'amplify.edelman.sh', | |
hostedZoneId: 'Z10312421HWSZ73AHQQQU', | |
} | |
); | |
// Create new child hosted zone for `gateway.amplify.edelman.sh` | |
const childZone = new route53.PublicHostedZone(this, 'ChildZone', { | |
zoneName: 'gateway.amplify.edelman.sh', | |
}); | |
// Create new custom domain with api gateway; import existing SSL certificate from | |
// certificate manager | |
const domainName = new api.DomainName(this, 'ApiCustomDomain', { | |
domainName: childZone.zoneName, | |
certificate: acm.Certificate.fromCertificateArn( | |
this, | |
'Cert', | |
getCertificateArn() | |
), | |
}); | |
// Create dns target/record in child zone for api gateway domain | |
new route53.ARecord(this, 'AliasRecord', { | |
zone: childZone, | |
target: route53.RecordTarget.fromAlias( | |
new alias.ApiGatewayv2DomainProperties( | |
domainName.regionalDomainName, | |
domainName.regionalHostedZoneId | |
) | |
), | |
}); | |
// Create zone delegation record in parent zone to forward requests to child | |
const delegationRecord = new route53.ZoneDelegationRecord( | |
this, | |
'DelegationRecord', | |
{ | |
zone: parentZone, | |
recordName: childZone.zoneName, | |
nameServers: childZone.hostedZoneNameServers!, | |
} | |
); | |
// Add delegationRecord dependency on childZone to ensure NS are present | |
delegationRecord.node.addDependency(childZone); | |
// Store GitHub private key for app using secrets manager; encrypt with kms key | |
const encryptionKey = new kms.Key(this, 'GitHubSecretEncryptionKey'); | |
const secret = new secretsmanager.Secret(this, 'GitHubSecret', { | |
encryptionKey, | |
generateSecretString: { | |
secretStringTemplate: JSON.stringify({ key: getGitHubPrivateKey() }), | |
generateStringKey: 'password', | |
}, | |
}); | |
// Create execution role for lambda api handlers | |
const lambdaExecutionRole = new iam.Role(this, `FuncExecutionRole`, { | |
roleName: 'FuncExecutionRole', | |
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), | |
managedPolicies: [ | |
iam.ManagedPolicy.fromAwsManagedPolicyName( | |
'service-role/AWSLambdaBasicExecutionRole' | |
), | |
], | |
inlinePolicies: { | |
customApiFunctionPolicy: new iam.PolicyDocument({ | |
statements: getPolicyStatementsForLambdaExecRole(), | |
}), | |
}, | |
}); | |
// Add permission to read GitHub secret to lambda execution role | |
secret.grantRead(lambdaExecutionRole); | |
// Create lambda api handler for GitHub app webhook | |
const webhookHandler = new lambda.NodejsFunction( | |
this, | |
'GitHubWebhookHandler', | |
{ | |
handler: 'handler', | |
runtime: Runtime.NODEJS_14_X, | |
role: lambdaExecutionRole, | |
entry: path.join(__dirname, '../../docs-assistant-lambda/src/index.ts'), | |
bundling: { | |
externalModules: ['aws-sdk'], | |
tsconfig: path.join(__dirname, '../../docs-assistant/tsconfig.json'), | |
nodeModules: ['probot', 'probot-commands'], | |
}, | |
depsLockFilePath: path.join(__dirname, '../../../yarn.lock'), | |
tracing: Tracing.ACTIVE, | |
environment: { | |
APP_ID: '112080', | |
PRIVATE_KEY: secret.secretValueFromJson('key').toString(), | |
WEBHOOK_SECRET: 'development', | |
NODE_ENV: 'production', | |
LOG_LEVEL: 'debug', | |
SECRET_ID: secret.secretArn, | |
STAGE: 'development', | |
SENTRY_DSN: | |
'https://[email protected]/5733906', | |
}, | |
} | |
); | |
// Create lambda proxy integration for HttpApi | |
const gitHubWebhookIntegration = new LambdaProxyIntegration({ | |
handler: webhookHandler, | |
}); | |
// Create actual HttpApi | |
const httpApi = new api.HttpApi(this, 'HttpApi'); | |
// Create development stage for HttpApi & map custom domain | |
const developmentStage = new api.HttpStage(this, 'DevStage', { | |
httpApi, | |
stageName: 'dev', | |
autoDeploy: true, | |
domainMapping: { domainName, mappingKey: 'dev' }, | |
}); | |
// Add route for GitHub webhook handler & attach integration | |
httpApi.addRoutes({ | |
path: `/docs-assistant/webhook`, | |
methods: [api.HttpMethod.POST, api.HttpMethod.PATCH], | |
integration: gitHubWebhookIntegration, | |
}); | |
// Output relevant data, endpoint urls, etc. | |
new cdk.CfnOutput(this, 'HttpApiBaseEndpoint', { | |
value: httpApi.apiEndpoint, | |
}); | |
new cdk.CfnOutput(this, 'HttpApiDevStageEndpoint', { | |
value: developmentStage.url, | |
}); | |
} | |
} | |
function getPolicyStatementsForLambdaExecRole() { | |
return [ | |
new iam.PolicyStatement({ | |
actions: [ | |
'ec2:DescribeNetworkInterfaces', | |
'ec2:CreateNetworkInterface', | |
'ec2:DeleteNetworkInterface', | |
'ec2:DescribeInstances', | |
'ec2:AttachNetworkInterface', | |
'secretsmanager:GetSecretValue', | |
], | |
resources: ['*'], | |
}), | |
]; | |
} | |
function getGitHubPrivateKey() { | |
return fs | |
.readFileSync( | |
path.join( | |
__dirname, | |
'../../docs-assistant/amplify-docs-assistant.2021-04-23.private-key.pem' | |
) | |
) | |
.toString(); | |
} | |
function getCertificateArn() { | |
return 'arn:aws:acm:us-east-1:728134986050:certificate/3d8d5457-b4e8-4cee-860f-a1dda2f50427'; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment