Как принудительно обновить учетные данные входа AWS SSO для предотвращения истечения срока действия токена во время длительно выполняющихся задач?
Я использую Metaflow с S3 и мне необходимо пройти аутентификацию через AWS CLI единый вход (aws sso login). Проблема в том, что я не могу программно обновлять учетные данные входа SSO при их истечении срока действия.
Сценарий проблемы:
- Таймаут SSO установлен на 24 часа
- День 1: Вход в систему в 10:00 с помощью aws sso login
- День 2: Запуск программы в 9:00 с помощью aws sso login снова
- Токен все еще действителен при входе, но истекает в 10:00
- Мой Metaflow-поток аварийно завершается, когда он больше не может получить доступ к S3 после истечения срока действия токена
Как можно предотвратить эту проблему? Я не нашел релевантной информации при поиске. Стоит ли мне вручную удалять токены в ~/.aws/sso/cache?
У меня также есть длительно выполняющиеся задачи, которые превышают 24-часовой период таймаута.
Токены AWS SSO автоматически истекают через 24 часа по дизайну, но вы можете программно обновлять их с помощью команд AWS CLI, пользовательских скриптов или механизма кэширования AWS SSO. Для длительно работающих заданий, превышающих 24 часа, необходимо реализовать логику автоматического обновления учетных данных или использовать альтернативные методы аутентификации, такие как роли IAM или долгоживущие токены STS с MFA.
Содержание
- Понимание кэширования токенов AWS SSO
- Программные методы обновления учетных данных
- Решения для длительно работающих заданий
- Лучшие практики интеграции с Metaflow
- Ручное управление токенами
- Вопросы безопасности
Понимание кэширования токенов AWS SSO
При аутентификации с помощью aws sso login AWS CLI выполняет поток OIDC/OAuth и сохраняет файл JSON токена в директории кэша SSO, обычно расположенной по пути ~/.aws/sso/cache/. Этот кэш содержит важную информацию:
{
"accessToken": "Bearer_token_value",
"expiresAt": "2025-01-15T10:00:00Z",
"clientId": "client_id_value",
"clientSecret": "secret_value",
"region": "us-east-1",
"startUrl": "https://your-sso-start-url"
}
Отметка времени expiresAt определяет, когда токен становится недействительным. Вы не можете напрямую обновлять этот токен программно - он предназначен для обновления путем повторного выполнения aws sso login при истечении срока действия. Согласно документации AWS, токены SSO являются краткосрочными мерами безопасности, которые снижают риск утечки учетных данных по сравнению с долгоживущими ключами доступа.
Программные методы обновления учетных данных
Метод 1: Скрипт обновления токенов AWS SSO
Создайте скрипт, который проверяет срок действия токена и обновляет его при необходимости:
#!/bin/bash
CACHE_DIR="$HOME/.aws/sso/cache"
TOKEN_FILE=$(ls -t $CACHE_DIR/*.json | head -1)
if [ -f "$TOKEN_FILE" ]; then
EXPIRES_AT=$(jq -r '.expiresAt' "$TOKEN_FILE")
CURRENT_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
if [[ "$CURRENT_TIME" > "$EXPIRES_AT" ]]; then
echo "Токен истек, обновляем..."
aws sso login --profile your-sso-profile
else
echo "Токен все еще действителен"
fi
else
echo "Токен не найден, выполняем вход..."
aws sso login --profile your-sso-profile
fi
Метод 2: Скрипт Python с Boto3
Для программного доступа используйте AWS SDK для получения учетных данных роли:
import boto3
import json
import os
from datetime import datetime, timedelta
def get_sso_credentials(sso_start_url, sso_region, sso_account_id, sso_role_name):
"""Получение учетных данных SSO с использованием токена AWS SSO из кэша"""
sso_client = boto3.client('sso', region_name=sso_region)
# Читаем кэшированный токен
cache_file = os.path.expanduser('~/.aws/sso/cache/*.json')
with open(cache_file, 'r') as f:
token_data = json.load(f)
# Получаем учетные данные роли
response = sso_client.get_role_credentials(
accessToken=token_data['accessToken'],
accountId=sso_account_id,
roleName=sso_role_name
)
credentials = response['roleCredentials']
return {
'aws_access_key_id': credentials['accessKeyId'],
'aws_secret_access_key': credentials['secretAccessKey'],
'aws_session_token': credentials['sessionToken'],
'expiration': credentials['expiration']
}
def check_and_refresh_credentials():
"""Проверка необходимости обновления учетных данных и возврат новых"""
# Конфигурация SSO
config = {
'sso_start_url': 'https://your-sso-start-url',
'sso_region': 'us-east-1',
'sso_account_id': '123456789012',
'sso_role_name': 'YourRoleName'
}
return get_sso_credentials(**config)
Метод 3: Использование AWS STS с MFA
Для получения учетных данных с более длительным сроком действия используйте AWS STS с MFA:
#!/bin/bash
MFA_ARN="arn:aws:iam::123456789012:mfa/your-user"
DURATION=86400 # 24 часа
PROFILE="your-profile"
echo -n "Введите код MFA: "
read TOKEN_CODE
# Получение временных учетных данных
CREDS=$(aws sts get-session-token \
--serial-number "$MFA_ARN" \
--token-code "$TOKEN_CODE" \
--duration-seconds "$DURATION" \
--profile "$PROFILE" \
--output json)
# Извлечение учетных данных
AWS_ACCESS_KEY_ID=$(echo $CREDS | jq -r '.Credentials.AccessKeyId')
AWS_SECRET_ACCESS_KEY=$(echo $CREDS | jq -r '.Credentials.SecretAccessKey')
AWS_SESSION_TOKEN=$(echo $CREDS | jq -r '.Credentials.SessionToken')
# Экспорт для использования в скриптах
export AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN
Решения для длительно работающих заданий
Решение 1: Автоматическое обновление учетных данных в Metaflow
Модифицируйте ваш скрипт Metaflow для обработки обновления учетных данных:
import os
import subprocess
import time
from datetime import datetime, timedelta
import boto3
class RefreshableCredentials:
def __init__(self):
self.credentials = None
self.expiration = datetime.now()
self.refresh_threshold = timedelta(minutes=30)
def refresh_if_needed(self):
"""Обновление учетных данных, если они скоро истекут"""
if datetime.now() > (self.expiration - self.refresh_threshold):
self.refresh_credentials()
def refresh_credentials(self):
"""Обновление AWS учетных данных"""
try:
# Выполнение aws sso login для обновления токена
subprocess.run(['aws', 'sso', 'login'], check=True)
# Создание новой сессии boto3
session = boto3.Session()
self.credentials = session.get_credentials()
self.expiration = datetime.now() + timedelta(hours=1) # Токены SSO действуют 1 час после обновления
except subprocess.CalledProcessError as e:
print(f"Не удалось обновить учетные данные: {e}")
raise
# Использование в потоке Metaflow
class MyFlow(FlowSpec):
@step
def start(self):
self.credentials = RefreshableCredentials()
self.next(self.process_data)
@step
def process_data(self):
# Обновление учетных данных перед длительной операцией
self.credentials.refresh_if_needed()
# Установка переменных окружения для boto3
os.environ['AWS_ACCESS_KEY_ID'] = self.credentials.credentials.access_key
os.environ['AWS_SECRET_ACCESS_KEY'] = self.credentials.credentials.secret_key
os.environ['AWS_SESSION_TOKEN'] = self.credentials.credentials.token
# Ваши операции S3 здесь
s3 = boto3.client('s3')
# ... ваш код ...
self.next(self.end)
@step
def end(self):
pass
Решение 2: Роли IAM для EC2/ECS
Если выполняется на AWS инфраструктуре, используйте роли IAM вместо учетных данных SSO:
# Для EC2 экземпляров
aws ec2 associate-iam-instance-profile \
--instance-id i-1234567890abcdef0 \
--iam-instance-profile Name=YourIAMRoleName
# Для ECS задач
aws ecs run-task \
--cluster your-cluster \
--task-definition your-task-definition \
--launch-type FARGATE \
--network-configuration "awsvpcConfiguration={subnets=[subnet-123456],securityGroups=[sg-123456]}"
Решение 3: Долгоживущие учетные данные с MFA
Для действительно длительно работающих заданий используйте AWS STS для получения учетных данных сроком до 12 часов с MFA:
import boto3
from datetime import datetime, timedelta
def get_long_lived_credentials():
"""Получение учетных данных, действительных до 12 часов, с MFA"""
sts_client = boto3.client('sts')
# Получение ARN устройства MFA
iam_client = boto3.client('iam')
mfa_devices = iam_client.list_mfa_devices(UserName='your-username')
mfa_arn = mfa_devices['MFADevices'][0]['SerialNumber']
# Запрос кода MFA
mfa_code = input("Введите код MFA: ")
# Получение сессионного токена
response = sts_client.get_session_token(
DurationSeconds=43200, # 12 часов
SerialNumber=mfa_arn,
TokenCode=mfa_code
)
credentials = response['Credentials']
expiration = credentials['Expiration']
return {
'access_key': credentials['AccessKeyId'],
'secret_key': credentials['SecretAccessKey'],
'session_token': credentials['SessionToken'],
'expiration': expiration
}
Лучшие практики интеграции с Metaflow
Подход к конфигурации 1: Переменные окружения
Настройте Metaflow для использования переменных окружения для AWS учетных данных:
# В вашем .bashrc или профиле
export AWS_PROFILE=your-sso-profile
export AWS_CONFIG_FILE=~/.aws/config
# Конфигурация Metaflow
export METAFLOW_SERVICE_ROLE=your-service-role
export METAFLOW_DEFAULT_DATASTORE=s3://your-bucket
export METAFLOW_DEFAULT_METADATA_SERVICE=rds-postgres://your-db
Подход к конфигурации 2: Плагин Metaflow AWS
Используйте плагин Metaflow AWS для лучшей интеграции:
from metaflow import FlowSpec, step, S3
class AWSFlow(FlowSpec):
@step
def start(self):
# Использование S3 с автоматической обработкой учетных данных
s3_path = S3('your-bucket/your-file.txt')
# Ваш код здесь
self.next(self.process)
@step
def process(self):
# Metaflow автоматически обрабатывает обновление учетных данных
# при использовании операций S3
self.next(self.end)
@step
def end(self):
pass
Подход к конфигурации 3: Поставщик пользовательских учетных данных
Создайте поставщик пользовательских учетных данных для Metaflow:
import boto3
from botocore.credentials import DeferredRefreshableCredentials
class SSOCredentialProvider:
def __init__(self):
self.session = boto3.Session()
def get_credentials(self):
# Проверяем, нужно ли обновлять
if hasattr(self, '_credentials') and self._credentials is not None:
exp_time = self._credentials.time_remaining()
if exp_time > 300: # 5 минут
return self._credentials
# Обновление учетных данных
try:
self.session.refresh()
self._credentials = self.session.get_credentials()
return self._credentials
except Exception as e:
print(f"Не удалось обновить учетные данные: {e}")
raise
# Использование в Metaflow
credentials = SSOCredentialProvider()
os.environ['AWS_ACCESS_KEY_ID'] = credentials.get_credentials().access_key
os.environ['AWS_SECRET_ACCESS_KEY'] = credentials.get_credentials().secret_key
os.environ['AWS_SESSION_TOKEN'] = credentials.get_credentials().token
Ручное управление токенами
Когда удалять файлы кэша
Следует вручную удалять файлы кэша в следующих сценариях:
# Удаление всех файлов кэша SSO
rm -rf ~/.aws/sso/cache/*
# Удаление конкретных истекших токенов
find ~/.aws/sso/cache -name "*.json" -mtime +1 -delete
# Проверка дат истечения срока действия токенов
ls -la ~/.aws/sso/cache/
cat ~/.aws/sso/cache/*.json | jq '.expiresAt'
Автоматическая очистка кэша
Создайте cron задачу для очистки старых токенов:
# Редактирование crontab
crontab -e
# Добавьте эту строку для очистки токенов старше 24 часов
0 2 * * * find ~/.aws/sso/cache -name "*.json" -mtime +1 -delete >/dev/null 2>&1
Однако ручное удаление токенов не является рекомендуемым решением для вашего случая использования. Это временный исправление, требующее ручного вмешательства и не решающий основной проблемы длительно работающих заданий, превышающих срок действия токена.
Вопросы безопасности
Риск хранения токенов
Обратите внимание, что файлы кэша AWS SSO хранятся в открытом тексте, что создает риски безопасности:
# Проверка прав доступа к файлу
ls -la ~/.aws/sso/cache/
# Должно быть: -rw------- (права 600)
Лучшие практики
- Используйте короткие сроки действия токенов - Стандартный срок действия токена в 1 час является хорошим балансом
- Включите MFA - Всегда требуйте многофакторную аутентификацию для доступа SSO
- Используйте роли IAM - отдавайте предпочтение ролям экземпляров вместо долгоживущих учетных данных
- Мониторьте использование токенов - Регулярно просматривайте журналы истечения срока действия токенов
- Реализуйте ротацию учетных данных - Автоматически обновляйте учетные данные перед истечением срока их действия
Альтернативные подходы
Для действительно длительно работающих заданий рассмотрите эти альтернативы:
- Используйте роли AWS IAM - Назначайте роли EC2 экземплярам, ECS задачам или функциям Lambda
- Используйте AWS STS AssumeRole - Получайте временные учетные данные с настраиваемыми сроками действия
- Используйте OIDC Federation - Подключайте GitHub Actions или другие CI/CD системы напрямую к AWS
- Используйте файл учетных данных AWS - Генерируйте долгоживущие ключи с соответствующими мерами безопасности
Заключение
Чтобы предотвратить истечение срока действия токенов AWS SSO во время длительно работающих заданий:
- Реализуйте автоматическое обновление учетных данных с помощью Python скриптов, которые проверяют срок действия токена и выполняют
aws sso loginпри необходимости - Используйте AWS STS с MFA для получения учетных данных сроком до 12 часов
- Используйте роли IAM при возможности для аутентификации на основе инфраструктуры
- Интегрируйте обновление учетных данных непосредственно в потоки Metaflow с помощью управления переменными окружения
- Избегайте ручного удаления токенов, так как это не масштабируемое решение и требует постоянного мониторинга
Наиболее устойчивым решением является реализация программного обновления учетных данных в ваших рабочих процессах Metaflow, обеспечивая беспрепятственный доступ к AWS ресурсам без перерывов. Для производственных сред рассмотрите использование ролей IAM или STS AssumeRole для лучшей безопасности и более простого управления.
Источники
- Использование токенов AWS Identity Center (SSO) для скриптинга по нескольким аккаунтам - DEV Community
- Что такое SSO? - Объяснение Single Sign-On - AWS
- Автоматическое обновление временных учетных данных AWS CLI с MFA - Medium
- AWS Security Token Service STS и использование - DEV Community
- AWS SSO | Документация DBeaver