AWS Config - кастомные правила для автоматизации работы системного администратора

Сервис AWS Config предназначен для оценки и аудита конфигурации ресурсов AWS. AWS Config ведет непрерывный мониторинг конфигурации ресурсов AWS и фиксирует результаты. Сервис позволяет автоматизировать сопоставление записанных и требуемых конфигураций и оценку соответствия.

Что это означает на практике? Расскажу о своем недавнем кейсе.

Ко мне обратился клиент, использующий сервис AWS Secrets Manager для хранения API ключей и токенов OAuth. Ключей и токенов было очень много (несколько сотен).

Они были разного типа, и их ротация (обновление) осуществлялась с использованием различных AWS Lambda функций. Администраторам было сложно вручную отслеживать, все ли в системе работает корректно, нет ли ключей, которые по какой-то причине не обновлены в течение заданного промежутка времени. К примеру, если кто-то внесет изменение в функцию, отвечающую за ротацию ключа, он перестанет обновляться, и этого не будет видно.

Передо мной встала задача создания 2х кастомных правил AWS Config:

1) Дата последнего обновления любого ключа AWS Secrets Manager должна быть не старше, чем 90 дней назад.

2) Не должно быть Secrets, для которых не задана функция ротации, и в настройках автоматического выполнения функции ротации должен стоять период ротации менее 90 дней.

Для создания и проверки выполнения данных правил в системе мне понадобилось создать 2 AWS Lambda функции с доступом к AWS Config, AWS Secrets Manager и CloudWatch (для логирования).



Далее я создала сами правила AWS Config, подключив в каждом из них соответствующую Lambda-функцию для проверки и указав периодичность проверки:


Чтобы запрограммировать логику проверки правила в AWS Lambda функции, нужно проработать несколько моментов:

1) Мы ожидаем, что обращаться к функции будет только сервис AWS Config, и это нужно проверять при запуске функции. Источник обращения передается в функцию в переменной event. Для тестирования в ходе написания Lambda-обработчика конфигурационного правила можно использовать следующий шаблон:
{
"invokingEvent": "{\"configurationItem\":{\"configurationItemCaptureTime\":\"2016-02-17T01:36:34.043Z\",\"awsAccountId\":\"123456789012\",\"configurationItemStatus\":\"OK\",\"resourceId\":\"i-00000000\",\"ARN\":\"arn:aws:ec2:us-east-2:123456789012:instance/i-00000000\",\"awsRegion\":\"us-east-2\",\"availabilityZone\":\"us-east-2a\",\"resourceType\":\"AWS::EC2::Instance\",\"tags\":{\"Foo\":\"Bar\"},\"relationships\":[{\"resourceId\":\"eipalloc-00000000\",\"resourceType\":\"AWS::EC2::EIP\",\"name\":\"Is attached to ElasticIp\"}],\"configuration\":{\"foo\":\"bar\"}},\"messageType\":\"ConfigurationItemChangeNotification\"}",
"ruleParameters": "{\"myParameterKey\":\"myParameterValue\"}",
"resultToken": "myResultToken",
"eventLeftScope": false,
"executionRoleArn": "arn:aws:iam::123456789012:role/config-role",
"configRuleArn": "arn:aws:config:us-east-2:123456789012:config-rule/config-rule-0123456",
"configRuleName": "change-triggered-config-rule",
"configRuleId": "config-rule-0123456",
"accountId": "123456789012",
"version": "1.0"
}


2) После проверки источника запроса (код проверки, как и другие скучные моменты я не привожу в данном посте) необходимо получить  необходимые данные - в данном кейсе это настройки Secrets. Для доступа к ресурcам AWS используется python библиотека boto3. Получить данные, необходимые для проверки - очень просто:
secrets_list = []
response = self._lambda_client.list_secrets()
for secrets_dict in response['SecretList']:
secrets_list.append(secrets_dict)
while "NextMarker" in response:
response = self._lambda_client.list_secrets(
Marker=response["NextMarker"])
for secrets_dict in response['SecretList']:
secrets_list.append(secrets_dict)
for item in secrets_list:
if key in item:
detail_response = self._lambda_client.describe_secret(
SecretId=item['ARN'])

3) Анализируем полученные данные на соответствие заданным правилам и готовим ответ:
@staticmethod
def prepare_report(item):
"""Prepare report for answer to AWS Config"""
rotation_arn = item['RotationLambdaARN']
aa_days = item['RotationRules']['AutomaticallyAfterDays']
secret_name = item['Name']
if not rotation_arn:
answer = {
"type": "NON_COMPLIANT",
"annotation": "Value of RotationLambdaARN = null (empty) for Secret {}. Refer to documentation here: {}. ".format(
secret_name,
Environment.get_reference_url(),
)
}
elif aa_days > 90:
answer = {
"type": "NON_COMPLIANT",
"annotation": "Automatic rotation for the Secter {} is after {} days. Refer to documentation here: {}. ".format(
secret_name,
aa_days,
Environment.get_reference_url(),
)
}
else:
answer = {
"type": "COMPLIANT",
"annotation": "Automatic rotation for the Secter {} is after {} days. Refer to documentation here: {}. ".format(
secret_name,
aa_days,
Environment.get_reference_url(),
)
}
return answer


4) После того, как ответ подготовлен, его нужно отправить обратно запросившему его правилу AWS Config: 
config_delegator = ConfigDelegator(event["resultToken"], CONFIG_CLIENT)
config_delegator.add_evaluation(
answer["type"], answer["annotation"], item['Name'], self._resource_type)

Здесь answer["type"] может принимать 2 значения: COMPLIANT, если правило выполняется или NON_COMPLIANT, если правило не выполняется.


Если какое-то из правил не выполняется, это сразу видно в дашборде AWS Config:


Можно перейти в подробности и посмотреть, для какого конкретного Secret не выполняется правило:



Таким образом экономится рабочее время системных администраторов - им не нужно ежедневно перепроверять все секретные ключи и токены в Secrets Manager вручную - достаточно время от времени заходить в дашборд.

Комментарии

Популярные сообщения из этого блога

Настройка почты через biz.mail.ru в БитриксВМ

Git обновить текущую ветку из master

AWS S3 - Лучшие практики