###############################################################################
### AWS Cloudformation Template
### InfluxData Documentation Website Hosting and Deployment
###############################################################################
AWSTemplateFormatVersion: 2010-09-09
Description: >
  Cloudformation template to stand up the AWS resources for hosting the
  InfluxData documentation static website created using Hugo. Cloudfront
  distribution is used to cache requests to an S3 bucket configured as a static
  website. A Lambda@Edge function rewrites requests with paths ending in
  index.html and requests to old v1 docs endpoints, which reside in a second
  bucket. Finally, a lambda is used to generate new versions of the docs using
  the GitHub source based on event and webhook triggers.

###############################################################################
Parameters:
###############################################################################

  AcmCertificateArn:
    Type: String
    Description: >
      The ARN of the SSL certificate to use for the CloudFront
      distribution.

  DomainName:
    Type: String
    Description: The docs website domain name.
    Default: docs.influxdata.com

###############################################################################
Outputs:
###############################################################################

  DocsProdBucketArn:
    Description: The ARN of the S3 bucket hosting the static content.
    Value: !GetAtt DocsBucket.Arn

  DocsCircleCIDeployAccessKeyId:
    Description: The access key ID for CircleCI deployment to S3.
    Value: !Ref DocsCircleCIDeployAccessKey

  DocsCircleCIDeploySecretAccessKey:
    Description: The secret access key for CircleCI deployment to S3.
    Value: !GetAtt DocsCircleCIDeployAccessKey.SecretAccessKey

###############################################################################
Resources:
###############################################################################

  DocsCloudFrontDistribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        Aliases:
          - !Ref DomainName
        DefaultCacheBehavior:
          TargetOriginId: !Ref DocsBucket
          ViewerProtocolPolicy: redirect-to-https
          DefaultTTL: 2592000
          Compress: true
          ForwardedValues:
            QueryString: false
          LambdaFunctionAssociations:
            - EventType: origin-request
              LambdaFunctionARN: !Ref DocsOriginRequestRewriteLambdaVersion
        DefaultRootObject: '/'
        CustomErrorResponses:
          - ErrorCachingMinTTL: 300
            ErrorCode: 403
            ResponseCode: 404
            ResponsePagePath: /404.html
        Enabled: true
        HttpVersion: http2
        Origins:
          - Id: !Ref DocsBucket
            DomainName: !Join [ "", [ !Ref DocsBucket, ".s3.amazonaws.com" ] ]
            S3OriginConfig:
              OriginAccessIdentity:
                !Sub "origin-access-identity/cloudfront/${DocsCloudFrontOriginAccessIdentity}"
        PriceClass: PriceClass_100
        ViewerCertificate:
          AcmCertificateArn: !Ref AcmCertificateArn
          MinimumProtocolVersion: TLSv1.1_2016
          SslSupportMethod: sni-only
      Tags:
        - Key: Domain
          Value: !Ref DomainName

  DocsCloudFrontOriginAccessIdentity:
    Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
    Properties:
      CloudFrontOriginAccessIdentityConfig:
        Comment: !Sub 'CloudFront Origin Access Identity for ${DomainName}'

  DocsBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          -
            ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      Tags:
        - Key: Domain
          Value: !Ref DomainName

  DocsBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref DocsBucket
      PolicyDocument:
        Statement:
          -
            Effect: Allow
            Action:
              - s3:GetObject
            Resource: !Sub "arn:aws:s3:::${DocsBucket}/*"
            Principal:
              CanonicalUser: !GetAtt DocsCloudFrontOriginAccessIdentity.S3CanonicalUserId

  DocsOriginRequestRewriteLambda:
    Type: AWS::Lambda::Function
    Properties:
      Description: Lambda function performing request URI rewriting.
      Code:
        ZipFile: |
          'use strict';

          // This is a a placeholder lambda function. Use the AWS Lambda console
          // to add/update the contents of deploy/edge.js to the actual Lambda
          // function and deploy it to Lambda@Edge

          const { request } = event.Records[0].cf;

          exports.handler = (event, context, callback) => {
            callback(null, request);
          };

      Handler: index.handler
      MemorySize: 128
      Role: !Sub ${DocsOriginRequestRewriteLambdaRole.Arn}
      Runtime: nodejs12.x
      Tags:
        - Key: Domain
          Value: !Ref DomainName

  DocsOriginRequestRewriteLambdaVersion:
    Type: AWS::Lambda::Version
    Properties:
      FunctionName: !Ref DocsOriginRequestRewriteLambda
      Description: !Sub "URL rewriting for ${DomainName}"

  DocsOriginRequestRewriteLambdaRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action: sts:AssumeRole
            Principal:
              Service:
                - edgelambda.amazonaws.com
                - lambda.amazonaws.com
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

  DocsCircleCIDeployUser:
    Type: AWS::IAM::User
    Properties:
      Policies:
        - PolicyName: giveaccesstoupdatedocsbuckets
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - s3:ListBucket
                  - s3:GetBucketLocation
                Resource:
                  - !Sub "arn:aws:s3:::${DocsBucket}"
              - Effect: Allow
                Action:
                  - s3:PutObject
                  - s3:PutObjectAcl
                  - s3:DeleteObject
                Resource:
                  - !Sub "arn:aws:s3:::${DocsBucket}/*"
              - Effect: Allow
                Action:
                  - cloudfront:GetDistribution
                  - cloudfront:CreateInvalidation
                Resource: "*"

  DocsCircleCIDeployAccessKey:
    Type: AWS::IAM::AccessKey
    Properties:
      UserName: !Ref DocsCircleCIDeployUser