Skip to content

Commit

Permalink
Commit updated infrastructure code
Browse files Browse the repository at this point in the history
  • Loading branch information
gugzkumar committed Dec 15, 2019
1 parent 6a03f80 commit e230f7a
Show file tree
Hide file tree
Showing 14 changed files with 298 additions and 18 deletions.
1 change: 1 addition & 0 deletions .aws-infrastructure/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ node_modules
# CDK asset staging directory
.cdk.staging
cdk.out
.cdk/
3 changes: 2 additions & 1 deletion .aws-infrastructure/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
FROM node:13.3.0-alpine
ENV HOME=/usr/src/app
WORKDIR $HOME
COPY ./ $HOME
COPY ./package.json $HOME/package.json
RUN npm install -g aws-cdk@1.18.0 --quiet
RUN npm install --quiet
COPY ./ $HOME
15 changes: 14 additions & 1 deletion .aws-infrastructure/bin/CheetSheetInfrastructure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,19 @@
import 'source-map-support/register';
import cdk = require('@aws-cdk/core');
import { CheetSheetInfrastructureStack } from '../lib/CheetSheetInfrastructure-stack';
const ENVIRONMENT = process.env['ENVIRONMENT'] || '';

if (ENVIRONMENT === '') {
throw new Error('ENVIRONMENT env variable cannot be blank');
}

const app = new cdk.App();
new CheetSheetInfrastructureStack(app, 'CheetSheetInfrastructureStack');
new CheetSheetInfrastructureStack(
app,
`CheetSheetInfrastructureStack-${ENVIRONMENT}`,
{
env: {
'region': process.env['AWS_DEFAULT_REGION']
}
}
);
178 changes: 174 additions & 4 deletions .aws-infrastructure/lib/CheetSheetInfrastructure-stack.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,179 @@
import cdk = require('@aws-cdk/core');
import s3 = require('@aws-cdk/aws-s3');
import cloudfront = require('@aws-cdk/aws-cloudfront');
import route53 = require('@aws-cdk/aws-route53');
import targets = require('@aws-cdk/aws-route53-targets/lib');
import cognito = require('@aws-cdk/aws-cognito');
import iam = require('@aws-cdk/aws-iam');


// Read environment variables
const UI_DISTRIBUTION_TYPE = process.env['UI_DISTRIBUTION_TYPE'] || '';;
const AWS_ROUTE53_HOSTED_ZONE_ID = process.env['AWS_ROUTE53_HOSTED_ZONE_ID'] || '';
const SITE_SUB_DOMAIN = process.env['SITE_DOMAIN'] || '';
const SITE_DOMAIN = process.env['SITE_SUB_DOMAIN'] || '';
const AWS_ACM_CERTIFICATE_ARN = process.env['AWS_ACM_CERTIFICATE_ARN'] || '';
const ENVIRONMENT = process.env['ENVIRONMENT'] || '';
const CREATE_IAM_POLICIES = process.env['CREATE_IAM_POLICIES'] || 'true';

const toBoolean = (value: string | number | boolean): boolean =>
[true, 'true', 'True', 'TRUE', '1', 1].includes(value);

export class CheetSheetInfrastructureStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);

// The code that defines your stack goes here
}
siteHostname = `${SITE_SUB_DOMAIN}.${SITE_DOMAIN}`;
siteDomainName = SITE_DOMAIN;
uiDistributionType = UI_DISTRIBUTION_TYPE;
shouldCreateIamPolicies = toBoolean(CREATE_IAM_POLICIES);

constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);

// Create these resources to host our API and UI only if on a remote environment
if (ENVIRONMENT !== 'local') {
this.constructWebsiteResources(this.uiDistributionType);
this.constructApiRequiredResources(this.shouldCreateIamPolicies);
}

// Create our resources for our Authentication Management system
this.constructCognitoResources();

// Set up our private bucket that will save our application data (Sheet data is saved here)
this.constructApiRequiredResources(toBoolean(CREATE_IAM_POLICIES))

}


constructApiRequiredResources(shouldCreateIamPolicies: boolean) {
// Set up our private bucket that will be used to save and track deployment Artifacts for our API
const apiDeploymentBucket = new s3.Bucket(this, 'S3APIDeploymentBucket', {
removalPolicy: cdk.RemovalPolicy.DESTROY,
accessControl: s3.BucketAccessControl.PRIVATE
});

// Create IAM Policies to necessary for our Lambda functions in our API
if (shouldCreateIamPolicies) {
const role = new iam.Role(this, 'MyRole', {
assumedBy: new iam.ServicePrincipal('sns.amazonaws.com')
});

role.addToPolicy(new iam.PolicyStatement({
resources: ['*'],
actions: ['lambda:InvokeFunction'] })
);
}
}

/**
* This method constructs all methods needed to setup our authentication
* management in Cognito
*/
constructCognitoResources() {
// Create our Cognito Userpool for tracking users
const userPool = new cognito.UserPool(this, 'CognitoAppUserPool', {
signInType: cognito.SignInType.USERNAME,
autoVerifiedAttributes: [cognito.UserPoolAttribute.EMAIL],
userPoolName: this.siteHostname,
usernameAliasAttributes: [ cognito.UserPoolAttribute.PREFERRED_USERNAME ]
});
new cognito.CfnUserPoolGroup(this, "CognitoAdminsGroup", {
groupName: 'admin',
userPoolId: userPool.userPoolId,

});

const logoutUrLs = [
`https://${this.siteHostname}`,
`https://${this.siteHostname}/login`,
`https://${this.siteHostname}/logout`,
`http://${this.siteHostname}`,
`http://${this.siteHostname}/login`,
`http://${this.siteHostname}/logout`
]
const callbackUrLs = [
`https://${this.siteHostname}`,
`https://${this.siteHostname}/login`,
`https://${this.siteHostname}/logout`,
`http://${this.siteHostname}`,
`http://${this.siteHostname}/login`,
`http://${this.siteHostname}/logout`
]

const userPoolClient = new cognito.CfnUserPoolClient(this, 'CognitoAppUserPoolClient', {
userPoolId: userPool.userPoolId,
explicitAuthFlows: [ cognito.AuthFlow.USER_PASSWORD ],
logoutUrLs: logoutUrLs,
callbackUrLs: callbackUrLs,
allowedOAuthFlows: [ 'implicit', 'code'],
allowedOAuthScopes: [ "email", "openid", "aws.cognito.signin.user.admin", "profile"],
refreshTokenValidity: 30
});

const userPoolDomain = new cognito.CfnUserPoolDomain(this, 'CognitoAppUserPoolDomain', {
userPoolId: userPool.userPoolId,
domain: 'cheet-sheet-dev'
});
}

/**
* Create all resources needed to host our UI. There are two options.
* You can directly host from S3, or you can set up a Cloud Front CDN
* if you expect more trafic.
*
* @param targetResourceType - "buket" or "cloudfront"
*/
constructWebsiteResources(targetResourceType = 'bucket') {
if (targetResourceType !== 'bucket' && targetResourceType !== 'cloudfront')
throw new Error('Your UI distribution type must be "bucket" or "cloudfront"');

// Set up our public bucket that hosts our frontend
const clientUIAssetsBucket = new s3.Bucket(this, 'S3ClientUIAssetsBucket', {
websiteIndexDocument: 'index.html',
websiteErrorDocument: 'error.html',
bucketName:this.siteHostname,
publicReadAccess: true,
removalPolicy: cdk.RemovalPolicy.DESTROY
});

let targetResource: route53.IAliasRecordTarget = new targets.BucketWebsiteTarget(clientUIAssetsBucket);
if (targetResourceType!=='bucket') {
const clientUIWebDistribution = new cloudfront.CloudFrontWebDistribution(this, 'CloudFrontClientUIWebDistribution', {
originConfigs: [
{
s3OriginSource: {
s3BucketSource: clientUIAssetsBucket
},
behaviors: [
{
isDefaultBehavior: true,
allowedMethods: cloudfront.CloudFrontAllowedMethods.ALL,
defaultTtl: cdk.Duration.seconds(60)
},
]
}
],
aliasConfiguration: {
acmCertRef: AWS_ACM_CERTIFICATE_ARN,
names: [ this.siteHostname ],
sslMethod: cloudfront.SSLMethod.SNI,
securityPolicy: cloudfront.SecurityPolicyProtocol.TLS_V1_1_2016
}
});
targetResource = new targets.CloudFrontTarget(clientUIWebDistribution);
}

const zone = route53.HostedZone.fromHostedZoneAttributes(this, 'Zone', {
hostedZoneId: AWS_ROUTE53_HOSTED_ZONE_ID,
zoneName: this.siteDomainName
});

const clientUIDNSRecord = new route53.ARecord(this, 'SiteAliasRecord', {
recordName: 'cheet-sheet-dev',
target: route53.AddressRecordTarget.fromAlias(
targetResource
),
zone
});
}

}
10 changes: 9 additions & 1 deletion .aws-infrastructure/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": ".aws-infrastructure",
"name": "cheet-sheet-infrastructure",
"version": "0.1.0",
"bin": {
"src": "bin/CheetSheetInfrastructure.js"
Expand All @@ -21,6 +21,14 @@
"typescript": "~3.7.2"
},
"dependencies": {
"@aws-cdk/aws-certificatemanager": "^1.18.0",
"@aws-cdk/aws-cloudfront": "^1.18.0",
"@aws-cdk/aws-cognito": "^1.18.0",
"@aws-cdk/aws-iam": "^1.18.0",
"@aws-cdk/aws-route53": "^1.18.0",
"@aws-cdk/aws-route53-targets": "^1.18.0",
"@aws-cdk/aws-s3": "^1.18.0",
"@aws-cdk/aws-s3-deployment": "^1.18.0",
"@aws-cdk/core": "^1.18.0",
"source-map-support": "^0.5.16"
}
Expand Down
15 changes: 15 additions & 0 deletions .env_templates/infrastructure.template.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# What unique environment is this infrastructure, ex: local, prod, dev, staging
# If this is set to local, the cdk will only create resources you need to
# run this app locally, not host it to the public.
ENVIRONMENT=
UI_DISTRIBUTION_TYPE=

AWS_DEFAULT_REGION=
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=

AWS_ROUTE53_HOSTED_ZONE_ID=
SITE_SUB_DOMAIN=
SITE_DOMAIN=

AWS_ACM_CERTIFICATE_ARN=
27 changes: 27 additions & 0 deletions .env_templates/local.template.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# AWS Credentials and regions
AWS_DEFAULT_REGION=
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=

# Tell SAM Local the Path of the API, so it can properly mount volumes
SAM_LOCAL_ABSOLUTE_PATH=

# Comment this out if your okay with SAM sending data
SAM_CLI_TELEMETRY=0

# AWS Lambda Layer ARN, with necessary dependencies for the Python3.7 API
# - pyjwt==1.7.1
# - cryptography==2.8
LAMBDA_LAYER=

# Info for S3 Database which saves sheets
# SHEET_DATA_S3_BUCKET: S3 bucket that stores all sheets
# APP_ADMIN_USER: user who can edit, add and delete public sheets
# PUBLIC_SHEETS_FOLDER: what folder in S3 hosts the public sheets folder
APP_ADMIN_USER=
PUBLIC_SHEETS_FOLDER=
SHEET_DATA_S3_BUCKET=

# Base Encode JSON Web Tokens for Cognito
COGNITO_ID_JWK_BASE4=
COGNITO_ACCESS_JWK_BASE4=
32 changes: 32 additions & 0 deletions .env_templates/remote.template.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# AWS Credentials and regions
AWS_DEFAULT_REGION=
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=

# Comment this out if your okay with SAM sending data
SAM_CLI_TELEMETRY=0

# AWS Lambda Layer ARN, with necessary dependencies for the Python3.7 API
# - pyjwt==1.7.1
# - cryptography==2.8
LAMBDA_LAYER=

# Info for S3 Database which saves sheets
# SHEET_DATA_S3_BUCKET: S3 bucket that stores all sheets
# APP_ADMIN_USER: user who can edit, add and delete public sheets
# PUBLIC_SHEETS_FOLDER: what folder in S3 hosts the public sheets folder
APP_ADMIN_USER=
PUBLIC_SHEETS_FOLDER=
SHEET_DATA_S3_BUCKET=

# Base Encode JSON Web Tokens for Cognito
COGNITO_ID_JWK_BASE4=
COGNITO_ACCESS_JWK_BASE4=

# S3 Bucket For the Client UI
SHEET_DATA_S3_BUCKET=

# S3 bucket that hosts the client UI
CLIENT_UI_S3_BUCKET=
# S3 bucket that saves deploy Artifacts for the API
API_DEPLOYMENT_S3_BUCKET=
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
node_modules
package-lock.json
*.env
!*.template.env
backup.env
.ipynb_checkpoints
SimpleServer.ipynb
Expand Down
13 changes: 10 additions & 3 deletions docker-compose.deploy.code.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
# - API Gateway
# - S3 Bucket for UI hosting
# - S3 Bucket for App Data Storage
# - IAM Role for a Lambda Function
# Should have permission to update the App Data Storage bucket
#
# ------------------------------------------------------------------------------
version: '3.7'
Expand All @@ -22,7 +24,7 @@ services:
# --------------------------------------------------------------------------
serverless-angular-client-ui:
build: ./client-ui
container_name: serverless-angular-client-ui
container_name: serverless-deploy-angular-client-ui
volumes:
- ./client-ui:/usr/src/app
- /usr/src/app/node_modules
Expand All @@ -32,12 +34,17 @@ services:
# --------------------------------------------------------------------------
serverless-lambda-api:
build: ./api
container_name: serverless-lambda-api
container_name: serverless-deploy-lambda-api
volumes:
- ./api:/app
env_file:
- remote.env
environment:
- AWS_DEFAULT_REGION=$AWS_DEFAULT_REGION
- AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID
- AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY
- LAMBDA_LAYER:$LAMBDA_LAYER
# command: bash deploy.sh

networks:
default:
name: cheet-sheet-deploy-code
4 changes: 4 additions & 0 deletions docker-compose.deploy.infrastructure.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,7 @@ services:
- ./package.json:/usr/src/.aws-infrastructure/package.json
- ./.aws-infrastructure:/usr/src/app/
- /usr/src/app/node_modules

networks:
default:
name: cheet-sheet-deploy-infrastructure
6 changes: 0 additions & 6 deletions docker-compose.deploy.network.yml

This file was deleted.

Loading

0 comments on commit e230f7a

Please sign in to comment.