Description: "AWS Workshop - Cloud One Application Security with Lambda." Resources: applicationsecuritywebapp63AC9131: Type: AWS::ApiGateway::RestApi Properties: Description: Our very first serverless app! Name: Application Secuirty - Serverless Web App Tags: - Key: Name Value: ApplicationSecurityVulnerableWebApp applicationsecuritywebappCloudWatchRole5BF6FEF3: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Action: sts:AssumeRole Effect: Allow Principal: Service: apigateway.amazonaws.com Version: "2012-10-17" ManagedPolicyArns: - Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - :iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs Tags: - Key: Name Value: ApplicationSecurityVulnerableWebApp applicationsecuritywebappAccount60E83E28: Type: AWS::ApiGateway::Account Properties: CloudWatchRoleArn: Fn::GetAtt: - applicationsecuritywebappCloudWatchRole5BF6FEF3 - Arn DependsOn: - applicationsecuritywebapp63AC9131 applicationsecuritywebappDeploymentA6C2500D3e772887de3b3d90a7d5cfec3698233d: Type: AWS::ApiGateway::Deployment Properties: RestApiId: Ref: applicationsecuritywebapp63AC9131 Description: Automatically created by the RestApi construct DependsOn: - applicationsecuritywebappbackendGET6ED6D804 - applicationsecuritywebappbackendE38F6F09 - applicationsecuritywebappGET4BCBF288 applicationsecuritywebappDeploymentStageprod686052F7: Type: AWS::ApiGateway::Stage Properties: RestApiId: Ref: applicationsecuritywebapp63AC9131 DeploymentId: Ref: applicationsecuritywebappDeploymentA6C2500D3e772887de3b3d90a7d5cfec3698233d StageName: prod Tags: - Key: Name Value: ApplicationSecurityVulnerableWebApp applicationsecuritywebappGETApiPermissionServerlessAppStackapplicationsecuritywebapp05738232GET1A7309EC: Type: AWS::Lambda::Permission Properties: Action: lambda:InvokeFunction FunctionName: Fn::GetAtt: - ApplicationSecurityFrontendPage0CFDB182 - Arn Principal: apigateway.amazonaws.com SourceArn: Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":execute-api:" - Ref: AWS::Region - ":" - Ref: AWS::AccountId - ":" - Ref: applicationsecuritywebapp63AC9131 - / - Ref: applicationsecuritywebappDeploymentStageprod686052F7 - /GET/ applicationsecuritywebappGETApiPermissionTestServerlessAppStackapplicationsecuritywebapp05738232GET3467C1F8: Type: AWS::Lambda::Permission Properties: Action: lambda:InvokeFunction FunctionName: Fn::GetAtt: - ApplicationSecurityFrontendPage0CFDB182 - Arn Principal: apigateway.amazonaws.com SourceArn: Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":execute-api:" - Ref: AWS::Region - ":" - Ref: AWS::AccountId - ":" - Ref: applicationsecuritywebapp63AC9131 - /test-invoke-stage/GET/ applicationsecuritywebappGET4BCBF288: Type: AWS::ApiGateway::Method Properties: HttpMethod: GET ResourceId: Fn::GetAtt: - applicationsecuritywebapp63AC9131 - RootResourceId RestApiId: Ref: applicationsecuritywebapp63AC9131 AuthorizationType: NONE Integration: IntegrationHttpMethod: POST RequestTemplates: text/html: '{ "statusCode": "200" }' Type: AWS_PROXY Uri: Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":apigateway:" - Ref: AWS::Region - :lambda:path/2015-03-31/functions/ - Fn::GetAtt: - ApplicationSecurityFrontendPage0CFDB182 - Arn - /invocations applicationsecuritywebappbackendE38F6F09: Type: AWS::ApiGateway::Resource Properties: ParentId: Fn::GetAtt: - applicationsecuritywebapp63AC9131 - RootResourceId PathPart: backend RestApiId: Ref: applicationsecuritywebapp63AC9131 applicationsecuritywebappbackendGETApiPermissionServerlessAppStackapplicationsecuritywebapp05738232GETbackend0E9D3252: Type: AWS::Lambda::Permission Properties: Action: lambda:InvokeFunction FunctionName: Fn::GetAtt: - ApplicationSecurityBackendPage7A3846DF - Arn Principal: apigateway.amazonaws.com SourceArn: Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":execute-api:" - Ref: AWS::Region - ":" - Ref: AWS::AccountId - ":" - Ref: applicationsecuritywebapp63AC9131 - / - Ref: applicationsecuritywebappDeploymentStageprod686052F7 - /GET/backend applicationsecuritywebappbackendGETApiPermissionTestServerlessAppStackapplicationsecuritywebapp05738232GETbackendD6BFF261: Type: AWS::Lambda::Permission Properties: Action: lambda:InvokeFunction FunctionName: Fn::GetAtt: - ApplicationSecurityBackendPage7A3846DF - Arn Principal: apigateway.amazonaws.com SourceArn: Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":execute-api:" - Ref: AWS::Region - ":" - Ref: AWS::AccountId - ":" - Ref: applicationsecuritywebapp63AC9131 - /test-invoke-stage/GET/backend applicationsecuritywebappbackendGET6ED6D804: Type: AWS::ApiGateway::Method Properties: HttpMethod: GET ResourceId: Ref: applicationsecuritywebappbackendE38F6F09 RestApiId: Ref: applicationsecuritywebapp63AC9131 AuthorizationType: NONE Integration: IntegrationHttpMethod: POST RequestTemplates: text/html: '{ "statusCode": "200" }' Type: AWS_PROXY Uri: Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - ":apigateway:" - Ref: AWS::Region - :lambda:path/2015-03-31/functions/ - Fn::GetAtt: - ApplicationSecurityBackendPage7A3846DF - Arn - /invocations ApplicationSecurityFrontendPageServiceRole1980AAB8: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Action: sts:AssumeRole Effect: Allow Principal: Service: lambda.amazonaws.com Version: "2012-10-17" ManagedPolicyArns: - Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - :iam::aws:policy/service-role/AWSLambdaBasicExecutionRole Tags: - Key: Name Value: ApplicationSecurityFrontendPage ApplicationSecurityFrontendPage0CFDB182: Type: AWS::Lambda::Function Properties: Code: ZipFile: |+ import json import urllib3 HTTP = urllib3.PoolManager() INSECURE_HTML = ''' ACME App

Oh no!

Either your app is insecure, or you've missed a step!

''' SECURE_HTML_DAY_ONE = ''' ACME App

Congratulations!

It looks like you've enabled Application Security!

Just to be sure though, check the Application Security dashboard. If you don't see attacks being blocked, you might have missed a step!

''' SECURE_HTML_DAY_TWO = ''' ACME App

Congratulations!

You've removed the bug from your code!

''' def _get_backend_url(event): domain_name = event['requestContext']['domainName'] stage_name = event['requestContext']['stage'] backend_url = f'https://{domain_name}/{stage_name}/backend' return backend_url def main_handler(event, context): backend_url = _get_backend_url(event) resp = HTTP.request('GET', backend_url) print(f'Status: {resp.status}') message = json.loads(resp.data).get('message') print(f'Message: {message}') if resp.status == 502: return { "statusCode": 200, "body": SECURE_HTML_DAY_ONE, "headers": { 'Content-Type': 'text/html', } } elif resp.status == 200 and 'welcome to our secure website' in message.lower(): return { "statusCode": 200, "body": SECURE_HTML_DAY_TWO, "headers": { 'Content-Type': 'text/html', } } else: return { "statusCode": 200, "body": INSECURE_HTML, "headers": { 'Content-Type': 'text/html', } } return resp Role: Fn::GetAtt: - ApplicationSecurityFrontendPageServiceRole1980AAB8 - Arn Description: Application Security Web GUI FunctionName: ApplicationSecurityFrontendPage Handler: index.main_handler Runtime: python3.8 Tags: - Key: Name Value: ApplicationSecurityFrontendPage DependsOn: - ApplicationSecurityFrontendPageServiceRole1980AAB8 ApplicationSecurityBackendPageServiceRole68735343: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Action: sts:AssumeRole Effect: Allow Principal: Service: lambda.amazonaws.com Version: "2012-10-17" ManagedPolicyArns: - Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - :iam::aws:policy/service-role/AWSLambdaBasicExecutionRole Tags: - Key: Name Value: ApplicationSecurityBackendPage ApplicationSecurityBackendPage7A3846DF: Type: AWS::Lambda::Function Properties: Code: ZipFile: |+ import json vars_file_path = '../../proc/self/environ' def main_handler(event, context): message = {"message": "Welcome to our secure website"} f = open(vars_file_path, "r"); f.readline(); f.close(); message = {"message": "Welcome to our website"} return { "statusCode": 200, "body": json.dumps(message), } Role: Fn::GetAtt: - ApplicationSecurityBackendPageServiceRole68735343 - Arn Description: Application Security Vulnerable app - PLEASE SECURE ME! Environment: Variables: TREND_AP_HELLO_URL: !Ref C1RegionEndpoint FunctionName: ApplicationSecurityBackendPage Handler: index.main_handler MemorySize: 512 Runtime: python3.8 Tags: - Key: Name Value: ApplicationSecurityBackendPage Timeout: 10 DependsOn: - ApplicationSecurityBackendPageServiceRole68735343 ApplicationSecurityDayOneVerificationLambdaServiceRoleE4A6FAED: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Action: sts:AssumeRole Effect: Allow Principal: Service: lambda.amazonaws.com Version: "2012-10-17" ManagedPolicyArns: - Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - :iam::aws:policy/service-role/AWSLambdaBasicExecutionRole Tags: - Key: Name Value: ApplicationSecurityDayOneVerificationLambda ApplicationSecurityDayOneVerificationLambda679755A8: Type: AWS::Lambda::Function Properties: Code: ZipFile: |+ import os import json import urllib3 HTTP = urllib3.PoolManager() def main_handler(event, context): web_app_url = os.environ['WEB_APP_URL'] backend_url = f'{web_app_url}/backend/' resp = HTTP.request('GET', backend_url) message = json.loads(resp.data).get('message') if message == 'Internal server error' or 'welcome to our secure website' in message.lower(): return True else: raise Exception("Either your app is insecure, or you've missed a step!") Role: Fn::GetAtt: - ApplicationSecurityDayOneVerificationLambdaServiceRoleE4A6FAED - Arn Description: Application Security Day One verificaiton Environment: Variables: WEB_APP_URL: Fn::Join: - "" - - https:// - Ref: applicationsecuritywebapp63AC9131 - .execute-api. - Ref: AWS::Region - "." - Ref: AWS::URLSuffix - / - Ref: applicationsecuritywebappDeploymentStageprod686052F7 - / FunctionName: ApplicationSecurityDayOneVerificationLambda Handler: index.main_handler Runtime: python3.8 Tags: - Key: Name Value: ApplicationSecurityDayOneVerificationLambda Timeout: 10 DependsOn: - ApplicationSecurityDayOneVerificationLambdaServiceRoleE4A6FAED ApplicationSecurityDayTwoVerificationLambdaServiceRole8B65B915: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Action: sts:AssumeRole Effect: Allow Principal: Service: lambda.amazonaws.com Version: "2012-10-17" ManagedPolicyArns: - Fn::Join: - "" - - "arn:" - Ref: AWS::Partition - :iam::aws:policy/service-role/AWSLambdaBasicExecutionRole Tags: - Key: Name Value: ApplicationSecurityDayTwoVerificationLambda ApplicationSecurityDayTwoVerificationLambda65AE9CE5: Type: AWS::Lambda::Function Properties: Code: ZipFile: |+ import os import json import urllib3 HTTP = urllib3.PoolManager() def main_handler(event, context): web_app_url = os.environ['WEB_APP_URL'] backend_url = f'{web_app_url}/backend/' resp = HTTP.request('GET', backend_url) message = json.loads(resp.data).get('message') if 'welcome to our secure website' in message.lower(): return True else: raise Exception("Either your app is insecure, or you've missed a step!") Role: Fn::GetAtt: - ApplicationSecurityDayTwoVerificationLambdaServiceRole8B65B915 - Arn Description: Application Security Day Two verificaiton Environment: Variables: WEB_APP_URL: Fn::Join: - "" - - https:// - Ref: applicationsecuritywebapp63AC9131 - .execute-api. - Ref: AWS::Region - "." - Ref: AWS::URLSuffix - / - Ref: applicationsecuritywebappDeploymentStageprod686052F7 - / FunctionName: ApplicationSecurityDayTwoVerificationLambda Handler: index.main_handler Runtime: python3.8 Tags: - Key: Name Value: ApplicationSecurityDayTwoVerificationLambda Timeout: 10 DependsOn: - ApplicationSecurityDayTwoVerificationLambdaServiceRole8B65B915 Parameters: C1RegionEndpoint: Type: String Description: Enter your Cloud One Region Endpoint Outputs: applicationsecuritywebappEndpoint1AF7957D: Value: Fn::Join: - "" - - https:// - Ref: applicationsecuritywebapp63AC9131 - .execute-api. - Ref: AWS::Region - "." - Ref: AWS::URLSuffix - / - Ref: applicationsecuritywebappDeploymentStageprod686052F7 - / ApplicationSecurityWebAppUrl: Description: Application Security Web app URL Value: Fn::Join: - "" - - https:// - Ref: applicationsecuritywebapp63AC9131 - .execute-api. - Ref: AWS::Region - "." - Ref: AWS::URLSuffix - / - Ref: applicationsecuritywebappDeploymentStageprod686052F7 - / Export: Name: ApplicationSecurityWebAppUrl ApplicationSecurityBackendLambdaCode: Description: Application Security Backend Lambda code Value: Fn::Join: - "" - - https:// - Ref: AWS::Region - .console.aws.amazon.com/lambda/home?region= - Ref: AWS::Region - "#/functions/ApplicationSecurityBackendPage?tab=code" Export: Name: ApplicationSecurityBackendLambdaCode ApplicationSecurityBackendLambdaFunctionArn: Description: Application Security Backend Lambda function ARN Value: Fn::GetAtt: - ApplicationSecurityBackendPage7A3846DF - Arn Export: Name: ApplicationSecurityBackendLambdaFunctionArn