AWS: IAM Access Analyzer policy generation – створення IAM Policy

Автор |  24/07/2024
 

Доволі частий кейс, коли на новому проекті, який тільки створює свою інфраструктуру і CI/CD, робиться це як MVP/PoC, і на початку на тюнінг AWS IAM Roles та IAM Policies час не витрачається, а просто підключається AdministratorAccess.

Власне, саме так відбувалось і в моєму проекті, але ми ростемо, і прийшов час навести лад в IAM.

Проблема і задача

Отже, маємо GitHub Actions джоби, які деплоять інфрастуктуру з Terraform.

Для доступу до AWS з GitHub використовується Identity Provider з IAM Role: GitHub Actions Worker при старті джоби виконує аутентифікацію та авторизацію в AWS з заданою IAM Role, і потім запускає власне деплой з Terraform.

Для IAM Role зараз підключена політика AdministratorAccess, і наша задача – написати нову fine grained політику, де б не було зайвих доступів.

Варіант перший – це створити пусту політику, підключити її до ролі замість AdministratorAccess, і раз за разом запускати джобу дивлячись на помилки в логах:

AWS: IAM Access Analyzer policy generation - створення IAM Policy

А потім по черзі додавати дозволи, наприклад lambda:ListVersionsByFunction.

Варіант другий – це використати IAM Access Analyzer policy generation:

AWS: IAM Access Analyzer policy generation - створення IAM Policy

Він використає CloudTrail events для конкретної ролі та створить IAM Policy в якій будуть тільки ті API-виклики, які дійсно робились цією роллю.

Окрім IAM Access Analyzer є цікава тулза iann0036/iamlive, але в нашому випадку вона не дуже підходить, бо IAM Role використовується в GitHub Actions з AWS Indetity Provider.

Давайте глянемо, як налаштувати IAM Access Analyzer policy generation – створимо CloudTrail, IAM Role, напишемо Terraform-код який буде створювати ресурси, а потім перевіримо які політики нам запропонує  Access Analyzer.

Створення CloudTrail Trail

Перше, що нам буде потрібно – це створити CloudTrail Trail, який буде логувати дії. Детальніше про CloudTrail писав в AWS: CloudTrail – обзор и интеграция с CloudWatch и Opsgenie, але зараз нам цікаві тільки типи івентів, які він вміє записувати:

  • Management events: все, що стосується змін в ресурсах – створення EC2, VPC, зміни в SecurtyGroups тощо
  • Data events: все, що стосується даних – створення об’єктів в S3-бакетах, зміни в таблицях DynamoDB, виклики Lambda-функцій

Отже, якщо наш Terraform-код займається тільки створенням ресурсів в AWS – то має вистачити Management events, якщо ж він додатково виконує якісь дії з даними/об’єктами – то потрібні обидва. Можна включити всі, але майте на увазі, що CloudTrail trails не безкоштовний – див. AWS CloudTrail pricing.

Переходимо в CloudTrail > Trails, створюємо новий Trail:

AWS: IAM Access Analyzer policy generation - створення IAM Policy

Включаємо логування обох типів – просто для перевірки, в цьому випадку точно вистачило б тільки Management events:

AWS: IAM Access Analyzer policy generation - створення IAM Policy

Для Data events вибираємо які саме сервіси будемо логувати:

AWS: IAM Access Analyzer policy generation - створення IAM Policy

Переходимо до IAM.

Створення IAM Role

Додаємо нову роль з Trusted entity type == AWS Account, бо зараз тестувати будемо локально з AWS CLI від свого IAM-юзера, а не через GitHub OIDC Identity Provider:

AWS: IAM Access Analyzer policy generation - створення IAM Policy

Підключаємо AdministratorAccess:

AWS: IAM Access Analyzer policy generation - створення IAM Policy

Зберігаємо цю роль:

AWS: IAM Access Analyzer policy generation - створення IAM Policy

Налаштування AWS CLI

Тестити будемо локально, але імітуємо роботу GitHub Actions.

Що нам треба – це створити AWS CLI Profile, який буде виконувати AssumeRole, яку ми створили, а потім з цим профайлом Terraform буде створювати ресурси в AWS.

В файлі ~/.aws/config додаємо новий профайл:

[profile iam-test]
region = us-east-1
role_arn = arn:aws:iam::492***148:role/iam-generator-test-TO-DEL
source_profile = work

source_profile = work тут – це мій робочий профайл, в якому задані Access та Secrets keys.

Перевіряємо, чи працює IAM Role Assume:

$ aws --profile iam-test s3 ls
2023-02-01 13:29:34 amplify-staging-112927-deployment
2023-02-02 17:40:56 amplify-dev-174045-deployment
...

Окей – корзини бачимо, доступ працює.

Створення Terraform

Напишемо простий код, який буде створювати S3 бакет використовуючи створений вище IAM CLI Profile iam-test (пам’ятаємо, що ім’я бакету має бути унікальним для заданого AWS Region, інакше AWS спробує створити корзину в іншому регіоні):

provider "aws" {
  region = "us-east-1"
  profile = "iam-test"
}

resource "aws_s3_bucket" "my_bucket" {
  bucket = "blablabla-bucket-iam-test-to-del"

  force_destroy = true
}

Робимо terraform init та terraform plan:

AWS: IAM Access Analyzer policy generation - створення IAM Policy

І запускаємо terraform apply:

...
aws_s3_bucket.my_bucket: Creating...
aws_s3_bucket.my_bucket: Creation complete after 3s [id=blablabla-bucket-iam-test-to-del]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Використання IAM Access Analyzer policy generation

Краще зачекати хвилин 5 після запуску Terraform, аби CloudTrail встиг записати всі події, а потім можемо згенерувати IAM Policy для цієї ролі:

AWS: IAM Access Analyzer policy generation - створення IAM Policy

Вибираємо період, регіон та створений раніше Trail:

AWS: IAM Access Analyzer policy generation - створення IAM Policy

Чекаємо 5-10 хвилин, поки проаналізуються логи CloudTrail (можна перезавантажувати сторінку з F5, бо іноді Status сам не оновлюється):

AWS: IAM Access Analyzer policy generation - створення IAM Policy

І дивимось які політики нам пропонуються:

AWS: IAM Access Analyzer policy generation - створення IAM Policy

AWS: IAM Access Analyzer policy generation - створення IAM Policy

Ціла купа, і основна для нашого тесту – s3:CreateBucket.

Клікаємо Next, і маємо саму політику в JSON:

AWS: IAM Access Analyzer policy generation - створення IAM Policy

Зверніть увагу, що Access Analyzer створив окремі правила на API-виклики, які стосуються всіх бакетів – s3:ListAllMyBuckets, і окремі правила для викликів, які стосуються конкретного бакету/бакетів – s3:CreateBucket.

При цьому в Resource використовується ${BucketName}, який ми можемо замінити на своє значення:

AWS: IAM Access Analyzer policy generation - створення IAM Policy

Зберігаємо та підключаємо цю політику:

AWS: IAM Access Analyzer policy generation - створення IAM Policy

AWS: IAM Access Analyzer policy generation - створення IAM Policy

І тепер можемо відключити AdministratorAccess.

Але маємо на увазі, що ми виконували тільки створення ресурсів і, відповідно, виконувались API-виклики пов’язані тільки зі створенням корзини.

Тобто, якщо ми зараз приберемо AdministratorAccess і залишимо тільки цю нову політику – то виконати terraform destroy не зможемо, бо, по-перше – у нас нема права на s3:DeleteBucket, по-друге – при видаленні корзини AWS має перевірити чи нема в ній об’єктів, а для цього виконується операція s3:ListBucket – тому отримаємо помилку operation error S3: HeadBucket:

AWS: IAM Access Analyzer policy generation - створення IAM Policy

Тож треба виконати всі дії з Terraform, а вже після цього генерувати політику:

AWS: IAM Access Analyzer policy generation - створення IAM Policy

І потім відключати AdministratorAccess. Але навіть в такому випадку s3:ListBucket (для S3: HeadBucket) треба додавати вручну.

Хоча це вже проблема більш специфічна саме до S3, але може бути подібна і з іншими ресурсами.