AWS LambdaからS3への接続をS3Endpointを使用し、S3バケットポリシーで接続元を制限してみた - あめがえるのITブログ

あめがえるのITブログ

頑張りすぎない。ほどほどに頑張るブログ。

AWS LambdaからS3への接続をS3Endpointを使用し、S3バケットポリシーで接続元を制限してみた

やること

こうではなく

こうする
バケットポリシーのconditionでS3Endpointのみを許可するように変更

実践!

1.環境作成
1-1.CloudFormationで下記を実行
※StringNotEqualsIfExists:に何かしらのアカウントを許可する。
 許可しないとファイルのアップロードができない。

AWSTemplateFormatVersion: '2010-09-09'
Resources:
  MyVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: MyVPC

  InternetGateway:
    Type: AWS::EC2::InternetGateway

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

  PublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref MyVPC
      CidrBlock: 10.0.1.0/24
      MapPublicIpOnLaunch: true
      AvailabilityZone: !Select [0, !GetAZs '']

  PrivateSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref MyVPC
      CidrBlock: 10.0.2.0/24
      AvailabilityZone: !Select [0, !GetAZs '']

  NatGatewayEIP:
    Type: AWS::EC2::EIP

  NatGateway:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId: !GetAtt NatGatewayEIP.AllocationId
      SubnetId: !Ref PublicSubnet

  PrivateSubnetRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref MyVPC

  PublicSubnetRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref MyVPC

  PublicSubnetRoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PublicSubnetRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway

  PrivateSubnetRoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PrivateSubnetRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref NatGateway

  PublicSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet
      RouteTableId: !Ref PublicSubnetRouteTable

  PrivateSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet
      RouteTableId: !Ref PrivateSubnetRouteTable

  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
        - arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess

  LambdaSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Allow Lambda access to VPC
      VpcId: !Ref MyVPC

  MyLambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      Handler: index.handler
      Role: !GetAtt LambdaExecutionRole.Arn
      Code:
        ZipFile: |
          import boto3
          def handler(event, context):
              s3 = boto3.client('s3')
              response = s3.get_object(Bucket='my-s3-bucket-example', Key='test.txt')
              data = response['Body'].read()
              print(data)
      Runtime: python3.9
      VpcConfig:
        SubnetIds:
          - !Ref PrivateSubnet
        SecurityGroupIds:
          - !Ref LambdaSecurityGroup

  MyS3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: my-s3-bucket-example1234567899999
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true

  MyS3BucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref MyS3Bucket
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Deny
            Principal: "*"
            Action: "s3:*"
            Resource:
              - !Sub "arn:aws:s3:::my-s3-bucket-example1234567899999"
              - !Sub "arn:aws:s3:::my-s3-bucket-example1234567899999/*"
            Condition:
              StringNotEquals:
                "aws:SourceVpce": !Ref S3VPCEndpoint
              StringNotEqualsIfExists:
                "aws:PrincipalArn": "arn:aws:iam::xxxxxxxxxxxx:root"

  S3VPCEndpoint:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      VpcId: !Ref MyVPC
      ServiceName: !Sub com.amazonaws.${AWS::Region}.s3
      VpcEndpointType: Gateway
      RouteTableIds:
        - !Ref PrivateSubnetRouteTable

2.テスト
2-1.作成したS3バケットにtest.txtをアップロード
2-2.作成したLambdaでテストを行い、test.txtの中身が表示されることを確認

感想

NatGateway通っている可能性あるので明示的にEndpointを指定したほうがよさげ