Vault には TOTP Secrets Engine があり、TOTP コードの生成や検証が可能になっている。

ここでは、TOTP Secrets Engine を利用し、Go からそれを利用する方法についてメモ程度に書く。

TOTP Secrets Engine を有効にする

$ vault secrets enable totp

デフォルトでは totp/ という Path になるので、必要に応じて -path オプションで変更する。

CLI で試す

generate=true というオプションを渡すことで named key を作ることができ、 account_name と紐付けることができる。

❯ vault write totp/keys/username generate=true issuer=Vault-TOTP-Demo account_name=user@example.com
Key        Value
---        -----
barcode    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
url        otpauth://totp/Vault-TOTP-Demo:user@example.com?algorithm=SHA1&digits=6&issuer=Vault-TOTP-Demo&period=30&secret=I2O7ICIEYIXIQNX5AAARCTWW5BX6N3AD

barcode は QR コードを Base64 エンコードしたもの。

適当に echo $BARCODE | base64 -d > qrcode.png などして開き、Google Authenticator などで開くと利用できる。

TOTP コードの検証はパスに write するだけで可能。

❯ vault write totp/code/username code=123456
Key      Value
---      -----
valid    false # 間違っている場合は false

❯ vault write totp/code/username code=892373
Key      Value
---      -----
valid    true # 正しい場合は true

Go から使う

Vault は API クライアントがあり、これを利用する。

package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"time"
  "os"

	"github.com/hashicorp/vault/api"
)

const (
	vaultAddr   = os.Getenv("VAULT_ADDR")
	staticToken = os.Getenv("VAULT_TOKEN")
)

var httpClient = &http.Client{
	Timeout: 10 * time.Second,
}

func main() {
	token := staticToken

	client, err := api.NewClient(&api.Config{Address: vaultAddr, HttpClient: httpClient})
	if err != nil {
		panic(err)
	}

	client.SetToken(token)

  code := "123456"
  username := "username"
  path := "totp/code/" + username

	data := map[string]interface{}{"code": code}
	resp, err := client.Logical().Write(path, data)
	if err != nil {
		panic(err)
	}

	b, _ := json.Marshal(resp.Data)
	fmt.Println(string(b))
}

❯ go run totp.go # 間違っている場合
{"valid":false}

❯ go run totp.go # 正しい場合
{"valid":true}

このように、かなり簡単に TOTP が利用できる。バックアップコードなどはアプリケーション側で生成して持つようにして、TOTP の実装は Vault に任せるとすると手軽で良さそう。

vault  TOTP