В попередній частині – 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 – див. Terraform: створення AWS OpenSearch Service cluster та юзерів.
Зміст
Ручне створення кластера в 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)
- Resource-based policies: політики, які описуються безпосередньо в налаштуваннях самого кластеру
- Identity-based policies: якщо Resource-based policies є частиною налаштувань security-політик кластера – то Identity-based policies є звичайними AWS IAM Policies, які додаються конкретному юзеру чи ролі
- Domain Access 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 буде таким:
- AWS API отримує запит від юзера, наприклад
es:ESHttpGet- AWS IAM виконує аутентифікацію – перевіряє ACCESS:SECRET ключі або Session token
- AWS IAM виконує авторизацію:
- перевіряє IAM Policy юзера (Identity-based policy), якщо тут є явний дозвіл – пропускаємо
- перевіряє Domain Access Policy (Resource-based policy) кластеру, якщо тут явний дозвіл – пропускаємо
- запит приходить до самого OpenSearch
- якщо Fine-grained access control не включений – дозволяємо
- якщо є налаштований 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" : [ ]
}
}
Готово.






























