Skip to content

Commit

Permalink
Trying to get a minimal lambda deployed
Browse files Browse the repository at this point in the history
  • Loading branch information
wildjames committed Nov 13, 2024
1 parent 124b710 commit 0a424a9
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 11 deletions.
12 changes: 12 additions & 0 deletions packages/cdk/nagSuppressions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@ export const nagSuppressions = (stack: Stack) => {
]
)

// TODO: Is the appropriate? Needs elab
safeAddNagSuppression(
stack,
"/StatelessStack/TrackerUserInfo/TrackerUserInfoLambda/LambdaPutLogsManagedPolicy/Resource",
[
{
id: "AwsSolutions-IAM5",
reason: "Lambda requires wildcard permissions for log streams, so it can write logs."
}
]
)

// !! Remove after auth has been implemented !!
safeAddNagSuppression(
stack,
Expand Down
13 changes: 9 additions & 4 deletions packages/cdk/resources/LambdaFunction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {Stream} from "aws-cdk-lib/aws-kinesis"
import {Construct} from "constructs"

import {getDefaultLambdaOptions} from "./LambdaFunction/helpers"
import path from "path"

const insightsLayerArn = "arn:aws:lambda:eu-west-2:580247275435:layer:LambdaInsightsExtension:53"

Expand All @@ -46,6 +47,7 @@ export interface LambdaFunctionProps {

/**
* The base path of the Lambda function code package.
* Relative to the root of the repository, e.g. "packages/cdk/resources/TrackerUserInfo"
*/
readonly packageBasePath: string

Expand Down Expand Up @@ -176,7 +178,6 @@ export class LambdaFunction extends Construct {
}
)

// Create a Subscription Filter to send logs to the Splunk delivery stream via Kinesis
new SubscriptionFilter(this, "LambdaLogsSplunkSubscriptionFilter", {
logGroup: lambdaLogGroup,
filterPattern: FilterPattern.allTerms(),
Expand All @@ -197,22 +198,26 @@ export class LambdaFunction extends Construct {
]
})

// Get default Lambda options from a helper function
const lambdaOptions = getDefaultLambdaOptions({
functionName: `${props.serviceName}-${props.lambdaName}`,
packageBasePath: props.packageBasePath,
entryPoint: props.entryPoint
})

// Create the Node.js Lambda function
// Include the tsconfig in the build
const bundlingOptions = {
tsconfig: path.resolve(__dirname, "../tsconfig.json")
}

const lambdaFunction = new NodejsFunction(this, props.lambdaName, {
...lambdaOptions,
role: lambdaRole,
environment: props.lambdaEnvironmentVariables,
logGroup: lambdaLogGroup,
layers: [
insightsLambdaLayer
]
],
bundling: bundlingOptions
})

// Suppress specific AWS Config rules for the Lambda function
Expand Down
3 changes: 1 addition & 2 deletions packages/cdk/resources/TrackerUserInfo/TrackerUserInfo.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {Construct} from "constructs"
import * as path from "path"
import {LambdaFunction} from "../LambdaFunction"

export interface TrackerUserInfoProps {
Expand All @@ -17,7 +16,7 @@ export class TrackerUserInfo extends Construct {
serviceName: props.serviceName,
stackName: props.stackName,
lambdaName: "TrackerUserInfo",
packageBasePath: path.join(__dirname),
packageBasePath: "packages/cdk/resources/TrackerUserInfo",
entryPoint: "handler.ts",
lambdaEnvironmentVariables: {
// Add any required environment variables here
Expand Down
80 changes: 75 additions & 5 deletions packages/cdk/stacks/StatelessResourcesStack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ import {CloudfrontDistribution} from "../resources/CloudfrontDistribution"
import {nagSuppressions} from "../nagSuppressions"

// Lambda resources
import {LambdaIntegration} from "aws-cdk-lib/aws-apigateway"
import {AuthorizationType, CognitoUserPoolsAuthorizer, LambdaIntegration} from "aws-cdk-lib/aws-apigateway"
import {TrackerUserInfo} from "../resources/TrackerUserInfo/TrackerUserInfo"
import {CfnUserPool, UserPool} from "aws-cdk-lib/aws-cognito"
import {CfnWebACL, CfnWebACLAssociation} from "aws-cdk-lib/aws-wafv2"

export interface StatelessResourcesStackProps extends StackProps {
readonly serviceName: string
Expand Down Expand Up @@ -56,6 +58,41 @@ export class StatelessResourcesStack extends Stack {
stackName: props.stackName
})

// Protect the gateway with WAFv2
const webAcl = new CfnWebACL(this, "WebACL", {
defaultAction: {allow: {}},
scope: "REGIONAL",
visibilityConfig: {
cloudWatchMetricsEnabled: true,
metricName: `${props.serviceName}-web-acl`,
sampledRequestsEnabled: true
},
rules: [
{
name: "AWS-AWSManagedRulesCommonRuleSet",
priority: 0,
statement: {
managedRuleGroupStatement: {
name: "AWSManagedRulesCommonRuleSet",
vendorName: "AWS"
}
},
overrideAction: {
none: {}
},
visibilityConfig: {
cloudWatchMetricsEnabled: true,
metricName: `${props.serviceName}-aws-managed-rules`,
sampledRequestsEnabled: true
}
}
]
})
new CfnWebACLAssociation(this, "WebACLAssociation", {
resourceArn: apiGateway.restApiGateway.deploymentStage.stageArn,
webAclArn: webAcl.attrArn
})

// --- Methods & Resources

// - Cloudfront
Expand Down Expand Up @@ -233,10 +270,43 @@ export class StatelessResourcesStack extends Stack {
serviceName: props.serviceName,
stackName: props.stackName
})
// Add /user resource to API Gateway
const userResource = apiGateway.restApiGateway.root.addResource("trackerUserInfo")
// Add GET method to /user resource
userResource.addMethod("GET", new LambdaIntegration(trackerUserInfo.lambdaFunction.lambda))

// Add /trackerUserInfo resource to API Gateway
const trackerUserInfoResource = apiGateway.restApiGateway.root.addResource("trackerUserInfo")

// Authorisation control for the lambda (the american spelling causes pain)
// What user pool should this use??? As a temporary measure, I suppose I'll define one, but this needs to be removed
const userPool = new UserPool(this, "UserPool", {
userPoolName: `${props.serviceName}-user-pool`,
selfSignUpEnabled: false,
signInAliases: {username: true, email: true},
passwordPolicy: {
minLength: 8,
requireUppercase: true,
requireLowercase: true,
requireDigits: true,
requireSymbols: true
}
// AIAIK, this is also where we would require MFA, which cfn also nags about...
})

// Set advanced security mode to ENFORCED
const cfnUserPool = userPool.node.defaultChild as CfnUserPool
cfnUserPool.userPoolAddOns = {
advancedSecurityMode: "ENFORCED"
}

// Create the authoriSer
const authorizer = new CognitoUserPoolsAuthorizer(this, "CognitoAuthorizer", {
cognitoUserPools: [userPool],
authorizerName: `${props.serviceName}-authorizer`
})

// Add the resource to the lambda
trackerUserInfoResource.addMethod("GET", new LambdaIntegration(trackerUserInfo.lambdaFunction.lambda), {
authorizer: authorizer,
authorizationType: AuthorizationType.COGNITO
})

/* Resources to add:
- api gateway resources
Expand Down

0 comments on commit 0a424a9

Please sign in to comment.