从Lambda创建Elasticsearch映射时出现“授权异常”

时间:2019-08-15 15:11:43

标签: node.js amazon-web-services elasticsearch aws-lambda aws-elasticsearch

我根本无法启用Lambda函数来连接以在我的AWS Elasticsearch服务器上创建映射。我正在使用Node和elasticsearch软件包,并且收到以下错误(在CloudWatch日志中):

ERROR   Uncaught Exception
{
    "errorType": "Error [ERR_UNHANDLED_ERROR]",
    "errorMessage": "Unhandled error. ({ message: 'Unable to create Elasticsearch mapping for Log',\n  data:\n   'Error: Authorization Exception\\n    at respond (/var/task/node_modules/elasticsearch/src/lib/transport.js:308:15)\\n    at checkRespForFailure (/var/task/node_modules/elasticsearch/src/lib/transport.js:267:7)\\n    at done (/var/task/node_modules/http-aws-es/connector.js:48:7)\\n    at IncomingMessage.cleanUp (/var/task/node_modules/http-aws-es/src/node.js:20:7)\\n    at IncomingMessage.emit (events.js:203:15)\\n    at IncomingMessage.EventEmitter.emit (domain.js:448:20)\\n    at endReadableNT (_stream_readable.js:1129:12)\\n    at process._tickCallback (internal/process/next_tick.js:63:19)' })",
    "code": "ERR_UNHANDLED_ERROR",
    "stack": [
        "Error [ERR_UNHANDLED_ERROR]: Unhandled error. ({ message: 'Unable to create Elasticsearch mapping for Log',",
        "  data:",
        "   'Error: Authorization Exception\\n    at respond (/var/task/node_modules/elasticsearch/src/lib/transport.js:308:15)\\n    at checkRespForFailure (/var/task/node_modules/elasticsearch/src/lib/transport.js:267:7)\\n    at done (/var/task/node_modules/http-aws-es/connector.js:48:7)\\n    at IncomingMessage.cleanUp (/var/task/node_modules/http-aws-es/src/node.js:20:7)\\n    at IncomingMessage.emit (events.js:203:15)\\n    at IncomingMessage.EventEmitter.emit (domain.js:448:20)\\n    at endReadableNT (_stream_readable.js:1129:12)\\n    at process._tickCallback (internal/process/next_tick.js:63:19)' })",
        "    at Object.emit (events.js:187:17)",
        "    at limiter.removeTokens (/var/task/node_modules/@my-company/my-package/lib/logger.js:158:10)",
        "    at afterTokensRemoved (/var/task/node_modules/limiter/lib/rateLimiter.js:87:7)",
        "    at process._tickCallback (internal/process/next_tick.js:61:11)"
    ],
    "context": {
        "message": "Unable to create Elasticsearch mapping for Log",
        "data": "Error: Authorization Exception\n    at respond (/var/task/node_modules/elasticsearch/src/lib/transport.js:308:15)\n    at checkRespForFailure (/var/task/node_modules/elasticsearch/src/lib/transport.js:267:7)\n    at done (/var/task/node_modules/http-aws-es/connector.js:48:7)\n    at IncomingMessage.cleanUp (/var/task/node_modules/http-aws-es/src/node.js:20:7)\n    at IncomingMessage.emit (events.js:203:15)\n    at IncomingMessage.EventEmitter.emit (domain.js:448:20)\n    at endReadableNT (_stream_readable.js:1129:12)\n    at process._tickCallback (internal/process/next_tick.js:63:19)"
    }
}

似乎Lambda能够连接到Elasticsearch服务器,但是它收到授权异常错误(我认为是403)。

我正在使用无服务器框架。我的无服务器配置如下:

provider:
  name: aws
  runtime: nodejs10.x
  stage: ${opt:stage, 'dev'}
  region: us-east-2
  memorySize: 512
  timeout: 30
  vpc:
    securityGroupIds:
      - ${ssm:/my-company/security-group/lambda}
    subnetIds:
      - ${ssm:/my-company/subnet/lambda1/id}
      - ${ssm:/my-company/subnet/lambda2/id}
      - ${ssm:/my-company/subnet/lambda3/id}

functions:
  myFunctionName:
    handler: src/my-function-name.handler
    events:
      - sqs:
          arn: ${ssm:/my-company/${self:provider.stage}/update-print-image-status-queue-arn}

package:
  exclude:
    - .circleci/**
    - .terraform/**
    - test/**

Lambda使用的IAM角色具有完全的Elasticsearch访问权限:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "sqs:DeleteMessage",
                "logs:CreateLogStream",
                "sqs:ReceiveMessage",
                "sqs:GetQueueAttributes"
            ],
            "Resource": [
                "arn:aws:logs:us-east-2:<AWS account ID>:log-group:/aws/lambda/<project-name>-dev*:*",
                "arn:aws:sqs:us-east-2:<AWS account ID>:update-print-image-status-queue-dev"
            ]
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": "logs:PutLogEvents",
            "Resource": "arn:aws:logs:us-east-2:<AWS account ID>:log-group:/aws/lambda/<project-name>-dev*:*:*"
        },
        {
            "Sid": "VisualEditor2",
            "Effect": "Allow",
            "Action": "es:*",
            "Resource": "*"
        }
    ]
}

VPC和子网肯定存在,并且预期的子网与Lambda相关联。 Lambda能够毫无问题地访问和查询我的MongoDB EC2服务器。 Elasticsearch服务器与MongoDB EC2服务器位于同一VPC和子网中。

这是我如何从Node初始化ES客户端的方法:

const AWS = require('aws-sdk');
const elasticsearch = require('elasticsearch');

client = elasticsearch.Client({
  host: process.env.ELASTICSEARCH_HOSTS,
  connectionClass: require('http-aws-es'),
  awsConfig: new AWS.Config({
    accessKeyId: process.env.AWS_ACCESS_KEY_ID,
    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
    region: process.env.ELASTICSEARCH_REGION,
  })
});

ELASTICSEARCH_HOSTSELASTICSEARCH_REGION都被定义为Lambda的具有正确值的环境变量。

然后,Monososastic使用该客户端。

相同的代码无需更改即可在EC2服务器(与MongoDB EC2服务器位于同一VPC和子网)中的EC2服务器上正常运行。

Elasticsearch服务(由AWS管理;版本6.3)具有以下策略:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "*"
      },
      "Action": "es:*",
      "Resource": "arn:aws:es:us-east-2:<aws account ID>:domain/<my domain>/*"
    }
  ]
}

因此,我很困惑为什么看到“授权异常”。有什么想法吗?

2 个答案:

答案 0 :(得分:0)

    import gitlab
    import logging
    from elasticsearch import Elasticsearch, RequestsHttpConnection
    from requests_aws4auth import AWS4Auth
    import boto3
    #from aws_requests_auth.aws_auth import AWSRequestsAuth

    LOGGER = logging.getLogger()
    ES_HOST = {'host':'search-testelasticsearch-xxxxxxxxx.eu-west-2.es.amazonaws.com', 'port': 443}


    def lambda_handler(event, context):
        LOGGER.info('started')
        gl = gitlab.Gitlab('xxxxxxx', private_token='xxxxxx')
        group = gl.groups.get('Thunderbird')
        project = gl.projects.get(92, lazy=True)
        mrs = project.mergerequests.list(state='opened', order_by='updated_at')
        first_mr = mrs[0]
        dump = {
          'title': first_mr.title,
          'state': first_mr.state,
          'name': first_mr.author.get('name'),
          'comments': first_mr.user_notes_count
        }

        dump2={
            'number_of_mrs': 9
        }

        service = 'es'
        credentials = boto3.Session().get_credentials()
        awsauth = AWS4Auth(credentials.access_key, credentials.secret_key, "eu-west-2", service, session_token=credentials.token)
        es = Elasticsearch(hosts=[ES_HOST], http_auth = awsauth, use_ssl = True, verify_certs = True, connection_class = RequestsHttpConnection)
        DAVID_INDEX = 'david_test_index'
        response = es.index(index=DAVID_INDEX, doc_type='is_this_important?', body=dump2, id='4')```





答案 1 :(得分:0)

我相信我已经解决了这个问题。以下作品:

const AWS = require('aws-sdk');
const elasticsearch = require('elasticsearch');

client = elasticsearch.Client({
  host: process.env.ELASTICSEARCH_HOSTS,
  connectionClass: require('http-aws-es')
});

不需要指定访问密钥。我具有用于Elasticsearch服务器的安全组设置,以便Lambda安全组具有入口访问权限。