概要
複数のAWSアカウントをSSO管理している環境で、アカウント間の切り替えをスムーズに行うための手法について解説します。特にArcブラウザと自作スクリプトを組み合わせることで、意図しないアカウントへのログインを防ぎ、効率的な運用を実現する方法を紹介します。
課題
マルチアカウント環境での課題
- 多数のAWSアカウントをSSO管理しており、アカウント間の行き来が頻繁に発生
- Arcを使用して各アカウント用のプロファイルを分けて管理している状態
CLI操作時の認証における問題点
- AWS CLIやCDKを使用する際、各アカウントでの
aws sso login
が必要 aws sso login
実行時、デバイスコード認証のためブラウザが自動起動- ブラウザは直前に使用したSSOセッションのプロファイルで開かれてしまう
- その結果、意図しないアカウントでログインしてしまう可能性が高い
解決方法
以下のような工夫を実装したスクリプトを作成することで問題を解決しました:
- デバイスコードの認証時にURLに
sso_session=${sso name}
のクエリパラメータを追加 - Arcの「Air Traffic Control」機能で
sso_session=${sso name}
の値に応じてプロファイルを切り替えるよう設定- 「Air Traffic Control」機能により、URLパターンに基づいて自動的にプロファイルを切り替え可能
- 利便性向上のため、補完機能も実装
スクリプトの実装
メインスクリプト(bin/aws_sso_login
)
#!/bin/bash
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &> /dev/null && pwd)"
PYTHON_SCRIPT="${SCRIPT_DIR}/aws_sso_login.py"
if [ "$#" -eq 0 ]; then
profiles=$("$PYTHON_SCRIPT")
echo "利用可能なプロファイル:"
echo "$profiles"
echo "使用方法: aws_sso_login "
exit 1
fi
"$PYTHON_SCRIPT" "$@"
補完機能スクリプト(bin/aws_sso_login_completion
)
#!/bin/bash
_aws_sso_login_completion() {
local cur prev opts
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
opts=$(~/.aws/bin/aws_sso_login.py)
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
}
complete -F _aws_sso_login_completion aws_sso_login
メインロジック(bin/aws_sso_login.py
)
#!/usr/bin/env python3
import os
import sys
import subprocess
import configparser
import webbrowser
import time
import re
def get_profiles_with_sso_session():
config = configparser.ConfigParser()
config.read(os.path.expanduser("~/.aws/config"))
profiles = {}
for section in config.sections():
if section.startswith("profile "):
profile_name = section.split()[1]
sso_session = config[section].get("sso_session", "")
if sso_session: # sso_sessionが設定されている場合のみ追加
profiles[profile_name] = sso_session
return profiles
def run_aws_sso_login(profile_name, sso_session):
command = f"aws sso login --profile {profile_name} --no-browser"
print(f"プロファイル {profile_name} の AWS SSO ログインを開始します...")
process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
url_with_code = None
for line in process.stdout:
print(line, end='')
# user_code付きのURLを探す
match = re.search(r'(https://\\S+user_code=\\S+)', line)
if match:
url_with_code = match.group(1)
break
if url_with_code:
# URLにsso_sessionパラメータを追加
modified_url = f"{url_with_code}&sso_session={sso_session}"
print(f"\\n認証 URL をブラウザで開きます: {modified_url}")
try:
webbrowser.open(modified_url)
except webbrowser.Error:
print("ブラウザを自動で開けませんでした。以下のURLを手動でブラウザにコピー&ペーストしてください:")
print(modified_url)
print("\\nブラウザで認証を完了してください。")
print("認証が完了したら、このターミナルに戻ってきてEnterキーを押してください。")
input()
# 残りの出力を表示
for line in process.stdout:
print(line, end='')
else:
print("user_code付きの認証 URL が見つかりませんでした。")
process.wait()
if process.returncode != 0:
print("エラー: AWS SSO ログインに失敗しました。")
print(process.stderr.read())
else:
print("AWS SSO ログインが正常に完了しました。")
def main():
profiles = get_profiles_with_sso_session()
if len(sys.argv) < 2:
for profile in profiles:
print(profile)
sys.exit(0)
profile_name = sys.argv[1]
if profile_name not in profiles:
print(f"エラー: プロファイル '{profile_name}' が見つかないか、sso_sessionが設定されていません。", file=sys.stderr)
print("利用可能なプロファイル (sso_sessionが設定されているもの):", file=sys.stderr)
for profile in profiles:
print(profile, file=sys.stderr)
sys.exit(1)
sso_session = profiles[profile_name]
run_aws_sso_login(profile_name, sso_session)
if __name__ == "__main__":
main()
おわりに
今回の工夫により、以下のような利点が得られました:
- 意図したアカウントへの確実なログイン
- プロファイル切り替えの自動化
- コマンド補完による操作性の向上
結果として、複数アカウントの管理における人的ミスのリスクを低減し、より効率的な運用が可能になりました。
株式会社Grandreamでは、フルリモートであなたのスキルを活かし、活躍できるエンジニアを募集しております。
詳しくは採用ページをご確認いただき、お気軽にお問い合わせください。