1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[AWS CloudFormation] VPC Lambda & EFS定義

Last updated at Posted at 2022-08-13

目的

LambdaからEFS(Amazon Elastic File System)を使用するためのCloudFormationテンプレートを作成する
VPC内にLambdaを配置する必要があるため、以下の定義を行う

  • VPC関連リソース
  • EFS関連リソース
  • Lambda(SQSトリガ)
  • VPC LambdaからAWSリソースへアクセスするためのVPCエンドポイント

テンプレート

template.yaml
  vpcSample:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true
      InstanceTenancy: default
      Tags: 
        - Key: Name   # タグで名前を設定する
          Value: !Sub ${EnvName}-vpcSample

  subnetSample1:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone:
        Fn::Select:
          - 0  # 使用可能なAZリストのindex0を使用
          - !GetAZs   # 使用可能なAZリスト取得
            Ref: AWS::Region
      CidrBlock: 10.0.0.0/24
      VpcId: !Ref vpcSample
      Tags: 
        - Key: Name   # タグで名前を設定する
          Value: !Sub ${EnvName}-subnetSample1

  subnetSample2:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone:
        Fn::Select:
          - 1
          - !GetAZs 
            Ref: AWS::Region
      CidrBlock: 10.0.1.0/24
      VpcId: !Ref vpcSample
      Tags: 
        - Key: Name
          Value: !Sub ${EnvName}-subnetSample2

  # VPC作成時に自動作成されるメインルートテーブルは、
  # cfnから参照できないためルートテーブルを作成
  routeTableSample:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref vpcSample

  # ルートテーブルとサブネットの関連付け
  subnetRouteTableSample1:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref routeTableSample
      SubnetId: !Ref subnetSample1

  subnetRouteTableSample2:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref routeTableSample
      SubnetId: !Ref subnetSample2

  # VPC LambdaからS3にアクセスするためのVPCエンドポイント
  vpcEndpointS3Sample:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      VpcId: !Ref vpcSample
      VpcEndpointType: Gateway
      ServiceName: !Sub com.amazonaws.${AWS::Region}.s3
      RouteTableIds:
        - !Ref routeTableSample

  # VPC LambdaからDynamoDBにアクセスするためのVPCエンドポイント
  vpcEndpointDynamodbSample:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      VpcId: !Ref vpcSample
      VpcEndpointType: Gateway
      ServiceName: !Sub com.amazonaws.${AWS::Region}.dynamodb
      RouteTableIds:
        - !Ref routeTableSample

  # VPC LambdaからSQSにアクセスするためのVPCエンドポイント
  vpcEndpointSqsSample:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      VpcId: !Ref vpcSample
      VpcEndpointType: Interface  # Gatewayタイプが対応しているのはS3, DynamoDBのみ
      PrivateDnsEnabled: true
      ServiceName: !Sub com.amazonaws.${AWS::Region}.sqs
      SubnetIds: 
        - !Ref subnetSample1
        - !Ref subnetSample2
      SecurityGroupIds:
        - !GetAtt securityGroupSampleSQS.GroupId

  # Lambdaが使用するセキュリティグループ
  securityGroupSampleLambda:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub ${EnvName}-securityGroupSampleLambda
      GroupDescription: for lambda
      VpcId: !Ref vpcSample
      SecurityGroupEgress:
        - CidrIp: 0.0.0.0/0
          IpProtocol: -1

  # EFSに設定するセキュリティグループ
  securityGroupSampleEFS:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub ${EnvName}-securityGroupSampleEFS
      GroupDescription: for efs
      VpcId: !Ref vpcSample
      SecurityGroupEgress:
        - CidrIp: 0.0.0.0/0
          IpProtocol: -1
      SecurityGroupIngress:
        - IpProtocol: tcp
          SourceSecurityGroupId: !GetAtt securityGroupSampleLambda.GroupId  # Lambdaが使用するsgを通す
          FromPort: 2049 # NFSに使用するポート番号
          ToPort: 2049

  # SQS用のVPCエンドポイントに設定するセキュリティグループ
  securityGroupSampleSQS:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub ${EnvName}-securityGroupSampleSQS
      GroupDescription: for sqs
      VpcId: !Ref vpcSample
      SecurityGroupEgress:
        - CidrIp: 0.0.0.0/0
          IpProtocol: -1
      SecurityGroupIngress:
        - IpProtocol: tcp
          SourceSecurityGroupId: !GetAtt securityGroupSampleLambda.GroupId  # Lambdaが使用するsgを通す
          FromPort: 443 # HTTPSに使用するポート番号
          ToPort: 443

  efsFileSystemSample:
    Type: AWS::EFS::FileSystem
    Properties:
      BackupPolicy:
        Status: ENABLED
      PerformanceMode: generalPurpose
      Encrypted: true
      LifecyclePolicies:
        - TransitionToIA: AFTER_30_DAYS
        - TransitionToPrimaryStorageClass: AFTER_1_ACCESS
      FileSystemTags: 
        - Key: Name   # タグで名前を設定する
          Value: !Sub ${EnvName}-efsFileSystemSample

  efsMountTargetSample1:
    Type: AWS::EFS::MountTarget
    Properties:
      FileSystemId: !Ref efsFileSystemSample
      SubnetId: !Ref subnetSample1
      SecurityGroups:
        - !GetAtt securityGroupSampleEFS.GroupId

  efsMountTargetSample2:
    Type: AWS::EFS::MountTarget
    Properties:
      FileSystemId: !Ref efsFileSystemSample
      SubnetId: !Ref subnetSample2
      SecurityGroups:
        - !GetAtt securityGroupSampleEFS.GroupId

  efsAccessPointSample:
    Type: AWS::EFS::AccessPoint
    Properties:
      FileSystemId: !Ref efsFileSystemSample
      PosixUser:  # このアクセスポイントを使用するLambdaが使用するユーザ/グループID
        Uid: 1001
        Gid: 1001
      RootDirectory:
        CreationInfo: # ディレクトリ作成者のユーザ/グループID
          OwnerGid: 1001
          OwnerUid: 1001
          Permissions: 755 # パーミッション
        Path: /my-function  # ファイルシステム上に生成されるディレクトリ

  SampleLambdaRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: SampleLambdaRole
      Path: /
      MaxSessionDuration: 3600
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: SampleVpcAccess
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Resource: [
                  '*'
                ]
                Action: [
                  ec2:CreateNetworkInterface,
                  ec2:DescribeNetworkInterfaces,
                  ec2:DeleteNetworkInterface,
                  ec2:AssignPrivateIpAddresses,
                  ec2:UnassignPrivateIpAddresses
                ]
        - PolicyName: SampleEfsAccess
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Resource: [
                  '*'
                ]
                Action: [
                  elasticfilesystem:ClientMount,
                  elasticfilesystem:ClientWrite,
                  elasticfilesystem:DescribeMountTargets
                ]

  sqsSampleLambda:
    Type: AWS::Serverless::Function
    DependsOn: 
      - efsMountTargetSample1   # LambdaからEFS使用に必須
      - efsMountTargetSample2
    Properties:
      Handler: main.lambda_handler
      Runtime: python3.7
      Role: !Sub arn:aws:iam::${AWS::AccountId}:role/SampleLambdaRole
      # ...省略
      Environment:
        Variables:
          DNS_NAME: !Sub https://sqs.${AWS::Region}.amazonaws.com   # VPC LambdaからSQS使用の際に必要
      Events:
        sqsSampleQueueEvent:
          Type: SQS   # LambdaのトリガとしてSQSを使用するのみであればSQS用のVPCエンドポイントは不要
          Properties:
            Queue:
              Fn::GetAtt:
                - sqsSampleQueue
                - Arn
            BatchSize: 1
      VpcConfig:  # VPC設定
        SecurityGroupIds:
          - !GetAtt securityGroupSampleLambda.GroupId
        SubnetIds:
          - !Ref subnetSample1
          - !Ref subnetSample2
      FileSystemConfigs:  # EFS設定
        - Arn: !GetAtt efsAccessPointSample.Arn
          LocalMountPath: /mnt/efs  # /mnt/efs にアクセスポイントパス /my-function がマウントされる

  sqsSampleQueue:
    Type: AWS::SQS::Queue
    Properties:
      DelaySeconds: 0
      KmsMasterKeyId: alias/aws/sqs
      # ...省略

EFSアクセスポイント定義内容

EFSアクセスポイントには以下の設定を行う

  • ディレクトリパス
  • ユーザID、グループID(このアクセスポイントを使用してアクセスした者に割り当たるID)
  • ディレクトリ所有者のユーザID、グループID
  • パーミッション

上記テンプレートは、
ユーザID、グループID(Lambdaに割り当てるID)とディレクトリ所有者のユーザID、グループIDと同じとし、
Lambdaはディレクトリ所有者としてアクセスするよう設定している
パーミッションは755とし、ディレクトリ所有者は読み書き可能にしている

EFSアクセスポイントの注意点

アクセスポイントを作成すると、
EFS上に指定した属性(ディレクトリ所有者のユーザID、グループID、パーミッション)でディレクトリが作成される
このディレクトリは、アクセスポイントの削除や、同一ディレクトリパスでアクセスポイントを追加しても削除/更新されない

VPC LambdaからAWSリソースアクセス時の注意点

VPC Lambdaからboto3でAWSリソースアクセス時、以下のようにendpoint_urlを指定する必要があるものがある
このオプションがない場合、アクセスタイムアウトが発生する

template.yaml
      Environment:
        Variables:
          DNS_NAME: !Sub https://sqs.${AWS::Region}.amazonaws.com   # VPC LambdaからSQS使用の際に必要
handler.py
sqs_dns_name = os.environ.get('SQS_DNS_NAME')
sqs = boto3.resource('sqs', endpoint_url=sqs_dns_name)

SQS以外にSTSも同様にendpoint_urlが必要だったが、すべてのAWSリソースアクセスに必要なわけではない
(S3は不要だった)

client = boto3.client('sts', endpoint_url=dns_name)
1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?