Об оптимизации для скорости: как провести полное сканирование AWS Security&Compliance за 5 минут

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

Оценки лучших практик безопасности AWS

Для поддержки безопасности в первую очередь необходимо проверить свою учетную запись на соответствие лучшим практикам и эталонам. Двумя наиболее используемыми из них являются
AWS Foundational Security Best Practices от AWS и CIS (Center for Internet Security) AWS Benchmark.

Я сравню широко используемый инструмент prowler (git 5.1k звезд) с более новым, steampipe (git 1.2k звезд), который демонстрирует благоприятный подход.

Prowler

Prowler представляет себя:

«Prowler — это инструмент безопасности с открытым исходным кодом для выполнения оценки лучших практик безопасности AWS, аудита, реагирования на инциденты, непрерывного мониторинга, укрепления и готовности к судебной экспертизе. Он содержит более 200 элементов управления, охватывающих CIS, PCI-DSS, ISO27001, GDPR, HIPAA, FFIEC, SOC2, AWS FTR, ENS и системы безопасности custome».

Архитектура

Приложение работает на основе сценариев bash с AWS CLI в качестве основы. Запросы выполняются с помощью комбинации bash pipes и синтаксиса cli «query». Это делает внедрение элементов управления простым на начальном этапе.

Сценарий bash ожидает после каждого запроса AWS API.

Скорость

Проблема такой архитектуры заключается в том, что сканирование может занимать от 30 минут до нескольких часов.

Давайте рассмотрим одну проверку в качестве примера:

проверка122 в качестве примера

В checks/check121 из репозитория prowler вы найдете этот bash-скрипт:

Раздел конфигурации

Атрибуты проверки хранятся в переменных окружения.

CHECK_ID_check122="1.22"
CHECK_TITLE_check122="[check122] Ensure IAM policies that allow full "*:*" administrative privileges are not created"
CHECK_SCORED_check122="SCORED"
CHECK_CIS_LEVEL_check122="LEVEL1"
CHECK_SEVERITY_check122="Medium"
CHECK_ASFF_TYPE_check122= "Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark"
CHECK_ASFF_RESOURCE_TYPE_check122="AwsIamPolicy"
CHECK_ALTERNATE_check122="check122"
CHECK_SERVICENAME_check122="iam"
CHECK_RISK_check122='IAM policies are the means by which privileges are granted to users; groups; or roles. It is recommended and considered a standard security advice to grant least privilege—that is; granting only the permissions required to perform a task. Determine what users need to do and then craft policies for them that let the users perform only those tasks instead of allowing full administrative privileges. Providing full administrative privileges instead of restricting to the minimum set of permissions that the user is required to do exposes the resources to potentially unwanted actions.'
CHECK_REMEDIATION_check122='It is more secure to start with a minimum set of permissions and grant additional permissions as necessary; rather than starting with permissions that are too lenient and then trying to tighten them later. List policies an analyze if permissions are the least possible to conduct business activities.'
CHECK_DOC_check122='http://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html'
CHECK_CAF_EPIC_check122='IAM'
Вход в полноэкранный режим Выход из полноэкранного режима

Раздел кода

  1 check122(){
  2   # "Ensure IAM policies that allow full "*:*" administrative privileges are not created (Scored)"
  3   LIST_CUSTOM_POLICIES=$($AWSCLI iam list-policies --output text $PROFILE_OPT --region $REGION --scope Local --query 'Policies[*].[Arn,Defau    ltVersionId]' | grep -v -e '^None$' | awk -F 't' '{print $1","$2"n"}')
  4   if [[ $LIST_CUSTOM_POLICIES ]]; then
  5     for policy in $LIST_CUSTOM_POLICIES; do
  6       POLICY_ARN=$(echo $policy | awk -F ',' '{print $1}')
  7       POLICY_VERSION=$(echo $policy | awk -F ',' '{print $2}')
  8       POLICY_WITH_FULL=$($AWSCLI iam get-policy-version --output text --policy-arn $POLICY_ARN --version-id $POLICY_VERSION --query "[Policy    Version.Document.Statement] | [] | [?Action!=null] | [?Effect == 'Allow' && Resource == '*' && Action == '*']" $PROFILE_OPT --region $REGION    )
  9       if [[ $POLICY_WITH_FULL ]]; then
 10         POLICIES_ALLOW_LIST="$POLICIES_ALLOW_LIST $POLICY_ARN"
 11       fi
 12     done
 13     if [[ $POLICIES_ALLOW_LIST ]]; then
 14       for policy in $POLICIES_ALLOW_LIST; do
 15         textFail "$REGION: Policy $policy allows "*:*"" "$REGION" "$policy"
 16       done
 17     else
 18         textPass "$REGION: No custom policy found that allow full "*:*" administrative privileges" "$REGION"
 19     fi
 20   else
 21     textPass "$REGION: No custom policies found" "$REGION"
 22   fi
 23 }
Вход в полноэкранный режим Выход из полноэкранного режима

Код выполняет следующие действия:

1. Перечислить политики (строка 3)

$AWSCLI iam list-policies
Войти в полноэкранный режим Выйти из полноэкранного режима

2. Петля (строки 5-12)

$AWSCLI iam get-policy-version
Войти в полноэкранный режим Выход из полноэкранного режима

Скорость работы AWS cli

При использовании python для каждого вызова запускается интерпретатор python, занимая время на каждый вызов.

Позвольте мне показать вам, что я имею в виду:

time aws iam list-policies
aws iam list-policies  0,93s user 0,13s system 15% cpu 6,894 total
Войти в полноэкранный режим Выход из полноэкранного режима

Это занимает около 7 секунд. Теперь «list-policies» является затратной по времени операцией, поэтому я рассмотрю более простую, S3 list.

Чтобы понять, какая часть — это время python, а какая — время AWS, я сравниваю «aws s3 ls» с более быстрым приложением go.

Это AWS python cli:

time aws s3 ls
aws s3 ls  0,46s user 0,07s system 72% cpu 0,726 total
Вход в полноэкранный режим Выход из полноэкранного режима

Теперь вы можете сказать, что вывод терминала занимает некоторое время. Мы устраним это:

time aws s3 ls >/dev/null
aws s3 ls > /dev/null  0,43s user 0,07s system 79% cpu 0,635 total
Войти в полноэкранный режим Выход из полноэкранного режима

Итого 0,635 секунды для AWS CLI/Python.

Напротив, небольшая программа GO занимает меньше времени:

time ./s3list >/dev/null
./s3list > /dev/null  0,01s user 0,01s system 11% cpu 0,183 total
Войти в полноэкранный режим Выход из полноэкранного режима

Где основной код выглядит так:

 res, err := client.ListBuckets(context.TODO(), &s3.ListBucketsInput{})
for _, bucket := range res.Buckets {
        bucketarray = append(bucketarray, bucket.Name)
}
return bucketarray, nil
Войти в полноэкранный режим Выход из полноэкранного режима

Итого 0,183 секунды для скомпилированной GO-программы.

Некоторые из вас могут сказать: Rust — новый король скорости — хорошо, давайте попробуем:

Rust может быть быстрее.
Но на данный момент rust SDK все еще находится в бета-версии, поэтому он занимает больше времени, чем GO, но быстрее, чем python.

time target/debug/rust-s3 >/dev/null
target/debug/rust-s3 > /dev/null  0,15s user 0,03s system 43% cpu 0,403 total
Вход в полноэкранный режим Выход из полноэкранного режима

Итого 0,403 секунды для скомпилированной Rust-программы, созданной с помощью cargo build.

Это код Rust:

use aws_config::meta::region::RegionProviderChain;
use aws_sdk_s3::{Client, Error};
#[tokio::main]
async fn main() -> Result<(), Error> {
    let region_provider = RegionProviderChain::default_provider().or_else("eu-central-1");
    let config = aws_config::from_env().region(region_provider).load().await;
    let client = Client::new(&config);
    if let Err(e) = show_buckets(&client).await
    {
        println!("{:?}", e);
    };
    Ok(())
}
async fn show_buckets( client: &Client) -> Result<(), Error> {
    let resp = client.list_buckets().send().await?;
    let buckets = resp.buckets().unwrap_or_default();
    for bucket in buckets {
        println!("{}", bucket.name().unwrap_or_default());
    }
    println!();
    Ok(())
}
Вход в полноэкранный режим Выход из полноэкранного режима

Оптимизация

Как вы видите, скомпилированная GO-программа намного быстрее, чем python-скрипт. Поэтому я попытался оптимизировать cli с помощью GO-кэша.

Проект называется «https://github.com/megaproaktiv/awclip». Пожалуйста, рассматривайте его как эксперимент; он как-то работает, но не дает желаемых результатов.

Вот что я обнаружил:

  • AWS CLI делает гораздо больше вещей, чем просто вызов сервиса.
  • AWS CLI не всегда работает с json.

Смотрим на строку 8 проверки:

--query "[Policy    Version.Document.Statement]
Войти в полноэкранный режим Выйти из полноэкранного режима

Это работает на json, но важные APIS, такие как EC2 API, S3 API и IAM, отвечают на запросы с помощью XML, а не json.

Поэтому заменить функцию «запрос» собственной программой не так-то просто.

Наиболее перспективным подходом является параллельная предварительная выборка регионов. Prowler делает все последовательно.

Но проработав около дня, я получил лишь 10% прироста скорости от prowler. Это заставило меня понять, что мое мышление было неправильным.

Я оптимизировал локально, а не глобально.

Если вы читали книгу «Цель», то там сказано:

«Нас не волнуют локальные оптимумы».

Поэтому мой подход к замене AWS cli в качестве локального оптимума привел в никуда — обратно к чертежной доске. После некоторых исследований я обнаружил проект, в котором использовался глобальный оптимизационный подход: Steampipe

Steampipe — другой подход

Steampipe использует Postgres Foreign Data Wrapper для представления данных и сервисов из внешних систем в виде таблиц базы данных.

Запросы не выполняются на JSON, как в AWS cli. Данные AWS представлены в таблицах, и запросы работают непосредственно с этими таблицами. Все результаты кэшируются, и запросы выполняются на локальной таблице postgres, а не как вызовы служб AWS.

Поэтому когда я смотрю на подобный контроль, например check-122, который здесь называется «Control: 1 IAM policies should not allow full ‘*’ administrative privileges», запрос пишется на SQL.

Конфигурация (foundational_security/iam.sp) отделена от логики в отдельном файле и выглядит следующим образом:

control "foundational_security_iam_1" {
  title         = "1 IAM policies should not allow full '*' administrative privileges"
  description   = "This control checks whether the default version of IAM policies (also known as customer managed policies) has administrator access that includes a statement with 'Effect': 'Allow' with 'Action': '*' over 'Resource': '*'. The control only checks the customer managed policies that you create. It does not check inline and AWS managed policies."
  severity      = "high"
  sql           = query.iam_custom_policy_no_star_star.sql
  documentation = file("./foundational_security/docs/foundational_security_iam_1.md")

  tags = merge(local.foundational_security_iam_common_tags, {
    foundational_security_item_id  = "iam_1"
    foundational_security_category = "secure_access_management"
  })
}
Войти в полноэкранный режим Выйти из полноэкранного режима

Этот запрос находится в query/iam/iam_policy_no_star_star.sql в репозитории github.

С помощью prowler это запрос с AWS cli и pipe some Bash logic:

--query "[PolicyVersion.Document.Statement] | [] | [?Action!=null] | [?Effect == 'Allow' && Resource == '*' && Action == '*']"
Войти в полноэкранный режим Выйти из полноэкранного режима

С steampipe синтаксис — sql:

with bad_policies as (
  select
    arn,
    count(*) as num_bad_statements
  from
    aws_iam_policy,
    jsonb_array_elements(policy_std -> 'Statement') as s,
    jsonb_array_elements_text(s -> 'Resource') as resource,
    jsonb_array_elements_text(s -> 'Action') as action
  where
    s ->> 'Effect' = 'Allow'
    and resource = '*'
    and (
      (action = '*'
      or action = '*:*'
      )
  )
  group by
    arn
)
Enter fullscreen mode Выход из полноэкранного режима

Текстовый компаризм bash Effect == 'Allow' становится where s ->> 'Effect' = 'Allow'.

Разработка SQL-запросов

Вы можете разрабатывать sql-запросы с помощью команды steampipe query, которая предоставляет вам локальный инструмент sql-запросов.
Первый шаг заключается в том, что с помощью команды .tables вы получаете все таблицы AWS после установки плагина AWS.

inspect aws_iam_policy

Второй шаг — посмотреть, какие поля вы можете запросить:

Команда .inspect показывает поля.

Вы можете начать экспериментировать с запросами:

> select policy_std from aws_iam_policy
+----------------------------------------------------------------------------------------------------------------------
| policy_std
+----------------------------------------------------------------------------------------------------------------------
| {"Statement":[{"Action":["logs:createloggroup",...
Войти в полноэкранный режим Выйти из полноэкранного режима

Функции для работы с JSON позволяют интерпретировать документы политики, см:

в следующем утверждении:

jsonb_array_elements(policy_std -> 'Statement') as s,
jsonb_array_elements_text(s -> 'Resource') as resource,
jsonb_array_elements_text(s -> 'Action') as action
where
  s ->> 'Effect' = 'Allow'
  and resource = '*'
  and (
    (action = '*'
    or action = '*:*'
    )
)
Войти в полноэкранный режим Выйти из полноэкранного режима

Теперь мы знаем, как строится элемент управления, давайте посмотрим на скорость.

Скорость для одиночного элемента управления

Скорость с prowler

Запуск одиночного элемента управления с prowler занимает более 2 минут:

Скорость со стимпайпом

При использовании steampipe это время уменьшилось до 23 секунд, при этом результаты остались прежними.

Скорость для полного сканирования

При полном сканировании prowler требует около 30 минут для одного региона, steampipe работает за 3 минуты.

Возможно, вы хотите попробовать это сами — тогда CloudShell — ваш друг.

Вот небольшое полное руководство по проверке вашего аккаунта!

Начало работы

Общие шаги таковы:

  • Скачайте и установите Steampipe
  • Установите плагин AWS
  • Клонируйте репозиторий steampipe-mod-aws-compliance
  • Сгенерируйте отчет об учетных данных AWS
  • Настройте регионы (необязательно)
  • Запустите все контрольные показатели
  • Загрузить файл отчета

Подробнее:

1. Войдите в свою учетную запись AWS с правами администратора

2. Откройте cloudshell

3. Выполните эти команды:

sudo /bin/sh -c "$(curl -fsSL https://raw.githubusercontent.com/turbot/steampipe/main/install.sh)"
steampipe plugin install steampipe
steampipe plugin install aws
git clone https://github.com/turbot/steampipe-mod-aws-compliance.git
cd steampipe-mod-aws-compliance
aws iam generate-credential-report
Войти в полноэкранный режим Выйти из полноэкранного режима

4. (Необязательно) Редактирование конфигурации региона

Если вы хотите сканировать только определенный регион (регионы), вы можете задать это в конфигурации_

vi ~/.steampipe/config/aws.spc
Войти в полноэкранный режим Выйти из полноэкранного режима
  1 connection "aws" {
  2   plugin    = "aws"
  3 
  4   regions     = ["eu-central-1","us-east-1"]
  5 
  6 }
Войти в полноэкранный режим Выйти из полноэкранного режима

Вы знаете, что номера строк не копируются, не так ли 😉

5. Дождитесь отчета об авторизации

aws iam generate-credential-report
Войти в полноэкранный режим Выйти из полноэкранного режима

Вы получите это, когда отчет будет запущен:

{
    "State": "STARTED",
    "Description": "No report exists. Starting a new report generation task"
}
Войти в полноэкранный режим Выход из полноэкранного режима

И вот это, когда отчет готов:

{
    "State": "COMPLETE"
}
Войти в полноэкранный режим Выйти из полноэкранного режима

6. Выполните полную проверку с выводом html

steampipe check all --export=html
Войти в полноэкранный режим Выйти из полноэкранного режима

Это должно занять всего 3-5 минут.

Вы видите, что процесс запущен:

7. Скачайте отчет

Найдите файл all-$date-$time.html. например all-20220412-150100.html.

В меню «Действия» cloudshell вы можете «Загрузить» html-файл:

Вы должны написать полный путь, например, так:

Теперь у вас есть полный отчет:

Заключение

Сканирование безопасности

На github есть много хороших инструментов для сканирования соответствия AWS и безопасности с открытым исходным кодом.

С полным отчетом — включая установку на облачную оболочку — примерно за 5 минут, SteamPipe является новой падающей звездой в моем портфеле инструментов. Посмотрим в долгосрочной перспективе.

Вам стоит потратить 10 минут, чтобы попробовать!

Оптимизация

Чему я научился:

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

Обратная связь и обсуждение

Для обсуждения, пожалуйста, свяжитесь со мной в twitter @megaproaktiv

Узнайте больше о GO

Хотите узнать больше об использовании GOLANG на AWS? — Изучайте GO на AWS: здесь.

Источники

  • Голдратт, Элияху М.; Джефф Кокс. Цель: процесс непрерывного совершенствования. North River Press. Kindle-версия.
  • Проверка стимпайпа
  • Steampipe Hub
  • Prowler

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *