プログラマーのメモ書き

伊勢在住のプログラマーが気になることを気ままにメモったブログです

Cognito AdminCreateUser で作成したユーザーの仮パスワードのリセット

cognito の小ネタです。

cognito ユーザープールのユーザーを管理者が作成する際に、仮パスワードを発行することができます。

管理者としてのユーザーアカウントの作成 - Amazon Cognito

その仮パスワードの有効期間が切れた場合の再発行方法は、

aws --profile プロファイル名 cognito-idp  admin-create-user
--user-pool-id ユーザープールID --username ユーザー名(メールアドレス)
-user-attributes "[{\"Name\":\"email\",\"Value\":\メールアドレス\"},{\"Name\":\"email_verified\",\"Value\":\"true\"}]"
--desired-delivery-mediums "EMAIL" --message-action RESEND

(適宜改行を入れています)

のように admin-create-user を同じユーザー名を指定して --message-action RESEND を追加して呼ぶだけのようです(CLIでの例になります)。

知らなかったなー。

元ネタはこちら。

How do I reset a Cognito user's password that has expired? - Stack Overflow

リファレンスにもちゃんと書いてありました。

admin-create-user — AWS CLI 1.18.197 Command Reference

pip3 のアップデートに失敗しました

別の記事で書きました、 aws cli からクロスアカウントを使う設定をする際に、いろいろと試していました。

その時、

mor@DESKTOP-H6IEJF9:~$ aws --version
aws-cli/1.16.269 Python/3.6.6 Linux/4.4.0-18362-Microsoft botocore/1.13.5

となっていたので、aws cli を更新してみるかと思い、 一度 aws cli をアップデートしてみました。

まずは、最新版を確認しようとして

mor@DESKTOP-H6IEJF9:~$ pip3 list -o

とすると

mor@DESKTOP-H6IEJF9:~$ pip3 list -o
DEPRECATION: The default format will switch to columns in the future. You can use --format=(legacy|columns) (or define a format=(legacy|columns) in your pip.conf under the [list] section) to disable this warning.
Exception:
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/pip/basecommand.py", line 215, in main
    status = self.run(options, args)
  File "/usr/lib/python3/dist-packages/pip/commands/list.py", line 157, in run
    packages = self.get_outdated(packages, options)
  File "/usr/lib/python3/dist-packages/pip/commands/list.py", line 168, in get_outdated
    dist for dist in self.iter_packages_latest_infos(packages, options)
  File "/usr/lib/python3/dist-packages/pip/commands/list.py", line 169, in <listcomp>
    if dist.latest_version > dist.parsed_version
TypeError: '>' not supported between instances of 'Version' and 'Version'
mor@DESKTOP-H6IEJF9:~$

エラーとなります。

ググってみると、

exception error when ```pip3 list --outdated``` · Issue #6786 · pypa/pip · GitHub

とのことで、pip3 のバージョンを上げれば修正されてるっぽいです。

ということで、まずは、pip3 を更新してみました。

mor@DESKTOP-H6IEJF9:~$ pip3 install --upgrade pip
Collecting pip
  Cache entry deserialization failed, entry ignored
  Using cached https://files.pythonhosted.org/packages/00/b6/9cfa56b4081ad13874b0c6f96af8ce16cfbc1cb06bedf8e9164ce5551ec1/pip-19.3.1-py2.py3-none-any.whl
Installing collected packages: pip
Successfully installed pip-19.3.1
mor@DESKTOP-H6IEJF9:~$

あれ?pip3 ではなく pip がインストールされたっポイぞ。

mor@DESKTOP-H6IEJF9:~$ pip --version
pip 19.3.1 from /home/mor/.local/lib/python3.6/site-packages/pip (python 3.6)
mor@DESKTOP-H6IEJF9:~$

pip3 はどうなってるんだろうか?

mor@DESKTOP-H6IEJF9:~$ pip3 --version
Traceback (most recent call last):
  File "/usr/bin/pip3", line 9, in <module>
    from pip import main
ImportError: cannot import name 'main'
mor@DESKTOP-H6IEJF9:~$

エラーになってる・・・。

まあ、気にせず、 pip で更新してみると

mor@DESKTOP-H6IEJF9:~$ pip install --upgrade awscli
(中略)
ERROR: Could not install packages due to an EnvironmentError: [Errno 13] 許可がありません: '/usr/local/lib/python3.6/dist-packages/botocore'
Consider using the `--user` option or check the permissions.

mor@DESKTOP-H6IEJF9:~$

途中でエラーになります。 やっちゃったようです。

まあ、よくよく考えてみると、原因は、pip3 は apt 経由でパッケージで入れてるので、これと、 pip3 自身でアップデートしたものが齟齬をきたしてるみたいです。

【Ubuntu】pip install –upgrade pip コマンドを実行すると、その後、ImportError: cannot import name main というエラーが発生する場合の対応方法 – ラボラジアン

下記を参考に復旧します。

Python pip3 - pip upgradeした後 「cannot import name 'main' 」error - KOKENSHAの技術ブログ

mor@DESKTOP-H6IEJF9:~$ sudo python3 -m pip uninstall pip
WARNING: The directory '/home/mor/.cache/pip/http' or its parent directory is not owned by the current user and the cache has been disabled. Please check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag.
Uninstalling pip-19.3.1:
  Would remove:
    /home/mor/.local/bin/pip
    /home/mor/.local/bin/pip3
    /home/mor/.local/bin/pip3.6
    /home/mor/.local/lib/python3.6/site-packages/pip-19.3.1.dist-info/*
    /home/mor/.local/lib/python3.6/site-packages/pip/*
Proceed (y/n)? y
  Successfully uninstalled pip-19.3.1
mor@DESKTOP-H6IEJF9:~$ sudo apt install python3-pip --reinstall

もう一度pip3を動かしてみます。

mor@DESKTOP-H6IEJF9:~$ pip3 --version
pip 9.0.1 from /usr/lib/python3/dist-packages (python 3.6)
mor@DESKTOP-H6IEJF9:~$ aws --version
aws-cli/1.16.269 Python/3.6.6 Linux/4.4.0-18362-Microsoft botocore/1.13.5
mor@DESKTOP-H6IEJF9:~$

ふー、とりあえず元に戻せたようです。

まあ、最終的に aws cli のバージョンの問題ではなくMFAの設定の問題だったので、 pip3 も aws cli もいまのままとしておきます。

とはいえ、いずれはどこかで、pip3 の再インストールからしないといけないようですね。

クロスアカウントを CLI でも使う

こちらの記事で書いたリザーブドインスタンスの期限切れを通知する処理は、結局、 AWS コンソールで提供される機能を使うことになったため、不要になりました。

でも、この時クロスアカウントアクセスの設定方法が分かったので、複数アカウント管理を簡単にするために、これを活用しようと思います。

前述の記事を試す途中で、IAMユーザーでクロスアカウントアクセスするのは試したので、次は、CLIからクロスアカウントアクセスをやろうと思います。

これがうまくいけば、管理対象のアカウントの IAM ユーザーを削減できるので、楽になりそうです。

設定

下記の IAM のチュートリアルにあるやり方は、STS で一時クレデンシャルを取得して、そのたびに、環境変数を設定するという方法です。

IAM チュートリアル: AWS アカウント間の IAM ロールを使用したアクセスの委任 - AWS Identity and Access Management

たぶん、まっとうな方法(先の記事中でAPI経由で扱う時はこれと同じですね)なんですが、毎回やるのはどう考えても面倒です。

で、いい方法ないかな?と調べてみると、ここの設定を自動でやってくれる書き方がありました。

これだと、一度設定ファイルを書いておけば、CLI実行時のプロファイルを切り替えるだけで使えるので、現実的です。

~/.aws/config を次のようにしました。

[profile mor_test]
region = ap-northeast-1

[profile mor_test_cross]
region = ap-northeast-1
role_arn = arn:aws:iam::信頼するほうのアカウントID:role/引き受けられるロール名
source_profile = mor_test

mor_test がクロスアカウントを行うアカウント(信頼されるアカウント)になります。

ためす

さっそく試します。ec2 のリザーブドインスタンスの情報を取ってみます。

mor@DESKTOP-H6IEJF9:~$ aws ec2 describe-reserved-instances --profile mor_test_cross

An error occurred (AccessDenied) when calling the AssumeRole operation: User: arn:aws:iam::信頼されるほうのアカウントID:user/mor_test is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::信頼するほうのアカウントID:role/引き受けられるロール名
mor@DESKTOP-H6IEJF9:~$

しかし、なぜかうまくいかないです。

ちょっとネットを調べるとこんな記事がありました。

クロスアカウントなAWS CLI処理でハマった話 | Developers.IO

あ、引き受けさせたいロールの条件として、MFAは必須にしてましたね。信頼する側のロールにアタッチされているポリシーが下記のようになってます。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::信頼されるほうのアカウントID:root"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "Bool": {
          "aws:MultiFactorAuthPresent": "true"
        }
      }
    }
  ]
}

でも、CLI で MFA どうやって扱うの?
ということで、MFAのやり方を調べてみます。

CLI での MFA

すぐにやり方は見つかりました。

AWS CLI での IAM ロールの使用 - AWS Command Line Interface

こちらを参考にして、クロスアカウント元になるユーザー(上記の例だと mor_test )に対して、MFAを設定します。

次に、 ~/.aws/config を編集して、 mfa_serial を追加します。

[profile mor_test]
region = ap-northeast-1

[profile mor_test_cross]
region = ap-northeast-1
role_arn = arn:aws:iam::信頼するほうのアカウントID:role/引き受けられるロール名
mfa_serial = arn:aws:iam::信頼されるほうのアカウントID:mfa/mor_test
source_profile = mor_test

この状態にして確かめると、

mor@DESKTOP-H6IEJF9:~$ aws rds describe-reserved-db-instances --profile mor_test_cross
Enter MFA code for arn:aws:iam::信頼されるほうのアカウントID:mfa/mor_test:

と画面に表示されて、信頼されるほうのアカウント mor_test の MFA のコードを入力するように求められます。 正しい、コードが入力できると、

{
    "ReservedDBInstances": [
        {
(後略)

のように、応答が返ってきました。

なお、下記のページにあるように、

MFA 保護 API アクセスの設定 - AWS Identity and Access Management

  • MFA に関する条件は、信頼する側(クロスアカウントされる側、または、引き受けられるロールを提供する側)で設定する
  • 信頼される側のポリシーでは、MFA条件は設定しない

とするのがよいようです。

また、MFAに関する条件をいろいろと設定することもできるようです。下記などが参考になります。

AWS グローバル条件コンテキストキー - AWS Identity and Access Management

なにはともあれ、これでクロスアカウントアクセスがコンソールでもCLIでもできるようになったので、アカウント管理が(多少は)楽になりそうです。