NRIネットコム社員が様々な視点で、日々の気づきやナレッジを発信するメディアです

注目のタグ

    IAMロールの信頼ポリシーへのユーザー追加処理をAWS CLIを使ってスクリプト化してみた

    はじめに

    はじめまして。新入社員の佐々木陽菜です。
    クラウド部に配属されてからあっという間に半年が経過しました。
    振り返ると様々なお仕事を任せてもらえたと感じていますが、その中でも初めて依頼いただいた開発のお仕事は学ぶことや考えることがたくさんありました。 そんな私の初仕事の内容は、「CIツール実行時に指定したユーザーをIAMロールの信頼ポリシーに追加できるように、シェルスクリプトの作成をする」です。 配属されて3週間かつ、AWSの知識はほぼゼロ、開発経験は集合研修でJavaを学んだ程度だったので分からないことが多く大変でしたが、とても勉強になったので紹介したいと思います。

    1. タスクの背景と概要

    前提として、IAMロールの信頼ポリシーにユーザーを追加すると、そのユーザーはAssumeRole(権限を一時的に取得)し、AWSマネジメントコンソール上でSwitch Role(ロールの切り替え)ができるようになります。
    これまで、IAMロールを利用するユーザーが増減した際に、IAMロールの信頼ポリシーで指定しているユーザーの追加・削除をAWSマネジメントコンソール上で手動で行っていました。 この作業負荷を軽減するために、 CIツールから追加・削除したいユーザーを指定するだけで、信頼ポリシーへのユーザー追加・削除処理をできるようにすることをタスクとして依頼いただきました。私は信頼ポリシーへのユーザー追加処理の実装を担当しました。

    2.作成したスクリプト

    2-1. スクリプトで信頼ポリシーを更新する

    CIツールで追加したいユーザーを指定し実行することで、信頼ポリシーを更新できるようにするために、シェルスクリプトを実装することにしました。 スクリプトでAWSサービスを操作する方法を調べてみると、コマンドラインから AWSサービスを制御することができるAWS CLI(以降CLI)というインターフェイスを使用することが分かりました。 CLIはスクリプトを通じてAWSサービスの操作を自動化することができ、コンソールで行う手動での作業を省略することができます。 aws.amazon.com まずはCLI を使用してIAMロールの信頼ポリシーを更新できるかを試しました。 信頼関係はCLIの「update-assume-role-policy」コマンドで更新が可能です。
    「Test-Role」というIAMロールの信頼ポリシーを「Test-Role-Trust-Policy.json」に記載された内容に上書きするという内容です。

    aws iam update-assume-role-policy \
        --role-name Test-Role \
        --policy-document file://Test-Role-Trust-Policy.json

    docs.aws.amazon.com

    上記のコマンドを実行するために、IAMロール(Test-Role)を作成しスクリプト内のPARAMSに信頼関係の更新に必要な情報を格納しました。

    #!/bin/bash
    set -eu
    
    PARAMS=$(cat<<EOM
    {
      "Version": "2012-10-17",
      "Statement": [
         {
          "Sid": "",
          "Effect": "Allow",
          "Principal": {
             "AWS": [
                 "arn:aws:iam::アカウントID:user/tanaka"
             ]
          },
          "Action": "sts:AssumeRole"
         }
      ]
    }
    EOM
    )
    
    #IAMロールの信頼ポリシーを更新するCLIコマンド
    aws iam update-assume-role-policy --role-name Test-Role --policy-document "${PARAMS}"
    

    上記のスクリプトを実行すると、Test-Roleの信頼ポリシーがPARAMSの内容に更新されました。

    2-2. IAMロールの信頼ポリシーに追加したいユーザーをコマンド引数から渡す

    次に、現在PARAMSの中に直書きしているユーザー情報( "arn:aws:iam::アカウントID:user/tanaka")をコマンド引数で渡して、任意のユーザーを追加できるようにします。
    追加したいユーザーが複数名いる場合にも 一つのコマンド引数から複数名指定できるようにするために、ユーザー名をカンマ区切り文字としてコマンド引数で渡し、処理の中で分割しました。 以下の例では「 tanaka,yamada」が一つのコマンド引数としてスクリプトに渡されるので、「,」でユーザーを区切った後に「"arn:aws:iam::アカウントID:user/tanaka"」「"arn:aws:iam::アカウントID:user/yamada"」の形に成形するよう処理を考えました。

    #!/bin/bash
    set -eu
    
    #$1にユーザー名(tanaka,yamada)を代入し、変数ADD_ENTITY_LISTに格納する。
    ADD_ENTITY_LIST=$1
    
    # , でユーザーを区切ってADD_ENTITY_SPLIT に格納
    ADD_ENTITY_LIST_SPLIT=(${ADD_ENTITY_LIST//,/ })
    #(ADD_ENTITY_LIST_SPLIT= tanaka yamada)になる
    
    #入力された人数分の "arn:aws:iam::アカウントID:user/ユーザー名"を作成し、USER_LIST_JOINに格納
    for USER in ${ADD_ENTITY_LIST_SPLIT[@]};do
        USER_LIST_JOIN+=\"arn:aws:iam::アカウントID:user/""$USER\"","
    done
    #USER_LIST_JOIN=( "arn:aws:iam::アカウントID:user/tanaka","arn:aws:iam::アカウントID:user/yamada", )になる
    
    #末尾の , を消去する
    USER_LIST=${USER_LIST_JOIN/%?/}
    
    PARAMS=$(cat<<EOM
    {
      "Version": "2012-10-17",
      "Statement": [
         {
          "Sid": "",
          "Effect": "Allow",
          "Principal": {
             "AWS": [
              $USER_LIST
             ]
          },
          "Action": "sts:AssumeRole"
         }
      ]
    }
    EOM
    )
    
    #エンティティ更新処理
    aws iam update-assume-role-policy --role-name Test-Role --policy-document "${PARAMS}"
    

    任意のユーザーを複数名コマンド引数から指定し実行することで、信頼ポリシーを更新することができるスクリプトを作成できました。
    ですが、現段階では信頼ポリシーの更新のみ行っている状態で、既存の信頼ポリシーで指定していたユーザーも新しい信頼ポリシーの内容に上書きされてしまいます。 そのため、既存の信頼ポリシーに存在していたユーザーと、新規に追加したいユーザーとを合体させてから信頼ポリシーを更新する必要があります。既存の信頼ポリシーに存在するユーザーを確認するためには、現在の信頼ポリシーの内容を取得する必要があるので、CLIの「GetRolePolicy」コマンドを利用して取得します。
    「Test-Role」というIAMロールの信頼ポリシーの中身を取得するという内容です。

    aws iam get-role \
        --role-name Test-Role

    docs.aws.amazon.com

    現在の信頼ポリシーからユーザー情報だけを取得するために、 GetRolePolicyコマンドに
    「--query 'Role.AssumeRolePolicyDocument.Statement[].Principal.AWS'」を追加しました。そうすることでIAMロールの信頼ポリシーのステートメントの中からユーザー(Principal)情報だけを取得できます。 作成したスクリプトでは「arn:aws:iam::アカウントID:user/tanaka」の形で取得できたユーザー情報から、「arn:aws:iam::アカウントID:user/」を削除し、ユーザー名のみ「tanaka」を抽出しました。この後はこれまでの処理と同様です。
    最後に既存のユーザー情報と新規に追加したいユーザー情報を合体させてPARAMSに渡します。

    #!/bin/bash
    set -eu
    
     #現在のユーザー情報を取得
     CURRENT_ENTITY=$(aws iam get-role --role-name Test-Role --query 'Role.AssumeRolePolicyDocument.Statement[].Principal.AWS' --output text)
    #(CURRENT_ENTITY= arn:aws:iam::アカウントID:user/tanaka arn:aws:iam::アカウントID:user/yamada)になる。
    
    #CURRENT_ENTITYのarn:aws:iam::アカウントID:user/部分を削除しtanaka yamadaの形にした後、人数分の "arn:aws:iam::アカウントID:user/**ユーザー名**"を作成し、USER_LIST_JOINに格納
    for USER in ${CURRENT_ENTITY[@]};do
          USERNAME=${USER##*'user/'}
          USER_LIST_JOIN+=\"arn:aws:iam::アカウントID:user/""$USERNAME\"","
    done
    #( USER_LIST_JOIN="arn:aws:iam::アカウントID:user/tanaka","arn:aws:iam::アカウントID:user/yamada",)になる
    
    #$1にユーザー名(sato,sasaki)を代入し、変数ADD_ENTITYに格納する。
    ADD_ENTITY_LIST=$1
    
    # , でユーザーを区切ってADD_ENTITY_SPLIT に格納
    ADD_ENTITY_LIST_SPLIT=(${ADD_ENTITY_LIST//,/ })
    #(ADD_ENTITY_LIST_SPLIT= sato sasaki)になる
    
    #入力された人数分の "arn:aws:iam::アカウントID:user/ユーザー名"を作成し、USER_LIST_JOINに追加
    for USER in ${ADD_ENTITY_LIST_SPLIT[@]};do
        USER_LIST_JOIN+=\"arn:aws:iam::アカウントID:user/""$USER\"","
    done
    #( USER_LIST_JOIN="arn:aws:iam::アカウントID:user/tanaka","arn:aws:iam::アカウントID:user/yamada","arn:aws:iam::アカウントID:user/sato ", "arn:aws:iam::アカウントID:user/sasaki",)になる
    
    #末尾の , を消去する
    USER_LIST=${USER_LIST_JOIN/%?/}
    
    PARAMS=$(cat<<EOM
    {
      "Version": "2012-10-17",
      "Statement": [
         {
          "Sid": "",
          "Effect": "Allow",
          "Principal": {
             "AWS": [
              $USER_LIST
             ]
          },
          "Action": "sts:AssumeRole"
         }
      ]
    }
    EOM
    )
    
    #エンティティ更新処理
    aws iam update-assume-role-policy --role-name Test-Role --policy-document "${PARAMS}"
    

    これで、IAMロールの信頼ポリシーへユーザーを追加することができました。 今回作成したスクリプトをCIツールで実行すると、IAMユーザー名の入力のみで信頼ポリシーにユーザーを追加することができ、とても便利になりました! 私はユーザー追加処理のみ実装しましたが、今後は削除処理の実装にも挑戦したいと思います。

    学んだこと

    作成したスクリプトの内容からいくつか抜粋して紹介しましたが、その他にもアカウント情報をSSMパラメータストアから呼び出したり、更新したいロールをコマンド引数から指定したりなど、依頼内容に沿ったスクリプトを作成することができました。 とはいっても、このスクリプトは先輩からたくさん助けていただきやっと完成したもので、1人で作成していく中では何を依頼されているのか、今自分が何をしているのか何度も分からなくなりました。曖昧な理解で突き進むのではなく、フロー図を描きながら、これから行う作業が依頼内容と合致しているかどうかの認識合わせをこまめに行うことが大切だと学びました。今はまだ開発経験も少ないので、これからもいろいろな言語でコードを書いて経験を積みたいと思います!
    最後までお読みいただき、ありがとうございました!