LoginSignup
0
0

More than 1 year has passed since last update.

CloudFront DistributionからALB-Lambdaを呼び出す構築ハンズオン

Posted at

はじめに

先日CloudFrontからAPIGateway経由でLambdaへの構築を行なったので、そしたらセットでALB経由でLambdaこ構築に関してもCFn化しておこうと思い立ち、さっそくハンズオンしていきます。

構成図


ハンズオン

構築の流れ

1.VPC作成

2.Lambda作成

3.ALB作成

4.CloudFront作成

上記の順番で構築を行なっていきます。
最終的には、CloudFrontのディストリビューションドメインから、ALB経由でLambdaのメッセージ部分をダウンロードできるまでを行なっていきます。

1.VPC作成

以前記載したブログCloudFormationを使ってVPC構築に沿って、VPCを構築します。

2.Lambda作成

特別な設定はせずstatusCode200を返す、Lambdaを構築します。
ALB経由でアクセスした際にダウンロードされる、body部分のメッセージを一部修正しています。
AWSTemplateFormatVersion: '2010-09-09'
Description:
  Lambda Create
# ------------------------------------------------------------#
#  Metadata
# ------------------------------------------------------------#
Metadata:
  "AWS::CloudFormation::Interface":
    ParameterGroups:
      - Label:
          default: "Lambda Configuration"
        Parameters:
        - FunctionName
        - Description
        - Handler
        - MemorySize
        - Runtime
        - Timeout

# ------------------------------------------------------------#
#  InputParameters
# ------------------------------------------------------------#
Parameters:
  FunctionName:
    Type: String
    Default: "cfn-lmd-inamura"
  Description:
    Type: String
    Default: "cfn-lmd-inamura"
  Handler:
    Type: String
    Default: "index.lambda_handler"
  MemorySize:
    Type: String
    Default: "128"
  Runtime:
    Type: String
    Default: "python3.9"
  Timeout:
    Type: String
    Default: "10"

# ------------------------------------------------------------#
#  Resources
# ------------------------------------------------------------#
Resources:
# ------------------------------------------------------------#
#  Lambda
# ------------------------------------------------------------#
  Lambda:
    Type: 'AWS::Lambda::Function'
    Properties:
      Code:
        ZipFile: |
          import json

          def lambda_handler(event, context):
              # TODO implement
              print(event)
              return {
                  'statusCode': 200,
                  'body': json.dumps('Hello CloudFront-ALB!')
              }

      Description: !Ref Description
      FunctionName: !Ref FunctionName
      Handler: !Ref Handler 
      MemorySize: !Ref MemorySize
      Runtime: !Ref Runtime
      Timeout: !Ref Timeout
      Role: !GetAtt LambdaRole.Arn

  LambdaRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub "${FunctionName}-role"
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Action: "sts:AssumeRole"
            Principal:
              Service: lambda.amazonaws.com
      Policies:
        - PolicyName: !Sub "${FunctionName}-policy"
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: "Allow"
                Action:
                  - "logs:CreateLogStream"
                  - "logs:PutLogEvents"
                  - "logs:CreateLogGroup"
                Resource: !Sub "arn:${AWS::Partition}:logs:*:*:*"

# ------------------------------------------------------------#
# Output Parameters
#------------------------------------------------------------#          
Outputs:
  LambdaArn:
    Value: !GetAtt Lambda.Arn
    Export:
      Name: !Sub "${FunctionName}-arn"
  LambdaName:
    Value: !Ref FunctionName
    Export:
      Name: !Sub "${FunctionName}-name"

3.ALB作成

##### 3.1.この後作成するCloudFrontのCustom-Headerを利用して、CloudFront経由でアクセスしたユーザにはLambdaへのアクセスを許可して、直接ALBへアクセスしたユーザには【ERROR】ページを表示するようにします。

AWSTemplateFormatVersion: "2010-09-09"
Description: 
  ALB Create
# ------------------------------------------------------------#
#  Metadata
# ------------------------------------------------------------#
Metadata:
  "AWS::CloudFormation::Interface":
    ParameterGroups:
      - Label:
          default: "ALB Configuration"
        Parameters:
        - ALBName
        - Type
        - Scheme
        - IpAddressType
      - label:
          default: "ALB TargetGroup"
        Parameters:
        - TGName1
        - TargetType
      - label:
          default: "ALB SecurityGroup"
        Parameters:
        - GroupName
# ------------------------------------------------------------#
#  InputParameters
# ------------------------------------------------------------#
Parameters:
  ALBName:
    Type: String
    Default: "cfn-alb-inamura"
  Type:
    Type: String
    Default: "application"
  Scheme:
    Type: String
    Default: "internet-facing"
  IpAddressType:
    Type: String
    Default: "ipv4"
  TGName1:
    Type: String
    Default: "cfn-tgg1-inamura"
  TargetType:
    Type: String
    Default: "lambda"
  GroupName:
    Type: String
    Default: "cfn-sg-alb-inamura"

# ------------------------------------------------------------#
#  Resources
# ------------------------------------------------------------#
Resources:
# ------------------------------------------------------------#
#  ALB
# ------------------------------------------------------------#
  ALB:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Name: !Ref ALBName
      Type: !Ref Type
      Scheme: !Ref Scheme
      IpAddressType: !Ref IpAddressType
      Subnets: 
        - !ImportValue cfn-inamura-public-subneta
        - !ImportValue cfn-inamura-public-subnetc
      SecurityGroups: 
        - !Ref ALBSecurityGroup

  ListenerHTTP:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref TargetGroup1
      LoadBalancerArn: !Ref ALB
      Port: 80
      Protocol: HTTP

  ListenerRule1:
    Type: AWS::ElasticLoadBalancingV2::ListenerRule
    Properties:
      Actions:
        - Type: forward
          TargetGroupArn: !Ref TargetGroup1
      Conditions:
        - Field: path-pattern
          Values: 
            - '*'
        - Field: http-header
          HttpHeaderConfig:
            HttpHeaderName: Custom-Header
            Values: 
              - inamura
      ListenerArn: !Ref ListenerHTTP
      Priority: 1

  ListenerRule2:
    Type: AWS::ElasticLoadBalancingV2::ListenerRule
    Properties:
      Actions:
        - Type: "fixed-response"
          FixedResponseConfig:
            ContentType: 'text/html'
            MessageBody: |
              <!DOCTYPE html>
              <html lang="ja">
              <head>
              <meta charset="UTF-8">
              <title>【ERROR】</title>
              </head>
              <body>
                <h1>CloudFront経由でアクセスください</h1>
              </body>
              </html>
            StatusCode: 503
      Conditions:
        - Field: path-pattern
          Values: 
            - '*'
      ListenerArn: !Ref ListenerHTTP
      Priority: 2

  TargetGroup1:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    DependsOn: LambdaInvokePermission
    Properties:
      Name: !Ref TGName1
      TargetType: !Ref TargetType
      Targets:
        - Id: !ImportValue cfn-lmd-inamura-arn

# ------------------------------------------------------------#
#  ALB SG
# ------------------------------------------------------------#
  ALBSecurityGroup:
    Type: "AWS::EC2::SecurityGroup"
    Properties:
        GroupDescription: "ALB SG"
        GroupName: !Ref GroupName
        VpcId: !ImportValue cfn-inamura-vpc
        SecurityGroupIngress:
          - IpProtocol: tcp
            FromPort: 80
            ToPort: 80
            CidrIp: 0.0.0.0/0

# ------------------------------------------------------------#
#  リソースベースポリシー
# ------------------------------------------------------------#
  LambdaInvokePermission:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !ImportValue cfn-lmd-inamura-arn
      Action: lambda:InvokeFunction
      Principal: elasticloadbalancing.amazonaws.com

# ------------------------------------------------------------#
# Output Parameters
# ------------------------------------------------------------#    
Outputs:
  ALBURL:
    Description: ALB endpoint URL
    Value: !Join
        - ""
        - - http://
          - !GetAtt ALB.DNSName
  ALBDomain:
    Description: ALB Domain
    Value:  !GetAtt ALB.DNSName
    Export:
      Name: cfn-alb-dns
  HostedZoneID:
    Description: The ID of the Amazon Route 53 hosted zone associated with the load balancer.
    Value:  !GetAtt ALB.CanonicalHostedZoneID
    Export:
      Name: cfn-alb-id

3.2.CFnのタブ『出力』から、下記赤枠部分の『ALBURL』を押下する

3.3.下記画面に遷移する
Custom-Headerが付与されていないアクセスのためALBで【ERROR】ページに遷移されてしまう

4.CloudFront作成

3.で構築したALBをオリジンとして、Custom-Headerを設定しています。

AWSTemplateFormatVersion: '2010-09-09'
Description:
  CloudFront Create
# ------------------------------------------------------------#
#  Resources
# ------------------------------------------------------------#
Resources:
# ------------------------------------------------------------#
#  CloudFront
# ------------------------------------------------------------#
  Distribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        Comment: "Create CloudFront with CloudFormation"
        PriceClass: PrinceClass_All
        DefaultCacheBehavior:
          AllowedMethods:
            - GET
            - HEAD
          CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6
          Compress: true
          TargetOriginId: !ImportValue cfn-alb-id
          ViewerProtocolPolicy: allow-all
        Enabled: true
        HttpVersion: http2and3
        Origins:
          - CustomOriginConfig:
              HTTPSPort: '80'
              OriginProtocolPolicy: http-only
            DomainName: !ImportValue cfn-alb-dns
            Id: !ImportValue cfn-alb-id
            OriginCustomHeaders: 
            - HeaderName: Custom-Header
              HeaderValue: inamura
        PriceClass: PriceClass_All
# ------------------------------------------------------------#
# Output Parameters
#------------------------------------------------------------#          
Outputs:
  DomainName:
    Value: !GetAtt Distribution.DomainName
    Export:
      Name: cfn-clf-dns

挙動の確認

①構築されたCloudFrontからドメイン名を確認する

オリジンにはALBのDNSが設定されていることも確認できる

②ブラウザにドメインを入力するとダウンロードが開始される

③ダウンロードされた資材を確認して、Lambdaのbody部分のメッセージを確認することができる


さいごに

CloudFrontからALB間を、今回はCustom-Headerで設定しましたが、今時で言ったらSGにCloudFrontのマネージドプレフィックスを設定などの方法が良かったかもしれません。
さっそく次の作るものが見つかりましたが、残り少ない今年に捉われることもなく、時間を見つけては検証して、自分の作れるものを増やしていきたいと思います!
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0