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 получаем сообщение в таком виде:

готово