Skip to content
Published on

Zero TrustとIdentity-Aware Proxy — BeyondCorpモデルを自分で構築する

Authors

はじめに — なぜ今Identity-Aware Proxyなのか

2026年現在、「社内ネットワークにいれば信頼する」という前提は、事実上廃止されたセキュリティモデルです。リモートワークが標準になり、ワークロードはマルチクラウドに分散し、SaaSと社内ツールの境界も曖昧になりました。さらにAIエージェントが人間の代わりに社内システムへアクセスする流れが加わり、「誰が(あるいは何が)どのコンテキストでアクセスするのか」をリクエストごとに検証するidentity-firstセキュリティがデフォルトになっています。

本記事では、Zero Trustの中核的な実装であるIdentity-Aware Proxy(IAP)を扱います。GoogleのBeyondCorp論文が示したモデルを理解し、oauth2-proxyとKeycloakを組み合わせてIAPを自分で構築する全過程を、YAMLや設定ファイルのレベルまで追っていきます。最後にCloudflare Access、Google Cloud IAP、Pomeriumといった商用/オープンソースの代替を比較し、段階的な導入ロードマップとAIエージェント時代のアクセス制御まで見ていきます。

境界型セキュリティの終焉とidentity-firstセキュリティ

城と堀モデルの限界

従来のネットワークセキュリティはしばしば「城と堀(castle-and-moat)」モデルと呼ばれます。ファイアウォールとVPNで境界を築き、いったん内部に入ったトラフィックは広く信頼する方式です。このモデルの問題は明確です。

  • 攻撃者が境界を一度突破すれば(フィッシング、VPN資格情報の窃取、脆弱性)、内部での水平移動(lateral movement)は自由です。
  • VPNはネットワーク全体へのアクセスを付与します。特定のアプリ1つだけ使いたい外部委託者にも、事実上社内ネットワーク全体が開放されます。
  • 位置ベースの信頼は、リモートワーク、BYOD、マルチクラウド環境では意味を失います。
  • 内部脅威と侵害された端末に対して無防備です。

Zero Trustの基本原則

Zero TrustはNIST SP 800-207で標準化された概念で、次の原則に要約されます。

  1. ネットワーク上の位置は信頼の根拠にならない — 社内ネットワークでもカフェのWi-Fiでも同一に扱います。
  2. すべてのアクセスは認証・認可されなければならない — セッション単位ではなくリクエスト単位で検証します。
  3. 最小権限 — ユーザーとデバイスは業務に必要なリソースにのみアクセスします。
  4. コンテキストベースの動的ポリシー — ユーザーの身元、デバイスの状態、位置、時間などを総合してアクセスを判断します。
  5. 継続的な検証 — 一度通過したら終わりではなく、シグナルが変われば再評価されます。

この原則をHTTPアプリケーション層で実装するコンポーネントがIdentity-Aware Proxyです。

BeyondCorp論文の核心

Googleは2009年のOperation Aurora侵害事件を契機に、社内VPNを段階的に廃止し、すべての社内アプリケーションをインターネットに公開しつつアクセスプロキシで保護するBeyondCorpプロジェクトを開始しました。BeyondCorp論文シリーズの主要コンポーネントは次のとおりです。

  • Access Proxy — すべてのアプリケーションの前段に位置するリバースプロキシ。TLS終端、認証、認可を中央で処理します。
  • Device Inventory Database — 会社が管理するすべてのデバイスの状態(OSバージョン、パッチレベル、ディスク暗号化の有無)を追跡します。
  • User/Group Database — HRシステムと同期されるユーザー身元ストアです。
  • Trust Inference — ユーザーとデバイスのシグナルを総合し、信頼レベル(trust tier)を動的に算出します。
  • Access Control Engine — 「このユーザーが、このデバイスで、このアプリケーションに」アクセス可能かをポリシーで判断します。

BeyondCorpが残した最も重要な教訓は2つです。第一に、認証と認可をアプリケーションから切り離してプロキシ層に集約すれば、数百の社内アプリのセキュリティ水準を一括で引き上げられること。第二に、ユーザーの身元だけでは不十分で、デバイスの信頼も併せて評価しなければならないことです。

IAPの動作原理 — すべてのリクエストに認証と認可

IAPの動作を1枚で表すと次のようになります。

                        +----------------------------+
                        |   Identity Provider (IdP)  |
                        |   Keycloak / OIDC          |
                        +-------------+--------------+
                                      | (2) OIDC認証
                                      | Authorization Code + PKCE
+----------+   (1) HTTPS   +----------+-----------+   (4) ヘッダー注入  +-------------+
| ユーザーの +-------------->+  Identity-Aware Proxy +------------------->+  社内アプリ  |
| ブラウザ   |               |  (oauth2-proxyなど)   |   X-Forwarded-*    |  (adminなど) |
+----------+               +----------+-----------+                    +-------------+
                                      |
                                      | (3) ポリシー評価
                                      |  - ユーザーのグループ/ロール
                                      |  - デバイスの状態
                                      |  - 位置/時間コンテキスト
                                      v
                           +----------------------+
                           |  Policy / Device DB  |
                           +----------------------+

リクエスト処理の流れを段階ごとに見ると次のとおりです。

  1. ユーザーが保護対象アプリのURLにアクセスすると、リクエストは必ずIAPを経由します。IAPを迂回した直接アクセスはネットワークポリシーで遮断します。
  2. 有効なセッションがなければ、IAPはOIDC Authorization Code Flow(PKCE付き)でIdPに認証を委譲します。
  3. 認証が完了すると、IAPはIDトークンのクレーム(グループ、ロール)と追加コンテキスト(デバイス、IP、時間)に基づいて認可ポリシーを評価します。
  4. 通過したリクエストにのみユーザー身元ヘッダー(または署名済みJWT)を付与してアップストリームのアプリへ転送します。
  5. このプロセスは初回ログイン後もすべてのリクエストごとに、セッションCookieの検証とポリシー再評価の形で繰り返されます。セッションは短く保ち、refreshのたびにIdPの最新状態(アカウント無効化、グループ変更)を反映します。

従来型VPNとの違いを表で整理します。

項目VPNIdentity-Aware Proxy
信頼の単位ネットワーク(入れば終わり)リクエスト(毎回認証/認可)
アクセス範囲社内ネットワーク全体やサブネットアプリケーション単位
認可の基準IP、アカウント身元 + グループ + デバイス + コンテキスト
可視性トンネル内部は不透明リクエスト単位の監査ログ
ユーザー体験クライアント導入、接続断ブラウザだけでSSO
L3/L4対応可能基本はHTTP、TCPは別ソリューション

実践構築 — oauth2-proxy + KeycloakでIAPを作る

それでは実際に作ってみます。構成は次のとおりです。

  • IdP: Keycloak 26.6(2026年5月時点で26.6.2が最新、パスキーのログイン統合とFAPI 2.0 Final対応を含む)
  • IAP: oauth2-proxy 7.x
  • リバースプロキシ: nginx ingress(auth_requestパターン)
  • 保護対象: Kubernetesにデプロイされた社内admin用ダッシュボード

ステップ1 — Keycloakクライアントの設定

まずKeycloakにoauth2-proxy用のconfidential clientを作成します。realmはinternalと仮定します。Keycloak Admin CLI(kcadm)で次のように作成します。

# Keycloak admin CLIにログイン
kcadm.sh config credentials \
  --server https://keycloak.example.com \
  --realm master \
  --user admin

# oauth2-proxy用クライアントを作成
kcadm.sh create clients -r internal -f - <<'EOF'
{
  "clientId": "oauth2-proxy",
  "protocol": "openid-connect",
  "publicClient": false,
  "standardFlowEnabled": true,
  "directAccessGrantsEnabled": false,
  "serviceAccountsEnabled": false,
  "redirectUris": ["https://admin.example.com/oauth2/callback"],
  "attributes": {
    "pkce.code.challenge.method": "S256",
    "post.logout.redirect.uris": "https://admin.example.com"
  }
}
EOF

グループ情報をトークンに含めるため、groupsクレームのマッパーを追加します。

# groupsクレームをIDトークンに含めるマッパー
CLIENT_UUID=$(kcadm.sh get clients -r internal -q clientId=oauth2-proxy --fields id --format csv --noquotes)

kcadm.sh create clients/$CLIENT_UUID/protocol-mappers/models -r internal -f - <<'EOF'
{
  "name": "groups",
  "protocol": "openid-connect",
  "protocolMapper": "oidc-group-membership-mapper",
  "config": {
    "claim.name": "groups",
    "full.path": "false",
    "id.token.claim": "true",
    "access.token.claim": "true",
    "userinfo.token.claim": "true"
  }
}
EOF

Keycloak 26.6からはログインフォームにパスキーが条件付きUIとして統合されているため、internal realmの認証フローでWebAuthn Passwordlessポリシーを有効にすれば、パスワードレスの一次認証をデフォルトにできます。Zero Trustにおいて、フィッシング耐性のある認証手段は事実上必須です(WebAuthn Level 3FIDO passkeysを参照)。

ステップ2 — oauth2-proxyのデプロイ

Kubernetesにoauth2-proxyをデプロイします。マニフェスト全体は次のとおりです。

apiVersion: v1
kind: Secret
metadata:
  name: oauth2-proxy-secrets
  namespace: iap
type: Opaque
stringData:
  client-secret: 'REPLACE_WITH_KEYCLOAK_CLIENT_SECRET'
  # python -c 'import secrets; print(secrets.token_urlsafe(32))'
  cookie-secret: 'REPLACE_WITH_32_BYTE_RANDOM'
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: oauth2-proxy
  namespace: iap
  labels:
    app: oauth2-proxy
spec:
  replicas: 2
  selector:
    matchLabels:
      app: oauth2-proxy
  template:
    metadata:
      labels:
        app: oauth2-proxy
    spec:
      containers:
        - name: oauth2-proxy
          image: quay.io/oauth2-proxy/oauth2-proxy:v7.8.1
          args:
            - --provider=keycloak-oidc
            - --client-id=oauth2-proxy
            - --oidc-issuer-url=https://keycloak.example.com/realms/internal
            - --code-challenge-method=S256
            - --redirect-url=https://admin.example.com/oauth2/callback
            - --email-domain=example.com
            - --allowed-group=platform-admins
            - --scope=openid email profile groups
            - --cookie-secure=true
            - --cookie-samesite=lax
            - --cookie-refresh=4m
            - --cookie-expire=8h
            - --session-store-type=redis
            - --redis-connection-url=redis://redis.iap.svc.cluster.local:6379
            - --set-xauthrequest=true
            - --set-authorization-header=true
            - --pass-access-token=false
            - --skip-provider-button=true
            - --reverse-proxy=true
            - --http-address=0.0.0.0:4180
            - --metrics-address=0.0.0.0:44180
          env:
            - name: OAUTH2_PROXY_CLIENT_SECRET
              valueFrom:
                secretKeyRef:
                  name: oauth2-proxy-secrets
                  key: client-secret
            - name: OAUTH2_PROXY_COOKIE_SECRET
              valueFrom:
                secretKeyRef:
                  name: oauth2-proxy-secrets
                  key: cookie-secret
          ports:
            - containerPort: 4180
              name: http
            - containerPort: 44180
              name: metrics
          readinessProbe:
            httpGet:
              path: /ping
              port: 4180
          resources:
            requests:
              cpu: 50m
              memory: 64Mi
            limits:
              memory: 256Mi
---
apiVersion: v1
kind: Service
metadata:
  name: oauth2-proxy
  namespace: iap
spec:
  selector:
    app: oauth2-proxy
  ports:
    - name: http
      port: 4180
      targetPort: 4180

この設定で注目すべき点は次のとおりです。

  • code-challenge-method=S256 — OAuth 2.1 draftが事実上義務化したPKCEをconfidential clientにも適用します(RFC 7636draft-ietf-oauth-v2-1)。
  • allowed-group=platform-admins — Keycloakのグループに基づく一次認可をプロキシで実施します。
  • cookie-refresh=4m — 4分ごとにrefresh tokenでセッションを更新し、IdPの最新状態を反映します。アカウントが無効化されれば数分以内にアクセスが遮断されます。
  • session-store-type=redis — Cookieにトークン全体を入れず、Redisにセッションを保存することで、Cookieサイズの問題とトークン露出を軽減します。
  • set-xauthrequest=true — nginx auth_requestのレスポンスにX-Auth-Request-User、X-Auth-Request-Email、X-Auth-Request-Groupsヘッダーを載せ、アップストリームへ渡せるようにします。

ステップ3 — nginx auth_requestパターンの連携

nginxのauth_requestは「本リクエストを処理する前にサブリクエストを送って認証の有無を確認する」ディレクティブです。IAPパターンの要となる接着剤です。

server {
    listen 443 ssl;
    server_name admin.example.com;

    ssl_certificate     /etc/nginx/tls/tls.crt;
    ssl_certificate_key /etc/nginx/tls/tls.key;

    # 認証チェックのサブリクエスト — oauth2-proxyの /oauth2/auth は
    # 認証済みなら202、そうでなければ401を返す
    location = /oauth2/auth {
        internal;
        proxy_pass http://oauth2-proxy.iap.svc.cluster.local:4180;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        # ボディの転送は不要
        proxy_pass_request_body off;
        proxy_set_header Content-Length "";
    }

    # ログインフロー(リダイレクト、コールバック、ログアウト)
    location /oauth2/ {
        proxy_pass http://oauth2-proxy.iap.svc.cluster.local:4180;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location / {
        auth_request /oauth2/auth;
        # 401ならログインへリダイレクト
        error_page 401 = /oauth2/start?rd=$scheme://$host$request_uri;

        # authサブリクエストのレスポンスヘッダーから身元情報を取り出し
        # アップストリームへ注入する
        auth_request_set $user   $upstream_http_x_auth_request_user;
        auth_request_set $email  $upstream_http_x_auth_request_email;
        auth_request_set $groups $upstream_http_x_auth_request_groups;
        proxy_set_header X-Forwarded-User   $user;
        proxy_set_header X-Forwarded-Email  $email;
        proxy_set_header X-Forwarded-Groups $groups;

        # ユーザーが偽造した身元ヘッダーが通らないよう
        # 上のproxy_set_headerが常に上書きする構造を維持する

        proxy_pass http://admin-dashboard.apps.svc.cluster.local:8080;
    }
}

Kubernetesのingress-nginxを使うなら、同じパターンをアノテーションで表現できます。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: admin-dashboard
  namespace: apps
  annotations:
    nginx.ingress.kubernetes.io/auth-url: 'https://admin.example.com/oauth2/auth'
    nginx.ingress.kubernetes.io/auth-signin: 'https://admin.example.com/oauth2/start?rd=$scheme://$host$request_uri'
    nginx.ingress.kubernetes.io/auth-response-headers: 'X-Auth-Request-User, X-Auth-Request-Email, X-Auth-Request-Groups'
spec:
  ingressClassName: nginx
  rules:
    - host: admin.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: admin-dashboard
                port:
                  number: 8080
  tls:
    - hosts:
        - admin.example.com
      secretName: admin-dashboard-tls

ステップ4 — プロキシ迂回の遮断

IAPは迂回経路が1つでもあれば無力化されます。NetworkPolicyで、アップストリームのアプリがingressコントローラーからのトラフィックのみ受け付けるよう強制します。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: admin-dashboard-only-from-ingress
  namespace: apps
spec:
  podSelector:
    matchLabels:
      app: admin-dashboard
  policyTypes:
    - Ingress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: ingress-nginx
      ports:
        - protocol: TCP
          port: 8080

さらに、アップストリームのアプリは身元ヘッダーを信頼する前に「このリクエストは本当にプロキシから来たのか」を確認すべきです。最も堅牢な方法は、oauth2-proxyのset-authorization-headerで署名済みIDトークン(JWT)を受け取り、アプリ側で署名を検証することです。平文ヘッダーだけを信頼する構成は、内部ネットワークが侵害された場合に偽造のリスクがあります。

デバイス信頼とコンテキストベースのポリシー

BeyondCorpモデルの半分はデバイス信頼です。ユーザー認証がどれだけ強くても、マルウェアに感染した端末ならアクセスを制限すべきです。実務で段階的に適用できる方法は次のとおりです。

  1. mTLSクライアント証明書 — MDM(Intune、Jamfなど)で会社管理端末にのみクライアント証明書を配布し、プロキシでTLSクライアント認証を要求します。「管理端末かどうか」を最もシンプルに証明する方式です。
  2. デバイスポスチャーのシグナル — EDR/MDMのAPIからOSバージョン、ディスク暗号化、画面ロックの有無を取得し、ポリシーエンジンに供給します。Cloudflare AccessやPomeriumはデバイスポスチャー連携を内蔵しています。
  3. 信頼レベル(trust tier) — BeyondCorpのようにデバイスをfully-trusted、managed、unknownに分類し、アプリケーションの機密度とマッチングします。例えば決済adminはfully-trusted端末のみ、wikiはmanaged以上でアクセス可能とします。

nginx層でmTLSを要求する設定例は次のとおりです。

server {
    listen 443 ssl;
    server_name payments-admin.example.com;

    ssl_client_certificate /etc/nginx/tls/device-ca.crt;
    ssl_verify_client on;

    location / {
        auth_request /oauth2/auth;
        # デバイス証明書の情報をアップストリームと監査ログへ渡す
        proxy_set_header X-Device-Cert-DN $ssl_client_s_dn;
        proxy_set_header X-Device-Cert-Verify $ssl_client_verify;
        proxy_pass http://payments-admin.apps.svc.cluster.local:8080;
    }
}

コンテキストベースのポリシーとは、「同じユーザーでも状況によって異なる判断」を下すことです。代表的なシグナルとポリシー例は次のとおりです。

シグナルポリシー例
デバイスレベル非管理端末は読み取り専用アプリのみ許可
位置許可国以外からのアクセスにはstep-up認証(パスキー再認証)を要求
時間業務時間外の本番admin操作には承認ワークフローが必要
認証強度パスワードのみでログインしたセッションは機密アプリへアクセス不可
異常シグナル不可能な移動(impossible travel)検知時はセッションを即時失効

Keycloakでは認証フローの条件付き実行とstep-up authentication(ACR/LoA)で認証強度ポリシーを実装でき、26.6のWorkflows機能でアカウントライフサイクルの自動化(長期未使用アカウントの無効化など)をrealmレベルで構成できます。

VPN代替シナリオ

IAPでVPNを置き換える典型的なシナリオを整理します。

[Before] 全社員 --> VPN Gateway --> 社内ネットワーク全体 (wiki, CI, admin, DB, SSH ...)

[After]
  社員/委託先 --> IAP (HTTPS) --> wiki、CI、adminなどのWebアプリ        (トラフィックの大半)
  運用者     --> SSH/DB専用ソリューション(Boundary、Teleportなど)       (非HTTPプロトコル)
  レガシー    --> 残存VPN (段階的に縮小、対象サブネットを最小化)

ポイントは次のとおりです。

  • 社内トラフィックの大半を占めるWebアプリケーションからIAPへ移行すると、VPNの同時接続負荷とヘルプデスクのチケットが激減します。
  • SSH、データベース、RDPのような非HTTPプロトコルはIAPの守備範囲ではないため、Teleport、Boundary、Cloudflare Tunnel(TCP)などの専用ソリューションで同じidentity-firstの原則を適用します。
  • 委託先やパートナーにはVPNアカウントの代わりに特定アプリへのIAPアクセスのみを付与します。オフボーディングはIdPでアカウントを無効化するだけで完了します。

Cloudflare Access vs Google Cloud IAP vs Pomerium vs oauth2-proxy

項目Cloudflare AccessGoogle Cloud IAPPomeriumoauth2-proxy
形態SaaS(エッジネットワーク)GCPマネージドオープンソース + 商用オープンソース
稼働場所CloudflareエッジGCP LBと統合セルフホストセルフホスト
IdP連携あらゆるOIDC/SAMLGoogle + 外部IdP連携あらゆるOIDCあらゆるOIDC
デバイスポスチャー内蔵(WARPクライアント)内蔵(Endpoint Verification)内蔵(Pomerium Zero含む)なし(自前で構成)
ポリシー表現力グループ、国、デバイスなどIAM条件 + Access LevelsRego/式ベースの精緻なポリシーグループ/メール程度
非HTTP対応TCP/UDP (Tunnel)TCP forwardingTCP対応なし
ロックインCloudflare依存GCP依存低い低い
コストユーザー単位課金GCP料金に含まれるOSS無料 + 商用オプション無料

選定ガイドは次のとおりです。

  • GCP中心のインフラなら、Google Cloud IAPがLBとIAMに自然に統合され、運用負担が最も小さくなります。
  • マルチクラウド + SaaSエッジ志向なら、Cloudflare Accessがデバイスポスチャーと非HTTPまで含む最も完成されたパッケージです。
  • セルフホスト + 精緻なポリシーが必要なら、Pomeriumがoauth2-proxyよりポリシー表現力(コンテキスト条件、デバイス身元)で優れています。
  • シンプルなグループベース保護 + 最小依存なら、oauth2-proxy + nginxの組み合わせが軽量で実績のある選択です。

事例 — 社内adminツールの保護

実務で最も一般的で効果が大きい適用対象は社内adminツールです。Grafana、ArgoCD、Airflow、自社開発のバックオフィスのような、「認証が弱い、あるいは独自のアカウント体系を持つ」ツールが対象です。

典型的な適用パターンは次のとおりです。

  1. adminツール自体のログイン画面を無効化するか、ヘッダー/OIDC認証モードに切り替えます。例えばGrafanaはauth.proxy設定でX-Forwarded-Userヘッダーを信頼させられます。
# grafana.ini — IAPの背後でのヘッダーベース認証
[auth.proxy]
enabled = true
header_name = X-Forwarded-User
header_property = username
auto_sign_up = true
sync_ttl = 60
# プロキシのIPのみ信頼(偽造防止の最後の砦)
whitelist = 10.0.0.0/8
  1. IAP側でツールごとに許可グループを分けます。ArgoCDはplatformチームのグループのみ、Airflowはdataチームのグループのみ通す、といった具合です。ツールごとにoauth2-proxyを個別に立てるか、Pomeriumのようにルート単位のポリシーをサポートするプロキシを使います。
  2. すべてのアクセスを構造化ログに残します。誰が、いつ、どのデバイスで、どのアプリにアクセスしたかがリクエスト単位で記録されるため、監査対応が容易になります。
  3. break-glass経路を設計します。IdP障害時にadminツールへアクセスする緊急手順(一時的な静的資格情報 + 強力な監査)を文書化します。

段階的な導入ロードマップ

Zero Trustはビッグバン移行ではなく旅路です。現実的なロードマップは次のとおりです。

Phase 0  現状把握 (1か月)
         - 社内アプリのインベントリ、認証方式、機密度の分類
         - IdPの整備: グループ/ロール体系、MFA(可能ならパスキー)有効化

Phase 1  パイロット (1〜2か月)
         - 低リスクのアプリ2〜3個(wiki、ダッシュボード)をIAPの背後へ移行
         - ログインUX、セッションポリシー、障害モードの検証

Phase 2  拡大 (3〜6か月)
         - adminツール全体 + 新規アプリはデフォルトでIAP適用
         - デバイス証明書(mTLS)の配布、信頼レベルの導入
         - 非HTTPアクセス(SSH/DB)にTeleportなどを導入

Phase 3  VPN縮小 (6〜12か月)
         - VPNのアクセス対象をレガシーシステムに限定
         - コンテキストベースのポリシー(位置、時間、step-up)の高度化
         - ポリシーのコード化(IaC)と定期アクセスレビューの自動化

Phase 4  継続的改善
         - セッション異常検知、リスクベースの再認証
         - ワークロードidentity(SPIFFE)とユーザーidentityのポリシー統合

各フェーズで測定する指標も併せて定義するとよいでしょう。VPN同時接続数、IAPの背後へ移行したアプリの割合、平均オンボーディング/オフボーディング時間、認証関連のヘルプデスクチケット数が代表的です。

2026年の視点 — AIエージェントのアクセス制御まで

2026年の新しい課題は、人間ではない主体、特にAIエージェントによる社内システムへのアクセスです。エージェントが社内wikiを検索しadmin APIを呼び出すシナリオが日常化するにつれ、IAPのポリシー対象は「ユーザー + デバイス」から「ユーザー + デバイス + エージェント」へ拡大しています。

実務的に整理すると次のとおりです。

  • エージェントも第一級のidentityであるべきです。 人間アカウントのAPIキーをエージェントにコピーして渡すアンチパターンの代わりに、エージェント専用クライアントをIdPに登録し、短命のトークンを発行します。Keycloak 26.6のOAuth Client ID Metadata Document(CIMD)実験的サポートは、MCP(Model Context Protocol)ベースのエージェントが事前登録なしでも標準的にクライアント身元を提示するフローを可能にします。
  • 委譲チェーンの保存 — 「どのユーザーの代わりに、どのエージェントが呼び出しているのか」をトークンに記録すべきです。OAuth Token Exchange(RFC 8693)のactorクレームとdelegationパターンが標準のツールです。
  • エージェント専用ポリシー — エージェントには人間より狭いスコープ、短いトークン寿命、より厳しいレート制限と監査を適用します。IAP層でエージェントのトラフィックを識別(クライアント身元ベース)し、別のポリシーバンドルで評価する構造が定着しつつあります。
  • 非HTTPのツール呼び出し — MCPサーバーのようにエージェントが使うツールエンドポイントもIAPの背後に置き、エージェントのOAuthトークンを検証するパターンが推奨されます。KeycloakがMCP authorization serverの役割を担えるようになったのもこの文脈です。

BeyondCorpが「位置から身元へ」の転換だったとすれば、今は「人間の身元からすべての主体(human + non-human)の身元へ」の転換が進行中です。IAPを導入する際は、ポリシーモデルを人間専用に狭く設計せず、主体(subject)の抽象を広く取っておくことが2026年の設計ポイントです。

運用ベストプラクティスとアンチパターン

最後に運用観点のチェックリストを整理します。

ベストプラクティス

  • セッションCookieはSecure + HttpOnly + SameSite=Lax以上とし、cookie-refreshでIdPの状態を定期的に反映します。
  • IdP、IAP、アップストリームの時計がずれるとトークン検証が壊れます。NTP同期を監視します。
  • oauth2-proxyのメトリクス(ポート44180)をPrometheusで収集し、認証失敗率、セッション更新失敗率にアラートを設定します。
  • IdP障害は全社アプリ障害に直結するため、Keycloakはマルチインスタンス + 26.6のzero-downtime rolling patch updateで無停止パッチを運用します。
  • ポリシー変更はコードレビューを経るIaCで管理し、「誰がどのアプリにアクセスできるのか」を定期的にレビューします。

アンチパターン

  • 署名検証なしで身元ヘッダーを信頼し、NetworkPolicyもない構成 — ヘッダー偽造一発で突破されます。
  • IAP導入後もアプリ自体のログイン経路を残しておくこと — 迂回経路は必ず除去します。
  • セッション有効期限を極端に長く(数週間)設定すること — Zero Trustの「継続的な検証」と矛盾します。
  • すべてのアプリに同一ポリシーを適用すること — 機密度に基づく差別化ポリシーがZero Trustの本質です。
  • VPNを一夜で停止するビッグバン移行 — レガシーと非HTTPトラフィックの対策なしに強行すると業務が止まります。

おわりに

Identity-Aware ProxyはZero Trustを最も早く体感できる実装です。oauth2-proxy + Keycloak + nginx auth_requestという実績あるオープンソースの組み合わせだけで、BeyondCorpの核心である「すべてのリクエストに認証と認可」を今日から始められます。重要なのはツールではなく原則です。位置ではなく身元、セッションではなくリクエスト、静的なルールではなくコンテキスト。そして2026年には、その身元の範囲がAIエージェントまで広がったことを設計の初期から織り込んでください。

次回はIAPの先、すなわちAPI Gatewayとサービスメッシュ層でのトークン検証(Istio、Envoy)を扱います。

参考資料