Thank you for reading this post, don't forget to subscribe!
AWS CloudTrail явлется сервисом для аудита событий в AWS-аккаунте и включен в каждом аккаунте по-умолчанию.
В него записываются события обо всех событиях в аккаунте, которые были сделаны пользователем, ролью или сервисом AWS через AWS Console, AWS CLI или AWS SDK.
Записывает API-вызовы, логины в систему, события сервисов и является незаменимым инструментом для обеспечения безопасности AWS-аккаунта.
События хранятся в CloudTrail 90 дней, но можно настроить trail, который будет сохранять выбранные события в AWS S3, и/или отправлять их в CloudWatch, а уже в CloudWatch можно настроить Alarms, что бы получать уведомления.
Трейлы могут быть двух типов – глобальные, применяемые ко всем регионам, и локальные в рамках одного региона, см. How does CloudTrail behave regionally and globally?
AWS CloudTrail Events
См. What are CloudTrail events? и Logging management events for trails.
Event в CloudTrail это запись о любом событии в AWS-аккаунте. События могут быть трёх типов: management event, data event, insight event.
Management events
К Management events относятся все операции, которые выполняются с ресурсами в аккаунте – control plane operations, например:
- настройки безопасности (например, API-вызов
AttachRolePolicy
) - создание устройств (например, API-вызов
CreateDefaultVpc
) - настройка правил для роутинг (например, API-вызов
CreateSubnet
) - настройки логгирования (например, API-вызов
CreateTrail
)
Также, сюда входят не-API операции, такие как логин в AWS Management Console, см. Non-API Events Captured by CloudTrail.
Кроме того, события могут быть о read и write операциях с API. Read, очевидно, это операции, которые только запрашивают информацию о ресурсах (например, DescribeSubnets
), а write – модификация ресурсов (например, TerminateInstances
), см. Read and write events.
Data events
См. Data events.
Информация об операциях выполненных с ресурсом, или самим ресурсом – data plane operations, например:
- операции с S3-корзинами, такие как
GetObject
,DeleteObject
иPutObject
- вызовы AWS Lambda-функций
- операции с Amazon DynamoDB, например
PutItem
,DeleteItem
иUpdateItem
И т.д.
По-умолчанию они не логгируются, и должны быть добавлены в trail при его создании.
Insights events
CloudTrail Insights отслеживает аномалии в событиях и при обнаружении такой аномалии – создаёт event.
Такими аномалиями могут быть, к примеру, необычное количество API-вызовов к S3 корзине на удаление записей, или необычно высокое (или наоборот – низкое) количество вызовов AuthorizeSecurityGroupIngress
.
CloudTrail trail
Как уже говорилось выше, trail позволяет во-первых хранить события дольше 90 дней, во-вторых – интегрировать CloudTrail и CloudWatch, в-третих – собирать информацию о событиях во всех регионах, так как CloudTrail Dashboard выводит информацию о событиях только из текущего региона.
Создание CloudTrail trail
Переходим в Trails, кликаем Create trail:
Указываем имя, выбираем Create new S3 bucket, указываем имя корзины, пока отключаем шифрование логов в корзине:
Что бы настроить алертинг – включаем отправку событий в CloudWatch Logs:
Оставляем Management events, включаем Insights.
В Management events включаем и Read и Write, для Insights events включаем API call rate:
Проверяем в CloudWatch Logs:
Теперь можно создать метрики из этих событий, и настроить Alarms.
Интеграция CloudTrail и CloudWatch
Далее, создадим метрику на основе каких-то событий, а потом добавим Alarm, который будет в AWS SNS слать сообщения, а SNS заинтегрируем с Opsgenie, который будет слать нам сообщения в Slack.
Вопрос за какими именно событиями следить, но можно погуглить запросом типа “cloudtrail security alerts”, по которому находтся два достаточно толковых материала – Threat Hunting with CloudTrail and GuardDuty in Splunk и Key CloudTrail Events To Monitor for Security in AWS, или берём примеры из шаблона Creating CloudWatch Alarms with an AWS CloudFormation Template.
Например:
- логин в AWS Console не из офиса (в примере IP офиса == 8.8.8.8):
{ ($.eventName = ConsoleLogin) && ($.sourceIPAddress != "8.8.8.8") }
- рутовый логин в AWS Console:
{ ($.eventName = ConsoleLogin) && ($.userIdentity.type = "Root") }
- ошибки логинов в AWS Console:
{ ($.eventName = ConsoleLogin) && ($.errorMessage = "Failed authentication") }
- попытки выполнения запрещённых операций:
{ ($.errorCode = "*UnauthorizedOperation") || ($.errorCode = "AccessDenied*") }
- уведомления о запуске сверхбольших инстансов, например мы не пользуемся серверами свыше х4 (c5.4xlarge самый большой):
{ ($.eventName = RunInstances) && (($.requestParameters.instanceType = *.8xlarge) || ($.requestParameters.instanceType = *.4xlarge)) }
- добавление новых пользователей в систему:
{ $.eventName="CreateUser" }
См. Filter and pattern syntax.
Пока добавим алертинг про все логины в AWS-аккаунт.
Посмотрим, как выглядит сам евент – логинимся, и через ~15 минут смотрим события, фильтруем по Event name == ConsoleLogin:
Создание AWS CloudWatch custom metric
Переходим к созданной выше Log group, во вкладке Metric filters кликаем Create metric filter.
В Filter pattern используем { ($.eventName = ConsoleLogin) }
:
Заполняем поля:
Проверяем метрику в графиках:
Opsgenie и AWS Simple Notifications Service
Переходим в AWS SNS, создаём новый топик с типом Standart:
В Opsginie в Integration list находим Incoming Amazon SNS:
Сохраняем интеграцию, записываем API-ключ:
Возвращаемся к SNS, кликаем Create Subscription, выбираем метод HTTPS, указываем URL и API-ключ из Opsgenie:
Получаем подтверждение, что подписка подтверждена:
Создание AWS CloudWatch Alarm
Переходим в Alarms, кликаем Create alarm:
Выбираем метрику:
Описываем условия алерта – больше или равно 1 событию (логину):
Настраиваем отправку в созданный выше SNS-топик:
Указываем имя аларма, сохраняем его:
Через несколько минут проверяем статус – вместо Insufficient data станет ОК (либо In alarm, если логинились в систему):
Теперь можно залогиниться в AWS Console, через 15 минут, когда до CloudTrail-а дойдёт новое событие, и получим аларм:
И алерт в Slack:
Opsgenie и кастомные поля из AWS SNS
Из того, что хотелось бы ещё сделать – это отфильтровать сообщение в Slack, что бы выводить только нужные поля. Можно реализовать с помощью строковых функций Opsgenie.
Переходим к интеграции Incoming SNS, кликаем Advanced:
В поле Description добавляем вызов Message.extract()
для полей:
1 2 3 4 5 |
{{Message.extract(/AlarmDescription":"(.+)","AWSAccountId"/)}} AWS account ID: {{Message.extract(/AWSAccountId":"(.+)","NewStateValue"/)}} AWS region: {{Message.extract(/Region":"(.+)","AlarmArn"/)}} |
Теперь, когда Opsgenie получает JSON от AWS SNS, он из него возьмёт только три объекта – AlarmDescription
, AWSAccountId
и Region
, и в результате в Slack получаем сообщение в таком виде:
готово