- Authors

- Name
- Youngju Kim
- @fjvbn20031
- はじめに — シークレットを配布しない認証は可能か
- シークレットスプロール問題とnon-human identityトレンド
- SPIFFEの中核概念 — SPIFFE IDとSVID
- SPIREアーキテクチャ — server、agent、attestation
- Kubernetesデプロイ実践
- Envoy SDS統合 — 自動mTLS
- IstioとSPIFFEの互換性
- Federation — 信頼ドメイン間の認証
- Vault / cert-managerとの比較
- ワークロードidentityとユーザーidentityの接続
- AIエージェントidentityへの拡張
- 導入時の運用課題
- おわりに
- 参考資料
はじめに — シークレットを配布しない認証は可能か
サービス間認証の伝統的な解法はシークレットの配布でした。APIキー、共有パスワード、静的な証明書を作って各サービスに配る方式です。その結果が今日の**シークレットスプロール(secret sprawl)**です。環境変数、CI変数、コードリポジトリ、チャットログに散らばった資格情報は漏えい事故の常連原因であり、ローテーションは誰もが先送りする宿題になりました。
2026年の流れは明確です。マシン、サービス、パイプライン、そしてAIエージェントまで — non-human identityが人間のアカウント数を数十倍以上上回る環境では、シークレットを「配る」モデルはもはや運用不可能です。代替案は、ワークロードが自身の属性(どこで実行されているか、誰が起動したか)によって身元を証明され、短命の暗号学的な身元文書を自動発行されるモデルです。このモデルの標準がSPIFFE(Secure Production Identity Framework For Everyone)であり、リファレンス実装がSPIREです。
本記事ではSPIFFE IDとSVIDの概念からSPIREアーキテクチャ、Kubernetesデプロイの実践、Envoy SDS統合による自動mTLS、federation、Vault/cert-manager比較、そしてtransaction tokensとAIエージェントidentityへの拡張までを扱います。
シークレットスプロール問題とnon-human identityトレンド
まず、従来のシークレットベース認証の構造的な問題を整理します。
| 問題 | 内容 |
|---|---|
| ブートストラップの逆説 | シークレットを安全に届けるには、また別のシークレット(アクセス資格)が必要 |
| ローテーション負担 | 寿命が長いほど漏えい被害は大きいのに、ローテーションは手動で壊れやすい |
| 所有者不明 | このAPIキーを誰がなぜ作ったのか、6か月後には誰も知らない |
| 複製の容易さ | シークレットはコピーされた瞬間に追跡不能、どこで使われても区別不可 |
| 監査の困難 | 「鍵を持つ誰か」しか分からず、ワークロード単位の識別が不可能 |
ここにnon-human identityの爆発的増加が重なります。マイクロサービス、バッチジョブ、CIランナー、サーバーレス関数に続きAIエージェントが加わり、アイデンティティ管理の重心は人間からワークロードへ移りました。業界の調査はnon-human identityが人間identityの数十倍に達すると報告しており、その資格情報管理は侵害事故の主要原因として指摘されています。
SPIFFEの答えは発想の転換です。**シークレットを配布するのではなく、アイデンティティを発行せよ。**ワークロードは実行環境の属性で自身を証明し(attestation)、プラットフォームは短命の身元文書(SVID)を自動的に発行/更新します。人間が触るシークレットが消えます。
SPIFFEの中核概念 — SPIFFE IDとSVID
SPIFFE ID
SPIFFE IDはワークロードを識別するURIです。形式はspiffeスキーム + 信頼ドメイン + パスで構成されます。
spiffe://prod.example.com/ns/orders/sa/orders-sa
└─┬──┘ └──────┬───────┘ └─────────┬──────────┘
スキーム 信頼ドメイン ワークロードパス
(trust domain) (例: ネームスペース/サービスアカウント)
- **信頼ドメイン(trust domain)**はアイデンティティ発行の権威の単位です。通常は組織や環境(本番/ステージング)単位で分けます。
- パスは組織が自由に設計します。Kubernetesならネームスペースとサービスアカウントをエンコードするパターンが一般的です。
SVID — 身元文書
SVID(SPIFFE Verifiable Identity Document)はSPIFFE IDを含む検証可能な文書で、2つの形式があります。
| 項目 | X.509-SVID | JWT-SVID |
|---|---|---|
| 形式 | X.509証明書(SAN URIにSPIFFE ID) | JWT(subクレームにSPIFFE ID) |
| 用途 | mTLS接続の双方向認証 | L7プロキシ経由などTLSが終端する区間の認証 |
| 寿命 | 数分〜数時間(デフォルト1時間程度) | 数分(audience指定が必須) |
| リプレイリスク | 低い(鍵所有の証明) | あり(窃取されると寿命内は再利用可能) |
| 推奨 | 基本の選択肢 | mTLSを維持できない区間の補助手段 |
X.509-SVIDが基本で、JWT-SVIDはmTLSを最後まで維持できない区間(L7ロードバランサー経由など)の補助手段です。どちらの形式も核心は短い寿命 + 自動更新であり、漏えいしても被害時間が分単位に制限されます。
信頼バンドル
検証者は信頼ドメインごとのCA公開鍵の束であるtrust bundleでSVIDを検証します。バンドルの配布と更新もSPIREが自動化します。
SPIREアーキテクチャ — server、agent、attestation
SPIREはSPIFFEのリファレンス実装で、serverとagentの2層構造です。
+--------------------------------------------------------------+
| SPIRE Server |
| - 登録エントリ(registration entries)を保存 |
| - CAとしてSVIDに署名(またはupstream CAへ委譲) |
| - node attestationを検証 |
+------------------------------+-------------------------------+
| (1) node attestation
| 「このノード/エージェントは本物か」
+------------------------------+-------------------------------+
| SPIRE Agent (ノードごとのDaemonSet) |
| - Workload API(unixソケット)を公開 |
| - workload attestationを実施 |
| - SVIDのキャッシュ/更新 |
+------------------------------+-------------------------------+
| (2) workload attestation
| 「このプロセスはどのワークロードか」
+------------------+------------------+
| | |
+----+----+ +----+----+ +----+----+
| Pod A | | Pod B | | Pod C |
| (orders)| | (pay) | | (envoy) |
+---------+ +---------+ +---------+
動作の流れは次のとおりです。
- Node attestation — agentがserverに「自分は正当なノードで実行されている」ことを証明します。Kubernetesでは、agentのサービスアカウントトークンをserverがTokenReview APIで検証するk8s_psat方式が標準です。AWS/GCP/Azureではインスタンス身元文書ベースのattestorを使います。
- Workload attestation — ワークロードがagentのWorkload APIソケットに接続すると、agentは呼び出しプロセスのカーネルレベル情報(Kubernetesでは該当Podのネームスペース、サービスアカウント、ラベルなど)を収集します。
- 登録エントリのマッチング — 収集されたセレクターがserverに登録されたエントリと一致すれば、該当SPIFFE IDのSVIDを発行します。
- 自動更新 — agentはSVIDの期限前に自動で再発行を受け、ワークロードへプッシュします。
核心は、ワークロードがいかなるシークレットも事前に持つ必要がないことです。アイデンティティは「何を知っているか(シークレット)」ではなく「どこでどのように実行されているか(属性)」から導出されます。
Kubernetesデプロイ実践
本番環境では公式のSPIRE Helmチャートを推奨しますが、構造理解のため中核マニフェストを直接見ていきます。まずserverの設定です。
apiVersion: v1
kind: ConfigMap
metadata:
name: spire-server
namespace: spire
data:
server.conf: |
server {
bind_address = "0.0.0.0"
bind_port = "8081"
trust_domain = "prod.example.com"
data_dir = "/run/spire/data"
log_level = "INFO"
ca_ttl = "24h"
default_x509_svid_ttl = "1h"
}
plugins {
DataStore "sql" {
plugin_data {
database_type = "sqlite3"
connection_string = "/run/spire/data/datastore.sqlite3"
}
}
NodeAttestor "k8s_psat" {
plugin_data {
clusters = {
"prod-cluster" = {
service_account_allow_list = ["spire:spire-agent"]
}
}
}
}
KeyManager "disk" {
plugin_data {
keys_path = "/run/spire/data/keys.json"
}
}
Notifier "k8sbundle" {
plugin_data {
namespace = "spire"
}
}
}
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: spire-server
namespace: spire
spec:
serviceName: spire-server
replicas: 1
selector:
matchLabels:
app: spire-server
template:
metadata:
labels:
app: spire-server
spec:
serviceAccountName: spire-server
containers:
- name: spire-server
image: ghcr.io/spiffe/spire-server:1.12.0
args: ['-config', '/run/spire/config/server.conf']
ports:
- containerPort: 8081
volumeMounts:
- name: spire-config
mountPath: /run/spire/config
readOnly: true
- name: spire-data
mountPath: /run/spire/data
volumes:
- name: spire-config
configMap:
name: spire-server
volumeClaimTemplates:
- metadata:
name: spire-data
spec:
accessModes: ['ReadWriteOnce']
resources:
requests:
storage: 1Gi
agentはDaemonSetとしてすべてのノードにデプロイします。
apiVersion: v1
kind: ConfigMap
metadata:
name: spire-agent
namespace: spire
data:
agent.conf: |
agent {
data_dir = "/run/spire"
log_level = "INFO"
server_address = "spire-server.spire.svc.cluster.local"
server_port = "8081"
socket_path = "/run/spire/sockets/agent.sock"
trust_domain = "prod.example.com"
trust_bundle_path = "/run/spire/bundle/bundle.crt"
}
plugins {
NodeAttestor "k8s_psat" {
plugin_data {
cluster = "prod-cluster"
}
}
KeyManager "memory" {
plugin_data {}
}
WorkloadAttestor "k8s" {
plugin_data {
disable_container_selectors = false
}
}
}
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: spire-agent
namespace: spire
spec:
selector:
matchLabels:
app: spire-agent
template:
metadata:
labels:
app: spire-agent
spec:
hostPID: true
serviceAccountName: spire-agent
containers:
- name: spire-agent
image: ghcr.io/spiffe/spire-agent:1.12.0
args: ['-config', '/run/spire/config/agent.conf']
volumeMounts:
- name: spire-config
mountPath: /run/spire/config
readOnly: true
- name: spire-bundle
mountPath: /run/spire/bundle
readOnly: true
- name: spire-agent-socket
mountPath: /run/spire/sockets
volumes:
- name: spire-config
configMap:
name: spire-agent
- name: spire-bundle
configMap:
name: spire-bundle
- name: spire-agent-socket
hostPath:
path: /run/spire/sockets
type: DirectoryOrCreate
最後にワークロードを登録します。ordersネームスペースのorders-saサービスアカウントで実行されるPodにSPIFFE IDを付与するエントリです。
kubectl exec -n spire spire-server-0 -- \
/opt/spire/bin/spire-server entry create \
-spiffeID spiffe://prod.example.com/ns/orders/sa/orders-sa \
-parentID spiffe://prod.example.com/spire/agent/k8s_psat/prod-cluster/NODE_UUID \
-selector k8s:ns:orders \
-selector k8s:sa:orders-sa
手動登録は規模が大きくなると維持できません。実務ではSPIRE Controller Managerを併せてデプロイし、CRD(ClusterSPIFFEID)で登録を宣言的に管理します。
apiVersion: spire.spiffe.io/v1alpha1
kind: ClusterSPIFFEID
metadata:
name: default-workload-id
spec:
spiffeIDTemplate: 'spiffe://prod.example.com/ns/{{ .PodMeta.Namespace }}/sa/{{ .PodSpec.ServiceAccountName }}'
podSelector:
matchLabels:
spiffe.io/spire-managed-identity: 'true'
これでラベルの付いたすべてのPodが、ネームスペース/サービスアカウントに基づくSPIFFE IDを自動的に受け取ります。
Envoy SDS統合 — 自動mTLS
アプリケーションコードを変えずにmTLSを適用する標準パターンは、Envoyサイドカー + SPIRE agentのSDS(Secret Discovery Service)統合です。SPIRE agentはSDSサーバーの役割を果たせるため、Envoyは証明書をファイルではなくAPIで受け取ります。更新も無停止で行われます。
# Envoyサイドカー設定(抜粋) — ordersサービス
static_resources:
clusters:
# SPIRE agentのWorkload APIをSDSクラスターとして登録
- name: spire_agent
connect_timeout: 1s
http2_protocol_options: {}
load_assignment:
cluster_name: spire_agent
endpoints:
- lb_endpoints:
- endpoint:
address:
pipe:
path: /run/spire/sockets/agent.sock
# アップストリーム: paymentsサービスへのmTLS接続
- name: payments_upstream
connect_timeout: 2s
type: STRICT_DNS
load_assignment:
cluster_name: payments_upstream
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: payments.payments.svc.cluster.local
port_value: 8443
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
'@type': type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
common_tls_context:
# 自分の身元(X.509-SVID)をSDSで受け取る
tls_certificate_sds_secret_configs:
- name: spiffe://prod.example.com/ns/orders/sa/orders-sa
sds_config:
api_config_source:
api_type: GRPC
transport_api_version: V3
grpc_services:
- envoy_grpc:
cluster_name: spire_agent
# 相手の検証: 信頼バンドル + 期待するSPIFFE ID
combined_validation_context:
default_validation_context:
match_typed_subject_alt_names:
- san_type: URI
matcher:
exact: spiffe://prod.example.com/ns/payments/sa/payments-sa
validation_context_sds_secret_config:
name: spiffe://prod.example.com
sds_config:
api_config_source:
api_type: GRPC
transport_api_version: V3
grpc_services:
- envoy_grpc:
cluster_name: spire_agent
この設定一式で次が自動化されます。
- ordersのサイドカーは自身のX.509-SVIDをSPIREから受け取り、TLSクライアント証明書として使用します。
- payments側の証明書が信頼バンドルで検証され、SAN URIが期待するSPIFFE IDと完全一致するかを確認します。同じCAだから通すのではなく、ワークロード単位で認可するのがポイントです。
- 証明書の更新(1時間の寿命)はSDSプッシュにより無停止で処理されます。人間が触る証明書ファイルは存在しません。
サイドカーなしでアプリケーションから直接使うには、go-spiffeのようなSDKでWorkload APIを呼び出します。
// go-spiffe v2でmTLSクライアントを作る(抜粋)
source, err := workloadapi.NewX509Source(ctx)
if err != nil {
log.Fatal(err)
}
defer source.Close()
serverID := spiffeid.RequireFromString("spiffe://prod.example.com/ns/payments/sa/payments-sa")
tlsConfig := tlsconfig.MTLSClientConfig(source, source, tlsconfig.AuthorizeID(serverID))
client := &http.Client{
Transport: &http.Transport{TLSClientConfig: tlsConfig},
}
resp, err := client.Get("https://payments.payments.svc.cluster.local:8443/healthz")
IstioとSPIFFEの互換性
IstioのmTLSアイデンティティ体系は最初からSPIFFE形式です。サイドカー(またはambientのztunnel)が受け取る証明書のSAN URIは次の形式です。
spiffe://cluster.local/ns/orders/sa/orders-sa
したがって「Istioを使えばSPIREは不要か」という問いには次のように答えられます。
- メッシュ内部だけで足りるなら — Istio内蔵CA(istiod)で十分です。別途SPIREなしでSPIFFE形式のワークロードアイデンティティと自動mTLSが得られます。
- メッシュ外(VM、他クラスター、メッシュ未適用ワークロード、CIランナー)まで単一のアイデンティティ体系が必要なら — SPIREをアイデンティティの単一ソースに据える構成が有効です。IstioはSPIREを外部CAとして統合でき(SDS経由)、その場合メッシュ内外のワークロードが同じ信頼ドメインのSVIDで相互認証します。
- 注意点: Istioのデフォルト信頼ドメインはcluster.localなので、組織レベルの信頼ドメイン戦略(例: prod.example.com)と揃えるには、meshConfigのtrustDomain設定とSPIREのtrust_domainを整合させる必要があります。
Federation — 信頼ドメイン間の認証
異なる信頼ドメイン(別クラスター、別組織、別クラウド)のワークロードが相互認証するには、trust bundleを交換する必要があります。SPIREのfederation機能がこれを自動化します。
# SPIRE Server設定にfederationを追加(server.conf抜粋)
# federates_withで相手ドメインのバンドルエンドポイントを指定
federation {
bundle_endpoint {
address = "0.0.0.0"
port = 8443
}
federates_with "partner.example.org" {
bundle_endpoint_url = "https://spire.partner.example.org:8443"
bundle_endpoint_profile "https_spiffe" {
endpoint_spiffe_id = "spiffe://partner.example.org/spire/server"
}
}
}
登録エントリにもfederation対象を明示します。
spire-server entry create \
-spiffeID spiffe://prod.example.com/ns/orders/sa/orders-sa \
-selector k8s:ns:orders -selector k8s:sa:orders-sa \
-federatesWith spiffe://partner.example.org
これでordersワークロードは自身のSVIDとともに相手ドメインのtrust bundleを受け取り、partnerドメインのワークロードとmTLSを確立できます。バンドルの更新は両側のserverが定期的に同期します。マルチクラスター、ハイブリッドクラウド、組織間B2B連携で「共有CAなし」の相互認証を構成する標準的な方法です。
Vault / cert-managerとの比較
「証明書を自動発行する」という点で似て見えるツールとの役割の違いを整理します。
| 項目 | SPIRE | HashiCorp Vault | cert-manager |
|---|---|---|---|
| 本質 | ワークロードアイデンティティ発行基盤 | シークレット管理 + PKI発行エンジン | Kubernetes証明書ライフサイクル管理 |
| 身元の証明 | attestation(無資格ブートストラップ) | 認証方法が必要(k8s authなど) | 直接の証明なし(リソース権限ベース) |
| 発行対象 | ワークロード単位のSVID(X.509/JWT) | 汎用シークレット、PKI証明書 | 主にTLSサーバー証明書(Ingressなど) |
| 寿命の哲学 | 分〜時間単位、完全自動更新 | 設定次第(短くも長くも) | 通常数十日、自動更新 |
| 標準 | SPIFFE(CNCF graduated) | 独自API | ACMEなどの証明書標準 |
| 相互補完 | SVIDをVaultの認証手段に使える | Vault PKIをSPIREのupstream CAにできる | メッシュ外の証明書と併用 |
要点は競争ではなく組み合わせです。よく使われる構成は次のとおりです。
- SPIREがアイデンティティを、Vaultがシークレットを — ワークロードがSVIDでVaultにログイン(JWT/cert auth)し、DBパスワードのような残存シークレットを受け取ります。「シークレットにアクセスするためのシークレット」が消え、ブートストラップの逆説が解けます。
- Vault PKIをSPIREのUpstreamAuthorityに — 組織のPKI体系の中にSPIRE CAを従属させ、ガバナンスを維持します。
- cert-managerはエッジTLSを — 外部公開ドメインのサーバー証明書(Let’s Encryptなど)はcert-managerが、内部ワークロード間のmTLSはSPIREが担当する分業が自然です。
ワークロードidentityとユーザーidentityの接続
実際のリクエストには2つのアイデンティティが共存します。「ordersサービス(ワークロード)がuser-1234(ユーザー)の代わりにpaymentsを呼び出す」をどう表現するのでしょうか。
- トランスポート層 — mTLS(X.509-SVID)で呼び出し元ワークロードを認証します。
- リクエスト層 — ユーザーコンテキストはJWTで運びます。前回扱ったtoken exchange(RFC 8693)が委譲チェーンを記録します。
- transaction tokens — OAuth WGで議論中のTransaction Tokensドラフトはこのパターンを標準化します。外部トークンを信頼境界への進入時点で短命(分単位)の内部専用トークンに交換し、そこにユーザー身元 + リクエストコンテキスト + 呼び出しチェーンを載せて内部呼び出し全体へ伝播します。このときtransaction tokenサービスに交換を要求する主体の認証が、まさにワークロードidentity(SVID)です。
[ユーザーJWT] --> Gateway --(exchange)--> [Txn-Token: ユーザー + コンテキスト + チェーン]
|
v
orders (SVIDでmTLS) --> payments (SVIDでmTLS)
リクエストごと: Txn-Token検証 + 呼び出し元SPIFFE ID確認
ワークロードの身元(SPIFFE)とユーザーの身元(OIDC)が別々の体系ではなく、1つのリクエストの中で結合されること — これが2026年のZero Trustアーキテクチャの完成形です。
AIエージェントidentityへの拡張
non-human identityの最新の変曲点はAIエージェントです。エージェントは従来のサービスより動的に生成/消滅し、ユーザーの代わりに行動し、ツール呼び出しで権限を行使します。SPIFFEの観点からの適用方向は次のとおりです。
- **エージェントのランタイムもワークロードです。**エージェントを実行するプロセス/PodにSVIDを付与すれば、「どのエージェントランタイムがこのツールを呼んだのか」が暗号学的に識別できます。静的APIキーをエージェントに埋め込む慣行を置き換えます。
- 委譲チェーンの結合 — エージェントがユーザーの代わりに行動するとき、ワークロード身元(SVID) + ユーザー委譲(token exchangeのactクレームまたはtransaction token)を併せて検証します。「このエージェントが、このユーザーの代わりに、この範囲内で」がすべてトークンと証明書で証明されます。
- MCPエコシステムとの接点 — MCP(Model Context Protocol)サーバーがOAuth保護リソースとして標準化されるにつれ(Keycloak 26.6のCIMD実験的サポートなど)、エージェントのツールアクセスにも標準トークンフローが適用されつつあります。ツールサーバー間のmTLSにはSPIFFEが自然な相棒です。
- 短命の価値の最大化 — エージェントは行動範囲が広く、資格情報漏えいの波及が大きくなります。分単位のSVIDとaudienceの狭いJWT-SVIDの組み合わせは、エージェント環境で特に効果的です。
導入時の運用課題
SPIRE導入で実際に直面する課題と対応を整理します。
- SPIRE自体の可用性 — SVIDの寿命が1時間なら、SPIREが1時間以上停止すると更新が止まります。serverを冗長化(共有データストア + 複数レプリカ)し、agentキャッシュで短期障害を吸収し、SVID寿命と障害許容時間を一体で設計する必要があります。
- 登録エントリのガバナンス — セレクターを緩く設定すると(例: ネームスペースのみ)、意図より広いワークロードが同じアイデンティティを受け取ります。ClusterSPIFFEIDテンプレートをコードレビューの対象として管理し、アイデンティティ付与の基準を明文化します。
- 段階的な適用経路 — 全サービスの同時移行は不可能です。permissive(平文+mTLS併用)段階を経てSTRICTへ絞る経路、そしてmTLS適用率を測定するダッシュボードが必要です。
- 非SPIFFEシステムとの境界 — レガシーDBや外部SaaSは依然としてパスワード/APIキーを要求します。これらの残存シークレットはVaultに集約し、VaultへのアクセスをSVIDで認証することで、「シークレットの根」を1つに減らします。
- 可観測性 — SVID発行/更新の失敗、attestationの失敗、バンドル同期の遅延をメトリクスで監視しアラートを設定します。証明書期限切れによる連鎖障害は静かに始まるため、期限切れ間近のSVID比率がよい先行指標です。
- 時刻同期と鍵の保護 — 短命証明書はクロックスキューに敏感です。NTP監視は必須であり、serverの署名鍵はKMS/HSMバックエンド(KeyManagerプラグイン)で保護することが推奨されます。
おわりに
SPIFFE/SPIREが提示する転換を一文に要約するとこうなります。**シークレットを動かすのではなく、アイデンティティを発行せよ。**attestationでブートストラップの逆説を解き、短命のSVIDでローテーションを無意味にし、SPIFFE IDという標準的な命名でワークロード単位の認可とfederationを可能にします。Envoy SDSやIstio統合を使えば、アプリケーションコードの修正なしに自動mTLSへ到達できます。
そしてこの基盤はワークロードを越えて拡張されています。ユーザーの身元(OIDC)、委譲(token exchange、transaction tokens)、AIエージェントidentityがSPIFFEワークロード身元と1つのリクエストの中で結合されるのが、2026年のZero Trustスタックの標準形です。シークレットスプロールに疲れた組織なら、アイデンティティベース認証への転換をこれ以上先送りする理由はありません。
参考資料
- SPIFFE 公式ドキュメント
- SPIRE 公式ドキュメント
- SPIFFE ID / SVID 標準仕様 (GitHub)
- SPIRE Helm Charts (hardened)
- go-spiffe v2 SDK
- Envoy SDSとSPIREの統合ガイド
- Istio Security コンセプト
- RFC 8693 — OAuth 2.0 Token Exchange
- OAuth Transaction Tokens ドラフト
- RFC 7519 — JSON Web Token (JWT)
- RFC 9700 — Best Current Practice for OAuth 2.0 Security
- NIST SP 800-207 Zero Trust Architecture
- HashiCorp Vault ドキュメント
- cert-manager ドキュメント
- Keycloak ドキュメント