24 KiB
+++ title = "VaultのOIDCプロバイダー機能を試してみた" date = 2021-11-21T22:00:43+09:00 description = "Vault 1.9.0で新しく追加されたOIDC Identity Provider機能を試してみました" tags = ["Vault"] categories = ["インフラ", "HashiCorp"] author = "kazu634" +++
Vault as an OIDC Identity Provider | Vault - HashiCorp Learnを参考にして、Vault
をOIDC Providerとして利用するようにセットアップしてみました。
前提
Vault
はroot
トークンで使う前提だよ。環境はこちら:
事前作業
v.1.9.0
以前のバージョンからVault
をアップグレードして利用する場合には、以下のポリシーをdefault
に追加する必要があります:
# Allow a token to make requests to the Authorization Endpoint for OIDC providers.
path "identity/oidc/provider/+/authorize" {
capabilities = ["read", "update"]
}
default
ポリシー更新の操作例はこちら:
kazu634@boundary% vault policy read default > default.policy
kazu634@boundary% cp -P default.policy default.policy.new
kazu634@boundary% vi default.policy.new
kazu634@boundary% diff -u default.policy default.policy.new
--- default.policy 2021-11-23 14:54:30.108548827 +0900
+++ default.policy.new 2021-11-23 14:54:10.384179054 +0900
@@ -85,3 +85,8 @@
path "sys/control-group/request" {
capabilities = ["update"]
}
+
+# Allow a token to make requests to the Authorization Endpoint for OIDC providers.
+path "identity/oidc/provider/+/authorize" {
+ capabilities = ["read", "update"]
+}
kazu634@boundary% vault policy write default default.policy.new
Success! Uploaded policy: default
kazu634@boundary% vault policy read default
# Allow tokens to look up their own properties
path "auth/token/lookup-self" {
capabilities = ["read"]
}
# Allow tokens to renew themselves
path "auth/token/renew-self" {
capabilities = ["update"]
}
# Allow tokens to revoke themselves
path "auth/token/revoke-self" {
capabilities = ["update"]
}
# Allow a token to look up its own capabilities on a path
path "sys/capabilities-self" {
capabilities = ["update"]
}
# Allow a token to look up its own entity by id or name
path "identity/entity/id/{{identity.entity.id}}" {
capabilities = ["read"]
}
path "identity/entity/name/{{identity.entity.name}}" {
capabilities = ["read"]
}
# Allow a token to look up its resultant ACL from all policies. This is useful
# for UIs. It is an internal path because the format may change at any time
# based on how the internal ACL features and capabilities change.
path "sys/internal/ui/resultant-acl" {
capabilities = ["read"]
}
# Allow a token to renew a lease via lease_id in the request body; old path for
# old clients, new path for newer
path "sys/renew" {
capabilities = ["update"]
}
path "sys/leases/renew" {
capabilities = ["update"]
}
# Allow looking up lease properties. This requires knowing the lease ID ahead
# of time and does not divulge any sensitive information.
path "sys/leases/lookup" {
capabilities = ["update"]
}
# Allow a token to manage its own cubbyhole
path "cubbyhole/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
# Allow a token to wrap arbitrary values in a response-wrapping token
path "sys/wrapping/wrap" {
capabilities = ["update"]
}
# Allow a token to look up the creation time and TTL of a given
# response-wrapping token
path "sys/wrapping/lookup" {
capabilities = ["update"]
}
# Allow a token to unwrap a response-wrapping token. This is a convenience to
# avoid client token swapping since this is also part of the response wrapping
# policy.
path "sys/wrapping/unwrap" {
capabilities = ["update"]
}
# Allow general purpose tools
path "sys/tools/hash" {
capabilities = ["update"]
}
path "sys/tools/hash/*" {
capabilities = ["update"]
}
# Allow checking the status of a Control Group request if the user has the
# accessor
path "sys/control-group/request" {
capabilities = ["update"]
}
# Allow a token to make requests to the Authorization Endpoint for OIDC providers.
path "identity/oidc/provider/+/authorize" {
capabilities = ["read", "update"]
}
Vaultのユーザー、エンティティ、グループの設定
Vaultのユーザー、エンティティ、グループの設定をします。
Vaultのuserpass認証を有効に
ここではuserpass
認証を有効にし、end-user
という名称のユーザーを、パスワードとしてpassword
で作成しています:
kazu634@bastion2004% vault auth enable userpass
Success! Enabled userpass auth method at: userpass/
kazu634@bastion2004% vault write auth/userpass/users/end-user \
password="password" \
token_ttl="1h"
Success! Data written to: auth/userpass/users/end-user
アイデンティティ・エンティティの作成
以下のようにしてアイデンティティ・エンティティを作成します。end-user
という名前のアイデンティティ・エンティティを作成します。
kazu634@bastion2004% vault write identity/entity \
name="end-user" \
metadata="email=vault@hashicorp.com" \
metadata="phone_number=123-456-7890" \
disabled=false
Key Value
--- -----
aliases <nil>
id ea7a76f5-dc85-2d7e-f094-3011a73ee4da
name end-user
このend-user
アイデンティティ・エンティティはメタデータとして、メールアドレスと電話番号を持ちます。
アイデンティティ・グループの作成
以下のようにしてアイデンティティ・グループを作成します。今回はengineering
という名前のアイデンティティ・グループを作成します:
kazu634@bastion2004% ENTITY_ID=$(vault read -field=id identity/entity/name/end-user)
kazu634@bastion2004% vault write identity/group \
name="engineering" \
member_entity_ids="$ENTITY_ID"
Key Value
--- -----
id 6e134b6c-8adc-05e8-d1a1-015d5500c7c6
name engineering
アイデンティティ・エイリアスの作成
end-user
エンティティとend-user
userpass ユーザーを同一とみなせるように、アイデンティティ・エイリアスを作成します:
kazu634@bastion2004% GROUP_ID=$(vault read -field=id identity/group/name/engineering)
kazu634@bastion2004% USERPASS_ACCESSOR=$(vault auth list -detailed -format json | jq -r '.["userpass/"].accessor')
kazu634@bastion2004% vault write identity/entity-alias \
name="end-user" \
canonical_id="$ENTITY_ID" \
mount_accessor="$USERPASS_ACCESSOR"
Key Value
--- -----
canonical_id ea7a76f5-dc85-2d7e-f094-3011a73ee4da
id 7f50040a-be65-e984-7d88-bb40df05b9d2
VaultのOIDCクライアント用設定を作成する
VaultのOIDCクライアントは、以下のリソースにアクセスします:
OIDC assignment
- 暗号化キー
- クライアント・コールバックURL
- TTL
OIDC assignmentの作成
以下のようにしてOIDC assignment
を作成します:
kazu634@bastion2004% vault write identity/oidc/assignment/my-assignment \
entity_ids="{$ENTITY_ID}" \
group_ids="${GROUP_ID}"
Success! Data written to: identity/oidc/assignment/my-assignment
Vault
のOIDC認証プロセスは暗号化キーを必要とし、認証フローで作成されたJWTトークンを暗号化、検証します。
暗号化キーの作成
以下のようにして暗号化キーを作成します:
kazu634@bastion2004% vault write identity/oidc/key/my-key \
allowed_client_ids="*" \
verification_ttl="2h" \
rotation_period="1h" \
algorithm="RS256"
Success! Data written to: identity/oidc/key/my-key
allowed_client_ids
に*
が指定されているため、この暗号化キーはすべてのVault
OIDCクライアントで利用できます。
OIDCクライアントの作成
boundary
という名前のOIDCクライアントを作成します:
kazu634@bastion2004% vault write identity/oidc/client/boundary \
redirect_uris="http://192.168.10.175:9200/v1/auth-methods/oidc:authenticate:callback" \
assignments="my-assignment" \
key="my-key" \
id_token_ttl="30m" \
access_token_ttl="1h"
Success! Data written to: identity/oidc/client/boundary
redirect_uris
はクライアントのコールバックURLを指定します。http://192.168.10.175:9200/v1/auth-methods/oidc:authenticate:callback
は、デフォルトポートを利用して稼働するBoundary
のアドレスです。assignments
は、my-assignment
で定義されたエンティティとグループにアクセスを制限します。id_token_ttl
はID
トークンの期限切れ時間を30分に指定しています。access_token_ttl
は、アクセストークンの有効期限を1時間に指定します。
この辺は通常プロバイダー側で実施するOIDCの設定な気がします。
最後にクライアントIDを変数に格納します:
kazu634@bastion2004% CLIENT_ID=$(vault read -field=client_id identity/oidc/client/boundary)
OIDCプロバイダーの作成
VaultのOIDCプロバイダーは一つ以上のVault OIDCスコープをサポートします。これらのスコープはテンプレートで指定されたメタデータクレームを定義します。メタデータクレームは、ユーザーとOIDCサービスに関する情報を含んだキー・バリュー・ペアーです。
OIDCスコープの作成
USER_SCOPE_TEMPLATE
という変数を作成し、ユーザー・スコープ・テンプレートを格納します:
kazu634@bastion2004% USER_SCOPE_TEMPLATE=$(cat << EOF
{
"username": {{identity.entity.name}},
"contact": {
"email": {{identity.entity.metadata.email}},
"phone_number": {{identity.entity.metadata.phone_number}}
}
}
EOF
)
このテンプレートはエンティティのメタデータからメールアドレスと電話番号を取得します。次のコマンドを実行して、このユーザースコープテンプレートを利用して、user
という名前のVault OIDCスコープを作成します:
kazu634@bastion2004% vault write identity/oidc/scope/user \
description="The user scope provides claims using Vault identity entity metadata" \
template="$(echo ${USER_SCOPE_TEMPLATE} | base64 -)"
Success! Data written to: identity/oidc/scope/user
OIDCスコープの作成
GROUPS_SCOPE_TEMPLATE
という変数にグループスコープテンプレートを格納します:
kazu634@bastion2004% GROUPS_SCOPE_TEMPLATE=$(cat << EOF
{
"groups": {{identity.entity.groups.names}}
}
EOF
)
このテンプレートは定義されたすべてのグループ名を取得します。このグループスコープテンプレートを用いて、group
という名称のVaultのOIDCスコープを作成します:
kazu634@bastion2004% vault write identity/oidc/scope/groups \
description="The groups scope provides the groups claim using Vault group membership" \
template="$(echo ${GROUPS_SCOPE_TEMPLATE} | base64 -)"
Success! Data written to: identity/oidc/scope/groups
VautのOIDCプロバイダーには、クライアントIDとスコープのリストが必要です。
OIDCプロバイダーの作成
my-provider
という名前のVault OIDCプロバイダーを作成します:
kazu634@bastion2004% vault write identity/oidc/provider/my-provider \
allowed_client_ids="${CLIENT_ID}" \
scopes_supported="groups,user"
Success! Data written to: identity/oidc/provider/my-provider
このプロバイダーはboundary
のクライアントアクセスを許可します。
各種情報の確認
VaultのOIDC設定のためのエンドポイント情報を表示します:
kazu634@bastion2004% curl -s $VAULT_ADDR/v1/identity/oidc/provider/my-provider/.well-known/openid-configuration | jq
{
"issuer": "http://192.168.10.142:8200/v1/identity/oidc/provider/my-provider",
"jwks_uri": "http://192.168.10.142:8200/v1/identity/oidc/provider/my-provider/.well-known/keys",
"authorization_endpoint": "http://192.168.10.142:8200/ui/vault/identity/oidc/provider/my-provider/authorize",
"token_endpoint": "http://192.168.10.142:8200/v1/identity/oidc/provider/my-provider/token",
"userinfo_endpoint": "http://192.168.10.142:8200/v1/identity/oidc/provider/my-provider/userinfo",
"request_uri_parameter_supported": false,
"id_token_signing_alg_values_supported": [
"RS256",
"RS384",
"RS512",
"ES256",
"ES384",
"ES512",
"EdDSA"
],
"response_types_supported": [
"code"
],
"scopes_supported": [
"groups",
"user",
"openid"
],
"subject_types_supported": [
"public"
],
"grant_types_supported": [
"authorization_code"
],
"token_endpoint_auth_methods_supported": [
"client_secret_basic"
]
}
VaultのOIDCパブリックキーの情報を表示します:
kazu634@bastion2004% curl -s $VAULT_ADDR/v1/identity/oidc/provider/my-provider/.well-known/keys | jq
{
"keys": [
{
"use": "sig",
"kty": "RSA",
"kid": "c9ca478d-a2e2-fbf2-d514-2b8eda568f19",
"alg": "RS256",
"n": "42ko31pO37ARuFcadCOvi6z4S4andET-DgR306sGftasp6aeg1AOiditfmPDe_Gn953FBqvqmUEK9Dvg1dgypIcSWUevJmN9z4_fLA1hC9DmUjKGivNlqwRqFwSg2O6pljQzLH8ZXw16fxrWDUUCoke2IrPEsgYR40AoEhGxqWUwZTlimK_M-utr76DvnmY1XbZpPQLn88zq33noNVWmoCF41Fmf2ZWxz5LGXYGX3ZudeO5SQMzES_pU7JJ-xxHpKTqAoTJqU1g6pnz5tO6N6aZ9AwIAoVTzLq5h9ybrFeSEvkcdScaU9JHchabhjqdAFO1d8zicZh60wIfFbMHFTw",
"e": "AQAB"
},
{
"use": "sig",
"kty": "RSA",
"kid": "11e6dcf7-25bf-bf92-23b2-216827915508",
"alg": "RS256",
"n": "3PVhLrhzMG-FkqgyOaCppgkEL-hjcwW_aHoL54RvFV4Erh2USZXQSnZXNZtXjSB4RMq8LJZA7bfeEg9FwUEIauOcYJEK4eXSDU7hiYk2tKtyrAuESebdMWz73c9EZ_Uf5Y8FMc1aMQ4YNi7DKo92BWfhTI6Am9_si_59kLUuOo4XqMgA_lUCypuKjT2k54a3yNIHsyA2Rj_xr3C7bDCUUe1VEMMd27SuG0w3uMxBXHbs7PS4CTYawrWGCw79gRhj7c2uKj1jyQiRhD16_bmQMdyNBgo48jj8WXA7c7Oq1X_fY7DelTvvtCtQwiT5awjX9SabOxvJds0z_zhaw-Ysww",
"e": "AQAB"
}
]
}
Boundaryの起動・セットアップ
Boundary
の起動・セットアップについて説明します。
Boundaryの起動
別なターミナルでBoundary
を起動します。ここではlocalhost
ではなく、-host-address
と-api-listen-address
オプションを指定して、192.168.10.175
にバインドさせています:
kazu634@boundary% sudo boundary dev -host-address=192.168.10.175 -api-listen-address=192.168.10.175
[sudo] password for kazu634:
==> Boundary server configuration:
[Controller] AEAD Key Bytes: MRxx7K8uM05eT3TZ+lB+SOH1nlcITx7+lVAdfOgVypY=
[Recovery] AEAD Key Bytes: bc3rdR3DurJKo8j+d4I8JO0VzKWueE7LOdSiLK/1RRo=
[Worker-Auth] AEAD Key Bytes: dnJYhTV0gQg67Sg4slxuL+D+/ctMxGIqlpmDFDWqDeo=
[Recovery] AEAD Type: aes-gcm
[Root] AEAD Type: aes-gcm
[Worker-Auth] AEAD Type: aes-gcm
Cgo: disabled
Controller Public Cluster Addr: 127.0.0.1:9201
Dev Database Container: gracious_jemison
Dev Database Url: postgres://postgres:password@localhost:49156/boundary?sslmode=disable
Generated Admin Login Name: admin
Generated Admin Password: password
Generated Host Catalog Id: hcst_1234567890
Generated Host Id: hst_1234567890
Generated Host Set Id: hsst_1234567890
Generated Oidc Auth Method Id: amoidc_1234567890
Generated Org Scope Id: o_1234567890
Generated Password Auth Method Id: ampw_1234567890
Generated Project Scope Id: p_1234567890
Generated Target Id: ttcp_1234567890
Generated Unprivileged Login Name: user
Generated Unprivileged Password: password
Listener 1: tcp (addr: "192.168.10.175:9200", cors_allowed_headers: "[]", cors_allowed_origins: "[*]", cors_enabled: "true", max_request_duration: "1m30s", purpose: "api")
Listener 2: tcp (addr: "127.0.0.1:9201", max_request_duration: "1m30s", purpose: "cluster")
Listener 3: tcp (addr: "127.0.0.1:9202", max_request_duration: "1m30s", purpose: "proxy")
Log Level: info
Mlock: supported: true, enabled: false
Version: Boundary v0.7.1
Version Sha: abd695e5bc42d01e4412bf6c76211c3fc93a93d7
Worker Public Proxy Addr: 127.0.0.1:9202
==> Boundary server started! Log data will stream in below:
Boundaryのセットアップ
元のターミナルに戻って、Boundary
の設定を行います。192.168.10.175
にバインドしているため、BOUNDARY_ADDR
環境変数を指定します:
kazu634@boundary% export BOUNDARY_ADDR=http://192.168.10.175:9200
その後、admin
ユーザーのパスワードを指定します:
kazu634@boundary% boundary authenticate password \
-auth-method-id ampw_1234567890 \
-login-name admin \
-password password
Error opening keyring: Specified keyring backend not available
Token must be provided via BOUNDARY_TOKEN env var or -token flag. Reading the token can also be disabled via -keyring-type=none.
Authentication information:
Account ID: acctpw_1234567890
Auth Method ID: ampw_1234567890
Expiration Time: Sat, 27 Nov 2021 10:10:39 JST
User ID: u_1234567890
Error opening "pass" keyring: Specified keyring backend not available
The token was not successfully saved to a system keyring. The token is:
at_CP320WuH7f_s12TyNg8Rivoqi5fzP1TSoUrfthCuGpbwwm21f5phbKQUj1EYhbTXQHfZGoTSWm6qUYeAjfgzpbaQwDrWGfi2KdrypBLSEuYL1vpgNd1xocE3q
It must be manually passed in via the BOUNDARY_TOKEN env var or -token flag. Storing the token can also be disabled via -keyring-type=none.
ここで表示されたトークンを環境変数BOUNDARY_TOKEN
に格納します:
kazu634@boundary% export BOUNDARY_TOKEN=at_CP320WuH7f_s12TyNg8Rivoqi5fzP1TSoUrfthCuGpbwwm21f5phbKQUj1EYhbTXQHfZGoTSWm6qUYeAjfgzpbaQwDrWGfi2KdrypBLSEuYL1vpgNd1xocE3q
BoundaryのOIDC認証の設定
次のようにしてOIDC認証の設定を行います。ISSUER
という環境変数を定義して、そこにmy-provider
のissuer
フィールドの値を格納します:
kazu634@boundary% ISSUER=$(curl -s $VAULT_ADDR/v1/identity/oidc/provider/my-provider/.well-known/openid-configuration | jq -r .issuer)
kazu634@boundary% echo ${ISSUER}
http://192.168.10.142:8200/v1/identity/oidc/provider/my-provider
環境変数CLIENT_SECRET
に、Vault OIDCクライアントboundary
のclient_secret
フィールドに格納された値を格納します:
kazu634@boundary% CLIENT_SECRET=$(vault read -field=client_secret identity/oidc/client/boundary)
kazu634@boundary% echo ${CLIENT_SECRET}
hvo_secret_ZmxtbxiyWtjo9dVpU9BJZhR1bQVbczMRjTuZZHlf1HEfHaKZFOwGyDCoOKuaQAw9
VaultのOIDCプロバイダーを利用するように設定した、新しい認証方法を定義します:
kazu634@boundary% boundary auth-methods create oidc \
-issuer "${ISSUER}" \
-client-id "${CLIENT_ID}" \
-client-secret "${CLIENT_SECRET}" \
-signing-algorithm RS256 \
-api-url-prefix "http://192.168.10.175:9200" \
-claims-scopes "groups" \
-claims-scopes "user" \
-max-age 20 \
-name "Vault OIDC Provider"
Auth Method information:
Created Time: Sat, 20 Nov 2021 10:14:51 JST
ID: amoidc_TUXAIBhxIF
Name: Vault OIDC Provider
Type: oidc
Updated Time: Sat, 20 Nov 2021 10:14:51 JST
Version: 1
Scope:
ID: global
Name: global
Type: global
Authorized Actions:
no-op
read
update
delete
change-state
authenticate
Authorized Actions on Auth Method's Collections:
accounts:
create
list
managed-groups:
create
list
Attributes:
api_url_prefix: http://192.168.10.175:9200
callback_url: http://192.168.10.175:9200/v1/auth-methods/oidc:authenticate:callback
claims_scopes: [groups user]
client_id: VploN0lIIZEVpqAhN7xJS3eDnLYRMGR4
client_secret_hmac: qCpF9Qb5XxlnBOKn0m8iRG7Ns00U5naYxD-dTYuwlc8
issuer: http://192.168.10.142:8200/v1/identity/oidc/provider/my-provider
max_age: 20
signing_algorithms: [RS256]
state: inactive
AUTH_METHOD_ID
という環境変数に認証方式IDを格納します:
kazu634@boundary% AUTH_METHOD_ID="$(boundary auth-methods list -format json | jq -r '.items[] | select(.name == "Vault OIDC Provider") | .id')"
kazu634@boundary% echo ${AUTH_METHOD_ID}
amoidc_TUXAIBhxIF
認証方式の状態をactive-public
に変更します:
kazu634@boundary% boundary auth-methods change-state oidc \
-id "${AUTH_METHOD_ID}" \
-state active-public
Auth Method information:
Created Time: Sat, 20 Nov 2021 10:14:51 JST
ID: amoidc_TUXAIBhxIF
Name: Vault OIDC Provider
Type: oidc
Updated Time: Sat, 20 Nov 2021 10:16:06 JST
Version: 2
Scope:
ID: global
Name: global
Type: global
Authorized Actions:
no-op
read
update
delete
change-state
authenticate
Authorized Actions on Auth Method's Collections:
accounts:
create
list
managed-groups:
create
list
Attributes:
api_url_prefix: http://192.168.10.175:9200
callback_url: http://192.168.10.175:9200/v1/auth-methods/oidc:authenticate:callback
claims_scopes: [groups user]
client_id: VploN0lIIZEVpqAhN7xJS3eDnLYRMGR4
client_secret_hmac: qCpF9Qb5XxlnBOKn0m8iRG7Ns00U5naYxD-dTYuwlc8
issuer: http://192.168.10.142:8200/v1/identity/oidc/provider/my-provider
max_age: 20
signing_algorithms: [RS256]
state: active-public
global
スコープでOIDC認証方式を利用できるようにします:
kazu634@boundary% boundary scopes update \
-primary-auth-method-id "${AUTH_METHOD_ID}" \
-id global
Scope information:
Created Time: Sat, 20 Nov 2021 10:10:04 JST
Description: Global Scope
ID: global
Name: global
Primary Auth Method ID: amoidc_TUXAIBhxIF
Updated Time: Sat, 20 Nov 2021 10:16:26 JST
Version: 3
Scope (parent):
ID: global
Name: global
Type: global
Authorized Actions:
no-op
read
update
delete
Authorized Actions on Scope's Collections:
auth-methods:
create
list
auth-tokens:
list
groups:
create
list
roles:
create
list
scopes:
create
list
users:
create
list
動作確認
ブラウザーでhttp://192.168.10.175:9200
にアクセスすると、以下のように表示されるはずです:
Vault OIDC Provider
を選択して、Authenticate
ボタンをクリックします。すると新しいタブが開いて、Vault
のログイン画面が表示されます:
Username
を選択し、end-user
とpassword
を入力し、Sign in
ボタンをクリックします。すると、Boundary
にログインできるはずです。