AWS SSO × Arc:複数アカウントの安全な切り替えを自動化する

2024-11-06
市川 翔
#
#
#

概要

複数のAWSアカウントをSSO管理している環境で、アカウント間の切り替えをスムーズに行うための手法について解説します。特にArcブラウザと自作スクリプトを組み合わせることで、意図しないアカウントへのログインを防ぎ、効率的な運用を実現する方法を紹介します。

課題

マルチアカウント環境での課題

  • 多数のAWSアカウントをSSO管理しており、アカウント間の行き来が頻繁に発生
  • Arcを使用して各アカウント用のプロファイルを分けて管理している状態

CLI操作時の認証における問題点

  • AWS CLIやCDKを使用する際、各アカウントでのaws sso loginが必要
  • aws sso login実行時、デバイスコード認証のためブラウザが自動起動
  • ブラウザは直前に使用したSSOセッションのプロファイルで開かれてしまう
  • その結果、意図しないアカウントでログインしてしまう可能性が高い

解決方法

以下のような工夫を実装したスクリプトを作成することで問題を解決しました:

  1. デバイスコードの認証時にURLにsso_session=${sso name}のクエリパラメータを追加
  2. Arcの「Air Traffic Control」機能でsso_session=${sso name}の値に応じてプロファイルを切り替えるよう設定
    • 「Air Traffic Control」機能により、URLパターンに基づいて自動的にプロファイルを切り替え可能
  3. 利便性向上のため、補完機能も実装

スクリプトの実装

メインスクリプト(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()

おわりに

今回の工夫により、以下のような利点が得られました:

  1. 意図したアカウントへの確実なログイン
  2. プロファイル切り替えの自動化
  3. コマンド補完による操作性の向上

結果として、複数アカウントの管理における人的ミスのリスクを低減し、より効率的な運用が可能になりました。

株式会社Grandreamでは、フルリモートであなたのスキルを活かし、活躍できるエンジニアを募集しております。 詳しくは採用ページをご確認いただき、お気軽にお問い合わせください。

株式会社グランドリームでは、AWSを駆使した開発からUI/UXデザインまで、Webアプリケーションに関するすべての要望に応えます。
まずは一度お気軽にご相談ください。

お問い合わせはこちら