TL;DR

  • Используйте API ValidatePolicy AWS IAM Access Analyzer в CI/CD для обнаружения чрезмерно разрешающих политик до деплоя—это бесплатно и обнаруживает грамматические ошибки плюс нарушения лучших практик
  • Комбинируйте статический анализ (Checkov) с симуляцией политик (IAM Policy Simulator) для полного покрытия—статический обнаруживает паттерны, симуляция обнаруживает runtime поведение
  • Cross-cloud IAM тестирование требует разных инструментов: AWS Access Analyzer, Azure Policy Insights, GCP Policy Analyzer имеют уникальные возможности

Идеально для: Команд, управляющих IAM политиками в IaC, которым нужно предотвратить эскалацию привилегий и обеспечить минимальные привилегии Не подходит если: Вы используете managed identity сервисы, где политики абстрагированы (например, AWS SSO с готовыми permission sets) Время чтения: 14 минут

Чрезмерно разрешающие IAM политики остаются одной из главных причин облачных breaches. Один "Resource": "*" или отсутствующее условие может раскрыть всю вашу AWS учётную запись. Исследования показывают, что 82% облачных misconfigurations происходят из-за человеческих ошибок—делая автоматизированное тестирование IAM политик необходимым, а не опциональным.

Для более широкого контекста тестирования инфраструктуры, смотрите Тестирование Policy as Code и Тестирование Compliance для IaC.

Подходы с Использованием ИИ

Инструменты ИИ отлично справляются с анализом сложных IAM политик и генерацией комплексных тестовых наборов.

Анализ IAM политик на чрезмерные разрешения:

Проанализируй эту AWS IAM политику на проблемы безопасности:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:*"],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": ["iam:PassRole"],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": ["ec2:*"],
      "Resource": "*",
      "Condition": {
        "StringEquals": {"ec2:Region": "us-east-1"}
      }
    }
  ]
}

Определи: Риски эскалации привилегий, чрезмерно широкие разрешения,
отсутствующие условия, и предоставь альтернативу с минимальными
привилегиями для роли CI/CD пайплайна.

Генерация тест-кейсов для IAM политик:

Сгенерируй pytest тест-кейсы для валидации AWS IAM политик с использованием boto3:

1. Проверить, что никакие политики не разрешают iam:* или iam:PassRole к Resource "*"
2. Проверить, что S3 политики требуют условия шифрования
3. Убедиться, что никакие политики не разрешают assume-role к внешним аккаунтам без условий
4. Валидировать, что admin политики прикреплены только к break-glass ролям

Включи правильную настройку AWS сессии, парсинг документов политик и чёткие assertions.

Создание кастомных проверок Checkov:

Напиши кастомную проверку Checkov на Python, которая валидирует:

1. IAM политики не должны разрешать actions, заканчивающиеся на "*" (например, s3:*, ec2:*)
2. Все iam:PassRole statements должны иметь явные Resource ARNs
3. Политики с административными actions должны иметь MFA условия
4. Cross-account trust политики должны указывать явные account IDs

Включи класс проверки, логику оценки и поддерживаемые типы ресурсов.

Когда Использовать Разные Подходы к Тестированию

Фреймворк Принятия Решений по Стратегии Тестирования

Тип ТестаИнструментКогда ЗапускатьЧто Обнаруживает
Валидация грамматикиIAM Access AnalyzerPre-commit, CIСинтаксические ошибки, устаревшие элементы
Лучшие практикиAccess Analyzer ValidatePolicyCI пайплайнЧрезмерно разрешающие actions, отсутствующие условия
Статический анализCheckov, cfn-nagPre-commit, CIИзвестные плохие паттерны (Resource: “*”)
Симуляция политикIAM Policy SimulatorPre-deployРеальное поведение разрешений
Анализ доступаНаходки Access AnalyzerНепрерывноВнешний доступ, неиспользуемые разрешения
Кастомные правилаOPA/RegoCI пайплайнСпецифичные требования организации

Критические Проверки IAM Политик

Check IDОписаниеУровень Риска
CKV_AWS_1IAM политики не должны разрешать полные административные привилегии “*”Критический
CKV_AWS_49IAM политики не должны разрешать PassRole к “*”Критический
CKV_AWS_40IAM политики не должны разрешать эскалацию привилегийКритический
CKV_AWS_62IAM политики не должны иметь пустой SIDНизкий
CKV_AWS_109IAM политики не должны разрешать раскрытие credentialsВысокий
CKV_AWS_110IAM политики не должны разрешать управление разрешениями без ограниченийВысокий

Тестирование AWS IAM Политик

Валидация Политик с IAM Access Analyzer

# Установка Terraform IAM Policy Validator
pip install tf-policy-validator

# Валидация Terraform шаблона
tf-policy-validator validate \
  --template-path ./terraform \
  --region us-east-1

# Запуск конкретных проверок
tf-policy-validator validate \
  --template-path ./terraform \
  --region us-east-1 \
  --check-type VALIDATE_POLICY \
  --check-type CHECK_NO_NEW_ACCESS

Интеграция с GitHub Actions

name: Валидация IAM Политик

on:
  pull_request:
    paths:

      - 'terraform/**/*.tf'
      - 'cloudformation/**/*.yaml'

jobs:
  validate-iam-policies:
    runs-on: ubuntu-latest
    steps:

      - uses: actions/checkout@v4

      - name: Настройка AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-east-1

      - name: Валидация Terraform IAM Политик
        uses: aws-actions/terraform-aws-iam-policy-validator@v1
        with:
          template-path: terraform/
          region: us-east-1
          check-no-new-access: true
          check-access-not-granted: true
          check-no-public-access: true

      - name: Запуск Checkov
        uses: bridgecrewio/checkov-action@v12
        with:
          directory: terraform/
          check: CKV_AWS_1,CKV_AWS_40,CKV_AWS_49,CKV_AWS_109,CKV_AWS_110
          framework: terraform

Checkov для IAM Политик

# Установка Checkov
pip install checkov

# Сканирование на IAM-специфичные проблемы
checkov -d ./terraform --check CKV_AWS_1,CKV_AWS_40,CKV_AWS_49

# Вывод в JUnit для CI
checkov -d ./terraform --framework terraform \
  --check CKV_AWS_1,CKV_AWS_40,CKV_AWS_49,CKV_AWS_109,CKV_AWS_110 \
  --output junitxml > iam-checkov-results.xml

Кастомная Проверка Checkov

# custom_checks/iam_no_passrole_star.py
from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck
from checkov.common.models.enums import CheckResult, CheckCategories
import json

class IAMNoPassRoleStar(BaseResourceCheck):
    def __init__(self):
        name = "Убедиться, что IAM политики не разрешают PassRole ко всем ресурсам"
        id = "CKV_CUSTOM_IAM_1"
        supported_resources = ['aws_iam_policy', 'aws_iam_role_policy']
        categories = [CheckCategories.IAM]
        super().__init__(name=name, id=id, categories=categories,
                        supported_resources=supported_resources)

    def scan_resource_conf(self, conf):
        policy = conf.get('policy', [None])[0]
        if not policy:
            return CheckResult.UNKNOWN

        # Обработка форматов string и dict
        if isinstance(policy, str):
            try:
                policy = json.loads(policy)
            except json.JSONDecodeError:
                return CheckResult.UNKNOWN

        statements = policy.get('Statement', [])
        for statement in statements:
            if statement.get('Effect') != 'Allow':
                continue

            actions = statement.get('Action', [])
            if isinstance(actions, str):
                actions = [actions]

            resources = statement.get('Resource', [])
            if isinstance(resources, str):
                resources = [resources]

            # Проверка на PassRole с ресурсом *
            has_passrole = any('PassRole' in action for action in actions)
            has_star_resource = '*' in resources

            if has_passrole and has_star_resource:
                return CheckResult.FAILED

        return CheckResult.PASSED

check = IAMNoPassRoleStar()

Тестирование Политик на Python с boto3

import boto3
import json
import pytest

class TestIAMPolicies:
    @pytest.fixture
    def iam_client(self):
        return boto3.client('iam')

    @pytest.fixture
    def access_analyzer_client(self):
        return boto3.client('accessanalyzer')

    def test_no_admin_star_policies(self, iam_client):
        """Проверить, что никакие политики не дают полный admin доступ."""
        paginator = iam_client.get_paginator('list_policies')

        for page in paginator.paginate(Scope='Local'):
            for policy in page['Policies']:
                version = iam_client.get_policy_version(
                    PolicyArn=policy['Arn'],
                    VersionId=policy['DefaultVersionId']
                )

                document = version['PolicyVersion']['Document']
                statements = document.get('Statement', [])

                for stmt in statements:
                    if stmt.get('Effect') != 'Allow':
                        continue

                    actions = stmt.get('Action', [])
                    if isinstance(actions, str):
                        actions = [actions]

                    resources = stmt.get('Resource', [])
                    if isinstance(resources, str):
                        resources = [resources]

                    # Ошибка если Action: "*" и Resource: "*"
                    assert not (
                        '*' in actions and '*' in resources
                    ), f"Политика {policy['PolicyName']} имеет admin привилегии"

    def test_validate_policy_with_access_analyzer(self, access_analyzer_client):
        """Использовать Access Analyzer для валидации политики."""
        policy_document = {
            "Version": "2012-10-17",
            "Statement": [{
                "Effect": "Allow",
                "Action": ["s3:GetObject"],
                "Resource": "arn:aws:s3:::my-bucket/*"
            }]
        }

        response = access_analyzer_client.validate_policy(
            policyDocument=json.dumps(policy_document),
            policyType='IDENTITY_POLICY'
        )

        # Проверка на ошибки и предупреждения безопасности
        findings = response.get('findings', [])
        errors = [f for f in findings if f['findingType'] == 'ERROR']
        security_warnings = [f for f in findings
                           if f['findingType'] == 'SECURITY_WARNING']

        assert len(errors) == 0, f"Ошибки валидации политики: {errors}"
        assert len(security_warnings) == 0, f"Предупреждения безопасности: {security_warnings}"

Тестирование с IAM Policy Simulator

def test_policy_denies_unauthorized_actions(iam_client):
    """Симулировать политику для проверки запрещённых действий."""
    # Проверить, что роль разработчика не может получить доступ к production
    response = iam_client.simulate_principal_policy(
        PolicySourceArn='arn:aws:iam::123456789012:role/DeveloperRole',
        ActionNames=[
            'ec2:TerminateInstances',
            's3:DeleteBucket',
            'iam:CreateUser'
        ],
        ResourceArns=[
            'arn:aws:ec2:us-east-1:123456789012:instance/*',
            'arn:aws:s3:::production-*',
            'arn:aws:iam::123456789012:user/*'
        ]
    )

    for result in response['EvaluationResults']:
        assert result['EvalDecision'] == 'implicitDeny', \
            f"Роль разработчика не должна иметь разрешение {result['EvalActionName']}"

def test_policy_allows_required_actions(iam_client):
    """Проверить, что роль имеет необходимые разрешения."""
    response = iam_client.simulate_principal_policy(
        PolicySourceArn='arn:aws:iam::123456789012:role/CICDRole',
        ActionNames=[
            's3:PutObject',
            'ecr:PushImage',
            'ecs:UpdateService'
        ],
        ResourceArns=[
            'arn:aws:s3:::deployment-artifacts/*',
            'arn:aws:ecr:us-east-1:123456789012:repository/my-app',
            'arn:aws:ecs:us-east-1:123456789012:service/my-cluster/my-service'
        ]
    )

    for result in response['EvaluationResults']:
        assert result['EvalDecision'] == 'allowed', \
            f"CICD роль без требуемого разрешения: {result['EvalActionName']}"

Тестирование Azure IAM

Azure Policy для Валидации RBAC

# Список кастомных определений ролей
az role definition list --custom-role-only true --output table

# Проверка назначений ролей
az role assignment list --scope /subscriptions/<sub-id> --output table

# Валидация с Azure Policy
az policy assignment list --query "[?policyDefinitionId contains 'rbac']"

InSpec для Azure RBAC

control 'azure-no-owner-custom-roles' do
  impact 1.0
  title 'Кастомные роли не должны иметь разрешений эквивалентных Owner'

  azure_role_definitions.where(role_type: 'CustomRole').ids.each do |role_id|
    describe azure_role_definition(name: role_id) do
      its('permissions.first.actions') { should_not include '*' }
      its('permissions.first.not_actions') { should_not be_empty }
    end
  end
end

control 'azure-no-subscription-owner-assignments' do
  impact 1.0
  title 'Роль Owner не должна назначаться на уровне подписки'

  describe azure_role_assignments.where(
    scope: "/subscriptions/#{input('subscription_id')}",
    role_name: 'Owner'
  ) do
    its('count') { should be <= 2 }  # Разрешить только break-glass аккаунты
  end
end

Тестирование GCP IAM

GCP Policy Analyzer

# Анализ IAM политики проекта
gcloud policy-intelligence analyze-iam-policy \
  --project=my-project \
  --full-resource-name="//cloudresourcemanager.googleapis.com/projects/my-project"

# Проверка на чрезмерно разрешающие bindings
gcloud projects get-iam-policy my-project --format=json | \
  jq '.bindings[] | select(.members[] | contains("allUsers") or contains("allAuthenticatedUsers"))'

Terraform Валидация для GCP IAM

# variables.tf - Определение разрешённых ролей
variable "allowed_project_roles" {
  type = list(string)
  default = [
    "roles/viewer",
    "roles/editor",
    # Явно перечислить разрешённые роли
  ]
}

# Валидация в ресурсе
resource "google_project_iam_binding" "binding" {
  project = var.project_id
  role    = var.role
  members = var.members

  lifecycle {
    precondition {
      condition     = contains(var.allowed_project_roles, var.role)
      error_message = "Роль ${var.role} не в списке разрешённых ролей."
    }

    precondition {
      condition     = !contains(var.members, "allUsers") && !contains(var.members, "allAuthenticatedUsers")
      error_message = "Публичные IAM bindings (allUsers/allAuthenticatedUsers) не разрешены."
    }
  }
}

Интеграция CI/CD

Полный Workflow GitHub Actions

name: Безопасность IAM Политик

on:
  pull_request:
    paths:

      - 'terraform/iam/**'
      - 'policies/**'

jobs:
  static-analysis:
    runs-on: ubuntu-latest
    steps:

      - uses: actions/checkout@v4

      - name: Запуск IAM проверок Checkov
        uses: bridgecrewio/checkov-action@v12
        with:
          directory: terraform/iam/
          check: CKV_AWS_1,CKV_AWS_40,CKV_AWS_49,CKV_AWS_109,CKV_AWS_110
          output_format: sarif
          output_file_path: checkov-iam.sarif

      - name: Загрузка SARIF
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: checkov-iam.sarif

  access-analyzer:
    runs-on: ubuntu-latest
    needs: static-analysis
    steps:

      - uses: actions/checkout@v4

      - name: Настройка AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
          aws-region: us-east-1

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v3

      - name: Terraform Init
        run: terraform init
        working-directory: terraform/iam/

      - name: Валидация с Access Analyzer
        uses: aws-actions/terraform-aws-iam-policy-validator@v1
        with:
          template-path: terraform/iam/
          region: us-east-1
          check-no-new-access: true

  policy-simulation:
    runs-on: ubuntu-latest
    needs: access-analyzer
    if: github.event.pull_request.draft == false
    steps:

      - uses: actions/checkout@v4

      - name: Настройка AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
          aws-region: us-east-1

      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'

      - name: Установка зависимостей
        run: pip install boto3 pytest

      - name: Запуск тестов симуляции политик
        run: pytest tests/iam/ -v --tb=short

Измерение Успеха

МетрикаДо ТестированияПосле ТестированияКак Отслеживать
Чрезмерно разрешающие политикиНайдены на аудитах0 в productionОтчёты Checkov
Пути эскалации привилегийНеизвестны0 обнаруженоНаходки Access Analyzer
Время валидации политикРучная проверка (часы)Автоматизировано (минуты)Метрики CI/CD
Неиспользуемые разрешенияНакапливаются со временемКвартальная очисткаAccess Analyzer

Сигналы, что ваше IAM тестирование не работает:

  • Checkov проходит, но находки Access Analyzer в production
  • “Экстренные” изменения политик обходят CI/CD
  • Роли накапливают разрешения со временем
  • Service accounts с admin привилегиями

Заключение

Эффективное тестирование IAM политик требует нескольких уровней валидации:

  1. Статический анализ (Checkov) обнаруживает известные плохие паттерны в коде
  2. Валидация грамматики (Access Analyzer ValidatePolicy) обеспечивает синтаксис и структуру политик
  3. Симуляция политик (IAM Policy Simulator) проверяет реальное поведение разрешений
  4. Непрерывный анализ (находки Access Analyzer) обнаруживает drift и неиспользуемые разрешения

Ключевая идея: IAM политики слишком критичны для только ручной проверки. Автоматизированное тестирование в CI/CD пайплайнах обнаруживает проблемы до достижения production, а непрерывный мониторинг обнаруживает drift политик со временем.

Смотрите также

Официальные ресурсы