本番投入チェックリスト
各項目は、本番投入前に満たしておく条件と、それを説明するページへのリンクです。examples/53-production-sql は、このうち大半を 1 つのプログラムにまとめています。
鍵
- 署名鍵と cookie 鍵を
op.LoadKeysetとop.LoadSymmetricKeysで永続的な保管場所から読み込む。どのレプリカも同じkidを公開し、再起動してもユーザがログアウトされません。鍵ローテーションを参照してください。 - ローテーションの計画がある。退役中の署名鍵と cookie 鍵は、それが保護していたトークンとセッションの期限が切れるまで一覧に残します。鍵ローテーションを参照してください。
ストレージ
- スキーマはリリースごとにデプロイジョブから 1 回適用する。
Store.Migrations()を自前のマイグレーションツールで適用するかStore.Migrate(ctx)を呼び、各レプリカの起動時には適用しない。ストレージの保守を参照してください。 - MySQL では、既存データベースのインデックスとバイナリ照合順序は
Store.Migrations()のファイルから入り、Store.Migrateかマイグレーションツールが適用する。インデックスの欠落とバイナリでない照合順序は、スキーマの確認が報告します。永続化(SQL)を参照してください。 - 起動時に
op.Newが、設定が使うテーブルのスキーマを確認する。テーブルやカラムが足りなければ、後続のリクエストが失敗するのではなく起動が止まります。すべてのテーブルを検証するのは、デプロイ時のチェックでのStore.ValidateSchemaです。永続化(SQL)を参照してください。 - retention sweep(
Store.GCまたはRunGC)を、1 つのレプリカでスケジュールする。1 つで足り、複数のレプリカで重なって動いても安全なので、リーダー選出は要りません。期限切れの行を消す処理はほかにないため、sweep が動くまでテーブルは際限なく増え続けます。ストレージの保守を参照してください。 - サブストアごとにバックアップと復旧目標を決めてある。バックアップ / DRを参照してください。
ネットワークとクライアント
- リバースプロキシや ingress の CIDR を
op.WithTrustedProxiesに渡す。OP が実際のクライアントアドレスとスキームを認識します。未設定の間はX-Forwarded-*ヘッダを無視します。ルータへのマウントを参照してください。 - static クライアントは、新しいバージョンを起動する前に、デプロイジョブから
op.SyncStaticClientsで同期する。定義を変更したまま同期しないと、起動時に拒否されます。クライアントオンボーディングのパターンを参照してください。 - セキュリティプロファイルを意図して選んである。
startup.profile監査イベントで、デプロイした姿勢を確認できます。op.WithProfileを渡さない場合は全クライアントに PKCE が必須になり、PKCE を送れない RP を受け入れるにはprofile.OIDCCoreを宣言します。セキュリティプロファイルの宣言を参照してください。 - static の confidential クライアントはすべて、32 バイト以上の平文
Secret(op.NewClientSecretで生成)かSecretHashを持つ。それより短いSecretはop.Newが拒否します。クライアントオンボーディングのパターンを参照してください。 - DPoP proof を送るクライアントは、discovery で OP が公開しているエンドポイント URL に署名する。プロキシの内側の内部アドレスなど、それ以外の URL に署名した proof は、プロファイルに関係なく拒否されます。
運用
- 本番のオプション一覧に
op.WithAllowInsecureOutboundForDevとop.WithAllowLocalhostIssuerForDevを含めない。どちらも開発用 issuer のためのもので、前者は開発用以外の issuer に対してop.Newが拒否します。 op.WithLoggerを設定する。未設定だと、構成時の警告や、自前ストアに足りない任意 capability を挙げるログ行はslog.Default()に出ますが、リクエスト時の記録はすべて破棄されます。可観測性 を参照してください。- コンテナのメモリ上限に、ハッシュ計算用の
GOMAXPROCS × 64 MiBを見込む。パスワードの検証もclient_secretの検証も、1 回あたり 64 MiB・約 90 ms の Argon2id を実行し、同時実行はGOMAXPROCSまでです。高頻度の machine-to-machine クライアントはop.WithHighEntropyClientSecretsでこのコストを避けられます。サービス間(client_credentials)を参照してください。 - すべてのレプリカで、session、grant、replay 防御の集合のストアを共有する。DPoP の server nonce を有効にしている場合は同じ
op.DPoPNonceSourceも共有し、パスワードや第二要素のステップがあるログインフローには、永続的で共有されるロックアウトストアを用意する。マルチインスタンス展開を参照してください。 - 停止時は先に HTTP サーバを止め、そのあとで
Provider.Shutdownを呼ぶ。キューに残った back-channel logout の送信が完了します。マルチインスタンス展開を参照してください。 - ハンドラを
op.NewReloadableで作っている場合は、鍵やオプションの変更をReloadで反映し、起動時と再読み込みのたびに同じオプション一覧を使う。鍵ローテーションを参照してください。