CloudFormationテンプレートを使ってIAMユーザを一括作成

本記事ではCfnを使って遊びましたのでまとめてみます。

CFnとはなにか

CFnとは公式ドキュメント

Infrastructure as Codeと呼ばれるものです。
AWSで利用するEC2やVPCなどのリソースをコードでビルドすることができます。

Yaml、JSON形式で書かれたテンプレート(パラメータシート)を元に作成することができるため1度作成すれば同じ作業を繰り返すことが不要となります。

利用するCFnテンプレートを公開してますので参考になれば!!

本記事の概要

やること

  • 大量にIAMユーザを作成するための作業をIacコード化する。
    • とにかく作成できればよしとする。
    • 作成したユーザはユーザ名、初回PWのみ定義
  • 作成するInputファイルはCSV形式

CFnテンプレート作成

設計・テンプレート要約

  • 作成するユーザ情報はS3(dorablo-cloudformation-template/list/*’ )に   格納されたファイルをインプットとする。

<user-list.csv>

usernamepassword
user1Zaq12wsx
user2Zaq12wsx
user3Zaq12wsx

  • LambdaExecutionRole
    Lambda関数がAWSリソースにアクセスできるようにするIAMロール。このロールには、ログの作成、IAMユーザーの作成、S3からのオブジェクトの取得などの権限を付与
  • IamUserCreatorFunction
    Python 3.9を実行環境とするLambda関数。この関数は、イベントから受け取ったCSVファイルのS3パスを解析し、ファイルを取得して読み込みます。その後、CSVファイルからユーザー名と初回パスワードを取得し、IAMユーザーを作成して、初回ログイン時にパスワードをリセットするように設定する。
  • CreateUserCustomResource
    カスタムリソースとして定義されたこのリソースは、Lambda関数をトリガーします。CsvS3Pathプロパティを通じて、CSVファイルのS3パスがLambda関数に渡します。
AWSTemplateFormatVersion: '2010-09-09'
Description: CloudFormation template to create IAM users using a Lambda function and a CSV file

Resources:
  # IAM
  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - sts:AssumeRole
      Policies:
        - PolicyName: LambdaIamUserCreatorPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                Resource: '*'
              - Effect: Allow
                Action:
                  - iam:CreateUser
                  - iam:CreateLoginProfile
                Resource: '*'
              - Effect: Allow
                Action:
                  - s3:GetObject
                Resource: 'arn:aws:s3:::dorablo-cloudformation-template/list/*'

  # Lambda function
  IamUserCreatorFunction:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: NewIamUserCreator
      Handler: index.lambda_handler
      Runtime: python3.9
      Code:
        ZipFile: |
          import boto3
          import csv
          from urllib.parse import urlparse
          from botocore.exceptions import ClientError

          def lambda_handler(event, context):
              s3_path = event['ResourceProperties']['CsvS3Path']
              parsed_url = urlparse(s3_path)
              bucket = parsed_url.netloc
              key = parsed_url.path.lstrip('/')
              create_iam_users(bucket, key)

          def create_iam_users(bucket, key):
              s3 = boto3.client('s3')
              csv_content = s3.get_object(Bucket=bucket, Key=key)["Body"].read().decode('utf-8')
              reader = csv.DictReader(csv_content.splitlines())
              iam = boto3.client('iam')
              for row in reader:
                  username = row['username']
                  password = row['password']
                  try:
                      iam.create_user(UserName=username)
                      iam.create_login_profile(UserName=username, Password=password, PasswordResetRequired=True)
                      print(f"User {username} created with password reset required.")
                  except ClientError as e:
                      print(f"Error creating user {username}: {e}")
      Role: !GetAtt LambdaExecutionRole.Arn
      Timeout: 300

  # LambdaResource
  CreateUserCustomResource:
    Type: Custom::IamUserCreator
    Properties:
      ServiceToken: !GetAtt IamUserCreatorFunction.Arn
      CsvS3Path: 's3://dorablo-cloudformation-template/list/user_list.csv'

実行結果

CFnスタック作成結果

スタックの作成エラーなし

IAMユーザ確認

問題なく作成されてました。

Cloud Watchログ確認

エラーなし。

結果

期待通りの結果が得ることができました。
ただし、2回目の実行はすでに同名の関数名が存在するため、エラーとなってしまいます。。。汎用性を持たせるため修正は必要です(´;ω;`)

次回は実業務で想定されるストーリを元に
利用者が作成したいユーザを申請したら自動で払い出される仕組みにしたいと思います。