🍥
Meilisearch でマルチテナント
Meilisearch でマルチテナントを実現する方法を Meilisearch Go を利用してサンプルを作りました。
前提として検索対象のデータ自体は TimescaleDB にため込んで、検索部分を Meilisearch で処理するという仕組みです。
複数のクライアントが利用する場合はユーザー単位で検索サーバーを立てるわけには行かないので検索サーバーのマルチテナントが必要になります。
Meilisearch のマルチテナント戦略はとてもシンプルで、検索サーバーを利用するクライアントに渡す JWT にフィルター追加して特定のインデックスや特定のフィルターにマッチした中での検索しか行えないようにするというものです。
検索サーバーへのアクセスはアプリサーバー経由ではなく、クライアントが直接検索サーバーへアクセスするというのがポイントです。
マルチテナント向け JWT 生成サンプル
クライアントに渡す JWT を作成するサンプルを Meilisearch Go で書いてみました。
package main
import (
"fmt"
"github.com/meilisearch/meilisearch-go"
)
// ローカルで立てている Meilisearch の key なので隠していない
// API Key は masterKey を指定
// $ meilisearch --master-key=masterKey
func main() {
client := meilisearch.NewClient(meilisearch.ClientConfig{
Host: "http://127.0.0.1:7700",
APIKey: "masterKey",
})
token, err := client.GenerateTenantToken(
// ここには親となる API Key の uid を指定する
// API key の一覧は uid は keys で見れる
// index はすべて利用できるが、actions は search のみに限定されている
// curl -X GET 'http://localhost:7700/keys?limit=3' -H 'Authorization: Bearer masterKey' | jq
// {
// "name": "Default Search API Key",
// "description": "Use it to search from the frontend",
// "key": "d74a98765192c721273d6abf0e460a0526398e4db0bd3612adec0c3fc33e3a08",
// "uid": "712d3ba6-2c31-4f51-a507-4c6c6c1998e1",
// "actions": [
// "search"
// ],
// "indexes": [
// "*"
// ],
// "expiresAt": null,
// "createdAt": "2022-11-04T12:56:23.490397Z",
// "updatedAt": "2022-11-04T12:56:23.490397Z"
// },
"712d3ba6-2c31-4f51-a507-4c6c6c1998e1",
map[string]interface{}{
// ここで index 名を指定して制限をかける
"spam-logs": map[string]interface{}{
// フィルターのリストを作りたいときは []string を使う
// フィルターを強制した token を生成することでマルチテナントとして利用できる
"filter": []string{
// ham_id が abc かつ egg_id が xyz にマッチしている中での検索が行われる
"ham_id = abc",
"egg_id = xyz",
},
},
},
&meilisearch.TenantTokenOptions{},
)
if err != nil {
panic(err)
}
// トークン出力
fmt.Println(token)
}
Discussion