AWS SSO отлично подходит для централизованного управления идентификацией и доступом для всех учетных записей AWS из корневой учетной записи AWS. Вы найдете множество блогов, а также документы AWS по настройке и управлению AWS SSO.
Однако большинство организаций предпочитают эфемерные токены сеанса для повседневной деятельности по автоматизации с использованием AWS CLI, CI / CD или DevOps Pipelines вместо ключей доступа и секретных ключей, и текущие ограничения включают:
- Интеграция интерфейса командной строки AWS с AWS SSO с помощью команды cli «aws configure sso» не проверяет учетные данные до регистрации клиентского приложения AWS SSO, а также до регистрации устройства
- URL-адрес подтверждения регистрации устройства требует доступа браузера для выполнения аутентификации и авторизации для создания токена сеанса, что является своего рода ручным шагом
В этой статье дано пошаговое руководство по обходному пути для решения вышеуказанных ограничений.
Примечание. Доступ браузера для аутентификации и авторизации нельзя обойти в соответствии с AWS.
Python и Selenium - веб-драйвер Microsoft Edge (для автоматизации браузера) был выбран для быстрого развертывания и тестирования решений, тогда как выбор языка программирования и веб-драйвера зависит только от вас.
Вы можете загрузить веб-драйвер Microsoft Edge по адресу: https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/
Необходимые модули Python:
- BOTO3
- АДАЛ
- СЕЛЕН
- ИНСТРУМЕНТЫ ДЛЯ СЕЛЕНА MSEDGE
Установите необходимые модули Python, указанные выше, с помощью pip.
Примечание. Задайте указанные ниже переменные среды перед запуском модуля Python
- Прокси-сервер HTTP и HTTPS в случае использования прокси-сервера предприятия
- EDGE_DRIVER_PATH - укажите местоположение загруженного и извлеченного веб-драйвера MS Edge на вашем компьютере или сервере
Ниже приведен код Python для генерации токенов сеанса для авторизованного пользователя с использованием AWS SSO - AAD.
- Импортировать необходимые модули Python
import os import time from adal import AuthenticationContext import getpass import boto3 from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By from msedge.selenium_tools import Edge, EdgeOptions import argparse EDGE_DRIVER = os.environ["EDGE_DRIVER_PATH"]
- Разбор идентификатора учетной записи и входных аргументов роли
if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('--accountId', default='', help='provide AWS Account ID eg., 123456789012') parser.add_argument('--roleId', default='', help='provide AWS Federated SAML Role ID eg., Developer') args = parser.parse_args() accountId = "" if args.accountId: accountId = args.accountId else: print("Please provide accountId argument") roleId = "" if args.roleId: roleId = args.roleId else: print("Please provide roleId argument") main(accountId, roleId)
- предложить пользователю ввести адрес электронной почты и пароль пользователя
def main(accountId, roleId): print("User Email:", end=' ') username = input() password = getpass.getpass()
- Убедитесь, что введенные пользователем адрес электронной почты и пароль действительны, для этого шага требуются идентификатор клиента AAD, идентификатор клиента AAD, URL-адрес авторизации AAD и URL-адрес ресурса AAD.
AAD_AUTHORITY_HOST_URI = 'https://login.microsoftonline.com' AAD_TENANT_ID = << AAD AWS Enterprise App Tenant ID >> AAD_RESOURCE_URI = 'https://graph.windows.net' AAD_CLIENT_ID = << AAD AWS Enterprise App Client ID >> authority_uri = AAD_AUTHORITY_HOST_URI + '/' + AAD_TENANT_ID token = "" try: context = AuthenticationContext(authority_uri, api_version=None) mgmt_token = context.acquire_token_with_username_password(AAD_RESOURCE_URI, username, password, AAD_CLIENT_ID) print("AAD Token Generated, AD Credentials are valid") token = mgmt_token["accessToken"] except: print("Invalid AD Credentials, Please verify Entered Credentials")
- Зарегистрируйте клиента, если введенные пользователем учетные данные действительны
REGION = 'us-east-1' if token: sso_oidc = boto3.client('sso-oidc', region_name=REGION) client = sso_oidc.register_client( clientName= << Provide your appropriate Client Name >>, clientType='public' ) client_id = client.get('clientId') client_secret = client.get('clientSecret') print("Client Registered Successfully")
- Зарегистрируйте устройство с помощью сгенерированного идентификатора клиента и секрета клиента
AWS_SSO_START_URL = << AWS SSO Start URL from AWS SSO Console >> authz = sso_oidc.start_device_authorization( clientId=client_id, clientSecret=client_secret, startUrl=AWS_SSO_START_URL ) url = authz.get('verificationUriComplete') deviceCode = authz.get('deviceCode') print("Verification URL Generated Successfully")
- Код для автоматизации шагов браузера приведен ниже, открывает браузер MS Edge в частном режиме, учитывает перенаправления и автоматически вводит адрес электронной почты пользователя и пароль при появлении запроса, а также авторизует устройство.
browserOptions = EdgeOptions() browserOptions.use_chromium = True browserOptions.add_argument("-inprivate") browser = Edge(executable_path=EDGE_DRIVER, options=browserOptions) browser.get(url) wait = WebDriverWait(browser, 180) waitLoginURL = AAD_AUTHORITY_HOST_URI + "/" + AAD_TENANT_ID + "/saml2" wait.until(EC.url_contains(waitLoginURL)) nameWait = WebDriverWait(browser, 20) nameWait.until(EC.visibility_of_any_elements_located((By.NAME, 'loginfmt'))) browser.find_element_by_name('loginfmt').send_keys(username) browser.find_element_by_xpath("//input[@type='submit' and @value='Next']").click() wait.until(EC.visibility_of_any_elements_located((By.NAME, 'passwd'))) browser.find_element_by_name('passwd').send_keys(password) browser.find_element_by_xpath("//input[@type='submit' and @value='Sign in']").click() wait.until(EC.url_contains('/start/user-consent/authorize.html')) browser.find_element_by_id('cli_login_button').click() print("Successful Device Registration")
- Ввести 5-секундный спящий режим (на всякий случай, когда AWS необходимо распространить и сохранить событие авторизации API в базе данных AWS)
time.sleep(5)
- Сгенерируйте токен SSO AWS, используя зарегистрированный идентификатор клиента, секрет клиента и код устройства.
token_response = sso_oidc.create_token( clientId=client_id, clientSecret=client_secret, grantType="urn:ietf:params:oauth:grant-type:device_code", deviceCode=deviceCode ) sso_token = token_response.get('accessToken') print("SSO Token Generated Successfully")
- Получите список учетных записей AWS, к которым у пользователя есть доступ с помощью токена AWS SSO, созданного на шаге выше.
sso = boto3.client('sso', region_name=REGION) listAccounts = ssoListAccounts(sso, sso_token)
- Проверьте, входит ли предоставленный пользователем идентификатор учетной записи в авторизованный список учетных записей AWS, в случае положительного ответа продолжить и получить все роли учетных записей AWS.
if accountId in listAccounts: listAcctRoles = ssoListAccountRoles(sso, sso_token, accountId)
- Проверьте, входит ли предоставленный пользователем идентификатор роли в авторизованный список ролей учетных записей AWS, если да, продолжайте и сгенерируйте токен сеанса AWS SSO
if roleId in listAcctRoles: sts_credentials = sso.get_role_credentials( accessToken=sso_token, accountId=accountId, roleName=roleId ) aws_access_key_id = sts_credentials['roleCredentials']['accessKeyId'] aws_secret_access_key = sts_credentials['roleCredentials']['secretAccessKey'] aws_session_token = sts_credentials['roleCredentials']['sessionToken']
- Закройте браузер Microsoft Edge.
browser.close()
Подфункции Python:
- ssoListAccounts - это подфункция для обработки вызовов API разбивки на страницы в аккаунтах AWS SSO List, или вы можете использовать API разбиения на страницы boto3 по своему усмотрению.
def listAccounts(found_token, sso, sso_token): if found_token: accounts = sso.list_accounts(nextToken=found_token, accessToken=sso_token) else: accounts = sso.list_accounts(accessToken=sso_token) return accounts def ssoListAccounts(sso, sso_token): records = [] more_objects = True found_token = "" while more_objects: accounts = listAccounts(found_token, sso, sso_token) for account in accounts['accountList']: if 'accountId' in account: records.append(account['accountId']) # Now check there is more objects to list if 'nextToken' in accounts: found_token = accounts['nextToken'] more_objects = True else: break return records
- ssoListAccountRoles - это подфункция для обработки ролей учетных записей AWS SSO List.
def listAcctRoles(found_token, sso, sso_token, accountId): if found_token: roles_response = sso.list_account_roles(nextToken=found_token,accessToken=sso_token,accountId=accountId) else: roles_response = sso.list_account_roles(accessToken=sso_token,accountId=accountId) return roles_response def ssoListAccountRoles(sso, sso_token, accountId): records = [] more_objects = True found_token = "" while more_objects: accountRoles = listAcctRoles(found_token, sso, sso_token, accountId) for accountRole in accountRoles['roleList']: if 'roleName' in accountRole: records.append(accountRole['roleName']) # Now check there is more objects to list if 'nextToken' in accountRoles: found_token = accountRoles['nextToken'] more_objects = True else: break return records
Это был настоящий путь, который нельзя было обойти, а также ввести дополнительные шаги проверки, чтобы заставить это работать. Надеюсь, это поможет другим.
Больше контента на plainenglish.io