Skip to content

Commit

Permalink
update stack
Browse files Browse the repository at this point in the history
  • Loading branch information
gugzkumar committed Dec 16, 2019
1 parent e230f7a commit 42266aa
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 76 deletions.
195 changes: 125 additions & 70 deletions .aws-infrastructure/lib/CheetSheetInfrastructure-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ 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 AWS_CREATE_IAM_POLICIES = process.env['AWS_CREATE_IAM_POLICIES'] || 'true';

const toBoolean = (value: string | number | boolean): boolean =>
[true, 'true', 'True', 'TRUE', '1', 1].includes(value);
Expand All @@ -24,105 +24,77 @@ export class CheetSheetInfrastructureStack extends cdk.Stack {
siteHostname = `${SITE_SUB_DOMAIN}.${SITE_DOMAIN}`;
siteDomainName = SITE_DOMAIN;
uiDistributionType = UI_DISTRIBUTION_TYPE;
shouldCreateIamPolicies = toBoolean(CREATE_IAM_POLICIES);
shouldCreateIamPolicies = toBoolean(AWS_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);
}
// Set up our app data storage resources
const storageARNs = this.constructDataStorageResources();

// 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))
// Create these resources to host our API and UI only if on a remote environment
if (ENVIRONMENT !== 'local') {
this.constructApiRequiredResources(this.shouldCreateIamPolicies, storageARNs);
this.constructClientUiResources(this.uiDistributionType);
}

}


constructApiRequiredResources(shouldCreateIamPolicies: boolean) {
/**
* Create all resources needed to host our API.
* You can directly host from S3, or you can set up a Cloud Front CDN
* if you expect more trafic.
*
* @param shouldCreateIamPolicies: boolean
* true - create the IAM policy for our API's lambda function
* false - skip creating the IAM policy for our API's lambda functions
*/
constructApiRequiredResources(shouldCreateIamPolicies: boolean, storageARNs: Array<string>) {
// 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
accessControl: s3.BucketAccessControl.PRIVATE,
bucketName: `${this.siteDomainName}-api-deployment`
});

// 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')
const role = new iam.Role(this, 'LambdaExecutionRole', {
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com')
});

role.addToPolicy(new iam.PolicyStatement({
resources: ['*'],
actions: ['lambda:InvokeFunction'] })
);
resources: storageARNs,
actions: [
's3:GetObject',
's3:DeleteObject',
's3:PutObject',
's3:ListBucket',
'dynamodb:BatchGetItem',
'dynamodb:BatchWriteItem',
'dynamodb:DeleteItem',
'dynamodb:DescribeTable',
'dynamodb:GetItem',
'dynamodb:GetRecords',
'dynamodb:PutItem',
'dynamodb:Query',
'dynamodb:Scan',
]
}));
}
}

/**
* 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') {
constructClientUiResources(targetResourceType = 'bucket') {
if (targetResourceType !== 'bucket' && targetResourceType !== 'cloudfront')
throw new Error('Your UI distribution type must be "bucket" or "cloudfront"');

Expand All @@ -146,7 +118,7 @@ export class CheetSheetInfrastructureStack extends cdk.Stack {
behaviors: [
{
isDefaultBehavior: true,
allowedMethods: cloudfront.CloudFrontAllowedMethods.ALL,
allowedMethods: cloudfront.CloudFrontAllowedMethods.GET_HEAD_OPTIONS,
defaultTtl: cdk.Duration.seconds(60)
},
]
Expand Down Expand Up @@ -176,4 +148,87 @@ export class CheetSheetInfrastructureStack extends cdk.Stack {
});
}

/**
* This method constructs all resources needed to setup our authentication
* management in Cognito
*/
constructCognitoResources() {
// Restrictions placed on password
const policies: cognito.CfnUserPool.PoliciesProperty = {
passwordPolicy: {
minimumLength: 8,
requireNumbers: false,
requireSymbols: false,
requireUppercase: false,
requireLowercase: false,
}
};

// List of Valid client facing urls for cognito
const logoutUrLs = [
`https://${this.siteHostname}`,
`https://${this.siteHostname}/login`,
`https://${this.siteHostname}/logout`,
`https://${this.siteHostname}/login/callback`,
`http://${this.siteHostname}`,
`http://${this.siteHostname}/login`,
`http://${this.siteHostname}/logout`,
`http://${this.siteHostname}/login/callback`,
]
const callbackUrLs = [
`https://${this.siteHostname}`,
`https://${this.siteHostname}/login`,
`https://${this.siteHostname}/logout`,
`https://${this.siteHostname}/login/callback`,
`http://${this.siteHostname}`,
`http://${this.siteHostname}/login`,
`http://${this.siteHostname}/logout`,
`http://${this.siteHostname}/login/callback`,
]

// Construct the actual user pool, its groups and its clients
const userPool = new cognito.CfnUserPool(this, 'CognitoAppUserPool', {
aliasAttributes: [cognito.UserPoolAttribute.EMAIL],
autoVerifiedAttributes: [cognito.UserPoolAttribute.EMAIL],
policies: policies,
userPoolName: this.siteHostname,
});
new cognito.CfnUserPoolGroup(this, "CognitoAdminsGroup", {
groupName: 'admin',
userPoolId: userPool.ref

});
const userPoolClient = new cognito.CfnUserPoolClient(this, 'CognitoAppUserPoolClient', {
userPoolId: userPool.attrArn,
explicitAuthFlows: [ cognito.AuthFlow.USER_PASSWORD ],
logoutUrLs: logoutUrLs,
callbackUrLs: callbackUrLs,
allowedOAuthFlows: [ 'implicit', 'code'],
allowedOAuthScopes: [ "email", "openid", "aws.cognito.signin.user.admin", "profile"],
refreshTokenValidity: 30,
supportedIdentityProviders: [ userPool.attrProviderName ]
});
const userPoolDomain = new cognito.CfnUserPoolDomain(this, 'CognitoAppUserPoolDomain', {
userPoolId: userPool.ref,
domain: 'cheet-sheet-dev'
});
}

/**
* This method constructs all resources needed for saving app data, like
* S3 buckets and dynamo DB tables.
*
* @return: list of resource ARNs
*/
constructDataStorageResources() {
// Set up our private bucket that will be used to save and track deployment Artifacts for our API
const appDataBucket = new s3.Bucket(this, 'S3AppDataStorageBucket', {
removalPolicy: cdk.RemovalPolicy.DESTROY,
accessControl: s3.BucketAccessControl.PRIVATE,
bucketName: `${this.siteDomainName}-sheetdata`
});
return [
appDataBucket.bucketArn
];
}
}
1 change: 1 addition & 0 deletions .aws-infrastructure/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"@aws-cdk/aws-cloudfront": "^1.18.0",
"@aws-cdk/aws-cognito": "^1.18.0",
"@aws-cdk/aws-iam": "^1.18.0",
"@aws-cdk/aws-logs": "^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",
Expand Down
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,20 @@ DO NOT TRY REPLICATING SERVICES
- Good for personal project, or small prototypes

- https://aws.amazon.com/premiumsupport/knowledge-center/decode-verify-cognito-json-token/
https://github.com/jpadilla/pyjwt/issues/359
- https://github.com/jpadilla/pyjwt/issues/359


docker-compose -f docker-compose.deploy.code.yml down -v && docker-compose -f docker-compose.deploy.code.yml up --build -d
docker-compose -f docker-compose.deploy.infrastructure.yml down -v && docker-compose -f docker-compose.deploy.infrastructure.yml up --build -d


<!-- -->

# Infrastructure Costs
AWS Certificate Manager - Free
AWS Route 53- Per Use
AWS Route 53 - Per Transaction, and Annual fee for Domains
AWS S3 - Per Transaction and Storage
AWS Lambda - Per Use
API Gateway - Per Use
AWS Lambda - Per Transaction
API Gateway - Per Transaction
AWS Cognito - Per User

https://github.com/aws-samples/aws-cdk-examples/tree/master/typescript/
2 changes: 1 addition & 1 deletion docker-compose.deploy.infrastructure.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ services:
infrastructure.env
command: tail -F anything
volumes:
- ./package.json:/usr/src/.aws-infrastructure/package.json
- ./.aws-infrastructure/package.json:/usr/src/.aws-infrastructure/package.json
- ./.aws-infrastructure:/usr/src/app/
- /usr/src/app/node_modules

Expand Down

0 comments on commit 42266aa

Please sign in to comment.