credential_processと1Password CLIでawsumeと共存できるセキュアな認証環境を作る

credential_processと1Password CLIでawsumeと共存できるセキュアな認証環境を作る

2025.12.16

はじめに

こんにちは、アノテーション株式会社 LINE/アプリDevOpsチームの草竹です。

普段、AWS CLIを利用する際、~/.aws/credentials にアクセスキーやシークレットアクセスキーを保存している方は多いと思います。しかし、重要な認証情報をローカルディスクに平文で保存しておくのは、セキュリティ的に少し不安に思ったことはないでしょうか?

この解決策として 1Password の公式AWSプラグイン が提供されています。公式から提供された素晴らしいツールであり、とても便利なのですが、これは aws コマンドをラップ(エイリアス化)する仕組みのため、 AWSume などのサードパーティ製スイッチロールツールと相性が悪い課題がありました。

私は AWSume の入力補完や使い勝手が手放せなかったので、「AWSume を使い続けつつ、認証情報は1Passwordの中にだけ保存する(ローカルには平文で置かない)」 方法を模索しました。

今回は、AWS CLI標準の credential_process 機能と 1Password CLI (op) を組み合わせ、それを実現する自作スクリプトを紹介します。

https://docs.aws.amazon.com/ja_jp/sdkref/latest/guide/feature-process-credentials.html

https://developer.1password.com/docs/cli/get-started/

実現したこと

  • セキュア: ローカルの ~/.aws/credentials にアクセスキー(平文)を一切保存しない。
  • 共存: 公式プラグインを使わないため、awsume がそのまま動く(補完も効く)。
  • 快適: MFA認証を通した後、セッションを1Password上にキャッシュし、有効期限内ならMFA入力をスキップする。

前提条件

環境

項目
OS macOS 15.7.2
シェル zsh

コマンド

項目 バージョン 補足
op (1Password CLI) 2.32.0
jq jq-1.7.1-apple
aws-cli (AWS CLI v2) 2.32.17
awsume 4.5.4 ※任意ですが、この記事のモチベーションです

仕組みの概要

credential_process は、AWS CLIが認証情報を必要とした際に外部プロセスを実行し、その標準出力(JSON)を受け取って認証に利用する機能です。これは awsume 等のツールからも透過的に利用されます。

今回は以下のフローで動作するスクリプトを作成しました。

  1. キャッシュ確認: 1Password上の独自フィールドに有効な一時クレデンシャルが保存されているか確認。
  2. (キャッシュ有効時): そのままJSONとして出力して終了。
  3. (キャッシュ無効時):
    1. 1PasswordからアクセスキーとMFAデバイスARNを取得。
    2. op item get --otp でMFAコードを取得(またはユーザー入力)。
    3. aws sts get-session-token を実行。
    4. 取得した一時クレデンシャルを1Passwordに書き込んでキャッシュ化。
    5. JSONとして出力。

実践:設定手順

1. 1Password にアイテムを作成

まず、1PasswordにAWS認証情報用のアイテムを作成します。

1password-aws

アイテム基本項目

項目 補足
カテゴリ API認証情報 どのカテゴリを選択するは任意です
アイテム名 AWS Access Key アイテム名は任意です

フィールド

1Passwordアイテムに登録するフィールドの項目名は自由ですが、1Passwordの公式AWSプラグインAccess Key ID, Secret Access Key, mfa serial として設定項目を期待しているため、以下項目名で登録していると、1Password公式プラグインに流用しやすく便利だと思います。

項目 補足
Access Key ID AKIAIOSFODNN7EXAMPLE AWS のアクセスキーです。
Secret Access Key wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY AWSのシークレットアクセスキーです。
mfa serial arn:aws:iam::123456789012:role/your-name MFAシリアルのARNです。
one-time password ******************** MFAシリアルと対応するワンタイムパスワードを生成するための文字列です
session_cache 空で作成。ここにスクリプトがキャッシュを書き込みます。

2. 認証スクリプトの作成

~/.aws/get-1password-creds.sh を作成し、実行権限を付与します。

下記項目にセットする値(1Passwordアイテムに設定しているフィールド名)はご自身の環境に合わせて変更してください。

  • OP_ITEM
  • OP_ITEM_LABEL_CACHE
  • OP_ITEM_LABEL_ACCESS_KEY
  • OP_ITEM_LABEL_SECRET_KEY
  • OP_ITEM_LABEL_MFA_SERIAL
~/.aws/get-1password-creds.sh
#!/bin/bash
set -e

# --- 設定 ---
# 1Password のアイテム名
OP_ITEM="AWS Access Key"
# キャッシュを保存するフィールドラベル
OP_ITEM_LABEL_CACHE="session_cache"

OP_ITEM_LABEL_ACCESS_KEY="Access Key ID"
OP_ITEM_LABEL_SECRET_KEY="Secret Access Key"
OP_ITEM_LABEL_MFA_SERIAL="mfa serial"

# --- 0. 環境変数を完全にクリア ---
# 親プロセス等の環境変数が邪魔をしないようクリアします
unset AWS_ACCESS_KEY_ID
unset AWS_SECRET_ACCESS_KEY
unset AWS_SESSION_TOKEN
unset AWS_SECURITY_TOKEN
unset AWS_PROFILE

# --- 1. 1Password からアイテム情報を一括取得 ---  
# キャッシュもクレデンシャルも同じアイテムにあるので、最初に1回取得するだけで済む
OP_JSON=$(op item get "$OP_ITEM" --format json)

# --- 2. キャッシュの確認 ---
# 指定フィールドの値を取得(なければ空)  
ENCODED_CACHE=$(echo "$OP_JSON" | jq -r --arg label "$OP_ITEM_LABEL_CACHE" '.fields[] | select(.label==$label).value // empty')

if [ -n "$ENCODED_CACHE" ]; then
    # Base64デコード
    DECODED_CACHE=$(echo "$ENCODED_CACHE" | base64 -d 2>/dev/null || echo "")

    if [ -n "$DECODED_CACHE" ]; then
        CURRENT_TIME=$(date +%s)
          
        # 有効期限チェック (+00:00 -> Z 置換含む)
        IS_VALID=$(echo "$DECODED_CACHE" | jq -r --argjson now "$CURRENT_TIME" '
            if .Credentials.Expiration then
                (.Credentials.Expiration | sub("\\+00:00$"; "Z") | sub("\\.[0-9]+Z$"; "Z") | fromdateiso8601) > ($now + 30)
            else
                false
            end
        ')

        if [ "$IS_VALID" = "true" ]; then
            # キャッシュ有効 -> そのまま出力して終了
            echo "$DECODED_CACHE" | jq '{Version: 1, AccessKeyId: .Credentials.AccessKeyId, SecretAccessKey: .Credentials.SecretAccessKey, SessionToken: .Credentials.SessionToken, Expiration: .Credentials.Expiration}'  
            exit 0
        fi
    fi
fi

# --- 3. キャッシュがない/切れそうな場合は新規取得 ---
# (キャッシュ切れ時の処理)
ACCESS_KEY=$(echo "$OP_JSON" | jq -r --arg label "$OP_ITEM_LABEL_ACCESS_KEY" '.fields[] | select(.label==$label).value')
SECRET_KEY=$(echo "$OP_JSON" | jq -r --arg label "$OP_ITEM_LABEL_SECRET_KEY" '.fields[] | select(.label==$label).value')
MFA_SERIAL=$(echo "$OP_JSON" | jq -r --arg label "$OP_ITEM_LABEL_MFA_SERIAL" '.fields[] | select(.label==$label).value')

# MFAコード取得
MFA_CODE=$(op item get "$OP_ITEM" --otp)

if [ -z "$ACCESS_KEY" ] || [ -z "$SECRET_KEY" ] || [ -z "$MFA_CODE" ]; then
    echo "Error: Failed to retrieve credentials from 1Password." >&2
    exit 1
fi

# --- 4. AWS STS 実行 ---
export AWS_ACCESS_KEY_ID="$ACCESS_KEY"
export AWS_SECRET_ACCESS_KEY="$SECRET_KEY"

OUTPUT=$(aws sts get-session-token \
    --serial-number "$MFA_SERIAL" \
    --token-code "$MFA_CODE" \
    --output json 2>&1)
STATUS=$?

if [ $STATUS -ne 0 ]; then
    echo "Error calling aws sts get-session-token:" >&2
    echo "$OUTPUT" >&2
    exit 1
fi

# --- 5. 1Password にキャッシュを保存 (書き込み) ---
# JSONをBase64エンコード
ENCODED_OUTPUT=$(echo "$OUTPUT" | base64)

# op item edit でフィールドを更新 (タイプは 'password' にしてUI上は隠す)
op item edit "$OP_ITEM" "$OP_ITEM_LABEL_CACHE[password]=$ENCODED_OUTPUT" >/dev/null 2>&1

# credential_process 用に出力
echo "$OUTPUT" | jq '{Version: 1, AccessKeyId: .Credentials.AccessKeyId, SecretAccessKey: .Credentials.SecretAccessKey, SessionToken: .Credentials.SessionToken, Expiration: .Credentials.Expiration}'

3. ~/.aws/config の設定

~/.aws/credentials にある固定のアクセスキー定義は削除し、~/.aws/configcredential_process を記述します。

credentials ファイル自体を空にできるため、誤って平文キーが漏洩するリスクをゼロにできます。

~/.aws/config
[default]
region = ap-northeast-1
credential_process = /Users/your-name/.aws/get-1password-creds.sh

[profile project-a-role]
role_arn = arn:aws:iam::999999999999:role/ProjectARole
source_profile = default
# defaultプロファイル側でMFA済みのため、ここには mfa_serial を書かないのがポイントです!

4. 競合する設定の解除

1Password公式プラグインなどが有効になっていると競合するため、無効化しておきます。

zsh
op plugin clear aws

.zshrc などにある source .../plugins.sh もコメントアウト or 削除します。

~/.zshrc
# source /Users/your-name/.config/op/plugins.sh

検証:awsume でスイッチしてみる

設定が完了したので、awsume を使ってロールスイッチしてみます。

zsh
awsume project-a-role

1password-auth

初回実行時:
1Passwordへのアクセス許可(指紋認証など)が求められ、その後バックグラウンドで sts get-session-token が走ります。

2回目以降(キャッシュ有効期間内):
awsume を実行すると、即座にスイッチが完了します! sts APIを叩かないため非常に高速です。

「認証情報の管理は1Passwordに任せたいけど、CLIの操作感は変えたくない」という私のニーズにハマりました。

まとめ

credential_process を活用することで、認証情報の保存場所を1Passwordに一本化しつつ、awsume 等のツールとも共存できる環境が作れました。

  • メリット
    • セキュリティ向上: 平文のアクセスキーがローカルディスクに一切残らない。
    • ツール互換性: AWS CLI標準の仕組みを使うため、awsume など既存のエコシステムを壊さない。
  • 注意点:
    • op item edit でのキャッシュ書き込み時に若干の待ち時間が発生する。

公式プラグインの競合に悩んでいた方は、ぜひ試してみてください!

最後までご覧いただき、ありがとうございました!

参考

アノテーション株式会社について

アノテーション株式会社はクラスメソッドグループのオペレーション専門特化企業です。
サポート・運用・開発保守・情シス・バックオフィスの専門チームが、最新 IT テクノロジー、高い技術力、蓄積されたノウハウをフル活用し、お客様の課題解決を行っています。
当社は様々な職種でメンバーを募集しています。
「オペレーション・エクセレンス」と「らしく働く、らしく生きる」を共に実現するカルチャー・しくみ・働き方にご興味がある方は、アノテーション株式会社 採用サイト をぜひご覧ください。

この記事をシェアする

FacebookHatena blogX

関連記事