Help us understand the problem. What is going on with this article?

CloudFormationでIAM Userをたくさん作る

More than 3 years have passed since last update.

IAMユーザをたくさん作る機会なんて滅多にないと思います(思いたいです)が、実際そういうケースに遭遇すると滅入ります。
一気に作れないかなぁとおもい、CloudFormationから作ってみました。

TL;DR

  • テンプレートを作ってCloudFormationにアップロードすればあとは待つだけ。1回作っておけば何度もやる場合は楽。
  • テンプレートを書くのは結構面倒な上、ユーザのパスワードの生成は自分でやらざるを得ない。
  • ユーザへのパスワードの伝達を自動化しないとそこで手間がかかる。
  • Stackを削除すると作ったユーザは消える。消えないようにもできる。

CloudFormationとは

ここを読んでもよくわかりませんが、簡単に言うとシステムの構成を管理するやつです。
プロビジョニングとかオーケストレーションとか呼ばれたりもします。

Stackという単位でシステム構成を定義しておき、それを実行することで定義通りの構成を一気に作ることができます。
また、リソース間の依存関係を理解して順序良くリソースを作成してくれたり、途中で失敗した時にロールバックしてくれたりもします。

テンプレートを作る

ものすごくシンプルに書くと、だいたい以下の感じになります。

CreateUsers.template
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Metadata": {
  },
  "Resources": {
    "{{Userリソース名}}": {
      "Type": "AWS::IAM::User",
      "Properties": {
        "UserName": "{{User名}}",
        "LoginProfile": {
            "Password": "{{パスワード}}",
            "PasswordResetRequired": true
        },
        "Groups": [
          { "Ref": "{{Groupリソース名1}}" },
          { "Ref": "{{Groupリソース名2}}" },
        ]
      }
    }
  }
}
  • Metadataの中身は割愛しました。
  • 可変部分を{{ }}で記載しました。
プレイスホルダ 説明
Userリソース名 このUserリソースを識別するための名前。
User名 ログイン時に使用するUser名。
パスワード ログイン時に使用するパスワード。
Groupリソース名N このUserが参加するGroupのリソース名。

{{Userリソース名}}: { ... }の定義を増やしていくことで、Userを増やすことができます。

上記の他、ManagedPolicyArnsPathPoliciesなどが指定できますが今回は使いません。

ドキュメントはここ

ランダムパスワードの生成ができない

IAMのコンソールを使うと、ランダムなパスワードを発行して設定してくれる機能がありますが、CloundFormationからはできません。

テンプレートを書くのが以外に面倒

あとはコピペしてプレイスホルダを置き換えて...なんですが、これも意外と面倒なのでスクリプトで生成することにしました。
スクリプトはこのエントリの終わりに記載しておきます。

テンプレートをアップロードしてStackを作る

  1. Create Stack
    Screen Shot 2016-11-29 at 9.29.10.png

  2. Choose a templateUpload a template to Amazon S3 を選択し、作ったテンプレートファイルを選択。
    Screen Shot 2016-11-29 at 9.30.17.png

  3. Stack name を設定。
    Screen Shot 2016-11-29 at 9.44.24.png

  4. 今回は特に何も指定しなくていいのでそのまま次へ。
    Screen Shot 2016-11-29 at 9.47.17.png

  5. I acknowledge that AWS CloudFormation might create IAM resources with custom names. にチェック。

完了を待つ

Stackを作ったあとそのまま実行されるので、StatusCREATE_COMPLETE になるまで待ちます。

Screen Shot 2016-11-29 at 9.54.56.png

失敗した場合

User名やGroup名がすでに存在するものと被ると失敗します。その場合、勝手にロールバックしてくれますが、Stackは残ってしまうので削除してやりなおしてください。

成功した場合

IAMを見ると、

  • ユーザが作成されている
  • グループに所属している
  • パスワードが設定されている

が確認できます。
Screen Shot 2016-11-29 at 9.59.07.png

また、CloudFormationに戻って、Designerを開くと構成が確認できます。
template1-designer.png

ユーザにログインアカウントを連絡する

現状は、この部分とログインURLをslackか何かで送る感じです。
ここ自動化しないとだいぶ手間だよなぁ...

        "UserName": "{{User名}}",
        "LoginProfile": {
            "Password": "{{パスワード}}",
            "PasswordResetRequired": true
          },

おまけ

Stackを削除すると

作ったユーザ、グループは消えます。
作ったユーザ、グループは消えます。
作ったユーザ、グループは消えます。

作成したStackを残して置いてメンテしていくのであれば問題ありませんが、そうでない場合は、 Deletion Policy を設定しておけばStackを消してもリソースは残ります。

ドキュメントはここ

ユーザの定義部分を生成するスクリプト(Node)

index.js
const process = require('process');
const args = require('args');
const genpass = require('generate-password');
const upperCamelCase = require('uppercamelcase');


const resourcename = username => {
  return upperCamelCase('user-' + username.replace(/[^a-zA-Z0-9]/, '_'));
}

const groups = list => {
  return list.split(',').map((g) => {
    return {
      "Ref": g
    }
  });
}

const password = () => {
  return genpass.generate({
    length: 16,
    numbers: true,
    symbols: true,
    uppercase: true
  });
}

///

args
  .option('user', 'User ID')
  .option('groups', 'Groups');

const params = args.parse(process.argv);

if (typeof params.user !== 'string') {
  console.error("User IDを指定してください。");
  process.exit(1);
}
if (params.groups != null && typeof params.groups !== 'string') {
  console.error("Group IDを指定してください。");
  process.exit(1);
}


// AWS::IAM::User Resource を作る。
const resname = resourcename(params.user);
const res = {};
res[resname] = {
  Type: "AWS::IAM::User",
  Properties: {
    UserName: params.user,
    LoginProfile: {
      Password: password(),
      PasswordResetRequired: true
    }
  }
};
if (params.groups != null) {
  res[resname].Properties.Groups = groups(params.groups);
}

// 出力
console.log(JSON.stringify(res, null, 2));

使い方

node index.js -u testuser1 -g AdministratorsGroup,DevelopersGroup
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away