ドキュメント公開されていないAWS Control Tower のAPI を呼んでみた。Use awsapilib
AWS事業本部の梶原@福岡オフィスです。 出オチですが、やっていることは以下となります。
awsapilibというGithubで公開されているライブラリを使用して、AWSでドキュメント公開されていないサービスのAPIをPythonから呼ぶ方法となります。
※注意
当然AWSのドキュメントにないものですので、本ブログの内容を実施したことによる影響については責任を持ちません。軽く動作することの確認はしておりますが、将来的なAPIの変更や突然APIが呼べなくなる可能性もありますので ご使用の際は十分にご検証することを推奨いたします。
ということで、最近、AWS Contorol Towerを触る機会が多いのですが、現時点(2022/04/26)ではControl Towerを操作するようなAPIのドキュメントは公開されておりません。 Control Towerを操作する上で必要なものはすべてコンソール上で可能です。 AWSからのご案内も下記のようになります。
https://aws.amazon.com/jp/controltower/faqs/
Q: Is there an API available for AWS Control Tower?
No. You can use AWS Control Tower through the AWS Management Console to perform all necessary operations.
でも、ブラウザなどをデバッグモードで追っていると、なんかあるんですよね。。。API
なんかあるんですよね。エンドポイント。。。
なんとかコードでControl Towerの情報を取得したい!!!(アカウント100とかあるんよ。200とか!切実
ということで、
思いきって、Githubの海に飛び込んだら、awsapilibに会えて、幸せ!
と、前置きはこんな雑な感じでいきます。
awsapilib とは
https://github.com/schubergphilis/awsapilib
A python library that exposes AWS services that are not covered by boto3, through the usage of undocumented APIs.
繰り返しになってしまいますが、AWSの名前は入ってしまってますが、単純にGithubに公開されているライブラリです。AWS SDK等で使用されているBoto3などではありませんので、ご使用は自己責任でお願いします。
対応しているサービス(一部のみ)
- ControlTower
- SSO
- Billing
- Account Manager
よく見ると前から欲しかったAPIが並んでますね。繰り返しになりますが、ドキュメント化されていないAWSサービスのAPIとなります。また、すべてのAPIがサポートされているわけでなく、一部のAPIになるようです。
やってみた
相変わらずですが、CloudFormation テンプレートでのご提供です。 AWSコンソールにログイン後に下記テンプレートのURLをクリックしてください。
□AWS CloudFormation によって IAM リソースが作成される場合があることを承認します。 をチェックし
スタックを実行すると、GetControlTowerAccounts というLambda関数が作成されます。
Lambada実行時にスイッチロールする権限(AwsApiLibRole)はAdministrator権限を割り当てているので、実際に使用する場合は必要なRole等を割り当ててください
テンプレート全体は、本ブログの最後に記載しています。
Control Tower 配下のアカウントの一覧を出力するLambda(Python)関数となります。
Lambda
Pyhon関数の実行時に、awsapilib (現在のバージョン 2.1.1) をinstallしています。 1分以内ではありますが、実際にプロダクションで使われる場合は、Lambda Layer化するなどの方法をご検討ください
抜粋
sys.path.insert(1, '/tmp/packages') subprocess.check_call([sys.executable, "-m", "pip", "install", '--target', '/tmp/packages', 'awsapilib==2.1.1'])
実際のawsapilibでContorl Towerのアカウントの一覧の取得処理は下記のようになります。
外部環境変数 'AWSAPILIB_CONTROL_TOWER_ROLE_ARN’ で、Administrator権限に割り当てられたAwsApiLibRoleを指定し、関数内でAssrume Roleしています。
抜粋
import awsapilib from awsapilib import ControlTower @exception_handling def lambda_handler(event, context): tower = ControlTower(os.environ['AWSAPILIB_CONTROL_TOWER_ROLE_ARN']) for account in tower.accounts: print(account.name)
結果
実行してみると
Audit, Log Archive などのContorl Tower 配下のアカウントが取得できており正常に動いているようです。 ソースコードを参照すると、Contorol Towerr のlistManagedAccounts のAPIが呼ばれています。
CoudTrail にもListManagedAccounts のアクセスが記録されていますので、正常に呼び出せているようです。
カスタマイズ
awsapilibのドキュメントを参照して、必要な情報を取得し、整形等すればちょっと使えそうな気がしています。
ソースコード等公開されていますので、必要なAPIが見つからない場合は、ちょっと?追加実装すれば対応できそうです。
とはいえ、仕様等は手探りになりますので、結構いばらの道かと思います。そこにAPIがあるから叩くんだくらいの気合はいると思います。
まとめ
Githubの海を漂っているうちにSuperwerker という、AWSが紹介しているQuickStartでControl Towerを有効化してアカウントを作成する際に中で使われていたりしたので、大部分はこちらのControlTowerの制御部分を参考にさせてもらっています。 https://aws-quickstart.github.io/quickstart-superwerker/
ドキュメント化されていないAPIになるので、ソースコードの確認や、IAM権限の確認、副作用の確認、AWSのサポートに 聞けない、などなど超えなければ行けない壁はひたすらありますが
- 適切権限を与える
- 変更を伴う操作はAPIでなく、コンソールから行う
- コンソールで設定した結果の確認、取得
- 現在の設定値の一覧を取得する
など、ユースケースによっては有用そうです。
参考情報
awsapilib Document https://awsapilib.readthedocs.io/en/latest/
awsapilib Github https://github.com/schubergphilis/awsapilib
Superwerker https://aws-quickstart.github.io/quickstart-superwerker/
テンプレート
# # The following template was used as a reference # https://github.com/aws-quickstart/quickstart-superwerker/blob/main/templates/control-tower.yaml # AWSTemplateFormatVersion: "2010-09-09" Resources: GetControlTowerAccounts: Type: AWS::Lambda::Function Properties: Handler: index.lambda_handler Runtime: python3.9 Timeout: 900 # give it more time since it installs awsapilib and tries to deploy control tower with retries Role: !GetAtt GetControlTowerAccountsRole.Arn # provide explicit role to avoid circular dependency with AwsApiLibRole Environment: Variables: AWSAPILIB_CONTROL_TOWER_ROLE_ARN: !GetAtt AwsApiLibRole.Arn FunctionName: GetControlTowerAccounts Code: ZipFile: | import boto3 import os import sys import subprocess # load awsapilib in-process as long as we have no strategy for bundling assets sys.path.insert(1, '/tmp/packages') subprocess.check_call([sys.executable, "-m", "pip", "install", '--target', '/tmp/packages', 'awsapilib==2.1.1']) import awsapilib from awsapilib import ControlTower def exception_handling(function): def catch(event, context): try: function(event, context) except Exception as e: print(e) print(event) return catch @exception_handling def lambda_handler(event, context): tower = ControlTower(os.environ['AWSAPILIB_CONTROL_TOWER_ROLE_ARN']) for account in tower.accounts: print(account.name) GetControlTowerAccountsRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: lambda.amazonaws.com Action: sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole AwsApiLibRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: AWS: !GetAtt GetControlTowerAccountsRole.Arn Action: sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/AdministratorAccess Outputs: MyFunctionArn: Value: !GetAtt GetControlTowerAccounts.Arn