AWSTemplateFormatVersion: "2010-09-09"
Description: "Handle HTTP Security Header at Edge injection for CloudFront"
Parameters:
  LambdaRuntime:
    Type: String
    Default: nodejs12.x
Resources:
  LambdaExecutePolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      Description: "Lambda@Edge ExecutePolicy"
      Path: "/"
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          -
            Effect: "Allow"         
            Action: "logs:CreateLogGroup"
            Resource: !Join
              - ""
              - - "arn:aws:logs:*:"
                - !Ref "AWS::AccountId"
                - ":*"
          -
            Effect: "Allow"
            Action: 
              - "logs:CreateLogStream"
              - "logs:PutLogEvents"
            Resource: !Join
              - ""
              - - "arn:aws:logs:*:"
                - !Ref "AWS::AccountId"
                - ":log-group:/aws/lambda/"
                - !Ref "AWS::StackName"
                - "-SecurityHeaders"
                - ":*"
  LambdaRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
        - Effect: "Allow"
          Principal: 
            Service:
            - edgelambda.amazonaws.com
            - lambda.amazonaws.com
          Action: "sts:AssumeRole"
      Path: "/"
      ManagedPolicyArns:
          - !Ref LambdaExecutePolicy
  LambdaCode:
    Type: AWS::Lambda::Function
    Properties: 
      Code:
        ZipFile: |
          'use strict';
          exports.handler = (event, context, callback) => {
            function add(h, k, v) {
                h[k.toLowerCase()] = [ { key: k, value: v } ];
            }
            const request = event.Records[0].cf.request;
            const response = event.Records[0].cf.response;
            const headers = response.headers;
            add(headers, 'Strict-Transport-Security', "max-age=31536000");
            //add(headers, 'Strict-Transport-Security', "max-age=31536000; includeSubdomains; preload");
            add(headers, 'Content-Security-Policy', "default-src 'none'; img-src 'self'; script-src 'self'; style-src 'self' ; object-src 'none'; frame-src 'none' ; connect-src 'none' ; frame-ancestors 'none'; font-src 'self' ; manifest-src: 'self'; base-uri 'self'; form-action 'self' ");
            add(headers, 'X-Content-Type-Options', "nosniff") ;
            add(headers, 'X-Frame-Options', "DENY") ;
            add(headers, 'X-XSS-Protection', "1; mode=block") ;
            add(headers, 'Referrer-Policy', "same-origin") ;
            add(headers, 'Expect-CT', "max-age=31536000, enforce");
            add(headers, 'Permissions-Policy', "geolocation=(), midi=(), notifications=(), push=(), sync-xhr=(self), microphone=(), camera=(), magnetometer=(), gyroscope=(), speaker=(), vibrate=(), fullscreen=(), payment=()");
            add(headers, 'Cache-Control', 'public, max-age=3600');
            callback(null, response);
          };
      Description: Inject HTTP Security Headers into responses from origin
      FunctionName: !Join
        - "-"
        - - !Ref AWS::StackName
          - "SecurityHeaders"
      Handler: index.handler
      MemorySize: 128
      Role: !GetAtt LambdaRole.Arn
      Runtime: !Ref LambdaRuntime
      Timeout: 1
  LambdaCodeVersionPublish: 
    Type: AWS::Lambda::Version
    Properties: 
      FunctionName: !Ref LambdaCode
      Description: "A version of Security Header injection for CloudFront"
      
Outputs:
  FunctionARN:
    Description: ARN of the Function
    Value: !Ref LambdaCodeVersionPublish