GoogleアカウントからVaultにログインしてみた

[JX通信社 Advent Calendar 2018](https://qiita.com/advent-calendar/2018/jxpress)、15日目担当のkain_jyです。

社内インフラでも利用している[Vault](https://www.vaultproject.io)の便利機能について紹介します。

## Vaultとは

Vaultとは機密情報を管理するためのソフトウェアです。パスワードを暗号化して保存することができたり、AWS/GCPの一時的認証情報を簡単に取得することができます。

会社ではCIサーバからクラウドプラットフォームの認証情報の取得や、VPNで使うクライアント証明書の発行といった用途で使っています。


## やりたいこと

Vaultがどんなにセキャアに機密情報を保つことができても、利用する側がVaultへのログインを甘々にしていたら意味がありません。

Vaultへのログインをどうするか、以前から悩まされていました。

会社にはLDAPやRADIUSといった認証基盤がなく、社内システムへのログインは基本、Googleアカウント（G Suite）を利用しています。

GoogleアカウントからもVaultへログインできればいいなとと思っていたところ、**Vault 0.10.4からJWT認証に対応**していました。**GoogleアカウントはOpenID Connectに対応してるため、JWT認証を利用したVaultへのログインが実現できる**というわけです。

## やってみた

まず、Googleアカウントの認証を使うために、まずはOAuthクライアントIDを発行します。

<img width="647" alt="1.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/1588/fa55c30c-ffb3-37b1-de18-582d79cf0285.jpeg">

<img width="648" alt="2.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/1588/17247044-2bd7-eede-3876-dfaa1f550ba2.jpeg">

<img width="627" alt="3.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/1588/c76c067b-0241-86f7-99bf-c07445803fdf.jpeg">

<img width="667" alt="4.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/1588/32de4716-9cf1-79e3-7bc7-e0f2fe4fcb12.jpeg">

クライアントID・クライアントシークレットをメモっておきます。

次に、Vaultの設定を行います。

```bash
$ vault server -dev  # vault開発サーバを立ち上げ

# Vault CLIを利用するためにアドレスとRoot Tokenを設定
$ export VAULT_ADDR='http://127.0.0.1:8200'
$ vault auth {{ Root Token }}

# JWT認証を有効化
$ vault auth enable jwt

# OpenID Connect Discovery URLを設定
# Googleアカウントの場合は `https://accounts.google.com` を指定
$ vault write auth/jwt/config \
    oidc_discovery_url="https://accounts.google.com"

# VaultのRoleを設定
$ vault write auth/jwt/role/my-role \
    bound_audiences="{{ GoogleのクライアントID }}" \
    user_claim="email" \
    policies=default \
    ttl=1h
```

設定は以上です。

それと、Googleアカウントの認証するため、コールバックを受け入れるためにWebサーバを立てておきます。

```
$ python3 -m http.server 5000                                                         
Serving HTTP on 0.0.0.0 port 5000 (http://0.0.0.0:5000/) ...
```

では、実際にGooleアカウントから認証してみましょう。認証のために踏んでもらうURLはこちらです。

```
https://accounts.google.com/o/oauth2/v2/auth?
   client_id={{ GoogleのクライアントID }}&
   response_type=code&
   scope=openid%20email&
   redirect_uri=http://localhost:5000/callback&
   hd=example.com   # G Suiteを利用している場合はドメインを指定
```

<img width="534" alt="スクリーンショット_2018-12-15_15_46_30.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/1588/9b482b32-66bb-c3e4-4618-654f3ad35e07.jpeg">

認証後に、以下のようなコールバックが返ってきます。

```
http://localhost:5000/callback?code={{ 認証コード、これをメモ  }}&...
```

受け取った認証コード（ `code` ）からJWTを取得します。

```bash
$ http -f POST https://www.googleapis.com/oauth2/v4/token \
    code="{{ 認証コード }}" \
    client_id="{{ GoogleのクライアントID }}" \
    client_secret="{{ Googleのクライアントシークレット }}" \
    redirect_uri="http://localhost:5000/callback" \
    grant_type="authorization_code"
```

すると、以下のようなレスポンスが返ってきます。

```json
{
    "access_token": "...",
    "expires_in": 3600,
    "id_token": "{{ JWT、これをメモ }}",
    "scope": "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/plus.me",
    "token_type": "Bearer"
}
```

`id_token` がJWTです。

JWTを使って、Vaultの認証トークンを取得します。

```bash
$ http -v POST $VAULT_ADDR/v1/auth/jwt/login \
    role="my-role" jwt="{{ JWT}}"
```

このレスポンスにある `auth.client_token` がVaultの認証トークンです。

```bash
$ vault login "{{ Vaultの認証トークン }}"
Success! You are now authenticated. The token information displayed below
```

ログインできたことを確認しました！


## まとめ

GoogleアカウントからVaultにログインする方法を紹介しました。Googleアカウント（G Suite）を利用している方は、よりセキュアにVaultを利用できます。

いまのところ、 **VaultのJWT認証はUIに対応していないません** 。実際に利用する際は、 **Googleアカウントの認証コード → JWT → Vaultの認証トークンを取得するフローを自動化** しておく必要があります。会社では簡単な[Webアプリ](https://gist.github.com/kain-jy/c7bb90113ad1af4492e855cfd5a32251)を立てて、実際にG SuiteからVaultにログインする仕組みを整えています。

GoogleアカウントとVaultを利用している方は是非お試しください。