Разрешение Lambda в VPC для доступа к домену Elasticsearch в том же VPC - PullRequest
0 голосов
/ 24 декабря 2018

Я учусь обходиться с сервисами Amazon, и, в частности, в настоящее время я хочу создать простую установку с помощью скрипта Cloud Formation: VPC с одной лямбда, написанной на JS, которая имеет доступ к сервису Elasticsearch в том жеVPC.

Почему-то я не могу заставить его работать.Все запросы от лямбды к домену Elasticsearch всегда истекают.Тем не менее, одинаковые запросы, сделанные из одного и того же кода JS или curl (даже без каких-либо дополнительных авторизаций, просто заворачивая конечную точку домена ES) из экземпляра EC2, работающего под управлением Amazon Linux 2 в одном и том же VPC, работают нормально, и я могу нормально общаться с Elasticsearchиз этого экземпляра EC2 (будучи SSHed в него).

В то же время лямбда способна получить доступ к кластеру Aurora в VPC, поэтому не является общим вопросом невозможность лямбда получить доступ к VPCресурсы.

Скажите, пожалуйста, что я делаю не так в моем описании настройки Cloud Formation?Ниже приведена соответствующая выдержка из моего шаблона Cloud Formation и пример кода JS, который может получить доступ к службе ES из экземпляра EC2, но не может сделать то же самое для лямбды:

AWSTemplateFormatVersion: 2010-09-09
Description: The AWS CloudFormation tutorial
Resources:

  SomeDeploymentBucket:
    Type: 'AWS::S3::Bucket'

  AppLogGroup:
    Type: 'AWS::Logs::LogGroup'
    Properties:
      LogGroupName: /aws/lambda/some-lambda

    # ========= The Lambda Execution Role =========

  IamRoleLambdaExecution:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      Policies:
        - PolicyName: !Join 
            - '-'
            - - dev
              - some-app
              - lambda
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - 's3:*'
                  - 'rds-db:connect'
                  - 'rds:*'
                  - 'es:*'
                Resource: '*'
      Path: /
      RoleName: !Join 
        - '-'
        - - some-app
          - dev
          - eu-west-1
          - lambdaRole
      ManagedPolicyArns:
        - !Join 
          - ''
          - - 'arn:'
            - !Ref 'AWS::Partition'
            - ':iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole'

    # ========= The Lambda =========

  AppLambdaFunction:
    Type: 'AWS::Lambda::Function'
    Properties:
      Code:
        S3Bucket: !Ref SomeDeploymentBucket
        S3Key: >-
          tutorial/some-app/dev/1545610972669-2018-12-24T00:22:52.669Z/some-app.zip
      FunctionName: some-lambda
      Handler: app.server
      MemorySize: 1024
      Role: !GetAtt 
        - IamRoleLambdaExecution
        - Arn
      Runtime: nodejs8.10
      Timeout: 6
      VpcConfig:
        SecurityGroupIds:
          - !Ref xxxVPCSecurityGroup
        SubnetIds:
          - !Ref xxxLambdaSubnet
    DependsOn:
      - AppLogGroup
      - IamRoleLambdaExecution

    # ========= VPC =========

  xxxVPC:
    Type: 'AWS::EC2::VPC'
    Properties:
      CidrBlock: 172.31.0.0/16
      InstanceTenancy: default
      EnableDnsSupport: 'true'
      EnableDnsHostnames: 'true'

  xxxVPCSecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      GroupName: VPC SG
      GroupDescription: VPC Security Group
      VpcId: !Ref xxxVPC

  xxxLambdaSubnet:
    Type: 'AWS::EC2::Subnet'
    Properties:
      VpcId: !Ref xxxVPC
      CidrBlock: 172.31.32.0/20

    # ========= Elasticsearch =========

  xxxESSecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      GroupName: ES SG
      GroupDescription: ES Security group
      VpcId: !Ref xxxVPC
      SecurityGroupIngress:
        - IpProtocol: -1
          FromPort: 0
          ToPort: 65535
          SourceSecurityGroupId: !Ref xxxVPCSecurityGroup

  xxxElasticSearch:
    Type: 'AWS::Elasticsearch::Domain'
    Properties:
      AccessPolicies:
        Version: 2012-10-17
        Statement:
          - Action:
              - 'es:*'
              - 'ec2:*'
              - 's3:*'
            Principal:
              AWS:
                - '*'
            Resource: '*'
            Effect: Allow
      DomainName: es-xxx-domain
      AdvancedOptions:
        rest.action.multi.allow_explicit_index: 'true'
      ElasticsearchVersion: 6.3
      ElasticsearchClusterConfig:
        InstanceCount: 2
        InstanceType: m3.medium.elasticsearch
        DedicatedMasterEnabled: 'false'
      VPCOptions:
        SecurityGroupIds:
          - !Ref xxxESSecurityGroup
        SubnetIds:
          - !Ref xxxLambdaSubnet

Код JS (версия без подписи с кредитами, но она не работает и при подписании):

var es = require('elasticsearch');
var client = new es.Client({
    host: 'vpc-es-domain-AMAZON.eu-west-1.es.amazonaws.com:80',
    log: 'trace'
});

client.ping({
    requestTimeout: 1000
}, function(error, res, status){
    if(error) {
        console.trace('es cluster error!');
        console.trace(error);
    } else {
        console.log('All is well');
        var response = {
            error: error,
            res: res,
            status: status
        }
        console.log(JSON.stringify(response));
    }
});

Выполнение этого в скручивании из экземпляра EC2 в том же VPC получает ответ от ESдомен без проблем :

curl vpc-es-domain-AMAZON.eu-west-1.es.amazonaws.com:80

Буду очень признателен за помощь, так как уже застрял с этим.

1 Ответ

0 голосов
/ 07 июля 2019

Замечено две проблемы в вашей настройке

  1. Вы создаете только одну подсеть в стеке и назначаете только одну подсеть для Lambda.Вам нужно назначить несколько подсетей для Lambda
  2. Вам необходимо исправить политику доступа для ES .Я вручную обновил до «Не требовать подписи с использованием учетных данных IAM» для моего тестирования в консоли.

Я обновил шаблон Cloudformation для создания лямбда-обработчика на основе Python для запроса эластичного поиска из того же виртуального процессора.Он не является полным, но если вы убедитесь в вышеупомянутых проблемах, он должен работать.

AWSTemplateFormatVersion: 2010-09-09
Description: The AWS CloudFormation tutorial
Resources:

  SomeDeploymentBucket:
    Type: 'AWS::S3::Bucket'

  AppLogGroup:
    Type: 'AWS::Logs::LogGroup'
    Properties:
      LogGroupName: /aws/lambda/some-lambda

    # ========= The Lambda Execution Role =========

  IamRoleLambdaExecution:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      Policies:
        - PolicyName: !Join
            - '-'
            - - dev
              - some-app
              - lambda
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - 's3:*'
                  - 'rds-db:connect'
                  - 'rds:*'
                  - 'es:*'
                Resource: '*'


      Path: /
      RoleName: !Join
        - '-'
        - - some-app
          - dev
          - eu-west-1
          - lambdaRole
      ManagedPolicyArns:
        - !Join
          - ''
          - - 'arn:'
            - !Ref 'AWS::Partition'
            - ':iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole'

    # ========= The Lambda =========

  AppLambdaFunction:
    Type: AWS::Lambda::Function
    DependsOn:
      - AppLogGroup
      - IamRoleLambdaExecution
    Properties:
      FunctionName: some-lambda
      Handler: index.lambda_handler
      Runtime: python2.7
      Timeout: 60
      MemorySize: 1024
      Role: !GetAtt
        - IamRoleLambdaExecution
        - Arn
      VpcConfig:
        SecurityGroupIds:
          - !Ref xxxVPCSecurityGroup
        SubnetIds:
          - !Ref xxxLambdaSubnet1
          - !Ref xxxLambdaSubnet2

      Code:
        ZipFile: !Sub |
          from __future__ import print_function
          import boto3
          iam = boto3.client('iam')

          def lambda_handler(event, context):
            print('called lambda_handler')

    # ========= VPC =========

  xxxVPC:
    Type: 'AWS::EC2::VPC'
    Properties:
      CidrBlock: 172.31.0.0/16
      InstanceTenancy: default
      EnableDnsSupport: 'true'
      EnableDnsHostnames: 'true'

  xxxVPCSecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      GroupName: VPC SG
      GroupDescription: VPC Security Group
      VpcId: !Ref xxxVPC

  xxxLambdaSubnet1:
    Type: 'AWS::EC2::Subnet'
    Properties:
      VpcId: !Ref xxxVPC
      CidrBlock: 172.31.32.0/20
  xxxLambdaSubnet2:
    Type: 'AWS::EC2::Subnet'
    Properties:
      VpcId: !Ref xxxVPC
      CidrBlock: 172.31.16.0/20


    # ========= Elasticsearch =========

  xxxESSecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      GroupName: ES SG
      GroupDescription: ES Security group
      VpcId: !Ref xxxVPC
      SecurityGroupIngress:
        - IpProtocol: -1
          FromPort: 0
          ToPort: 65535
          SourceSecurityGroupId: !Ref xxxVPCSecurityGroup

  xxxElasticSearch:
    Type: 'AWS::Elasticsearch::Domain'
    Properties:
      AccessPolicies:
        Version: 2012-10-17
        Statement:
          - Action:
              - 'es:*'
              - 'ec2:*'
              - 's3:*'
            Principal:
              AWS:
                - '*'
            Resource: '*'
            Effect: Allow
      DomainName: es-xxx-domain
      EBSOptions:
        EBSEnabled: true
        Iops: 0
        VolumeSize: 20
        VolumeType: "gp2"
      AdvancedOptions:
        rest.action.multi.allow_explicit_index: 'true'

      ElasticsearchClusterConfig:
        InstanceCount: 1
        InstanceType: m4.large.elasticsearch
        DedicatedMasterEnabled: 'false'
      VPCOptions:
        SecurityGroupIds:
          - !Ref xxxESSecurityGroup
        SubnetIds:
          - !Ref xxxLambdaSubnet1

Обновлен код обработчика лямбда-функции

  import urllib2

def lambda_handler(event, context):
    print('called lambda_handler')
    data = ''
    url = 'https://vpc-es-xxx-domain-fixthis.es.amazonaws.com'
    req = urllib2.Request(url, data, {'Content-Type': 'application/json'})
    f = urllib2.urlopen(req)
    for x in f:
        print(x)
    f.close()
...