Разрешения на доступ к 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"
        }
      }
    }
  ]
}

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

4 ответа

Решение

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

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

Теперь это возможно из вашего кода с 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:

Для внешнего (вне 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 создайте роль, которую будет выполнять функция 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 из сервиса Amazonasticsearch?

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

Вам нужно перейти к политике доступа Lambda и предоставить AWS ARN для подключения

http://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-aws-integrations.html

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

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

Другие вопросы по тегам