0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Hashicorp Vault Enterprise で userpass ログインに Sentinel EGP で IP 制限をかける

0
Posted at

やりたかったこと

Vault の userpass 認証では、IP 制限(token_bound_cidrs)はユーザー単位でしか設定できません。ユーザーが増えるたびに個別設定するのは運用上厳しいため、「Sentinel の EGP(Enterprise Governance Policy)を使えば、ユーザー個別設定に依存せず、ログインパス自体に一括でIP制限を掛けられるのでは?」という点を実機で検証しました。

結論:できました。ただし root tokenはバイパスされる/リバースプロキシ配下では別途設定が必要 といった制約がありますのでご注ください(詳細は末尾「運用上の注意点」)。

検証環境

  • Vault Enterprise 2.0.2+ent(Docker Compose、hashicorp/vault-enterprise イメージ)
  • ホストOS: Windows/Vaultは WSL2 Ubuntu上のDockerコンテナで稼働

1. ローカル環境(Ubuntu/WSL)からVaultへ接続

$ vault status
Key             Value
---             -----
Seal Type       shamir
Initialized     true
Sealed          false
Total Shares    1
Threshold       1
Version         2.0.2+ent
Build Date      2026-06-04T13:15:06Z
Storage Type    file
Cluster Name    vault-cluster-********
Cluster ID      ********-****-****-****-************
HA Enabled      false

2. ライセンス確認

featuresSentinel が含まれているので、EGP/RGPが使える構成であることを確認できます。

$ vault license get
Key                          Value
---                          -----
~~
features                     ~~ Sentinel ~~]
~~

3. userpass認証を有効化してサンプルユーザーを作成

$ vault auth enable userpass
$ vault write auth/userpass/users/taro password="<検証用パスワード>"
$ vault login -method=userpass username=taro password="<検証用パスワード>"
Key                    Value
---                    -----
token                  hvs.********
token_accessor         ********
token_duration         768h
token_renewable        true
token_policies         ["default"]
identity_policies      []
policies               ["default"]
token_meta_username    taro

ここではまだSentinelの制限は何もかけていないので、当然ログインできます。

4. Windowsから接続確認(EGP適用前)

ブラウザ

Web UI(https://127.0.0.1:8200/ui)から taro でログインし、成功することを確認しました。

image.png

CLI

Windowsのコマンドプロンプトでは export ではなく set を使います。

>set VAULT_ADDR=https://127.0.0.1:8200
>set VAULT_SKIP_VERIFY=true
>vault login -method=userpass username=taro password="<検証用パスワード>"
Success! You are now authenticated. The token information displayed below
is already stored in the token helper. You do NOT need to run "vault login"
again. Future Vault requests will automatically use this token.

Key                    Value
---                    -----
token                  hvs.********
token_accessor         ********
token_duration         768h
token_renewable        true
token_policies         ["default"]
identity_policies      []
policies               ["default"]
token_meta_username    taro

5. Sentinel EGPポリシーを作成

request.connection.remote_addr(Sentinelが参照できる送信元IP)をsockaddr.is_containedでCIDR判定し、許可外なら拒否するポリシーです。

$ cat egp.sentinel
import "sockaddr"

allowed_cidr = "127.0.0.1/32"   #許可するIPアドレスを設定

ip_is_allowed = rule {
    sockaddr.is_contained(allowed_cidr, request.connection.remote_addr)
}

main = rule {
    ip_is_allowed
}

6. EGPをVaultに登録

$ vault write sys/policies/egp/userpass-login-cidr \
    policy=@egp.sentinel \
    paths="auth/userpass/login/*" \
    enforcement_level="hard-mandatory"
Success! Data written to: sys/policies/egp/userpass-login-cidr

$ vault read sys/policies/egp/userpass-login-cidr
Key                  Value
---                  -----
enforcement_level    hard-mandatory
name                 userpass-login-cidr
paths                [auth/userpass/login/*]
policy               import "sockaddr"

allowed_cidr = "127.0.0.1/32"   #許可するIPアドレスを設定

ip_is_allowed = rule {
    sockaddr.is_contained(allowed_cidr, request.connection.remote_addr)
}

main = rule {
    ip_is_allowed
}

pathsauth/userpass/login/* を指定することで、未認証のログインリクエスト自体にこのポリシーが適用されます。ここが重要で、「ログイン成功後のトークンに制限を付与する」のではなく「ログイン試行そのものを拒否できる」ため、ブルートフォース攻撃の入口を塞ぐ効果があります。

不要になったら以下で削除できます。

$ vault delete sys/policies/egp/userpass-login-cidr
Success! Data deleted (if it existed) at: sys/policies/egp/userpass-login-cidr

7. EGP適用後のアクセス確認

Windows ブラウザ

EGP適用後、Windowsのブラウザから taro でログインを試すと、ログイン画面のまま失敗メッセージが表示され、認証できないことを確認しました。

image.png

Windows CLI

>vault login -method=userpass username=taro password="<検証用パスワード>"
Error authenticating: Error making API request.

URL: PUT https://127.0.0.1:8200/v1/auth/userpass/login/taro
Code: 400. Errors:

* 2 errors occurred:
        * egp standard policy "root/userpass-login-cidr" evaluation resulted in denial.

The specific error was:
<nil>
        * permission denied

taro ユーザー自身には token_bound_cidrs を何も設定していません。それでもEGPだけでブロックされているので、ユーザー個別のIP制限設定に依存せず、ログインパスへの一元的なIP制限として機能することが確認できました。

許可したIPからのアクセス(Docker内部からのアクセス)

docker compose exec でコンテナの中に入って実行したリクエストは 127.0.0.1 として見えるため、このケースだけ許可されます。

$ docker compose exec -T vault vault write -format=json auth/userpass/login/taro password="<検証用パスワード>"
{
  "request_id": "********",
  "lease_id": "",
  "lease_duration": 0,
  "renewable": false,
  "data": null,
  "warnings": null,
  "auth": {
    "client_token": "hvs.********",
    "accessor": "********)",
    "policies": [
      "default"
    ],
    "token_policies": [
      "default"
    ],
    "identity_policies": null,
    "metadata": {
      "username": "taro"
    },
    "orphan": true,
    "entity_id": "********)",
    "lease_duration": 2764800,
    "renewable": true,
    "mfa_requirement": null
  }
}

想定通り成功し、「EGPが送信元IPで判定して拒否/許可している」ことが裏付けられました。

まとめ

検証項目 結果
userpassのIP制限(token_bound_cidrs ユーザー単位のみ。マウント全体への一括設定フィールドはない
Sentinel EGP(paths=auth/userpass/login/* 未認証のログインパス自体にIP制限を適用できる。ユーザー個別設定に依存しない一元的な制御が可能
Windows ブラウザ/CLI EGP適用後は両方とも拒否される(同一のAPIパスを叩くため)
コンテナ内部からのアクセス 送信元IPが127.0.0.1になるため、127.0.0.1/32許可設定では通る

Sentinel EGPを使うことで、ユーザーが増えても個別にtoken_bound_cidrsを設定する必要がなく、ログインパスへの一括IP制限が実現できることを確認できました。

運用上の注意点

  • root tokenはSentinelの評価対象外です。
  • リバースプロキシ配下で運用する場合、そのプロキシがL7(HTTPモード)か L4/TLSパススルーかでVault側の対処が異なります。何も設定しないとremote_addrがプロキシ自身のIPになり、EGPのCIDR判定が意味を持たなくなる点は共通の注意点です。
    • ケース1: プロキシがHTTPを終端している(例: HAProxy mode http、ALB等) — プロキシが X-Forwarded-For ヘッダーを付与できるので、Vault側の listener 設定で x_forwarded_for_authorized_addrs(信頼するプロキシのCIDR)と x_forwarded_for_hop_skips 等を設定し、VaultにX-Forwarded-Forの値をremote_addrとして採用させます。
    • ケース2: プロキシがTCP/TLSパススルー(例: HAProxy mode tcp — L7のヘッダー挿入ができない(HTTPとして中身を見ていないため)ので、代わりに PROXY protocol を使います。HAProxy側ではserver行にsend-proxy(v1)またはsend-proxy-v2(v2)を付け、Vault側ではlistener "tcp"ブロックにproxy_protocol_behavior = "use_always"(またはallow_authorized)とproxy_protocol_authorized_addrs(PROXY protocolヘッダーの送信元として信頼するCIDR)を設定します。X-Forwarded-Forはここでは使えません。
    • どちらの方式でも、EGPのsockaddr.is_contained(...)が参照するrequest.connection.remote_addrに正しいクライアントIPが入っているかは、上記設定込みで実機確認することを推奨します(本記事では未検証)
  • EGPによる拒否時は、エラーレスポンス(および画面)にポリシー名がそのまま表示されます(今回の例では root/userpass-login-cidr)。攻撃者に制御の存在や意図を推測されるリスクがあるため、命名は内容が読み取りづらいものにすることを推奨します。
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?