VPC Lambda からプロキシ(Squid)を経由してインターネットへ接続する

記事タイトルとURLをコピーする

こんにちは、やまぐちです。

概要

VPC Lambda から NLB → Proxy (Squid) 経由でインターネットへアクセスするまでを書きます。

構成図は以下のような形です。

やってみる

1. リソース作成

まずは、以下のテンプレートを CloudFormation に流してリソースを作成します。

yaml テンプレート

AWSTemplateFormatVersion: "2010-09-09"
Description: "create EC2Instance and NLB"
Parameters:
  KeyName:
    Type: AWS::EC2::KeyPair::KeyName
    Description: "Key Pair Name"
  InstanceType:
    Type: String
    Description: "EC2 Instance Type"
    Default: "t3.micro"
  ImageId:
    Type: AWS::EC2::Image::Id
    Description: "EC2 Image ID"
    Default: "ami-05a03e6058638183d"

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: "EC2 Instance Configuration"
        Parameters:
          - KeyName
          - InstanceType
          - ImageId
    ParameterLabels:
      KeyName:
        default: "Key Pair Name"
      InstanceType:
        default: "EC2 Instance Type"
      ImageId:
        default: "EC2 Image ID"

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: squid-test-vpc

  PublicSubnet1a:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.1.0/24
      AvailabilityZone: ap-northeast-1a
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: squid-test-public-subnet-a

  PublicSubnet1c:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.2.0/24
      AvailabilityZone: ap-northeast-1c
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: squid-test-public-subnet-c

  PrivateSubnet1a:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.3.0/24
      AvailabilityZone: ap-northeast-1a
      Tags:
        - Key: Name
          Value: squid-test-private-subnet-a

  PrivateSubnet1c:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.4.0/24
      AvailabilityZone: ap-northeast-1c
      Tags:
        - Key: Name
          Value: squid-test-private-subnet-c

  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: squid-test-igw

  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: squid-test-public-route-table

  PublicRoute:
    Type: AWS::EC2::Route
    DependsOn: AttachGateway
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway

  PrivateRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: squid-test-private-route-table

  AttachPrivateRouteTable1a:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet1a
      RouteTableId: !Ref PrivateRouteTable

  AttachPrivateRouteTable1c:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet1c
      RouteTableId: !Ref PrivateRouteTable

  AttachPublicRouteTable1a:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet1a
      RouteTableId: !Ref PublicRouteTable

  AttachPublicRouteTable1c:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet1c
      RouteTableId: !Ref PublicRouteTable

  LambdaSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security Group with Inbound Rule for Port 3128
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: squid-test-lambda-sg

  EC2InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security Group with Inbound Rule for Port 3128
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 3128
          ToPort: 3128
          SourceSecurityGroupId: !Ref LambdaSecurityGroup
        - IpProtocol: tcp
          FromPort: 3128
          ToPort: 3128
          CidrIp: 10.0.3.0/24
        - IpProtocol: tcp
          FromPort: 3128
          ToPort: 3128
          CidrIp: 10.0.4.0/24
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: squid-test-sg


  VPCLambda:
    Type: AWS::Lambda::Function
    Properties:
      Handler: index.lambda_handler
      Role: !GetAtt LambdaExecutionRole.Arn
      FunctionName: squid-test-vpc-lambda
      Runtime: python3.12
      VpcConfig:
        SubnetIds:
          - !Ref PrivateSubnet1a
          - !Ref PrivateSubnet1c
        SecurityGroupIds:
          - !Ref LambdaSecurityGroup
      Code:
        ZipFile: |
          import urllib.request
          import os

          def lambda_handler(event, context):
              
              url = 'https://www.google.com/'
              
              with urllib.request.urlopen(url) as response:
                  print(response.getcode())

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

  EC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      KeyName: !Ref KeyName
      ImageId: !Ref ImageId
      InstanceType: t3.micro
      NetworkInterfaces:
        - AssociatePublicIpAddress: true
          DeviceIndex: 0
          GroupSet:
            - !Ref EC2InstanceSecurityGroup
          SubnetId: !Ref PublicSubnet1a
      UserData: !Base64 |
        #!/bin/bash -ex
          dnf install squid -y
          systemctl start squid
          systemctl enable squid
          sed -i "/network by proxying external TCP connections to unprotected services./a http_access allow localnet" /etc/squid/squid.conf
          systemctl restart squid
      Tags:
        - Key: Name
          Value: squid-test

  NLBTargets3128:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      HealthCheckTimeoutSeconds: 10
      Name: tg-squid-test-nlb-3128
      Port: 3128
      Protocol: TCP
      HealthyThresholdCount: 3
      UnhealthyThresholdCount: 3
      Tags: 
        - Key: Name
          Value: tg-squid-test-nlb-3128
      Targets: 
        - Id: !Ref EC2Instance
          Port: 3128
      TargetType: instance
      VpcId: !Ref VPC

  NLB:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties: 
      Name: squid-test-nlb
      Tags: 
        - Key: Name
          Value: squid-test-nlb
      Scheme: internal
      LoadBalancerAttributes: 
        - Key: deletion_protection.enabled
          Value: false
        - Key: load_balancing.cross_zone.enabled
          Value: true
      Subnets: 
        - !Ref PrivateSubnet1a
        - !Ref PrivateSubnet1c
      Type: network

  NLBListener3128: 
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties: 
      DefaultActions: 
        - TargetGroupArn: !Ref NLBTargets3128
          Type: forward
      LoadBalancerArn: !Ref NLB
      Port: 3128
      Protocol: TCP

スタックを作成すると構成図のリソースが作成されます。

EC2 インスタンスの OS は Amazon Linux 2023 にしました。
Squid の詳しい設定については、本ブログでは割愛します。

設定した内容は以下のブログで記載したものと同じで、今回はユーザデータですべての処理を完了させています。 blog.serverworks.co.jp

blog.serverworks.co.jp

2. Lambda の実行

では、さっそくテンプレートから作成した VPC Lambda をテスト実行してみます。
上手くいけば、レスポンスコード「200」が返ってくるはずです。

タイムアウトしてしまいました、
VPC からインターネットへアクセスができない状態となっているのがわかるかと思います。

環境変数の設定

ということで、VPC Lambda が プロキシ経由でインターネットへアクセスできるように環境変数を設定します。
「設定」-「環境変数」-「編集」を選択します。

以下のようにhttp_proxyhttps_proxyをキーとする環境変数を追加します。

キー
http_proxy http:// NLB の DNS 名:3128
https_proxy http:// NLB の DNS 名:3128


NLB の DNS 名はマネジメントコンソールからコピー可能です。

再度 Lambda を実行

ということで、環境変数を設定した状態でもう一度、Lambda を実行します。

「200」が返ってきました!

まとめ

VPC Lambda からプロキシ経由でインターネットへ接続したい場合は、環境変数に設定をしてあげると良い
というだけでした~

それではまたどこかで~

やまぐち まさる (記事一覧)

CS部・CS2課

AWS の構築・運用をやってます

3度の飯より野球が好き

2023 Japan AWS All Certifications Engineers