AWS: створення OpenSearch Service cluster та налаштування аутентифікації і авторизації

💡 Усі статті, обговорення, новини про DevOps — в одному місці. Приєднуйтесь до DevOps спільноти!

В попередній частині — AWS: знайомство з OpenSearch Service в ролі vector store — подивились на AWS OpenSearch Service взагалі, трохи розібрались з тим, як в ньому організовані дані, що таке shards та nodes, і які нам власне типи інстансів для data nodes треба.

Наступний крок — створити кластер і подивитись на аутентифікацію, яка, як на мене, в чомусь навіть складніша за AWS EKS. Хоча, можливо, просто справа звички.

Що будемо робити сьогодні — вручну створимо кластер AWS OpenSearch Service, глянемо на основні опції при створенні кластеру, а потім копнемо в налаштування доступу до кластеру і до OpenSearch Dashboards з AWS IAM та Fine-grained access control самого OpenSearch і його Security plugin.

А вже в наступній частині будемо писати Terraform.

Ручне створення кластера в AWS Console

Робити будемо мінімальний PoC, аби погратись, тобто з t3 інстансами і в одній Availability Zone та без Master Nodes.

В Production у нас теж планується один маленький кластер з трьома індексами dev/staging/prod в ролі vector store для AWS Bedrock Knowledge Base.

Документація від AWS — Creating OpenSearch Service domains.

Переходимо в Amazon OpenSearch Service > Domains, клікаємо «Create domain».

Задаємо ім’я, вибираємо «Standart create», аби мати доступ до всіх опцій:

В «Templates» вибираємо "Dev/«test — тоді можна буде вибрати конфіг без Master Nodes і можна буде деплоїти в одній Availability Zone.

В «Deployment option(s)» вибираємо «Domain without standby» — тоді нам будуть доступні інстанси t3:

Справа нам зручненько відразу показує весь сетап.

Storage

Питання кількості шардів на кластер розбирали в попередньому пості, будемо вважати, що у нас планується даних максимум 20-30 GiB, тому будемо створювати 1 primary шард та 1 replica. Але шарди налаштовуються пізніше, коли будемо робити індекси з Terraform і opensearch_index_template.

І для цих двох шардів будемо робити дві Data Nodes — одна для primary шарду, одна для репліки.

«Engine options» описані в Features by engine version in Amazon OpenSearch Service, просто залишаємо дефолтне значення, останню версію.

«Instance family» вибираємо «General puprose», в «Instance type» — t3.small.search.

«EBS storage size per node» візьмемо 50 GiB — 20-30 гігабайт під дані, і трохи запасу для самої операційної системи:

Nodes

«Number of master nodes» та «Dedicated coordinator nodes» залишаємо без змін, тобто без них:

Network

В «Custom endpoint» поки теж нічого не міняємо, але потім тут можна додати який власний домен із Route53 з сертифікатом з AWS Certificate Manager для доступу до кластеру, див. Creating a custom endpoint for Amazon OpenSearch Service.

В «Network» — поки робимо найпростіший варіант, з «Public access», але для Production будемо робити всередині VPC:

Але треба буде потестити доступ до Dashboards, бо якщо кластер створюється в сабнетах VPC, то до нього не можна застосувати IP-based policies, див. About access policies on VPC domains. Про IP-based policies будемо говорити тут далі.

Access && permissions

«Fine-grained access control» (FGAC) — поки відключаємо, далі детальніше подивимось на цей механізм. Хоча я не впевнений, що він буде потрібен, бо розділити доступ до різних індексів в одному кластері можна і просто з IAM.

SAML, JWT та IAM Identity Center залежать від FGAC, тому теж скіпаємо, і надалі я їх використовувати не планую, не наш кейс.

Cognito теж мимо — ми ним не користуємось (хоча пізніше, можливо, подивлюсь в сторону інтеграції з Auth0 чи Cognito для Dashboards):

«Access policy» можна порівняти з S3 Access Policy, або з IAM Policy для EKS яка дозволяє IAM-юзеру доступ до кластеру.

Детальніше поговоримо в частині про аутентифікацію, поки просто залишаємо дефолтний «Do not set domain level access policy»:

«Off-peak window» — час найменшого навантаження для встановлення апдейтів і виконання Auto-tune операцій.

У нас off-peak буде вночі по США, тому в Production тут буде Central Time (CT) 05:00 UTC.

Але так як зараз тестовий PoC — то теж скіпаємо.

Auto-Tune власне теж нормально описана, і недоступна для наших інстансів t3.

Automatic software update — корисна штука для Production, і буде виконуватись в час, заданий в Off-peak window:

В «Advanced cluster settings» можна відключити rest.action.multi.allow_explicit_index, але не знаю, як у нас будуть будуватись запити, і начебто десь зустрічав, що може поламати Dashboard — тому нехай залишиться дефолтне enabled:

Ну і все, в результаті маємо такий сетап:

Клікаємо «Create», і йдемо пити чай, бо створюється кластер довго — довше, ніж EKS, і створення OpenSearch зайняло хвилин 20.

Аутентифікація та авторизація

Тепер, мабуть, саме цікаве — про юзерів і доступи.

Після створення кластера по дефолту ми маємо обмежені права доступу до самого OpenSearch API:

Бо в «Security Configuration» у нас є явний Deny:

Доступ до AWS OpenSearch Service має три таких собі «рівня» — мережа, IAM, та Security Plugin самого OpenSearch.

При цьому в IAM у нас є дві сутності — Domain Access Policy, який ми бачимо в Security Configuration > Access Policy (атрибут access_policies в Terraform), та Identity-based policies — які є звичайними AWS IAM Policies.

Якщо говорити про ці рівні більш детально, то вони виглядають якось так:

  • мережа: параметр Network > VPC access або Public access: задаємо ліміт доступу на рівні мережі (див. Launching your Amazon OpenSearch Service domains within a VPC)
    • або, якщо брати аналогію з EKS — То це Public та Private API endpoint, або з RDS — створювати інстанс в публічних чи приватних сабнетах
  • AWS IAM:
    • Domain Access Policies:
      • Resource-based policies: політики, які описуються безпосередньо в налаштуваннях самого кластеру
        • доступ задається для IAM Role, IAM User, AWS Accounts до конкретного OpenSearch domain
      • IP-based policies: фактично ті самі Resource-based policies, але з можливістю дозволити доступ без аутентифікації для конкретних IP (тільки якщо тип доступу Public, див. VPC versus public domains)
    • Identity-based policies: якщо Resource-based policies є частиною налаштувань security-політик кластера — то Identity-based policies є звичайними AWS IAM Policies, які додаються конкретному юзеру чи ролі
  • Fine-grained access control (FGAC): Security Plugin самого OpenSearch — атрибут advanced_security_options в Terraform
    • якщо в Resource-based policies і Identity-based policies ми задаємо правила на рівні кластеру (домену) і індексів, то в FGAC можна додатково описати обмеження на конкретні документи або поля
    • і навіть якщо в Resource-based policies і Identity-based policies дозволено доступ до ресурсу в кластері — через Fine-grained access control його можна «обрізати»

Тобто authentification та authorization flow буде таким:

  1. AWS API отримує запит від юзера, наприклад es:ESHttpGet
    1. AWS IAM виконує аутентифікацію — перевіряє ACCESS:SECRET ключі або Session token
    2. AWS IAM виконує авторизацію:
      • перевіряє IAM Policy юзера (Identity-based policy), якщо тут є явний дозвіл — пропускаємо
      • перевіряє Domain Access Policy (Resource-based policy) кластеру, якщо тут явний дозвіл — пропускаємо
  2. запит приходить до самого OpenSearch
    1. якщо Fine-grained access control не включений — дозволяємо
    2. якщо є налаштований Fine-grained access control — перевіряємо внутрішні ролі, і якщо юзеру дозволено — то виконуємо запит

Давайте робити доступи, подивимось, як воно все працює.

Налаштування Domain Access policy

Базовий варіант — додати IAM User доступ до кластеру.

Resource-based policy

Редагуємо «Access policy», і вказуємо свого юзера, типи API-операцій та домен:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::492***148:user/arseny.zinchenko"
},
"Action": "es:*",
"Resource": "arn:aws:es:us-east-1:492***148:domain/test/*"
}
]
}

Чекаємо хвилину — і тепер маємо доступ до OpenSearch API (бо Cluster health в AWS Console отримується саме з OpenSearch — див. Cluster Health API):

І тепер можемо з curl та —aws-sigv4 отримати доступ до кластеру (див. Authenticating Requests (AWS Signature Version 4)):

$ curl --aws-sigv4 "aws:amz:us-east-1:es" \
> --user "AKI***B7A:pAu***2gW" \
> https://search-test-***.us-east-1.es.amazonaws.com/_cluster/health?pretty
{
"cluster_name" : "492***148:test",
"status" : "green",
"timed_out" : false,
"number_of_nodes" : 2,
"number_of_data_nodes" : 2,
"discovered_master" : true,
"discovered_cluster_manager" : true,
"active_primary_shards" : 5,
"active_shards" : 10,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 0,
"delayed_unassigned_shards" : 0,
"number_of_pending_tasks" : 0,
"number_of_in_flight_fetch" : 0,
"task_max_waiting_in_queue_millis" : 0,
"active_shards_percent_as_number" : 100.0
}

IP-based policies та доступ до OpenSearch Dashboards

Аналогічно, через Domain Access Policy можемо відкрити доступ до Dashboards — самий простий варіант, але працює тільки з Public domains. Якщо кластер буде в VPC — то треба буде робити додаткову аутентифікацію, див. Controlling access to Dashboards.

Редагуємо політику, додаємо умову IpAddress.aws:SourceIp:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::492***148:user/arseny.zinchenko"
},
"Action": "es:*",
"Resource": "arn:aws:es:us-east-1:492***148:domain/test/*"
},
{
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "es:ESHttp*",
"Resource": "arn:aws:es:us-east-1:492***148:domain/test/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": "178.***.***.184"
}
}
}
]
}

І тепер маємо доступ до дашборди:

Identity-based policy

Тепер другий варіант — створимо окремого IAM User і йому підключити окрему IAM Policy.

В AWS IAM додаємо юзера:

Можемо взяти AWS managed policies for Amazon OpenSearch Service:

Далі просто створюємо ключі доступу для Command Line Interface (CLI), і — нічого не змінюючи в Access policy самого кластеру — перевіряємо доступ:

$ curl --aws-sigv4 "aws:amz:us-east-1:es" --user "AKI***YUK:fXV***34I" https://search-test-***.us-east-1.es.amazonaws.com/_cluster/health?pretty
{
"cluster_name" : "492***148:test",
"status" : "green",
"timed_out" : false,
"number_of_nodes" : 2,
"number_of_data_nodes" : 2,
"discovered_master" : true,
"discovered_cluster_manager" : true,
"active_primary_shards" : 5,
"active_shards" : 10,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 0,
"delayed_unassigned_shards" : 0,
"number_of_pending_tasks" : 0,
"number_of_in_flight_fetch" : 0,
"task_max_waiting_in_queue_millis" : 0,
"active_shards_percent_as_number" : 100.0
}

Тобто тепер у нас є Domain Acces Policy — яка дозволяє доступ конкретно моєму юзеру, і є окрема IAM Ploicy — Identity-based policy — яка дозволяє доступ тестовому юзеру.

Але тут є один важливий момент: в IAM Policy ми вказуємо або весь домен — або тільки його subresources.

Тобто, якщо замість політики AmazonOpenSearchServiceFullAccess ми створимо власну полісі, в якій вкажемо "Resource":***:domain/test/*«:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"es:*"
],
"Resource": "arn:aws:es:us-east-1:492***148:domain/test/*"
}
]
}

То ми зможемо виконати es:ESHttpGet (GET _cluster/health) — але не зможемо виконати cluster-level операції, наприклад — es:AddTags, навіть при тому, що в Actions IAM-політики маємо дозвіл на всі виклики — es:*:

$ aws --profile test-os opensearch add-tags --arn arn:aws:es:us-east-1:492***148:domain/test --tag-list Key=environment,Value=test
An error occurred (AccessDeniedException) when calling the AddTags operation: User: arn:aws:iam::492***148:user/test-opesearch-identity-based-policy is not authorized to perform: es:AddTags on resource: arn:aws:es:us-east-1:492***148:domain/test because no identity-based policy allows the es:AddTags action

Якщо ж ми хочемо дозволити взагалі всі операції з кластером — то «Resource» задаємо як «arn:aws:es:us-east-1:492***148:domain/test», і тоді можемо додати теги.

Всі API actions див. в Actions, resources, and condition keys for Amazon OpenSearch Service.

Fine-grained access control

Документація — Fine-grained access control in Amazon OpenSearch Service.

Основна ідея дуже схожа з Kubernetes RBAC.

В OpenSearch маємо три основних концепти:

  • users — як Kubernetes Users та ServiceAccounts
  • roles — як Kubernetes RBAC Roles
  • mappings — як Kubernetes Role Bindings

Юзери можуть бути як з AWS IAM, так і з внутрішньої бази OpenSearch.

Як і в Kubernetes, в OpenSearch є набір дефолтних ролей — див. Predefined roles.

При цьому ролі, як і в Kubernetes, можуть бути cluster-wide або index-specific — аналог ClusterRoleBinding та просто namespaced RoleBinding в Kubernetes, плюс в OpenSearch FGAC можна додатково мати document level або field level permissions.

Налаштування Fine-grained access control

Важливий момент: після включення FGAC не можна буде повернутись на стару схему. Але всі доступи з IAM залишаться, навіть якщо переключитись на internal database.

Редагуємо «Security configuration», вмикаємо «Fine-grained access control»:

Спершу тут нам треба задати Master user, якого можна вказати з IAM — або створити локально в OpenSearch.

Якщо ми створюємо юзера через опцію «Create master user» — то вказуємо звичайний логін:пароль, і в такому випадку OpenSearch підключить internal user database (internal_user_database_enabled в Terraform).

Якщо використовуємо внутрішню базу OpenSearch — то можемо мати звичайних юзерів і виконувати HTTP basic authentication, див. документацію AWS — Tutorial: Configure a domain with the internal user database and HTTP basic authentication та Defining users and roles в документації самого OpenSearch, бо це вже його внутрішні механізми.

Має сенс, якщо не хочеться крутити Cognito чи SAML, і якщо налаштування юзерів у кожного кластеру будуть власні.

Якщо задавати IAM-юзера, то схема буде схожою з AIM аутентифікацією для RDS і IAM database authentication — доступ до кластеру контролюється AWS IAM, але внутрішні першмішени до схем та баз — ролями PostgreSQL чи MariaDB, див. AWS: RDS з IAM database authentication, EKS Pod Identities та Terraform.

Тобто в такому випадку AWS IAM буде виконувати виключно аутентифікацію юзера, а авторизація (перевірка прав доступу) вже через Security plugin та ролі самого OpenSearch.

Спробуємо локальну базу, і, думаю, в Production ми теж візьмемо цю схему:

«Access Policy» можемо залишити як є:

Переключення на internal database займе час, бо викличе blue/green deployment нового кластеру — див. Making configuration changes in Amazon OpenSearch Service.

І зайняло це прям багато часу — більше години, при тому, що в кластері нема ніяких наших даних.

Після того як зміни застосовані — в Dashboards у нас тепер буде просити логін і пароль, використовуємо нашого Master user:

Master user отримує дві підключені ролі — all_access та security_manager.

І саме security_manager дає доступ до розділу Security та Users в дашборді:

При цьому у нас залишається доступ наших AIM-юзерів, і ми можемо далі використовувати curl: IAM users будуть мапитись на роль default_role, яка дозволяє виконувати GET/PUT на всі індекси — див. About the default_role.

Перевіряємо доступ нашого тестового юзера зараз:

$ curl --aws-sigv4 "aws:amz:us-east-1:es" --user "AKI***YUK:fXV***34I" https://search-test-***.us-east-1.es.amazonaws.com/_cluster/health?pretty
{
"cluster_name" : "492***148:test",
"status" : "green",
"timed_out" : false,
"number_of_nodes" : 2,
...

А тепер поріжемо доступи всім IAM-юзерам.

Створення OpenSearch Role

Аби подивитись, як воно працює — додамо тестовий індекс і замапимо нашого тестового юзера з доступом до цього індексу.

Додаємо індекс:

Переходимо в Securty > Roles, додаємо роль:

Задаємо Index permissions — повний доступ на індекс (crud):

Далі в цій ролі переходимо до Mapped users > Map users:

І додаємо ARN нашого тестового юзера:

Видаляємо дефолтну роль:

Тепер наш юзер не має доступ до GET _cluster/health — тут отримуємо помилку 403, no permissions:

$ curl --aws-sigv4 "aws:amz:us-east-1:es" --user "AKI***YUK:fXV***34I" https://search-test-***.us-east-1.es.amazonaws.com/_cluster/health?pretty
{
"error" : {
...
"type" : "security_exception",
"reason" : "no permissions for [cluster:monitor/health] and User [name=arn:aws:iam::492***148:user/test-opesearch-identity-based-policy, backend_roles=[], requestedTenant=null]"
},
"status" : 403
}

Але має доступ до тестового індексу:

$ curl --aws-sigv4 "aws:amz:us-east-1:es" --user "AKI***YUK:fXV***34I" https://search-test-***.us-east-1.es.amazonaws.com/test-allowed-index/_search?pretty -d '{
"query": {
"match_all": {}
}
}' -H 'Content-Type: application/json'
{
"took" : 78,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 0,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
}
}

Готово.

👍ПодобаєтьсяСподобалось6
До обраногоВ обраному3
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Підписатись на коментарі