Если вам надо выдать доступ к ресурсам аккаунта AWS, вы можете это сделать с помощью создания отдельной учетки. Но в таком случае будут выданы статичные логин и пароль, которые по-хорошему надо будет иногда менять, а также заботиться о их сохранности. Гораздо более безопасный вариант – создание отдельной роли в целевом аккаунте и выдача разрешения AssumRole для роли из другого аккаунта (cross-account access). Технически это более запутанная операция, а потому требует пояснений, в том числе когда речь заходит об официальных статьях.
AWS cross-account access
Сегодня хочу рассказать о небольшом опыте, который получил, когда возился с предоставлением cross-account доступа по статье Enabling cross-account access to Amazon EKS cluster resources.
Задача
Имеется EKS-кластер – source account – с развернутым в нем cloudwatch_exporter. Требуется делегировать экспортеру доступ на чтение метрик CloudWatch в другом аккаунте – target account. Для наглядности предположим следующее:
source account id: 111111111111
target account id: 222222222222
Пояснения
В пункте №3 инструкции после политики AssumeRole сразу ниже найдете приписку:
Once the role is created, attach the IAM policy that you want to associate with the serviceaccount
В этой IAM policy должны предоставляться права из source account (политику надо создавать именно в нем) до роли в target account. Сама политика при этом в terraform может выглядеть так (пример также доступен в пункте 3 в статье):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
resource "aws_iam_policy" "allow_cw_access_to_target_account" { name = "AllowCWAccessToTargetAccount" policy = <<-EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "sts:AssumeRole", "Resource": "arn:aws:iam::222222222222:role/AllowCloudWatchROFromSourceAccount" } ] } EOF } |
Все в том же пункте 3 статьи заметка:
Note that if you haven’t created the target account IAM role, please proceed to step 4 and complete configuring the target AWS account and then finish associating this policy.
Но она бесполезна, потому что создать в целевом аккаунте роль AWS вам не позволит. А все потому, что в этой роли придется прописывать Assume policy, в которой должен быть в явном виде указан принципал безопасности и AWS проверяет факт его существования. В нашем случае им является имя роли (AllowCWAccessToTargetAccount) в source account.
А вот создать роль в source account с указанием фейкового ресурса вполне себе получится. Поэтому смело игнорируем заметки в пункте 3 и спокойно его выполняем полностью. В крайнем случае потом измените имя ресурса дополнительным коммитом в свой репозиторий. Либо вообще пока не создавайте политику, докиньте её позже.
Итак, пункт 3 вы выполнили и теперь у вас есть роль с arn arn:aws:iam::111111111111:role/AllowCWAccessToTargetAccount. Самое время переходить к пункту 4, в котором нужно проделать следующее. Внутри target account создаем политику с разрешениями для R/O доступа до CloudWatch. Далее создаем роль и в Assume policy у нее вписываем arn роли из source account (см. выше arn). Разумеется после этого подключаем политику к роли. Вот так это может выглядеть в terraform:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
resource "aws_iam_role" "allow_cw_access_from_source_account" { name = "AllowCloudWatchROFromSourceAccount" assume_role_policy = <<-EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::111111111111:role/AllowCWAccessToTargetAccount" }, "Action": "sts:AssumeRole" } ] } EOF } resource "aws_iam_policy" "cloudwatch_read_only" { name = "CloudWatchRO" # https://github.com/prometheus/cloudwatch_exporter#credentials-and-permissions policy = <<-EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "tag:GetResources", "cloudwatch:GetMetricStatistics", "cloudwatch:ListMetrics" ], "Resource": "*" } ] } EOF } resource "aws_iam_role_policy_attachment" "cloudwatch_read_only" { policy_arn = aws_iam_policy.cloudwatch_read_only.arn role = aws_iam_role.allow_cw_access_from_source_account.name } |
На всякий случай делаем output с arn роли, чтобы подправить её в source account:
1 2 3 |
output "cloudwatch_role_arn" { value = aws_iam_role.allow_cw_access_from_source_account.arn } |
Применяйте изменения.
Если вы не стали создавать политику в source account или засунули в неё фейковый ресурс, то самое время сейчас это исправить, потому что arn этой роли вы получили на предыдущем пункте.
Сама же конфигурация cloudwatch_exporter может выглядеть так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
--- delay_seconds: 0 range_seconds: 300 role_arn: arn:aws:iam::222222222222:role/AllowCloudWatchROFromSourceAccount metrics: - aws_namespace: AWS/RDS aws_metric_name: ReadLatency aws_dimensions: [DBInstanceIdentifier] aws_statistics: [Average] - aws_namespace: AWS/RDS aws_metric_name: WriteLatency aws_dimensions: [DBInstanceIdentifier] aws_statistics: [Average] - aws_namespace: AWS/RDS aws_metric_name: DiskQueueDepth aws_dimensions: [DBInstanceIdentifier] aws_statistics: [Average] |
Обратите внимание на role_arn – берется arn именно той роли, которая находится в целевом аккаунте (target account). Это становится возможно, потому что операцию assume role под выполняет с правами назначенной ему роли в исходном аккаунте (source account). Ну а между ролями существуют доверительные отношения. Вот и вся магия