Разрешения на доступ к ElasticSearch от Lambda?

Я пытаюсь использовать Elasticsearch для хранения данных для лямбда-функции, подключенной к Alexa Skills Kit. Лямбда работает хорошо без Elasticsearch, но ES обеспечивает столь необходимое нечеткое соответствие.

Единственный способ получить доступ к нему через Lambda - это включить глобальный доступ Elasticsearch, но это действительно плохая идея. Я также смог получить доступ со своего компьютера через политику открытого доступа или политику IP-адресов. Есть ли способ сделать доступ только для чтения через Lambda и чтения-записи через IP?

На IAM я предоставил свою лямбда-роль AmazonESReadOnlyAccess. На стороне ES я попробовал это, но это работало только для IP-адреса:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": [
          "arn:aws:iam::NUMBER:root",
          "arn:aws:iam::NUMBER:role/lambda_basic_execution"
        ]
      },
      "Action": "es:*",
      "Resource": "arn:aws:es:us-east-1:NUMBER:domain/NAME/*"
    },
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "AWS": "*"
      },
      "Action": "es:*",
      "Resource": "arn:aws:es:us-east-1:NUMBER:domain/NAME/*",
      "Condition": {
        "IpAddress": {
          "aws:SourceIp": "MY IP"
        }
      }
    }
  ]
}

Этот пост форума задает тот же вопрос, но остался без ответа.

Ответ 1

Единственный способ, которым я знаю, это использовать политику на основе ресурсов или политику на основе IAM для вашего домена ES. Это ограничит доступ к определенному пользователю или роли IAM. Однако для выполнения этой работы вам также необходимо подписать свои запросы к ES с помощью SigV4.

Есть библиотеки, которые сделают это подписание для вас, например этот расширяет популярную библиотеку запросов Python для подписи запросов ElasticSearch через SigV4. Я считаю, что подобные библиотеки существуют для других языков.

Ответ 2

Теперь это возможно из вашего кода сasticsearch.js. Прежде чем попробовать, вы должны установить модуль http-aws-es.

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

const client = new elasticsearch.Client({
 host: 'YOUR_ES_HOST',
 connectionClass: httpAwsEs,
 amazonES: {
   region: 'YOUR_ES_REGION',
   credentials: new AWS.EnvironmentCredentials('AWS')
 }
});

// client.search({...})

Конечно, перед его использованием настройте доступ к доменуasticsearch: enter image description here

Ответ 4

Для внешнего (вне AWS) доступа к вашему кластеру Elasticsearch вы хотите создать кластер с политикой доступа на основе IP. Что-то вроде ниже:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "AWS": "*"
      },
      "Action": "es:*",
      "Condition": {
        "IpAddress": {
          "aws:SourceIp": [
            "<<IP/CIDR>>"
          ]
        }
      },
      "Resource": "arn:aws:es:<<REGION>>:<<ACCOUNTID>>:domain/<<DOMAIN_NAME>>/*"
    }
  ]
}

Для вашей лямбда-функции создайте роль, которую будет использовать функция Lambda с помощью нижеприведенного фрагмента политики.

{
  "Sid": "",
  "Effect": "Allow",
  "Action": [
    "es:DescribeElasticsearchDomain",
    "es:DescribeElasticsearchDomains",
    "es:DescribeElasticsearchDomainConfig",
    "es:ESHttpPost",
    "es:ESHttpPut"
  ],
  "Resource": [
    "arn:aws:es:<<REGION>>:<<ACCOUNTID>>:domain/<<DOMAIN_NAME>>",
    "arn:aws:es:<<REGION>>:<<ACCOUNTID>>:domain/<<DOMAIN_NAME>>/*"
  ]
},
{
  "Sid": "",
  "Effect": "Allow",
  "Action": [
    "es:ESHttpGet"
  ],
  "Resource": [
    "arn:aws:es:<<REGION>>:<<ACCOUNTID>>:domain/<<DOMAIN_NAME>>/_all/_settings",
    "arn:aws:es:<<REGION>>:<<ACCOUNTID>>:domain/<<DOMAIN_NAME>>/_cluster/stats",
    "arn:aws:es:<<REGION>>:<<ACCOUNTID>>:domain/<<DOMAIN_NAME>>/<<INDEX>>*/_mapping/<<TYPE>>",
    "arn:aws:es:<<REGION>>:<<ACCOUNTID>>:domain/<<DOMAIN_NAME>>/_nodes",
    "arn:aws:es:<<REGION>>:<<ACCOUNTID>>:domain/<<DOMAIN_NAME>>/_nodes/stats",
    "arn:aws:es:<<REGION>>:<<ACCOUNTID>>:domain/<<DOMAIN_NAME>>/_nodes/*/stats",
    "arn:aws:es:<<REGION>>:<<ACCOUNTID>>:domain/<<DOMAIN_NAME>>/_stats",
    "arn:aws:es:<<REGION>>:<<ACCOUNTID>>:domain/<<DOMAIN_NAME>>/<<INDEX>>*/_stats"
  ]
}

Я думаю, вы могли бы с легкостью сконденсировать вышеупомянутые два заявления о политике следующим образом:

{
  "Sid": "",
  "Effect": "Allow",
  "Action": [
    "es:DescribeElasticsearchDomain",
    "es:DescribeElasticsearchDomains",
    "es:DescribeElasticsearchDomainConfig",
    "es:ESHttpPost",
    "es:ESHttpGet",
    "es:ESHttpPut"
  ],
  "Resource": [
    "arn:aws:es:<<REGION>>:<<ACCOUNTID>>:domain/<<DOMAIN_NAME>>",
    "arn:aws:es:<<REGION>>:<<ACCOUNTID>>:domain/<<DOMAIN_NAME>>/*"
  ]
}

Мне удалось собрать все вместе из следующих источников:

https://aws.amazon.com/blogs/security/how-to-control-access-to-your-amazon-elasticsearch-service-domain/

Как получить доступ к Kibana из сервиса Amazon elasticsearch?

https://forums.aws.amazon.com/thread.jspa?threadID=217149

Ответ 5

AWS Lambda работает в публичных экземплярах EC2. Поэтому простое добавление белого списка IP-адресов в политику доступа Elasticsearch не будет работать. Один из способов сделать это - предоставить роли выполнения Lambda соответствующие разрешения для домена Elasticsearch. Убедитесь, что роль Lambda Execution имеет разрешения для домена ES, а политика доступа к домену ES имеет оператор, который позволяет этой роли Lambda Role ARN выполнять соответствующие действия. Как только это будет сделано, все, что вам нужно сделать, это подписать ваш запрос через SigV4 при доступе к конечной точке ES.

Надеюсь, что это поможет!

Ответ 6

Теперь это возможно из вашего кода сasticsearch.js. Прежде чем попробовать, вы должны установить модуль http-aws-es.

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

const client = new elasticsearch.Client({
  host: 'es-host',
  connectionClass: httpAwsEs,
  amazonES: {
    region: 'us-east-1',
    credentials: new AWS.EnvironmentCredentials('AWS')
  }
});

// client.search({...})

Конечно, прежде чем это сделать, настройте доступ к доменуasticsearch: enter image description here