Сценарий. У нас есть несколько рабочих нагрузок и сред, развернутых на нескольких аккаунтах в AWS Organization. Cloudwatch Logs используется для хранения журналов различных служб в рамках одной учетной записи AWS. EC2 ведут системные журналы, функции Lambda ведут журналы выполнения и так далее.
Для улучшения понимания журналов приложений может быть полезно агрегирование журналов из отдельных учетных записей AWS в один сервис или ведро S3. В зависимости от бизнеса, нормативные требования также могут обязать вас хранить журналы в течение определенного времени. Хранение журналов в течение длительного времени в централизованном аккаунте может помочь при реализации контроля доступа и графиков хранения.
В этой статье демонстрируется, как реализовать централизованное хранение журналов в организации с несколькими учетными записями в AWS Organizations. Основной целью является создание облачной инфраструктуры для:
- Хранить журналы приложений из нескольких учетных записей AWS в одном ведре S3.
- Выполнять специальные запросы к данным в S3 с помощью Amazon Athena.
Давайте начнем!
Обзор
Предлагаемое решение использует Cloudwatch Logs для сбора журналов с исходных учетных записей. Amazon Kinesis используется для доставки журналов в централизованное хранилище и S3 для долгосрочного хранения данных журналов. Наконец, мы будем использовать Amazon Athena для выполнения SQL-запросов к этим журналам.
Развертывание
Шаблоны Cloudformation для решения по ведению журналов можно найти здесь: https://github.com/markymarkus/cloudformation/tree/master/centralised-cloudwatch-logs.
logging-account-template.yml
обеспечивает инфраструктуру для Log Storage Account. Параметр шаблона OrganizationId
используется в политике доступа Cloudwatch Logs Destination для разрешения доставки журналов из учетных записей членов AWS Organizations.
member-account-template.yml
демонстрирует, как создать фильтр подписки на журналы Cloudwatch. Вы можете создать его на той же учетной записи, на которой развернут logging-account-template.yml
.
Учетные записи источников журналов
Учетные записи-источники содержат рабочие нагрузки, производящие и принимающие журналы в Cloudwatch Logs. Каждая группа журналов хранит события журналов из определенного источника. В нашем примере:
Наличие последовательных соглашений об именовании групп журналов пригодится нам при выполнении запросов Athena к данным. Запросы типа ‘/var/log/messages каждого экземпляра EC2 в каждой учетной записи AWS организации’ зависят от согласованного именования.
Журналы отправляются из учетной записи-члена в централизованное место назначения в Log Storage Account через фильтр подписки.
Учетная запись хранения журналов
Log Storage Account получает и подготавливает данные журналов для Athena и сохраняет журналы в ведро S3. Журналы хранятся в формате JSON по одной записи в строке. Поддерживается Athena и легко экспортируется другими сервисами и инструментами.
Преобразование событий журнала
По умолчанию Firehose записывает записи JSON в потоке в ведро S3 без разделителей и новых строк. Это работало бы, если бы мы не использовали Athena для выполнения запросов. Athena требует, чтобы каждая запись JSON была представлена в отдельной строке.
Для разделения записей JSON мы используем лямбда преобразование Firehose. Функция Lambda считывает пакет записей и добавляет символ новой строки + "n"
после каждой записи. Обработанные записи записываются обратно в поток Firehose, который в конечном итоге доставляет журналы в ведро S3.
output = []
for record in event['records']:
payload = base64.b64decode(record['data'])
striodata = BytesIO(payload)
with gzip.GzipFile(fileobj=striodata, mode='r') as f:
payload = f.read().decode("utf-8")
# Add newline to each record
output_record = {
'recordId': record['recordId'],
'result': 'Ok',
'data': base64.b64encode((payload + "n").encode("utf-8"))
}
output.append(output_record)
Выполнение запросов Athena
На данный момент у нас есть журналы приложений в ведре S3 в учетной записи Log Storage. Kinesis — это поток, основанный на времени, поэтому каждый файл содержит журналы из нескольких учетных записей и групп журналов Source AWS:
Чтобы запустить запросы Athena, сначала создайте внешнюю таблицу, указывающую на данные:
CREATE EXTERNAL TABLE logs (
messageType string,
owner string,
logGroup string,
subscriptionFilters string,
logEvents array<struct<id:string,
timestamp:string,
message:string
>>
)
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
LOCATION 's3://BUCKET_NAME/logs/year=2022/month=05/day=05/'
logEvents хранятся в структуре массива. Чтобы запросить поля журналов Cloudwatch внутри массива, необходимо UNNEST logEvents. Вот несколько запросов для начала работы:
Первый запрос возвращает последние потоковые журналы из учетных записей источников:
SELECT owner,loggroup,n.message FROM logs
CROSS JOIN UNNEST(logs.logevents) AS t (n)
LIMIT 20
######
1 111111111111 /var/log/messages May 5 03:07:48 ip-10-0-24-56 dhclient[2085]: XMT: Solicit on eth0, interval 119340ms.
2 222222222222 /aws/lambda/hello-world-lambda START RequestId: fcc9e873-d4c1-4ca3-a7de-fd5490300740 Version: $LATEST
3 222222222222 /aws/lambda/hello-world-lambda [DEBUG] 2022-05-05T03:07:50.972Z fcc9e873-d4c1-4ca3-a7de-fd5490300740 {'version': '0', 'id': ....
4 222222222222 /aws/lambda/hello-world-lambda [DEBUG] 2022-05-05T03:07:50.973Z fcc9e873-d4c1-4ca3-a7de-fd5490300740 Hello World!
5 111111111111 /aws/lambda/lambda-writer-LambdaFunction START RequestId: 38fb9b6b-dbea-4875-91cc-cf1dd5b36ab9 Version: $LATEST
6 111111111111 /aws/lambda/lambda-writer-LambdaFunction [DEBUG] 2022-05-05T03:08:16.81Z 38fb9b6b-dbea-4875-91cc-cf1dd5b36ab9
7 111111111111 /var/log/messages May 5 11:40:01 ip-10-0-24-56 systemd: Created slice User Slice of root.
8 111111111111 /var/log/messages May 5 11:40:01 ip-10-0-24-56 systemd: Started Session 169 of user root.
Следующий SQL-запрос возвращает количество событий журнала для каждого источника регистрации (группы журналов):
SELECT owner,loggroup,count(*) FROM logs
CROSS JOIN UNNEST(logs.logevents) AS t (n)
GROUP BY owner,loggroup
###
1 111111111111 /var/log/secure 429
2 111111111111 /var/log/messages 1670
3 222222222222 /aws/lambda/hello-world-lambda 5764
4 111111111111 /aws/lambda/lambda-writer-LambdaFunction 7198
...
Заключение
Если вы находитесь в процессе построения и планирования стратегии ведения журналов, это решение может стать хорошей отправной точкой. Вы можете собирать журналы Cloudwatch из нескольких учетных записей и регионов в одно ведро S3. Запросы Athena могут быть выполнены на основе консолидированных данных журналов. Я рекомендую вам поэкспериментировать с SQL-запросами к данным журналов. Анализ моделей ведения журналов по конкретным источникам и количества событий может помочь вам улучшить общий процесс управления журналами.
Спасибо за прочтение.