本記事では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>
username | password |
user1 | Zaq12wsx |
user2 | Zaq12wsx |
user3 | Zaq12wsx |
… |
- 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回目の実行はすでに同名の関数名が存在するため、エラーとなってしまいます。。。汎用性を持たせるため修正は必要です(´;ω;`)
次回は実業務で想定されるストーリを元に
利用者が作成したいユーザを申請したら自動で払い出される仕組みにしたいと思います。