Блог Amazon Web Services

Непрерывный мониторинг неиспользуемых ролей IAM с помощью AWS Config

Оригинал статьи: ссылка (Michael Chan, AWS Identity Developer Advocate и Roland AbiHanna, Sr. Solutions Architect)

Облачная разработка способствует итеративному подходу с частыми итерациями для развития ваших приложений и инфраструктуры. Такой же итеративный подход следует применять и к создаваемым вами ролям AWS Identity and Access Management (IAM). Периодическая проверка того, что все созданные вами роли IAM всё ещё используются, может снизить операционную сложность за счёт избавления от необходимости отслеживать неиспользуемые роли. Это также улучшает безопасность: идентификация неиспользуемых ролей помогает снизить вероятность ненадлежащего или непреднамеренного доступа к вашей критической инфраструктуре и рабочим нагрузкам.

IAM API предоставляет вам информацию о том, когда та или иная роль в последний раз использовалась для выполнения запроса к AWS API. В этом посте я продемонстрирую, как можно определить неактивные роли, используя время последнего использования ролей, и настроить непрерывный мониторинг активности ролей с помощью AWS Config.

Использованные сервисы и функциональность AWS

Это решение использует следующие сервисы и функциональность:

  • AWS IAM: Данный сервис позволяет безопасно управлять доступом к сервисам и ресурсам AWS. Он предоставляет API для получения времени последнего использования ролей IAM для выполнения запроса к AWS API, а также регион, в котором был сделан запрос.
  • AWS Config: Данный сервис позволяет непрерывно отслеживать и сохранять конфигурации ресурсов AWS. Он будет периодически запускать ваши AWS Config Rule (см. следующий пункт) и сохранять статус соответствия конфигурации ресурсов требованиям.
  • AWS Config Rule: Этот ресурс предоставляет возможность установить требуемые параметры конфигурации для конкретных ресурсов AWS или для всего аккаунта AWS. Далее, он проверит статус соответствия конфигурации ресурсов AWS требованиям. Вы можете задать правила, определяющие соответствие ролей требованиям. Они позволят вам пометить недавно использованные роли IAM как «соответствующие», а неактивные – как «несоответствующие».
  • AWS Lambda: Данный сервис позволяет выполнять программный код без создания серверов или управления ими. Функция Lambda будет использоваться для выполнения вызовов API для получения информации о времени последнего использования ролей и для проверки соответствия ролей требованиям AWS Config.
  • Amazon Simple Storage Service (Amazon S3): Это – высокодоступное и надёжное хранилище объектов. Вы будете использовать его для хранения исходного кода в zip-архиве для развёртывания функции Lambda.
  • AWS CloudFormation: Этот сервис предоставляет универсальный язык для описания и создания всех ресурсов облачной инфраструктуры AWS. Вы будете использовать его для создания всех ресурсов, описанных в этом решении.

Логика решения

Данное решение идентифицирует неиспользуемые роли IAM в вашем аккаунте. Для этого, вы будете использовать функцию AWS Lambda для проверки всех ролей IAM в вашем аккаунте. Сначала вы определите неиспользуемые роли, основываясь на установленном вами временном окне (число дней с момента последнего использования роли). В данном примере используется 60 дней, но этот параметр настраивается. Затем вы определите статус их соответствия требованиям на основе времени создания и информации о времени последнего использования. Наконец, вы отправите результаты в AWS Config, который сохранит статус соответствия или несоответствия каждой из ролей. Если роль не будет соответствовать требованиям, вы сможете принять меры по исправлению ситуации, например, запретить выполнение всех действий с использованием этой роли.

Необходимые условия

Это решение имеет следующие необходимые условия:

Архитектура решения

Изображение 1: Архитектура решения

Изображение 1: Архитектура решения

Как показано на диаграмме выше, AWS Config (1) проверяет AWS Config Rule с настраиваемой периодичностью (2), что, в свою очередь, запускает функцию Lambda (3). Функция Lambda запрашивает список всех ролей в аккаунте AWS и определяет дату их создания, а также время последнего использования каждой роли, которые предоставляются через GetAccountAuthorizationDetails IAM API (4). После того, как функция Lambda проверит соответствие всех ваших ролей требованиям, она отправляет статус их соответствия требованиям в AWS Config (5). AWS Config сохраняет историю изменений статуса соответствия всех ролей, проанализированных AWS Config Rule, установленным требованиям. Также, если такая опция настроена, уведомления об изменении статуса соответствия требованиям могут быть отправлены в тему (topic) Amazon Simple Notification Service (Amazon SNS). Статус соответствия можно либо посмотреть в консоли управления AWS, либо получить его с помощью AWS CLI или AWS SDK.

Развёртывание решения

Ресурсы для этого решения создаются через шаблон AWS CloudFormation. Прежде чем развернуть решение в вашем аккаунте с помощью шаблона AWS CloudFormation, вам необходимо подготовить исходный код функции Lambda.

Шаг 1: Подготовка к развёртыванию функции Lambda

Для начала, запустите командную строку *nix (Linux, Mac или подсистема Windows для Linux). Выполните приведённые ниже команды, чтобы создать пустую папку с именем iam-role-last-used, в которую вы поместите исходный код Lambda.

mkdir iam-role-last-used
cd iam-role-last-used
touch lambda_function.py

Обратите внимание, что каталог, который вы создали, и код, который будет в нём содержаться, позднее будут сжаты в zip-архив командой AWS CLI cloudformation package. Эта команда также загрузит zip-архив с исходным кодом в ваш бакет S3. Позже, команда cloudformation deploy будет ссылаться на этот бакет S3 при развёртывании шаблона решения.

Теперь создайте слой Lambda с последней версией boto3 SDK. Это гарантирует, что ваша функция Lambda будет использовать последнюю версию boto3 SDK и позволит вам управлять зависимостями при её развёртывании. Это можно сделать, следуя шагам с 1 по 4 в этой инструкции. Обязательно запишите ARN-идентификатор созданного вами слоя Lambda, поскольку он вам понадобится позже.

Наконец, откройте файл lambda_function.py в текстовом редакторе или интегрированной среде разработки (IDE) и скопируйте следующий исходный код в файл lambda_function.py:

import boto3
from botocore.exceptions import ClientError
from botocore.config import Config
import datetime
import fnmatch
import json
import os
import re
import logging


logger = logging.getLogger()
logging.basicConfig(
    format="[%(asctime)s] %(levelname)s [%(module)s.%(funcName)s:%(lineno)d] %(message)s", datefmt="%H:%M:%S"
)
logger.setLevel(os.getenv('log_level', logging.INFO))

# Configure boto retries
BOTO_CONFIG = Config(retries=dict(max_attempts=5))

# Define the default resource to report to Config Rules
DEFAULT_RESOURCE_TYPE = 'AWS::IAM::Role'

CONFIG_ROLE_TIMEOUT_SECONDS = 900

# Set to True to get the lambda to assume the Role attached on the Config service (useful for cross-account).
ASSUME_ROLE_MODE = False

# Evaluation strings for Config evaluations
COMPLIANT = 'COMPLIANT'
NON_COMPLIANT = 'NON_COMPLIANT'


# This gets the client after assuming the Config service role either in the same AWS account or cross-account.
def get_client(service, execution_role_arn):
    if not ASSUME_ROLE_MODE:
        return boto3.client(service)
    credentials = get_assume_role_credentials(execution_role_arn)
    return boto3.client(service, aws_access_key_id=credentials['AccessKeyId'],
                        aws_secret_access_key=credentials['SecretAccessKey'],
                        aws_session_token=credentials['SessionToken'],
                        config=BOTO_CONFIG
                        )


def get_assume_role_credentials(execution_role_arn):
    sts_client = boto3.client('sts')
    try:
        assume_role_response = sts_client.assume_role(RoleArn=execution_role_arn,
                                                      RoleSessionName="configLambdaExecution",
                                                      DurationSeconds=CONFIG_ROLE_TIMEOUT_SECONDS)
        return assume_role_response['Credentials']
    except ClientError as ex:
        if 'AccessDenied' in ex.response['Error']['Code']:
            ex.response['Error']['Message'] = "AWS Config does not have permission to assume the IAM role."
        else:
            ex.response['Error']['Message'] = "InternalError"
            ex.response['Error']['Code'] = "InternalError"
        raise ex


# Validates role pathname whitelist as passed via AWS Config parameters and returns a list of comma separated patterns.
def validate_whitelist(unvalidated_role_pattern_whitelist):
    # Names of users, groups, roles must be alphanumeric, including the following common
    # characters: plus (+), equal (=), comma (,), period (.), at (@), underscore (_), and hyphen (-).

    if not unvalidated_role_pattern_whitelist:
        return None

    regex = re.compile('^[-a-zA-Z0-9+=,.@_/|*]+')
    if regex.search(unvalidated_role_pattern_whitelist):
        raise ValueError("[Error] Provided whitelist has invalid characters")

    return unvalidated_role_pattern_whitelist.split('|')


# This uses Unix filename pattern matching (as opposed to regular expressions), as documented here:
# https://docs.python.org/3.7/library/fnmatch.html.  Please note that if using a wildcard, e.g. "*", you should use
# it sparingly/appropriately.
# If the rolename matches the pattern, then it is whitelisted
def is_whitelisted_role(role_pathname, pattern_list):
    if not pattern_list:
        return False

    # If role_pathname matches pattern, then return True, else False
    # eg. /service-role/aws-codestar-service-role matches pattern /service-role/*
    # https://docs.python.org/3.7/library/fnmatch.html
    for pattern in pattern_list:
        if fnmatch.fnmatch(role_pathname, pattern):
            # whitelisted
            return True

    # not whitelisted
    return False


# Form an evaluation as a dictionary. Suited to report on scheduled rules.  More info here:
#   https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/config.html#ConfigService.Client.put_evaluations
def build_evaluation(resource_id, compliance_type, notification_creation_time, resource_type=DEFAULT_RESOURCE_TYPE, annotation=None):
    evaluation = {}
    if annotation:
        evaluation['Annotation'] = annotation
    evaluation['ComplianceResourceType'] = resource_type
    evaluation['ComplianceResourceId'] = resource_id
    evaluation['ComplianceType'] = compliance_type
    evaluation['OrderingTimestamp'] = notification_creation_time
    return evaluation


# Determine if any roles were used to make an AWS request
def determine_last_used(role_name, role_last_used, max_age_in_days, notification_creation_time):

    last_used_date = role_last_used.get('LastUsedDate', None)
    used_region = role_last_used.get('Region', None)

    if not last_used_date:
        compliance_result = NON_COMPLIANT
        reason = "No record of usage"
        logger.info(f"NON_COMPLIANT: {role_name} has never been used")
        return build_evaluation(role_name, compliance_result, notification_creation_time, resource_type=DEFAULT_RESOURCE_TYPE, annotation=reason)


    days_unused = (datetime.datetime.now() - last_used_date.replace(tzinfo=None)).days

    if days_unused > max_age_in_days:
        compliance_result = NON_COMPLIANT
        reason = f"Was used {days_unused} days ago in {used_region}"
        logger.info(f"NON_COMPLIANT: {role_name} has not been used for {days_unused} days, last use in {used_region}")
        return build_evaluation(role_name, compliance_result, notification_creation_time, resource_type=DEFAULT_RESOURCE_TYPE, annotation=reason)

    compliance_result = COMPLIANT
    reason = f"Was used {days_unused} days ago in {used_region}"
    logger.info(f"COMPLIANT: {role_name} used {days_unused} days ago in {used_region}")
    return build_evaluation(role_name, compliance_result, notification_creation_time, resource_type=DEFAULT_RESOURCE_TYPE, annotation=reason)


# Returns a list of docts, each of which has authorization details of each role.  More info here:
#   https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/iam.html#IAM.Client.get_account_authorization_details
def get_role_authorization_details(iam_client):

    roles_authorization_details = []
    roles_list = iam_client.get_account_authorization_details(Filter=['Role'])

    while True:
        roles_authorization_details += roles_list['RoleDetailList']
        if 'Marker' in roles_list:
            roles_list = iam_client.get_account_authorization_details(Filter=['Role'], MaxItems=100, Marker=roles_list['Marker'])
        else:
            break

    return roles_authorization_details


# Check the compliance of each role by determining if role last used is > than max_days_for_last_used
def evaluate_compliance(event, context):

    # Initialize our AWS clients
    iam_client = get_client('iam', event["executionRoleArn"])
    config_client = get_client('config', event["executionRoleArn"])

    # List of resource evaluations to return back to AWS Config
    evaluations = []

    # List of dicts of each role's authorization details as returned by boto3
    all_roles = get_role_authorization_details(iam_client)

    # Timestamp of when AWS Config triggered this evaluation
    notification_creation_time = str(json.loads(event['invokingEvent'])['notificationCreationTime'])

    # ruleParameters is received from AWS Config's user-defined parameters
    rule_parameters = json.loads(event["ruleParameters"])

    # Maximum allowed days that a role can be unused, or has been last used for an AWS request
    max_days_for_last_used = int(os.environ.get('max_days_for_last_used', '60'))
    if 'max_days_for_last_used' in rule_parameters:
        max_days_for_last_used = int(rule_parameters['max_days_for_last_used'])

    whitelisted_role_pattern_list = []
    if 'role_whitelist' in rule_parameters:
        whitelisted_role_pattern_list = validate_whitelist(rule_parameters['role_whitelist'])

    # Iterate over all our roles.  If the creation date of a role is <= max_days_for_last_used, it is compliant
    for role in all_roles:

        role_name = role['RoleName']
        role_path = role['Path']
        role_creation_date = role['CreateDate']
        role_last_used = role['RoleLastUsed']
        role_age_in_days = (datetime.datetime.now() - role_creation_date.replace(tzinfo=None)).days

        if is_whitelisted_role(role_path + role_name, whitelisted_role_pattern_list):
            compliance_result = COMPLIANT
            reason = "Role is whitelisted"
            evaluations.append(
                build_evaluation(role_name, compliance_result, notification_creation_time, resource_type=DEFAULT_RESOURCE_TYPE, annotation=reason))
            logger.info(f"COMPLIANT: {role} is whitelisted")
            continue

        if role_age_in_days <= max_days_for_last_used:
            compliance_result = COMPLIANT
            reason = f"Role age is {role_age_in_days} days"
            evaluations.append(
                build_evaluation(role_name, compliance_result, notification_creation_time, resource_type=DEFAULT_RESOURCE_TYPE, annotation=reason))
            logger.info(f"COMPLIANT: {role_name} - {role_age_in_days} is newer or equal to {max_days_for_last_used} days")
            continue

        evaluation_result = determine_last_used(role_name, role_last_used, max_days_for_last_used, notification_creation_time)
        evaluations.append(evaluation_result)

    # Iterate over our evaluations 100 at a time, as put_evaluations only accepts a max of 100 evals.
    evaluations_copy = evaluations[:]
    while evaluations_copy:
        config_client.put_evaluations(Evaluations=evaluations_copy[:100], ResultToken=event['resultToken'])
        del evaluations_copy[:100]

Рассмотрим, как работает вышеупомянутый код. AWS Config Rule запускает функцию Lambda, вызывая функцию evaluate_compliance(). Функция evaluate_compliance() делает следующее:

  1. Запрашивает информацию о всех ролях IAM с помощью GetAccountAuthorizationDetails API, как уже упоминалось ранее. Эта информация включает в себя дату создания каждой роли, а также время последнего её использования.
  2. Помечает роль как соответствующую требованиям, если имя роли соответствует одному из шаблонов из списка whitelisted_role_pattern_list. Этот список шаблонов передается в Config Rule через параметр конфигурации шаблона CloudFormation с именем RolePatternWhitelist. В разделе «Игнорируемые роли» ниже приведены инструкции о том, как это сделать.
  3. Помечает роль как соответствующую требованиям, если её возраст в днях (role_age_in_days) меньше или равен параметру MaxDaysForLastUsed (max_days_for_last_used). Это значение также передаётся через параметр конфигурации шаблона CloudFormation. Этот параметр используется для конфигурации временного интервала, в течение которого роль может быть неактивна.
  4. Если ни одно из вышеперечисленных условий не выполняется, то вызывается функция determine_last_used(), и роль помечается как несоответствующая требованиям, если значение параметра days_unused больше, чем значение параметра max_age_in_days.
  5. В конце, функция evaluate_compliance() вызывает функцию put_evaluations(), чтобы сохранить статус соответствия ролей требованиям в AWS Config.

Шаг 2: Развёртывание шаблона AWS CloudFormation

Далее, создайте файл для шаблона CloudFormation с названием iam-role-last-used.yml. Этот шаблон использует AWS Serverless Application Model (AWS SAM), которая является расширением CloudFormation. AWS SAM упрощает развёртывание и избавляет вас от необходимости вручную загружать zip-архив с исходным кодом функции Lambda в бакет Amazon S3. Чтобы убедиться, что при развёртывании шаблона zip-архив с исходным кодом будет найден, поместите этот файл рядом с созданным вами ранее каталогом iam-role-last-used. Затем скопируйте код, приведённый ниже, и сохраните его в файл iam-role-last-used.yml.

AWSTemplateFormatVersion: '2010-09-09'
Description: "Creates an AWS Config rule and Lambda to check all roles' last used compliance"
Transform: 'AWS::Serverless-2016-10-31'
Parameters:

  MaxDaysForLastUsed:
    Description: Checks the number of days allowed for a role to not be used before being non-compliant
    Type: Number
    Default: 60
    MaxValue: 365

  NameOfSolution:
    Type: String
    Default: iam-role-last-used
    Description: The name of the solution - used for naming of created resources

  RolePatternWhitelist:
    Description: Pipe separated whitelist of role pathnames using simple pathname matching
    Type: String
    Default: ''
    AllowedPattern: '[-a-zA-Z0-9+=,.@_/|*]+|^$'

  LambdaLayerArn:
    Type: String
    Description: The ARN for the Lambda Layer you will use.
  
Resources:
  LambdaInvokePermission:
    Type: 'AWS::Lambda::Permission'
    DependsOn: CheckRoleLastUsedLambda
    Properties: 
      FunctionName: !GetAtt CheckRoleLastUsedLambda.Arn
      Action: lambda:InvokeFunction
      Principal: config.amazonaws.com
      SourceAccount: !Ref 'AWS::AccountId'

  LambdaExecutionRole:
    Type: 'AWS::IAM::Role'
    Properties:
      RoleName: !Sub '${NameOfSolution}-${AWS::Region}'
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            Service: lambda.amazonaws.com
          Action:
          - sts:AssumeRole
      Path: /
      Policies:
      - PolicyName: !Sub '${NameOfSolution}'
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
          - Effect: Allow
            Action:
            - config:PutEvaluations
            Resource: '*'
          - Effect: Allow
            Action:
            - iam:GetAccountAuthorizationDetails
            Resource: '*'
          - Effect: Allow
            Action:
            - logs:CreateLogStream
            - logs:PutLogEvents
            Resource:
            - !Sub 'arn:${AWS::Partition}:logs:${AWS::Region}:*:log-group:/aws/lambda/${NameOfSolution}:log-stream:*'

  CheckRoleLastUsedLambda:
    Type: 'AWS::Serverless::Function'
    Properties:
      Description: "Checks IAM roles' last used info for AWS Config"
      FunctionName: !Sub '${NameOfSolution}'
      Handler: lambda_function.evaluate_compliance
      MemorySize: 256
      Role: !GetAtt LambdaExecutionRole.Arn
      Runtime: python3.7
      Timeout: 300
      CodeUri: ./iam-role-last-used
      Layers:
      - !Ref LambdaLayerArn

  LambdaLogGroup:
    Type: 'AWS::Logs::LogGroup'
    Properties: 
      LogGroupName: !Sub '/aws/lambda/${NameOfSolution}'
      RetentionInDays: 30

  ConfigCustomRule:
    Type: 'AWS::Config::ConfigRule'
    DependsOn:
    - LambdaInvokePermission
    - LambdaExecutionRole
    Properties:
      ConfigRuleName: !Sub '${NameOfSolution}'
      Description: Checks the number of days that an IAM role has not been used to make a service request. If the number of days exceeds the specified threshold, it is marked as non-compliant.
      InputParameters: !Sub '{"role-whitelist":"${RolePatternWhitelist}","max_days_for_last_used":"${MaxDaysForLastUsed}"}'
      Source: 
        Owner: CUSTOM_LAMBDA
        SourceDetails: 
        - EventSource: aws.config
          MaximumExecutionFrequency: TwentyFour_Hours
          MessageType: ScheduledNotification
        SourceIdentifier: !GetAtt CheckRoleLastUsedLambda.Arn

Ниже приведена краткая информация о данном шаблоне CloudFormation.

  • Параметры (эти переменные можно переопределять):
    • MaxDaysForLastUsed – максимальное количество дней, в течение которого роль может быть неактивна прежде, чем она получит статус несоответствующей требованиям.
    • NameOfSolution – название решения: оно используется для именования создаваемых ресурсов.
    • RolePatternWhitelist – список ролей, перечисленных через разделитель («|»), которые всегда помечаются как соответствующие требованиям (см. раздел «Игнорируемые роли» ниже).
    • LambdaLayerArn – ARN-идентификатор слоя Lambda, созданного вами ранее на шаге 1.
  • Ресурсы (эти ресурсы будут созданы в вашем аккаунте AWS):
    • LambdaInvokePermission – разрешение для AWS Config запускать вашу функцию Lambda.
    • LambdaExecutionRole – роль IAM, которая будет использоваться функцией Lambda. Эта роль включает в себя политики с разрешениями производить следующие действия: iam:GetAccountAuthorizationDetails, config:PutEvaluations, logs:CreateLogStream, и logs:PutLogEvents. Действие PutEvaluations позволяет функции сохранять в AWS Config статус соответствия ресурсов требованиям. Действия CreateLogStream и PutLogEvents позволяют сохранять логи вашей функции Lambda в AWS CloudWatch Logs.
    • CheckRoleLastUsedLambda – описывает вашу функцию Lambda и её параметры.
    • LambdaLogGroup – группа CloudWatch Logs, где будут сохранены логи вашей функции Lambda.
    • ConfigCustomRule – описывает AWS Config Rule и его параметры.

Используйте команду AWS CLI cloudformation package с шаблоном CloudFormation, который вы сохранили ранее, чтобы создать zip-архив, содержащий исходный код вашей функции Lambda и загрузить его в указанный вами бакет S3, как показано ниже. Обязательно замените <YOUR REGION> на регион, в котором вы развёртываете решение и <YOUR S3 BUCKET> на имя бакета, не включая префикс s3://:

aws cloudformation package --region <YOUR REGION> --template-file iam-role-last-used.yml \
--s3-bucket <YOUR S3 BUCKET> \
--output-template-file iam-role-last-used-transformed.yml

В результате будет создан файл iam-role-last-used-transformed.yml, содержащий ссылку на бакет и путь к zip-архиву, содержащему исходный код, необходимые CloudFormation для развёртывания функции Lambda.

Теперь, разверните решение в вашем аккаунте AWS с помощью команды cloudformation deploy, приведённой ниже. Вы можете задать другие значения для NameOfSolutionMaxDaysForLastAccess, или RolePatternWhitelist, используя опцию --parameter-overrides. В противном случае будут использоваться значения по умолчанию, которые указаны в верхней части шаблона CloudFormation, в разделе Parameters. Не забудьте заменить <YOUR REGION> на регион, в котором вы развёртываете решение, и <YOUR LAMBDA LAYER ARN> на ARN-идентификатор слоя Lambda, созданного вами ранее на шаге 1.

aws cloudformation deploy --region <YOUR REGION> --template-file iam-role-last-used-transformed.yml \
--stack-name iam-role-last-used \
--parameter-overrides NameOfSolution='iam-role-last-used' \
MaxDaysForLastUsed=60 \
RolePatternWhitelist='/breakglass-role|/security-*' \
LambdaLayerArn='<YOUR LAMBDA LAYER ARN>' \
--capabilities CAPABILITY_NAMED_IAM

Развёртывание решения обычно занимает всего несколько минут и заканчивается сообщением AWS CLI об успешном завершении команды:

Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - iam-role-last-used

Шаг 3: Просмотр результатов

Теперь, когда развёртывание завершено, вы можете просмотреть результаты проверки соответствия требованиям, перейдя в консоль AWS Config.

  1. Выберите тот же регион, в котором был развёрнут шаблон CloudFormation.
  2. Выберите Rules в левой панели, в результате чего откроется текущий список Config Rules в вашем аккаунте AWS.
  3. Выберите Config Rule iam-role-last-used для просмотра детальной информации, как показано на изображении 2.

Если в поле Overall rule status отображается время последнего запуска проверки, первоначальная проверка соответствия завершена. Для успешного завершения проверки может потребоваться подождать несколько минут, если результаты ещё недоступны. Вы можете несколько раз обновить консоль в веб-браузере, чтобы проверить, завершена ли проверка.

Изображение 2: Детальная информация о AWS Config Rule

Изображение 2: Детальная информация о AWS Config Rule

После завершения проверки ваших ролей на соответствие требованиям вы сможете просмотреть результаты на этой же странице. На скриншоте ниже видно, что есть несколько несоответствующих требованиям ролей. Вы можете переключаться между просмотром соответствующих и несоответствующих требованиям ролей с помощью выпадающего меню в разделе Compliance status.

Изображение 3: Просмотр статуса соответствия требованиям

Изображение 3: Просмотр статуса соответствия требованиям

Вы можете навести курсор на символ «i», чтобы увидеть причину, по который роль была помечена как несоответствующая требованиям (см. изображение 4).

Изображение 4: Дополнительная информация о статусе роли

Изображение 4: Дополнительная информация о статусе роли

Шаг 4: Экспорт отчёта о соответствии требованиям

Возможно, после успешного завершения проверки, вы захотите создать экспортируемый отчёт о соответствии требованиям. Вы можете использовать AWS CLI для написания скриптов и автоматического создания отчётов для ваших команд разработки, или команды безопасности. Они могут использовать эти отчёты для дальнейшей проверки несоответствующих требованиям ролей и принятия мер, если та или иная роль больше не нужна. Команда AWS CLI, представленная ниже, демонстрирует, как можно это сделать. Обратите внимание, что команда, приведённая ниже, состоит из одной строки:

aws configservice get-compliance-details-by-config-rule --config-rule-name iam-role-last-used --output text --query 'EvaluationResults [*].{A:EvaluationResultIdentifier.EvaluationResultQualifier.ResourceId,B:ComplianceType,C:Annotation}'

Результат будет аналогичен приведённым ниже строкам, колонки будут отделены друг от друга отступами. В первой колонке выводится название роли. Во второй колонке указывается статус соответствия. Последняя колонка объясняет причину статуса соответствия или несоответствия:

AdminRole   COMPLIANT      Was last used in us-west-2 46 days ago
Ec2DevRole  NON_COMPLIANT  No record of usage

Исправление несоответствующих требованиям ролей

Теперь, когда у вас есть отчет о несоответствующих требованиям ролях, вы должны решить, что с ними делать. Если ваши команды согласны с тем, что роль не является необходимой, исправление может заключаться в простом удалении роли. Если вы не уверены, вы можете сохранить роль, но запретить выполнение всех действий. Вы можете сделать это, прикрепив новую политику, запрещающую все действия для всех ресурсов. Повторное включение роли будет очень простым, достаточно будет удалить добавленную политику. В противном случае, если роль необходима, но не часто используется, вы можете внести её в список игнорируемых ролей с помощью метода, описанного ниже. 

Игнорируемые роли

Игнорируемые роли будут помечены как соответствующие требованиям, даже если они не используются. У вас могут быть такие роли, как роль для реагирования на инциденты безопасности или для других экстренных ситуаций, которые требуют внесения в список разрешённых ролей.

Список игнорируемых ролей настраивается параметром RolePatternWhitelist шаблона CloudFormation и хранится как параметр AWS Config Rule. Синтаксис использует шаблон соответствия имен файлов UNIX. Если необходимо указать несколько шаблонов для названия ролей, используйте символ «|» в качестве разделителя между ними. При этом, каждый шаблон будет сопоставлен с именем роли, включая путь. Например, если необходимо внести в список игнорируемых ролей роли breakglass-role, security-incident-response-role и security-audit-role, то параметр RolePatternWhitelist шаблона CloudFormation будет выглядеть следующим образом:

/breakglass-role|/security-*

Важно: Используйте звёздочки (*) аккуратно, так как они будут соответствовать любому количеству любых символов в названии роли! 

Дополнительная функциональность

В этой статье я постарался сохранить архитектуру и код простыми, чтобы сделать решение более лёгким для использования. Однако вы можете дополнительно настроить решение с помощью следующей функциональности:

Выводы

В этой статье я показал вам, как использовать AWS IAM и AWS Config для реализации непрерывного мониторинга безопасности, который обеспечивает прозрачность ваших ролей IAM и времени их последнего использования. Я также показал, как просматривать результаты проверки соответствия ролей IAM требованиям в консоли управления AWS и экспортировать результаты с помощью AWS CLI. Наконец, я предложил различные опции исправления и возможность составления списка разрешённых ролей, которые необходимы, но при этом редко используются. Эти методы могут помочь вам улучшить методы обеспечения безопасности и соответствия требованиям, предотвращая непреднамеренный доступ через роли IAM.

Дополнительная информация