Як прийняти роль в AWS

AWS надає, мабуть, одні з самих розвинених сервісів аутентифікації та авторизації, базовими з яких є AWS Identity and Access Management (IAM) та AWS Security Token Service (AWS STS). Водночас AWS не рекомендує використовувати довготривалі облікові дані (long-term credentials), такі як ключ безпеки та ключ доступу, для щоденної роботи інженерів чи автоматизації.

Щоб знизити ризики компрометації доступу та спростити керування правами, найкращі практики рекомендують використання IAM ролей, що дозволяють реалізувати:

  • short-living credentials — тимчасові облікові дані з обмеженим терміном дії;
  • principle of the least privilege — надання лише мінімально необхідних дозволів для виконання конкретної задачі.

У цій статті ми розглянемо, як прийняти IAM роль (AssumeRole) та використати отримані тимчасові облікові дані для виконання практичних задач — наприклад, ручного деплою IaC-проєкту або запуску адміністративних скриптів у цільовому AWS акаунті.

Задача

Необхідно написати Bash-скрипт, який:

  • приймає IAM роль у вказаному AWS акаунті;
  • виводить отримані тимчасові облікові дані AWS, готові до подальшого використання;
  • обробляє та повідомляє про помилки.

Код сценарію

Рішення

Опис результату

В данному варіанті скрипт більше розрахований на ручний запуск – коли користувач дивиться на результат: опис помилки чи облікові дані для ролі. Проте, його легко адаптувати під автоматичний запуск, коли, наприклад облікові дані додаються в профіль через aws configure --profile <<NAME>> або як змінні оточення.

Для того щоб можна було прийняти роль, сутність з обліковий даними, під якими запускається скрипт, має мати дозвол на дію sts:AssumeRole по відношенню до ролі, яку хоче прийняти, наприклад

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "sts:AssumeRole",
            "Resource": "arn:aws:iam::123456789012:role/TargetRoleName"
        }
    ]
}

Крім того, роль мусить мати політику довіри (trust policy) для того, щоб дозволити іншій сутності прийняти себе. Для оточення розробки можна дозволити, наприклад, будь-якій сутності з акаунту приймати роль:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:root"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

але на практиці варто обмежити конкретною роллю або користувачем.

Використання

Використання сценарію:

./assume-role.sh \
    --role <<ROLE_NAME>> \
    [--profile <<PROFILE_NAME>>] \
    [--account <<ACCOUNT_ID>>] \
    [--duration <<DURATION>>]

де

  • ROLE_NAME — обов’язковий параметр, назва ролі, яку ми хочемо прийняти.
  • PROFILE_NAME — обов’язковий параметр, ім’я профілю з файла ~\.aws\credentials, в контексті якого запускається скрипт. Коли налаштовується AWS CLI, створюється профіль default, тому значення по замовченню для цього параметру – default.
  • ACCOUNT_ID — ідентифікатор акаунту, до якого належить роль. Якщо цей параметр не вказано, припускаємо, що профіль і роль належать до одного акаунту. Для цього перевіряється, чи відповідає ім’я профілю формату AccountID_Name, що зустрічається при використанні IAM Identity Center. В іншому випадку, генерується помилка.
  • DURATION — необов’язковий параметр, валідності облікових даних в годинах. Значення по замовчуванню – 1 година.

Наприклад, команда

./assume-role.sh --profile 123456789012_AdministratorAccess --role TargetRoleName -duration 2

запустить сценарій прийняти роль TargetRoleName в акаунті 123456789012 на 2 години сутністю з обліковими даними з профілю 123456789012_AdministratorAccess. Аналогічно, команда

./assume-role.sh --account 123456789012 --role TargetRoleName

запустить сценарій прийняти роль TargetRoleName в акаунті 123456789012 на 1 годину для користувача по замовчуванню.

Основні кроки сценарію

Скрипт реалізує стандартний та безпечний сценарій роботи з IAM ролями і складається з таких кроків:

  1. Скрипт перевіряє необхідні залежності, як, наприклад, встановлений AWS CLI. На рядках 28-47 перевіряються вхідні параметри, а далі на рядках 49-70 скрипт перевіряє надані значення та присвоює значення по замовчуванню, якщо потрібно.
  2. За допомогою aws sts assume-role скрипт отримує тимчасові облікові данні. Для обробки помилок створюється тимчасовий файл, рядок 76, в якій записується потік stderr. На рядку 84 ми перевіряємо результат виконання команди, і якщо він порожній, виводимо опис помилки з тимчасового файлу.
  3. Інакше, з результату в форматі json виділяємо значення ключа безпеки, ключа доступу та токену безпеки, рядки 91-94, та виводимо їх в зручному вигляді. Цей формат зручний для копіювання в інший профіль в ~\.aws\credentials, але вивід можна легко поміняти під інші задачі. Також інформативно виводимо час, коли закінчиться термін облікових даних.

Нижче наведено повний код сценарію.

Повний код сценарію

#!/bin/bash

# Використання
# ./assume-role.sh --profile 123456789012_AdministratorAccess --role TargetRoleName [-duration 2]
# або
# ./assume-role.sh --profile iamuser_name --account 123456789012 --role TargetRoleName [-duration 2]

set -euo pipefail

# Перевірка залежностей
command -v aws >/dev/null 2>&1 || { echo "aws CLI не знайдено"; exit 1; }
command -v jq  >/dev/null 2>&1 || { echo "jq не знайдено"; exit 1; }

usage() {
    echo "Використання:"
    echo "  $0 --role <role-name> [--profile <profile=default>] [--account <account-id>] [--duration <hours=1>]"
    exit 1
}

# Значення по замовчуванню
PROFILE="default"
ACCOUNT_ID=""
ASSUME_ROLE_NAME=""
DURATION=1

# Аналізуємо аргументи - генеруємо помилки
# якщо знайшли непередбачуваний аргумент
while [[ $# -gt 0 ]]; do
    key="$1"
    case $key in
        --profile)
            PROFILE="$2"
            shift 2 ;;
        --account)
            ACCOUNT_ID="$2"
            shift 2 ;;
        --role)
            ASSUME_ROLE_NAME="$2"
            shift 2 ;;
        --duration)
            DURATION="$2"
            shift 2 ;;
        *)
            echo "Невідомий параметр: $1"
            usage ;;
    esac
done

# Профіль може мати ім'я по замовчуванню default
if [[ -z "${PROFILE:-}" ]]; then
    PROFILE="default"
fi
# Перевіряємо порожнє значення для тривалості повноважень ролі
if [[ -z "${DURATION:-}" ]]; then
    DURATION=1
fi
# Ім'я ролі обов'язкове
[[ -z "${ASSUME_ROLE_NAME:-}" ]] && usage
# Якщо ідентифікатор акаунту не надано окремим параметром, намагаємось
# його відокремити з імені профілю (припускаємо формат AccountID_)
if [[ -z "${ACCOUNT_ID:-}" ]]; then
    if [[ "$PROFILE" =~ ^([0-9]{12})_ ]]; then
        ACCOUNT_ID="${BASH_REMATCH[1]}"
    fi
    if [[ ! "$ACCOUNT_ID" =~ ^[0-9]{12}$ ]]; then
        echo "Неможливо визначити Account ID із імені профіля '$PROFILE'"
        echo "  Очікуваний формат: 123456789012_name"
        exit 1
    fi
fi

ROLE_ARN="arn:aws:iam::$ACCOUNT_ID:role/$ASSUME_ROLE_NAME"
DURATION_SECONDS=$((DURATION * 3600))

# Приймаємо роль, помилки виводимо користувачу
TMP_ERR=$(mktemp)
CREDENTIALS=$(aws sts assume-role \
    --profile "$PROFILE" \
    --role-arn "$ROLE_ARN" \
    --role-session-name "AssumeRoleSession" \
    --duration-seconds "$DURATION_SECONDS" \
    --output json 2>"$TMP_ERR" || true)

if [[ -z "$CREDENTIALS" ]]; then
    echo "Помилка при прийнятті ролі $ASSUME_ROLE_NAME в акаунті $ACCOUNT_ID"
    cat "$TMP_ERR"   # показати помилку
    rm -f "$TMP_ERR" # видалити файл
    exit 1
fi

AWS_ACCESS_KEY_ID=$(echo "$CREDENTIALS" | jq -r '.Credentials.AccessKeyId')
AWS_SECRET_ACCESS_KEY=$(echo "$CREDENTIALS" | jq -r '.Credentials.SecretAccessKey')
AWS_SESSION_TOKEN=$(echo "$CREDENTIALS" | jq -r '.Credentials.SessionToken')
EXPIRATION=$(echo "$CREDENTIALS" | jq -r '.Credentials.Expiration')

cat <<EOF

aws_access_key_id=$AWS_ACCESS_KEY_ID
aws_secret_access_key=$AWS_SECRET_ACCESS_KEY
aws_session_token=$AWS_SESSION_TOKEN

# Закінчується в: $EXPIRATION
EOF


  1. Всі використані IP адреси, імена серверів, віртуальних машин, доменів, сайтів є фіктивними та використовуються виключно для демонстрації.
  2. Інформація надається «AS IS».
  3. При підготовці матеріалу використовувались AI помічники.
  4. Наданий матеріал відображає винятково точку зору автора.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.