Y_Yamashitaのブログ

勉強したことのアウトプット・メモ中心。たまに日記とか。

JAWS-UG CLI専門支部 #185R IAM入門 (ユーザー/グループ)を噛みしめながら復習する②

はじめに

今回のブログも前回同様、JAWS-UG CLI専門支部 #185R IAM入門を噛みしめながら復習します。
今回は、AWS CLIで利用するクレデンシャル情報に焦点を当てます。

JAWS-UG CLI専門支部 #185R IAM入門の内容はこちらを参照してください。

今回のやり方とよくあるやり方の相違について

まずは本題に入る前に、JAWS-UG CLI専門支部でのクレデンシャルファイルの作り方と、ネット上でよく見る作り方の相違について確認しておきます。

よくあるやり方(aws configureコマンド)

AWS CLIでプロファイルやクレデンシャルを作成する際には、aws configureコマンドを使用するケースが多いかと思います。この場合、クレデンシャル情報は~/.aws/credentialsに格納されます。

実際にやってみます。(今回はサンプルなので、アクセスキー/シークレットアクセスキーの情報はAWS公式ドキュメントのサンプルから拝借しました。)

[ec2-user@ip-10-0-0-127%]$ aws configure --profile sample-user1
AWS Access Key ID [None]: AKIAIOSFODNN7EXAMPLE
AWS Secret Access Key [None]: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Default region name [None]: ap-northeast-1
Default output format [None]: json
[ec2-user@ip-10-0-0-127%]$ 
[ec2-user@ip-10-0-0-127%]$ 
[ec2-user@ip-10-0-0-127%]$ cat ~/.aws/credentials
[sample-user1]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
[ec2-user@ip-10-0-0-127%]$ 

~/.aws/credentialsにプロファイル情報が追加されています。更に、プロファイルを追加してみます。

[ec2-user@ip-10-0-0-127%]$ 
[ec2-user@ip-10-0-0-127%]$  aws configure --profile sample-user2
AWS Access Key ID [None]: AKIAI44QH8DHBEXAMPLE
AWS Secret Access Key [None]: je7MtGbClwBF/2Zp9Utk/h3yCo8nvbEXAMPLEKEY
Default region name [None]: ap-northeast-1
Default output format [None]: json
[ec2-user@ip-10-0-0-127%]$ 
[ec2-user@ip-10-0-0-127%]$ 
[ec2-user@ip-10-0-0-127%]$ cat ~/.aws/credentials
[sample-user1]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
[sample-user2]
aws_access_key_id = AKIAI44QH8DHBEXAMPLE
aws_secret_access_key = je7MtGbClwBF/2Zp9Utk/h3yCo8nvbEXAMPLEKEY
[ec2-user@ip-10-0-0-127%]$ 

~/.aws/credentialsにクレデンシャル情報が追加されました。

このように、aws configureコマンドを使用した場合、クレデンシャル情報は一つのファイルに追記されます。1ファイルへの情報の集約は、プロファイルが非常に多くなっても一元管理が可能なメリットがある半面、特定のプロファイルの情報を抜き出したい、編集したい場合には苦労するかもしれません。(そのようなシーンがどれほどあるかはさておいて。。)

<2021/7/18追記> 今回のようなハンズオンが、まさに「特定のプロファイルの情報を抜き出したい、編集したい場合」に当てはまりましたね。だからこそ、後述するやり方を採用しているようです。

JAWS-UG CLI専門支部のやり方(プロファイル毎にクレデンシャル情報を分ける)

次に、JAWS-UG CLI専門支部のやり方ですが、こちらはタイトル通り、プロファイル毎にクレデンシャル情報を分けます。つまり別ファイルにします。メリデメは1ファイルに情報を集約する場合の逆と考えればよいかと思います。

<2021/7/18追記> 上記について、「credentialファイルを分離するメリットが出るのは、共有環境(ツール群の実行環境など: credentialsの編集リスクがありゴミが溜まりやすい)や、ハンズオン環境(参加者のアカウントで通常利用しているcredentialファイルをいじらせたくない)」とコメントを頂戴しましたので、追記させていただきます。

ただし、aws configureのようなawsコマンドでクレデンシャルファイルを分けることは出来ないので、少々遠回りをします。

クレデンシャル情報格納ファイルの作成方法

ようやく本題ですが、ここから、JAWS-UG CLI専門支部でのクレデンシャル情報格納ファイル(つまり~/.aws/credentialsの代替ファイル)の作成方法を具体的に見ていきます。

作成の流れ

作成の大まかな流れは以下です。

  1. アクセスキーを格納するためのアクセスキーファイル用の変数を定義する
  2. アクセスキーを新規作成し、アクセスキーファイルに格納する
  3. クレデンシャル情報を格納するためのファイル用の変数を定義する
  4. アクセスキーファイルから必要な情報を抜き出し、クレデンシャル情報格納ファイルを作成する



前提

作成の前提として、IAMユーザーとプロファイルは作成済みとします。IAMユーザー名は"handson-cli-novice-user"とします。
IAMユーザーやプロファイルの作成方法は前回のブログを参照ください。

アクセスキーを格納するためのアクセスキーファイル用の変数を定義する

まず最初に、アクセスキーを格納するためのアクセスキーファイル用の変数を定義します。この時点ではファイルそのものは作成せず、ファイルのパスを変数に格納します。

今回作成するアクセスキーファイルのパスの構成は以下です。

{ホームディレクトリ}/environment/conf-handson-cli-iam/{IAMユーザー名}-token-{キーのカウント数}.json

「キーのカウント数」とは、今回作成するアクセスキーが、何個目のキーであるか、という数です。初めて作る場合は「1」になります。(※ハンズオンでは0からカウントする手順になっていましたが、今回は1からカウントする手順にしてみます)

例として、ホームディレクトリが/home/ec2-user、IAMユーザー名がhandson-cli-novice-user、キーのカウント数が1の場合、ファイルパスは以下となります。

/home/ec2-user/environment/conf-handson-cli-iam/handson-cli-novice-user-token-1.json



それでは実際に作成してみます。アクセスキーファイルの作成にあたり、以下のシェル変数を定義・使用します。

変数名 用途
IAM_USER_NAME IAMユーザー名 handson-cli-novice-user
DIR_ACCESS_KEY アクセスキーファイルのディレクトリパス /home/ec2-user/environment/conf-handson-cli-iam
COUNT_IAM_ACCESS_KEYS キーのカウント数 1
FILE_ACCESS_KEY アクセスキーファイルのパス /home/ec2-user/environment/conf-handson-cli-iam/handson-cli-novice-user-token-1.json
[ec2-user@ip-10-0-0-127%]$ IAM_USER_NAME='handson-cli-novice-user'
[ec2-user@ip-10-0-0-127%]$ 
[ec2-user@ip-10-0-0-127%]$ DIR_ACCESS_KEY="${HOME}/environment/conf-handson-cli-iam"
[ec2-user@ip-10-0-0-127%]$ 
[ec2-user@ip-10-0-0-127%]$ ls -d ${DIR_ACCESS_KEY}
ls: cannot access /home/ec2-user/environment/conf-handson-cli-iam: No such file or directory
[ec2-user@ip-10-0-0-127%]$ 
[ec2-user@ip-10-0-0-127%]$ mkdir -p ${DIR_ACCESS_KEY}
[ec2-user@ip-10-0-0-127%]$ 
[ec2-user@ip-10-0-0-127%]$ ls -d ${DIR_ACCESS_KEY}
/home/ec2-user/environment/conf-handson-cli-iam
[ec2-user@ip-10-0-0-127%]$ 
[ec2-user@ip-10-0-0-127%]$ COUNT_IAM_ACCESS_KEYS=$( \
>   aws iam list-access-keys \
>     --user-name ${IAM_USER_NAME} \
>     --query 'length(AccessKeyMetadata[])' \
> ) \
>   && COUNT_IAM_ACCESS_KEYS=$((COUNT_IAM_ACCESS_KEYS + 1)) \
>   && echo ${COUNT_IAM_ACCESS_KEYS}
1
[ec2-user@ip-10-0-0-127%]$ 
[ec2-user@ip-10-0-0-127%]$ 
[ec2-user@ip-10-0-0-127%]$ FILE_ACCESS_KEY="${DIR_ACCESS_KEY}/${IAM_USER_NAME}-token-${COUNT_IAM_ACCESS_KEYS}.json" \
>   && echo ${FILE_ACCESS_KEY}
/home/ec2-user/environment/conf-handson-cli-iam/handson-cli-novice-user-token-1.json
[ec2-user@ip-10-0-0-127%]$

アクセスキーファイルのパスが格納されたシェル変数が作成できました。

なお、キーのカウント方法については、最後に補足としてもう少し掘り下げて確認してみたいと思います。

アクセスキーを新規作成し、アクセスキーファイルに格納する

次に、アクセスキーを作成し、アクセスキーファイルに格納します。アクセスキーの作成は、aws iam create-access-keyコマンドを使用します。詳しくは前回のブログを参照ください。

[ec2-user@ip-10-0-0-127%]$ aws iam create-access-key \
>   --user-name ${IAM_USER_NAME} \
>   > ${FILE_ACCESS_KEY} \
>     && cat ${FILE_ACCESS_KEY}
{
    "AccessKey": {
        "UserName": "handson-cli-novice-user",
        "AccessKeyId": "AKIATOXXXXXXXXXXXXX",
        "Status": "Active",
        "SecretAccessKey": "Gwhdvj1XXXXXXXXXXXXXXXXXXXXXX",
        "CreateDate": "2021-07-17T05:37:31Z"
    }
}
[ec2-user@ip-10-0-0-127%]$ 
[ec2-user@ip-10-0-0-127%]$ ls -al ${DIR_ACCESS_KEY}                                                                                                                                                                 
total 4
drwxrwxr-x 2 ec2-user ec2-user  50 Jul 17 05:37 .
drwxr-xr-x 4 ec2-user ec2-user  62 Jul 17 04:49 ..
-rw-rw-r-- 1 ec2-user ec2-user 267 Jul 17 05:37 handson-cli-novice-user-token-1.json
[ec2-user@ip-10-0-0-127%]$ 

作成されたアクセスキーが、JSON形式でアクセスキーファイルに格納されました。

クレデンシャル情報を格納するためのファイル用の変数を定義する

続いて、クレデンシャル情報を格納するためのファイル用の変数を定義します。ここも前回同様、ファイルそのものは作成せず、ファイルパスが格納された変数を用意します。

今回作成したいファイルパス構成は以下です。

{ホームディレクトリ}/environment/conf-handson-cli-iam/{IAMユーザー名}.ini

今回の環境では以下のようになります。

/home/ec2-user/environment/conf-handson-cli-iam/handson-cli-novice-user.ini

それでは早速作っていきます。今回は、すでに作成済みのシェル変数を使いまわしていきます。

[ec2-user@ip-10-0-0-127%]$ FILE_USER_CREDENTIAL="${DIR_ACCESS_KEY}/${IAM_USER_NAME}.ini" \
>   && echo ${FILE_USER_CREDENTIAL}
/home/ec2-user/environment/conf-handson-cli-iam/handson-cli-novice-user.ini
[ec2-user@ip-10-0-0-127%]$ 

作成できました。

アクセスキーファイルから必要な情報を抜き出し、クレデンシャル情報格納ファイルを作成する

最後に、アクセスキーファイルから必要な情報を抜き出して書式を整理し、クレデンシャル情報格納ファイルを作成します。 つまり、アクセスキーファイルのJSON形式から、~/.aws/credentialsと同じ形式のファイルを作成します。

f:id:YuY_83:20210717151527p:plain

それでは実際にやってみます。

[ec2-user@ip-10-0-0-127%]$ echo "[${IAM_USER_NAME}]" > ${FILE_USER_CREDENTIAL}
[ec2-user@ip-10-0-0-127%]$ 

これは非常にシンプルですね。1行目の[handson-cli-novice-user]を作成しています。

問題はここからです。アクセスキーIDとシークレットアクセスキーを引っこ抜いて、形式を整える必要があります。jp.pyとsedgrepを駆使して、なんか凄い頑張ってます。

[ec2-user@ip-10-0-0-127%]$ cat "${FILE_ACCESS_KEY}" \
>   | jp.py 'AccessKey' \
>   | sed '/[{}]/d' | sed 's/[\" ,]//g' | sed 's/:/=/' \
>   | sed 's/AccessKeyId/aws_access_key_id/' \
>   | sed 's/SecretAccessKey/aws_secret_access_key/' \
>   | grep '^aws_' \
>   >> ${FILE_USER_CREDENTIAL} \
>     && cat ${FILE_USER_CREDENTIAL}
[handson-cli-novice-user]
aws_access_key_id=AKIATOXXXXXXXXXXXXX
aws_secret_access_key=Gwhdvj1XXXXXXXXXXXXXXXXXXXXXX
[ec2-user@ip-10-0-0-127%]$ 
[ec2-user@ip-10-0-0-127%]$ 
[ec2-user@ip-10-0-0-127%]$ ls -l ${FILE_USER_CREDENTIAL}
-rw-rw-r-- 1 ec2-user ec2-user 128 Jul 17 06:20 /home/ec2-user/environment/conf-handson-cli-iam/handson-cli-novice-user.ini
[ec2-user@ip-10-0-0-127%]$ 

めでたくクレデンシャルファイルの形式になりました。とはいえ、これだけだと何をしているのかよく分かりませんね。こちらも最後に補足としてもう少し掘り下げてみたいと思います。

全体の流れとしては以上です。

補足

上記の作業において、少々わかりにくい箇所について掘り下げてみたいと思います。

キーのカウント数について

キーのカウント数については、aws iam list-access-keysコマンドでキーのリストを表示し、その中の"AccessKeyMetadata[]"の配列長を--query 'length(AccessKeyMetadata[])'でカウントしています。

そこで、ここでは--queryを実行せずに、aws iam list-access-keysコマンドのみを実行し、どのような出力結果になるか見てみます。まずはアクセスキーが一つも無い場合から。

[ec2-user@ip-10-0-0-127%]$ aws iam list-access-keys --user-name ${IAM_USER_NAME}
{
    "AccessKeyMetadata": []
}
[ec2-user@ip-10-0-0-127%]$ 

アクセスキーのメタデータが空であることが分かります。

このようにアクセスキーがない状態だと、"AccessKeyMetadata"が空なので、'length(AccessKeyMetadata)'の値は0になります。

[ec2-user@ip-10-0-0-127%]$ aws iam list-access-keys \
>    --user-name ${IAM_USER_NAME} \
>    --query 'length(AccessKeyMetadata[])'
0
[ec2-user@ip-10-0-0-127%]$ 



続いて、aws iam create-access-keyコマンドでアクセスキーを作った後の、aws iam list-access-keysの出力結果を見てみます。

[ec2-user@ip-10-0-0-127%]$ aws iam list-access-keys \
>     --user-name ${IAM_USER_NAME}
{
    "AccessKeyMetadata": [
        {
            "UserName": "handson-cli-novice-user",
            "AccessKeyId": "AKIATOXXXXXXXXXXXXX",
            "Status": "Active",
            "CreateDate": "2021-07-17T05:37:31Z"
        }
    ]
}
[ec2-user@ip-10-0-0-127%]$ 

今度はアクセスキーのメタデータとして、ユーザー名・アクセスキーID・ステータス・作成日時が追加されました。ただし、配列の中のオブジェクト({}で囲まれた部分)の数は一つなので、'length(AccessKeyMetadata[])'の値は1になります。

[ec2-user@ip-10-0-0-127%]$ aws iam list-access-keys \
>     --user-name ${IAM_USER_NAME} \
>     --query 'length(AccessKeyMetadata[])'
1
[ec2-user@ip-10-0-0-127%]$ 



アクセスキーファイルからクレデンシャルファイルを作成する部分の掘り下げ

続いて、アクセスキーファイルからクレデンシャルファイルを作成する部分を掘り下げてみます。 今回やりたいことを再掲します。

f:id:YuY_83:20210717151527p:plain

[handson-cli-novice-user]はecho "[${IAM_USER_NAME}]" > ${FILE_USER_CREDENTIAL}で作ったので、クレデンシャルファイルの2行目、3行目を作りたいわけです。

先ほどは文字の抽出や整形を一気にやってしまったので、今回は一つずつ出力結果を見ていきたいと思います。
まずは改めてcatでファイルの中身を表示します。

[ec2-user@ip-10-0-0-127%]$ cat "${FILE_ACCESS_KEY}"
{
    "AccessKey": {
        "UserName": "handson-cli-novice-user",
        "AccessKeyId": "AKIAXXXXXXXXXXXX",
        "Status": "Active",
        "SecretAccessKey": "GwhXXXXXXXXXXXXXXXXXXXXX",
        "CreateDate": "2021-07-17T05:37:31Z"
    }
}
[ec2-user@ip-10-0-0-127%]$ 


次に、jp.py 'AccessKey'で、AccessKeyの中身の部分だけ抽出します。

[ec2-user@ip-10-0-0-127%]$ cat "${FILE_ACCESS_KEY}" \
>   | jp.py 'AccessKey'
{
    "UserName": "handson-cli-novice-user",
    "AccessKeyId": "AKIAXXXXXXXXXXXX",
    "Status": "Active",
    "SecretAccessKey": "GwhXXXXXXXXXXXXXXXXXXXXX",
    "CreateDate": "2021-07-17T05:37:31Z"
}
[ec2-user@ip-10-0-0-127%]$ 

jp.pyはaws-cliをインストールすると一緒にインストールされるJSONのクエリコマンドで、用途はjqコマンドと一緒です。

続いて、sed '/[{}]/d'で、"{" もしくは "}" を含む行を削除します。

[ec2-user@ip-10-0-0-127%]$ cat "${FILE_ACCESS_KEY}" \
>   | jp.py 'AccessKey' \
>   | sed '/[{}]/d'
    "UserName": "handson-cli-novice-user",
    "AccessKeyId": "AKIAXXXXXXXXXXXX",
    "Status": "Active",
    "SecretAccessKey": "GwhXXXXXXXXXXXXXXXXXXXXX",
    "CreateDate": "2021-07-17T05:37:31Z"
[ec2-user@ip-10-0-0-127%]$ 



さらに、sed 's/[\" ,]//g'で、ダブルクォーテーションと空白スペースとカンマを削除します。行中の全てのダブルクォーテーションと空白スペースとカンマを対象としたいので、末尾にgをつけます。

[ec2-user@ip-10-0-0-127%]$ cat "${FILE_ACCESS_KEY}" \
>   | jp.py 'AccessKey' \
>   | sed '/[{}]/d' | sed 's/[\" ,]//g'
UserName:handson-cli-novice-user
AccessKeyId:AKIAXXXXXXXXXXXX
Status:Active
SecretAccessKey:GwhXXXXXXXXXXXXXXXXXXXXX
CreateDate:2021-07-17T05:37:31Z
[ec2-user@ip-10-0-0-127%]$ 



さらにさらに、sed 's/:/=/'で、コロンをイコールに置換します。これは各行で一回実行されれば良いので、末尾にgは不要です。

[ec2-user@ip-10-0-0-127%]$ cat "${FILE_ACCESS_KEY}" \
>   | jp.py 'AccessKey' \
>   | sed '/[{}]/d' | sed 's/[\" ,]//g' | sed 's/:/=/'
UserName=handson-cli-novice-user
AccessKeyId=AKIAXXXXXXXXXXXX
Status=Active
SecretAccessKey=GwhXXXXXXXXXXXXXXXXXXXXX
CreateDate=2021-07-17T05:37:31Z
[ec2-user@ip-10-0-0-127%]$

末尾にgをつけていないので、"CreateDate"の"05:37:31"のコロンが置換されていないのが分かります。

まだ続きますw
"AccessKeyId"を"aws_access_key_id"に、"SecretAccessKey"を"aws_secret_access_key"に置換します。クレデンシャルファイルの命名規則に合わせるためですね。

[ec2-user@ip-10-0-0-127%]$ cat "${FILE_ACCESS_KEY}" \
>   | jp.py 'AccessKey' \
>   | sed '/[{}]/d' | sed 's/[\" ,]//g' | sed 's/:/=/' \
>   | sed 's/AccessKeyId/aws_access_key_id/' \
>   | sed 's/SecretAccessKey/aws_secret_access_key/'
UserName=handson-cli-novice-user
aws_access_key_id=AKIAXXXXXXXXXXXX
Status=Active
aws_secret_access_key=GwhXXXXXXXXXXXXXXXXXXXXX
CreateDate=2021-07-17T05:37:31Z
[ec2-user@ip-10-0-0-127%]$



ようやくラストです。"aws_access_key_id"と"aws_secret_access_key"以外は不要なので、grepで"aws"から始まる行だけ出力します。

[ec2-user@ip-10-0-0-127%]$ 
[ec2-user@ip-10-0-0-127%]$ cat "${FILE_ACCESS_KEY}" \
>   | jp.py 'AccessKey' \
>   | sed '/[{}]/d' | sed 's/[\" ,]//g' | sed 's/:/=/' \
>   | sed 's/AccessKeyId/aws_access_key_id/' \
>   | sed 's/SecretAccessKey/aws_secret_access_key/' \
>   | grep '^aws_'
aws_access_key_id=AKIAXXXXXXXXXXXX
aws_secret_access_key=GwhXXXXXXXXXXXXXXXXXXXXX
[ec2-user@ip-10-0-0-127%]$

うまくいきました。jp.pyを1回、sedを5回、grepを1回やってて、なかなかの力技ですねw

おわりに

ハンズオン当日から大分時間が空いてしまいましたが、クレデンシャルについて掘り下げて復習ができました。

こうやって掘り下げるとなんだか大変そうに見えますが、実際にハンズオンやってみるとかなり短時間で終わります。また、この手順自体をスクリプト化すればもっと速く終わるかと思います。

前回のブログから予定外に期間が空いてしまい、ちょっと今更感が出てしまったかもしれませんが、自分的にはちょうどよいタイミングでの復習になりました。