BLOGサブスレッドの日常

2024.03.11

AWSのアクセスキーを1Passwordに登録してCLIから利用する

ryosms

こんにちは! ryosms です
サブスレッドの日常をお届けします。

今日はAWS CLI系のめんどくさいをなんとかしようシリーズ第1回です。
初回のめんどくさいは「アクセスキーの管理がめんどくさい」です。

サブスレッドでは開発マシンとしてMacが支給されるので、基本的に本記事の内容はMacOSでの動作を前提としています。

AWSのアクセスキー管理のめんどくさい #とは

AWSのアクセスキーは使わないにこしたことはないとは思いますが、それでも使わざるをえないケースはまだあります。
AWSのアクセスキーには以下のような制限(めんどくささ)があります。

  • 1つのIAMユーザーで発行できるアクセスキーは2つまでである
    • アクセスキーはローテーションして使うのが推奨されているので、実質1つのアクセスキーのみが有効になる想定です
    • セキュリティポリシーによっては「ユーザーあたり有効なアクセスキーは1つまで」という制限があるところもあると聞いています
  • 複数デバイスでの共有が厳しい
    • 複数デバイスで利用しようと思えばできますが、ローテーションした時に全デバイスの情報を変更するのはめんどくさいです
    • ドキュメントは探し切れてませんが、1つのアクセスキーを複数のデバイスで利用するのは基本的にやらない方がいいでしょう(と某AWSの中の人にも聞いたことがあります)
  • プレーンテキストに平文で保存される
    • 1つのデバイスで利用するだけであればそこまで神経質になる必要もないのかなとは思いますが...
    • かつてGitHubにdoftilesなリポジトリを作るのが流行った時代(無課金ユーザーはPrivateリポジトリを作れない時代)に、誤ってPublicなリポジトリにアクセスキーをpushしてAWSから警告が来るとかよくありましたね...

1Passwordで解決する

上記のめんどくささを1Passwordで解決しようと思います。
具体的には、

  • アクセスキーを1Passwordで管理して
  • アクセスキーを利用するタイミングで1Passwordから取り出して使う

となります。
1Passwordでアクセスキーを管理することで以下のように、めんどくささが解消されます。
(前述の某AWSの中の人に「1Passwordでアクセスキー管理するのはOK」と聞いて(その人の見解では)OKと返事をもらっています。)

  • 複数デバイスでもセキュアにアクセスキーの同期が可能
  • ローテーションした時にデバイス間での同期漏れが防げる
  • ~/.aws/credentialsにアクセスキーが記載されないので安心

それではやっていきましょう。

アクセスキーを1Passwordで管理する

そのままです。
今回はAWSアカウントのコンソール用のユーザー名/パスワードを保存しているアイテムのカスタムフィールドに保存することします。
カスタムフィールドは1Passwordを使っている人なら作り方は知ってると思いますが、一応公式のリンクを貼っておきます。
Customize your 1Password items

今回は aws_access_key_id / aws_secret_access_key というフィールド名で保存することにします。
別のフィールド名で保存する場合や独立したアイテムとして保存する場合は、以降の手順で該当個所を読み替える必要があります。

アクセスキーを利用するタイミングで1Passwordから取り出す

AWS CLI用のconfig(~/.aws/config)では、各プロファイルでcredential_processとして外部プログラムを指定することで、指定したプログラムの出力内容をクレデンシャルとして利用する機能があります。
参考: Source credentials with an external process - AWS Command Line Interface

これを利用して、1Passwordからアクセスキーを取得して、AWS CLIの要求する形式に成形して返すプログラム(今回はシェルスクリプト)を作っていきます。
シェルスクリプトから1Passwordにアクセスするために、1Password CLIをセットアップしておきましょう。

セットアップができたらシェルスクリプトを作成していきますが、同じことを考えている先人はいて、そのまんまの記事を発見しました。

How to Use 1Password to Securely Store Your AWS credentials

ここに記載されているプログラムを利用すればそのまま動きそうですね。
こちらからは以上です。

...

と言いたいところですが、作者が英語圏の方なのでマルチバイト文字列のことが考慮されていません。

1Password CLIで op:// 形式を利用する場合、Vault名やアイテム名にマルチバイト文字列が入るとエラーを吐いて死にます。
そのため、マルチバイト文字列を手当してあげる必要があります。
あらかじめVault名やアイテム名からVaultやアイテムのIDを取得してop://に指定する、という手もありますが、今回は素直にop item getで各フィールドの内容を取ってくるようにしました。

ついでに、会社用の1Passwordと個人用の1Passwordを分けて使っている場合(サブスレッドでは全社員に1Passwordのアカウントを配布しています)に使い分けできるような改造も入れることにしましょう。
こっちはopコマンドの--accountオプションを指定可能にするだけですね。

できあがったのがこちらのシェルスクリプトです(3分間クッキング)。
これを例えば、~/.aws/op-credential-helper.sh に保存して、実行権限を付けます。

#!/usr/bin/env bash

usage() {
  echo "
1Passwordを利用したAWS CLI用のcredential helper

usage:
  $0 [-h / --help] : 本ヘルプを表示します
  $0 <ITEM> [-v|--vault <VAULT>] [-a|--account <ACCOUNT>]
    ITEM      : 認証情報を保存している1Passwordのアイテム名を指定します
    -v        : 認証情報を保存している1Passwordの保管庫名を指定します
    --vault     未指定の場合は Private になります
    -a        : 1Passwordのアカウントを指定します
    --account   未指定の場合はデフォルトの1Passwordアカウント(my.1password.com)になります
  " >&2
}

account="my.1password.com"
vault="Private"
pos_args=()
while [[ $# -gt 0 ]]; do
    case $1 in
        -h|--help) usage; exit 1;;
        -v|--vault) vault="${2}"; shift; shift;;
        -a|--account) account="${2}"; shift; shift;;
        *) pos_args+=("$1"); shift;;
    esac
done
# オプションの指定されていないパラメータ(位置引数)だけを並べ直す
#   "hoge -p fuga piyo" というパラメータが "hoge piyo" となる
set -- "${pos_args[@]}"

item_name="$1"
if [ "${item_name}" == "" ]; then
    usage
    exit 1
fi

cat <<END
{
    "Version": 1,
    "AccessKeyId": "$(op item get "${item_name}" --vault "${vault}" --account "${account}" --fields label=aws_access_key_id)",
    "SecretAccessKey": "$(op item get "${item_name}" --vault "${vault}" --account "${account}" --fields label=aws_secret_access_key)"
}
END

保存ができたら、AWS CLIのconfigに以下のようなprofileを作成します。
(なんと、~/.aws/credentialsは不要です!)

[profile op-test-profile]
region = ap-northeast-1
credential_process = "/path/to/op-credential-helper.sh" "item_name"

[profile other-profile]
region = ap-northeast-1
credential_process = "/path/to/op-credential-helper.sh" "other_item_name" -v "vault_name" -a <your_company>.1password.com

ここまでできたら、おもむろに aws sts get-caller-identity --profile op-test-profile を叩いてみます。
1Passwordのウィンドウが出てきてパスワードを入力(TouchIDの設定してるなら指紋読み取り)してAWS CLIから結果が返ってくれば成功です!

今日はここまで。
次回はAWS CLIでのMFAのめんどくささを解消したいと思います。

この記事を書いた人

ryosms