こんにちは、UOZUです!
アプリケーションからデータベースへ接続するとき、パスワードをどこに保管していますか?
設定ファイルやスクリプトへ直接記載していると、サーバーの台数が増えるにつれて変更箇所を把握しにくくなります。ソースコードやバックアップに認証情報が含まれてしまうこともあります。
今回は、さくらのクラウドの「シークレットマネージャ」を使って、パスワードの保管先をまとめる方法を紹介します。まずは検証用のダミー情報を登録し、アプリケーションから利用する仕組みを理解しましょう。
シークレットマネージャとは?
シークレットマネージャは、パスワードなどの機密情報を暗号化して保管するサービスです。コントロールパネルでは「シークレット保管庫」として管理します。利用には、暗号鍵を管理するKMSが必要です。
例えば、WebアプリケーションのDBパスワードを管理する場合、アプリケーションは必要な認証情報を保管庫から取得し、その情報でDBに接続する構成にできます。
導入するだけで既存の設定ファイルが自動的に置き換わるわけではありません。アプリケーション側にも、保管庫から値を取得して利用する実装が必要です。
KMSとシークレットマネージャの役割
両者は次のように役割が分かれています。
| サービス | 管理するもの | 今回の用途 |
|---|---|---|
| KMS | 暗号鍵 | 保管庫で使用する鍵を用意する |
| シークレットマネージャ | パスワードなどの機密情報 | DBパスワードを名前付きで保管する |
ここでは、検証専用のKMSキーと保管庫を1つずつ作成します。KMSキーと保管庫はそれぞれ課金対象になるため、作成前に公式サービスページで料金を確認してください。
1.KMSキーを作成する
コントロールパネルで [グローバル]→[KMS キー] を開きます。
[追加] を選択し、以下の内容で KMS キーを作成します。
| 項目 | 今回の設定例 |
|---|---|
| キー生成方法 | 自動生成 |
| 名前 | uozu-secret-key |
| 説明 | シークレットマネージャ検証用 |

KMSキーは、保管した情報を取り出すためにも必要です。単なる管理用のラベルとして扱わず、どの保管庫が利用しているかを把握しておきましょう。
2.シークレット保管庫を作成する
続いて、[グローバル]→[シークレット保管庫] を開き、[追加] を選択します。
「使用する KMS キー」で、先ほど作成した KMS キーを選択してシークレット保管庫を作成します。
| 項目 | 今回の設定例 |
|---|---|
| 使用するKMSキー | uozu-secret-key |
| 名前 | uozu-secret-vault |
| 説明 | シークレットマネージャ検証用 |

3.検証用パスワードを登録する
作成したシークレット保管庫の詳細画面の「シークレット」タブの「追加」から、名前と値を登録します。
「名前」は、アプリケーションから取得するシークレットを識別するための名称です。「値」には、保管するパスワードそのものを入力します。
シークレット保管庫の名前や説明欄には、パスワードなどの機密情報を記載しないでください。
| 項目 | 入力例 |
|---|---|
| 名前 | uozu-db-password |
| 値 | DemoOnly-Password |

※値は記事用のダミーです。実際のDBやサービスのパスワードには使用しないでください。
「名前」はアプリケーションから目的の情報を指定するための識別子、「値」は保管するパスワードそのものです。保管庫の名前や説明欄にパスワードを書かないようにします。
登録したパスワードはどう使う?
アプリケーションからの利用にはAPIを使います。
| 目的 | API操作(ベースURLからの相対パス) |
|---|---|
| シークレット一覧を取得 | GET /vaults/{vault_resource_id}/secrets |
| シークレットの値を復号して取得 | POST /vaults/{vault_resource_id}/secrets/unveil |
APIキーを利用する例
アプリケーションからシークレットを取得するには、API を利用します。
API キーは、ログイン後に [API キー] から発行できます。パスワードを表示させる為、「作成・削除」権限を付与した API キーを使用します。


作成後、アクセストークンとアクセストークンシークレットが表示されます。
アクセストークンおよびアクセストークンシークレットは、漏えいしないよう安全に保管してください。
curlでの表示例
curlコマンドで利用が可能です。非常にシンプルですが、権限に「作成・削除」が付与されているので、キーの利用には注意してください。
$ curl -s \
--user "アクセストークン:アクセストークンシークレット" \
--request POST \
--header 'Content-Type: application/json' \
--data '{"Secret":{"Name":"uozu-db-password"}}' \
'https://secure.sakura.ad.jp/cloud/zone/is1a/api/cloud/1.1/secretmanager/vaults/113802280710/secrets/unveil' \
| jq .
--
{
"Secret": {
"Name": "uozu-db-password",
"Version": 1,
"Value": "DemoOnly-Password"
},
"is_ok": true
}
サービスプリンシパルを利用する例
API の利用権限をより細かく制御したい場合は、サービスプリンシパルを利用できます。
サービスプリンシパルを作成した後、サービスプリンシパルキーを発行します。その際、RSA 公開鍵の登録が必要です。ssh-keygen などを使用して鍵ペアを作成し、公開鍵を登録してください。



続いて、IAM ポリシーでサービスプリンシパルにシークレットマネージャを利用するための権限を付与します。
「IAMポリシー」内の「サービスプリンシパル」へ、「シークレットマネージャ利用者」の権限の設定を行います。

実際の利用サンプル(サービスプリンシパル)
実際にAPIを利用してパスワード表示までが可能なスクリプトのサンプルを作成してみました。
利用の際は、サービスプリンシパルのリソースIDをSP_ID「000000000000」に、KID「XXX~」はサービスプリンシパルキーKIDに、KEY_FILE「$HOME/id_rsa」はサービスプリンシパルに登録した公開鍵と対になる秘密鍵を、VAULT_ID「111111111111」はシークレット保管庫のリソースIDを指定してください。
$ cat get-secret.sh
#!/usr/bin/env bash
set -euo pipefail
SP_ID='000000000000'
KID='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
KEY_FILE="$HOME/id_rsa"
VAULT_ID='111111111111'
SECRET_NAME='uozu-db-password'
TOKEN_URL='https://secure.sakura.ad.jp/cloud/api/iam/1.0/service-principals/oauth2/token'
if [ ! -r "$KEY_FILE" ]; then
echo "秘密鍵を読み込めません: $KEY_FILE" >&2
exit 1
fi
b64url() {
openssl base64 -A | tr '+/' '-_' | tr -d '='
}
JWT_HEADER=$(jq -cn --arg kid "$KID" \
'{alg:"RS256",kid:$kid,typ:"JWT"}' | b64url)
NOW=$(date +%s)
JWT_PAYLOAD=$(jq -cn \
--arg aud "$TOKEN_URL" \
--arg id "$SP_ID" \
--argjson now "$NOW" \
'{aud:$aud,iat:$now,exp:($now+300),iss:$id,sub:$id}' |
b64url)
JWT_INPUT="${JWT_HEADER}.${JWT_PAYLOAD}"
JWT_SIGNATURE=$(printf '%s' "$JWT_INPUT" |
openssl dgst -sha256 -sign "$KEY_FILE" |
b64url)
JWT="${JWT_INPUT}.${JWT_SIGNATURE}"
echo '1. トークン発行' >&2
if TOKEN_RESPONSE=$(curl --fail-with-body --silent --show-error \
--request POST \
--data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer' \
--data-urlencode "assertion=${JWT}" \
"$TOKEN_URL"); then
TOKEN=$(printf '%s' "$TOKEN_RESPONSE" |
jq -er '.access_token | select(type == "string" and length > 0)')
else
echo 'トークン発行エラー:' >&2
printf '%s\n' "$TOKEN_RESPONSE" >&2
exit 1
fi
echo '2. シークレット取得' >&2
REQUEST=$(jq -cn --arg name "$SECRET_NAME" \
'{Secret:{Name:$name}}')
if SECRET_RESPONSE=$(curl --fail-with-body --silent --show-error \
--request POST \
--header "Authorization: Bearer ${TOKEN}" \
--header 'Content-Type: application/json' \
--header 'X-Requested-With: XMLHttpRequest' \
--data "$REQUEST" \
"https://secure.sakura.ad.jp/cloud/zone/is1a/api/cloud/1.1/secretmanager/vaults/${VAULT_ID}/secrets/unveil"); then
printf '%s' "$SECRET_RESPONSE" |
jq -er '.Secret.Value // empty'
else
echo 'シークレット取得エラー:' >&2
printf '%s\n' "$SECRET_RESPONSE" >&2
exit 1
fi
以下のコマンドで利用が出来るはずです。
$ bash -n ~/get-secret.sh && bash ~/get-secret.sh
--
1. トークン発行
2. シークレット取得
DemoOnly-Password
APIの認証情報は別途保護する
DBパスワードを保管庫に移しても、APIにアクセスするための認証情報の管理は残ります。
この認証情報をソースコードに直接記載すると、別の秘密情報を埋め込むことになってしまいます。実行環境に適した方法で渡し、ファイルへ保存する場合はアクセスできるOSユーザーを限定します。
権限も、アプリケーションに必要な範囲へ絞ります。値を取得するプログラムに、無関係なリソースの削除や管理まで許可する必要があるかを確認しましょう。
シークレットマネージャは、秘密情報を一元管理するための仕組みです。サーバー自体への侵入や、取得後の値がログへ出力される問題まで自動的に防ぐものではありません。
さいごに
今回は、さくらのクラウドのシークレットマネージャを使用して、検証用のパスワードを保管・取得する手順を紹介しました。
API キーでシークレットを取得する場合は、必要な権限を事前に確認してください。検証時には、「リソース閲覧」や「設定編集」の権限ではシークレットを表示できず、「作成・削除」権限が必要でした。実際の運用では、必要最小限の権限で実現できるかを十分に検証することをおすすめします。
より細かな権限管理が必要な場合は、サービスプリンシパルの利用を検討できます。ただし、JWT の生成や秘密鍵による署名が必要になるため、鍵の保管方法やローテーション方法も含めて設計してください。
最後までお読みいただき、ありがとうございました!