【AWS Control Tower】監査アカウントからメンバーアカウントへの Lambda アクセスを試す

2022.02.21

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

aws-controltower-AuditAdministratorRole という Lambda 実行ロールが AWS Control Towerの 監査(Audit) アカウントには用意されています。 このロールを使って メンバーアカウントへアクセスできます(つまりクロスアカウントアクセス)。 主にセキュリティ周りの対応(修復) を行うためのものです。

img

  • ※1: Assume Role 先のロール名は aws-controltower-AdministratorExecutionRole
  • ※2: 読み取り専用(ReadOnly)用の Lambda 実行ロールも準備されています ( aws-controltower-AuditReadOnlyRole )

今回は aws-controltower-AuditAdministratorRole を使ってみます。 「メンバーアカウントへのアクセス基盤」作成として、最小限の実装を行ってみました。

作ったもの

メンバーアカウント先で sts:GetCallerIdentity を実行するだけ の 「何もしない (接続確認だけする) Lambda関数」 を作ります。

img

Lambda関数 基本設定

下図のような設定の Lambda関数です。 ランタイムとしては Python 3.8 を使っています。

img

実行ロールに aws-controltower-AuditAdministratorRole を指定しています。

img

Lambda関数 コード

以下のようなコードを作成しています。

src/check_assume_role/app.py

import boto3
import logging

logger = logging.getLogger()
logger.setLevel(logging.INFO)


def _sts_client(target_account_id):
    logger.info('[START] _sts_client')
    sts_connection = boto3.client('sts')
    try:
        # Assume Role
        role_arn = "arn:aws:iam::%s:role/aws-controltower-AdministratorExecutionRole" % target_account_id
        role_session_name = "CROSS_ACCOUNT_ACCESS_FROM_CTAUDIT"
        logger.info("- RoleArn=%s" % role_arn)
        logger.info("- RoleSessionName=%s" % role_session_name)
        target = sts_connection.assume_role(
            RoleArn=role_arn,
            RoleSessionName=role_session_name,
        )
    except Exception as e:
        logger.error(e)
        exit()
    else:
        client = boto3.client(
            'sts',
            aws_access_key_id=target['Credentials']['AccessKeyId'],
            aws_secret_access_key=target['Credentials']['SecretAccessKey'],
            aws_session_token=target['Credentials']['SessionToken']
        )
        logger.info('[END] _sts_client')
        return client


def check(sts_client):
    logger.info('[START] check')
    try:
        resp = sts_client.get_caller_identity()
        logger.info("- Account=%s" % resp['Account'])
        logger.info("- Arn=%s" % resp['Arn'])
    except Exception as e:
        logger.error(e)
        exit()
    else:
        logger.info('[END] check')
        return {"status": "success"}


def lambda_handler(event, context):
    logger.info('[START] lambda_handler')
    # Get Client
    sts_client = _sts_client(event['TargetAccountId'])
    # Run remediation(check)
    logger.info('# running check')
    results = check(sts_client)
    # End
    logger.info('[END] lambda_handler')
    return results

メンバーアカウントのアカウントIDを入力イベントに登録する想定です。 { "TargetAccountId": "123456789012" } のような入力イベントです。

(補足) SAMで作成

これらのリソース、設定を AWS SAM(Serverless Application Model) で展開しています。 template.yaml は以下のとおりです。

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31

Globals:
  Function:
    Runtime: python3.8
    Timeout: 600
    Handler: app.lambda_handler
    Architectures:
      - arm64            

Parameters:
  Project:
    Type: String
    Default: "audit-remediation"

Resources:
  CheckFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub "${Project}-check-assume-role"
      Role: !Sub "arn:aws:iam::${AWS::AccountId}:role/aws-controltower-AuditAdministratorRole"
      CodeUri: src/check_assume_role

Outputs:
  CheckFunction:
    Description: "Check Function ARN"
    Value: !GetAtt CheckFunction.Arn

確認

Lambda 関数の実行

以下のようなテストイベント { "TargetAccountId": "123456789012" } を作成して、実行します。

img

成功しました。以下のような出力としています。

img

各種ログの確認

### CloudWatch Logs の確認 at 監査アカウント

/aws/lambda/${関数名} ロググループに実行ログが保存されます。

img

### CloudTrail の確認 at 監査アカウント

メンバーアカウントへ Assume Role していることが CloudTrail イベントから確認できました。

img

### CloudTrail の確認 at メンバーアカウント

メンバーアカウント上で API実行(GetCallerIdentity) できていることを CloudTrail イベントから確認できました。

img

以下 イベントレコードの userIdentity 抜粋です。

img

おわりに

AWS Control Tower に用意されている aws-controltower-AuditAdministratorRole を使ったクロスアカウントアクセスを試してみました。

EventBridge や Step Functions と組み合わせることで、 「セキュリティリスクのあるリソースの自動修復」など 日々のセキュリティ運用に活用できそうです。

参考