Zero Trust Architecture を社内システムに実装する5ステップ

本記事では、Zero Trust Architectureを実務レベルで社内システムに導入するための具体的な実装手順を解説します。 認証・認可の設計パターン、実装時のハマりポイント、段階的な導入戦略を含めて、すぐに組織に適用できる知識を習得できます。

Zero Trust Architectureとは何か

Zero Trust Architecture(ゼロトラスト・アーキテクチャ)は、従来の「社内ネットワークは安全である」という前提を否定する新しいセキュリティモデルです。 社内・社外を問わず、すべてのアクセスに対して明示的な認証・認可を要求し、継続的に信頼度を検証するアプローチです。

筆者の経験上、多くの企業は境界型セキュリティ(ファイアウォール+VPN)に依存してきましたが、リモートワークの浸透や巧妙なフィッシング攻撃の増加に伴い、このモデルは時代遅れになっています。 Zero Trustは「信頼しない、検証する」というシンプルだが強力な原則に基づいています。

Zero Trustの7つのコア原則

  • すべてのアクセスを認証する — ユーザー、デバイス、アプリケーション全てを検証
  • 最小権限アクセス(Least Privilege) — 必要最小限の権限のみを付与
  • デバイス整合性の検証 — アクセス前にデバイスの状態を確認
  • 継続的な監視と検証 — アクセス後も常に信頼度を監視
  • ネットワークセグメンテーション — マイクロセグメント化による侵害範囲の最小化
  • ログと可視性 — 全アクティビティを記録し分析可能にする
  • 動的なアクセス制御 — コンテキストに応じた柔軟な権限管理

flowchart TD
    A[ユーザーのアクセス要求] --> B[デバイス整合性を検証]
    B --> C{デバイスが信頼できるか?}
    C -->|No| D[アクセス拒否]
    C -->|Yes| E[ユーザーを認証]
    E --> F{認証に成功したか?}
    F -->|No| D
    F -->|Yes| G[ユーザーの権限を確認]
    G --> H{最小権限で十分か?}
    H -->|No| D
    H -->|Yes| I[リソースへのアクセス許可]
    I --> J[アクティビティを継続監視]
    J --> K{異常な振る舞いを検知?}
    K -->|Yes| L[セッションを終了]
    K -->|No| M[アクセス継続]
  

実装ステップ1:現状分析とインベントリ作成

Zero Trustの導入は、組織のシステム全体を把握することから始まります。 これなしに実装を進めると、後々大きな手戻りが発生します。

実施すべき3つの調査

  • ユーザーとアイデンティティの棚卸し — 全ユーザーアカウント、サービスアカウント、一時アカウントを列挙
  • リソース(アプリ・データ)の分類 — ビジネス重要度、データ種別ごとに分類
  • アクセスパターンの可視化 — 現在の誰が何にアクセスしているかをマップする

実務では、Active Directoryのログ、VPNアクセスログ、ファイアウォールログを3ヶ月分収集し、分析することをお勧めします。 この過程で、不正なアクセスパターンや遺漡権限も発見できます。

インベントリ管理シートのテンプレート


# Zero Trust インベントリシート(CSV形式)
リソースID,リソース名,リソースタイプ,ビジネス重要度,データ分類,現在の保護方法,必要なセグメント
APP-001,給与システム,アプリケーション,高,機密,AD+VPN,Finance_Segment
DB-002,顧客DB,データベース,高,個人情報,ファイアウォール,Customer_Segment
APP-003,社内Wiki,アプリケーション,低,内部情報,なし,General_Segment
  

実装ステップ2:Identity and Access Management(IAM)の強化

Zero Trustの最初の関門は、ユーザーが本当にそのユーザーであることを確認することです。 パスワードのみの認証では不十分です。

多要素認証(MFA)の導入

MFAは3つのタイプに分類されます:

  • 何かを知っている — パスワード、セキュリティ質問
  • 何かを持っている — スマートフォン、セキュリティキー
  • 何かである — 生体認証、顔認証

筆者の経験上、組織全体への導入を考えると、スマートフォンのOTP(ワンタイムパスワード)アプリとセキュリティキーの組み合わせが最適です。 セキュリティキーはフィッシングにも強い(U2F/FIDO2プロトコルを使用)ため、特に管理者層には必須にすることをお勧めします。

Azure AD / Entra ID での MFA 設定例


# Azure Entra ID で条件付きアクセスポリシーを設定(PowerShell)

# 多要素認証が必須のポリシー
$policy = @{
    DisplayName = "Require MFA for all users"
    State = "Enabled"
    Conditions = @{
        Users = @{
            IncludeUsers = "All"
        }
        Applications = @{
            IncludeApplications = "All"
        }
    }
    GrantControls = @{
        Operator = "AND"
        BuiltInControls = @("mfa")
    }
}

# ポリシーを作成
New-AzureADMSConditionalAccessPolicy -PolicyBody $policy

# 検証: 全ユーザーがMFAを要求されるようになる
  

サービスアカウント管理の問題とその対策

多くの企業が見落とすのは、サービスアカウント(アプリケーション間連携に使うアカウント)のセキュリティです。 ハードコードされたパスワードや、長年変更されていない認証情報が放置されていることがあります。

Zero Trust実装時には、以下の対策を必須にしてください:

  • Secrets Manager の導入 — AWS Secrets Manager、Azure Key Vault、HashiCorp Vaultなどで認証情報を一元管理
  • 短寿命トークンの採用 — OAuth 2.0のアクセストークン、JWTなどで有効期限を短縮
  • API キーローテーション — 定期的にキーを変更する自動化

AWS Secrets Manager での API キー自動ローテーション例


# CloudFormation テンプレート (YAML)
# API キーを30日ごとにローテーション

AWSTemplateFormatVersion: '2010-09-09'
Resources:
  MyAppSecret:
    Type: AWS::SecretsManager::Secret
    Properties:
      Name: my-app/api-key
      SecretString: !Sub |
        {
          "api_key": "sk-1234567890abcdef"
        }
      RotationRules:
        AutomaticallyAfterDays: 30

  # ローテーション用Lambda関数
  RotationLambda:
    Type: AWS::Lambda::Function
    Properties:
      Runtime: python3.12
      Handler: index.lambda_handler
      Code:
        ZipFile: |
          import boto3
          import json
          
          client = boto3.client('secretsmanager')
          
          def lambda_handler(event, context):
              # 既存のシークレットを取得
              secret_response = client.get_secret_value(
                  SecretId=event['SecretId']
              )
              secret = json.loads(secret_response['SecretString'])
              
              # 新しいAPI キーを生成
              # (実装例:外部APIを呼び出して新キーを生成)
              new_api_key = generate_new_api_key()
              
              secret['api_key'] = new_api_key
              
              # 新しいシークレットをPut
              client.put_secret_value(
                  SecretId=event['SecretId'],
                  SecretString=json.dumps(secret)
              )
              
              return {'statusCode': 200}
  

実装ステップ3:デバイス整合性検証の仕組みづくり

ユーザーが本人であっても、使用しているデバイスが危険な状態では意味がありません。 Zero Trust では、アクセス前にデバイスの整合性を確認します。

検証すべきデバイス属性

  • OSバージョン — 最新のセキュリティパッチが当たっているか
  • ファイアウォール有効化 — Windows Defender/macOS ファイアウォール
  • ディスク暗号化 — BitLocker, FileVault 2など
  • アンチマルウェア — 定義ファイルが最新か
  • デバイス登録状態 — MDM(Mobile Device Management)に登録されているか
  • VPN 接続状態 — 認可されたネットワークのみからのアクセスか

Microsoft Intune での デバイスコンプライアンスポリシー設定例


# Intune デバイスコンプライアンスポリシー (JSON)
{
  "displayName": "Zero Trust Device Compliance",
  "description": "Corporate devices must meet security standards",
  "osMinimumVersion": "10.0.22621",  # Windows 11 22H2以上
  "osMaximumVersion": null,
  "passwordRequired": true,
  "passwordMinimumLength": 14,
  "passwordRequiredType": "complex",
  "passwordPreviousPasswordBlockCount": 24,  # 過去24回のパスワード変更を禁止
  "passwordExpirationDays": 90,
  "storageRequireEncryption": true,
  "requireHealthyDeviceReport": true,  # Defender ATP経由で常に整合性を確認
  "securityBlockJailbrokenDevices": true,
  "deviceThreatProtectionEnabled": true,
  "deviceThreatProtectionRequiredComplianceLevel": "high"
}
  

このポリシーを適用したデバイスが基準を満たさない場合、Conditional Access ポリシーによってアクセスが制限されます。

実装ステップ4:マイクロセグメンテーションの設計と実装

従来のネットワークセグメンテーション(部門ごと、オフィスごと)では不十分です。 Zero Trust では、ユーザー・デバイス・アプリケーション単位で細粒度のアクセス制御を行います。

マイクロセグメント化の3段階アプローチ

段階1: アプリケーション層のセグメント化

各アプリケーションに対して、以下のルールを定義します:


# セグメント定義例(YAML形式)
segments:
  - name: "PayrollApp_Segment"
    applications:
      - payroll-frontend
      - payroll-api
      - payroll-db
    allowed_users:
      - group: "Finance Team"
      - group: "HR Team"
      - group: "Payroll Administrators"
    device_requirements:
      - os_type: "Windows"
        min_version: "10.0.22621"
      - encryption: "required"
    network_policies:
      - source_location: ["Office_Tokyo", "Office_Singapore"]
      - time_restriction: "business_hours"
      - risk_level_max: "medium"

  - name: "GeneralApp_Segment"
    applications:
      - internal-wiki
      - communication-tools
      - time-tracking
    allowed_users:
      - group: "All Employees"
    device_requirements:
      - encryption: "preferred"
    network_policies:
      - source_location: ["Any"]
      - time_restriction: "none"
  

段階2: ネットワークレベルの実装(Zero Trust Network Access)

クラウドネイティブ環境では、以下のツールを使用してマイクロセグメンテーションを実装します:

  • BeyondCorp (Google) — アイデンティティベースのアクセス制御
  • Cloudflare Zero Trust (旧Cloudflare Access) — ゼロトラストネットワークプラットフォーム
  • Palo Alto Networks Prisma Access — クラウドベースのセキュアアクセス
  • AWS VPC Lattice — AWS環境内でのマイクロセグメント化

Cloudflare Zero Trust での セグメント制御例


# Cloudflare Access ポリシー(JSON)
{
  "name": "Payroll System Access Policy",
  "description": "Only Finance team on compliant devices can access payroll",
  "decision": "allow",
  "include": [
    {
      "email": {
        "domain": ["company.com"]
      }
    }
  ],
  "require": [
    {
      "group": ["Finance Team"]
    },
    {
      "device_posture": {
        "compliance_os": "windows",
        "compliance_status": "compliant"
      }
    },
    {
      "geo": {
        "country": ["JP", "SG"]
      }
    }
  ],
  "exclude": [
    {
      "login_method": ["saml"]
    }
  ],
  "session_duration": "12h"
}
  

段階3: アプリケーション層でのアクセス制御

さらに細粒度の制御のため、アプリケーション内でも ABAC(Attribute-Based Access Control)を実装します。


# Node.js + Express での ABAC 実装例

const express = require('express');
const jwt = require('jsonwebtoken');

const app = express();

// ミドルウェア: トークンとデバイス属性を検証
function zeroTrustMiddleware(requiredAttributes) {
  return (req, res, next) => {
    const token = req.headers.authorization?.split(' ')[1];
    
    if (!token) {
      return res.status(401).json({ error: 'Missing token' });
    }

    try {
      // トークンを検証
      const decoded = jwt.verify(token, process.env.JWT_SECRET);
      
      // ユーザー属性を取得
      const userAttributes = {
        groups: decoded.groups,
        department: decoded.department,
        location: decoded.location,
        device_id: req.headers['x-device-id'],
        device_compliance: req.headers['x-device-compliance'] === 'true'
      };

      // 必要な属性をチェック
      const hasAccess = requiredAttributes.every(attr => {
        if (attr.type === 'group') {
          return userAttributes.groups.includes(attr.value);
        }
        if (attr.type === 'department') {
          return userAttributes.department === attr.value;
        }
        if (attr.type === 'device_compliance') {
          return userAttributes.device_compliance === true;
        }
        return false;
      });

      if (!hasAccess) {
        return res.status(403).json({ error: 'Insufficient privileges' });
      }

      // ユーザー情報をリクエストに付加
      req.user = { ...decoded, ...userAttributes };
      next();
    } catch (err) {
      return res.status(401).json({ error: 'Invalid token' });
    }
  };
}

// 給与情報エンドポイント(Finance チームのみ、コンプライアントデバイスのみ)
app.get('/api/payroll/salaries', 
  zeroTrustMiddleware([
    { type: 'group', value: 'Finance Team' },
    { type: 'device_compliance', value: true }
  ]),
  (req, res) => {
    res.json({ data: 'Sensitive payroll data' });
  }
);

// 営業情報エンドポイント(Sales チームのみ)
app.get('/api/sales/pipeline',
  zeroTrustMiddleware([
    { type: 'group', value: 'Sales Team' }
  ]),
  (req, res) => {
    res.json({ data: 'Sales pipeline' });
  }
);

app.listen(3000);
  

graph TD
    A[ユーザーがAPIリクエスト] --> B[トークンを検証]
    B --> C{トークン有効?}
    C -->|No| D[401 Unauthorized]
    C -->|Yes| E[ユーザー属性を抽出]
    E --> F[required_attributes と比較]
    F --> G{全ての属性が一致?}
    G -->|No| H[403 Forbidden]
    G -->|Yes| I{デバイスコンプライアンスOK?}
    I -->|No| H
    I -->|Yes| J[リソースへのアクセス許可]
    J --> K[リクエストをログに記録]
  

実装ステップ5:監視・ログ・インシデント対応の自動化

アクセス制御を厳しくしても、異常を検知できなければ意味がありません。 Zero Trust では「継続的な監視」が重要です。

ログ収集の必須項目

  • ユーザーID、デバイスID、IPアドレス、タイムスタンプ
  • 認証成功/失敗の理由
  • デバイスコンプライアンス状態
  • アクセスしたリソース、操作内容
  • リスクスコア(異常度合い)

SIEM(Security Information and Event Management)との統合

膨大なログから脅威を自動検知するため、SIEM を導入します:

  • Microsoft Sentinel (Azure 環境)
  • Splunk Enterprise Security
  • Elasticsearch + Kibana (オンプレミス)

Azure Sentinel での 異常検知ルール設定例


// Kusto Query Language (KQL) での異常検知

// ルール1: 短時間に複数のリソースへのアクセス失敗
SigninLogs
| where ResultType != "0"  // 失敗したサインイン
| summarize 
    FailureCount = count(),
    UniqueResources = dcount(ResourceDisplayName),
    TimeWindow = max(TimeGenerated) - min(TimeGenerated)
    by UserId, DeviceId
| where FailureCount >= 5 and UniqueResources >= 3
| where TimeWindow <= 10m  // 10分以内

// ルール2: 通常と異なるロケーションからのアクセス
let baseline = SigninLogs
  | where TimeGenerated between(ago(30d) .. ago(1d))
  | summarize typical_locations = make_set(Location) by UserId;

SigninLogs
| where TimeGenerated >= ago(1d)
| join kind=leftanti (baseline) on UserId
| where Location !in (typical_locations)
| project UserId, Location, TimeGenerated, RiskLevel

// ルール3: 営業時間外のアクセス(管理者層を除く)
SigninLogs
| where UserPrincipalName !contains "admin"
| where hour(TimeGenerated) !between (8..18)
| where dayofweek(TimeGenerated) !in (6, 7)  // 土日以外
| where ResultType == "0"  // 成功したサインイン
| summarize AccessCount = count() by UserId, hour(TimeGenerated)
| where AccessCount >= 3
  

インシデント対応の自動化

脅威検知後の対応を自動化することで、平均対応時間を大幅に削減できます。


# Python + Azure Logic Apps での自動化例

import azure.functions as func
import json
from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient
from msgraph.core import GraphClient
from requests_oauthlib import OAuth2Session

def incident_auto_response(incident):
    """
    脅威インシデントを検知した場合の自動対応
    """
    
    risk_score = incident.get('risk_score', 0)
    user_id = incident.get('user_id')
    device_id = incident.get('device_id')
    
    # リスクレベルに基づいた自動対応
    if risk_score >= 80:  # 高リスク
        # アクション1: ユーザーセッションを終了
        revoke_user_sessions(user_id)
        
        # アクション2: デバイスのアクセスを無効化
        disable_device(device_id)
        
        # アクション3: MFA再認証を強制
        trigger_mfa_refresh(user_id)
        
        # アクション4: セキュリティチームにアラート
        send_alert_to_security_team(
            severity="critical",
            user=user_id,
            device=device_id,
            reason=incident.get('reason')
        )
        
    elif risk_score >= 50:  # 中リスク
        # アクション: 追加認証を要求
        trigger_step_up_authentication(user_id)
        
        # ネットワークセグメントを制限
        restrict_network_segment(user_id, "restricted_segment")
        
    elif risk_score >= 20:  # 低リスク
        # アクション: 監視を強化
        increase_monitoring(user_id)
        
    return {
        'statusCode': 200,
        'response_taken': True,
        'risk_score': risk_score
    }

def revoke_user_sessions(user_id):
    """すべてのユーザーセッションを無効化"""
    credential = DefaultAzureCredential()
    graph_client = GraphClient(credential=credential)
    
    # Azure AD の Sign-out sessions エンドポイント
    graph_client.post(
        f"/users/{user_id}/invalidateAllRefreshTokens"
    )

def disable_device(device_id):
    """デバイスを無効化(Intune経由)"""
    # デバイスの管理状態をDisabledに変更
    pass

def send_alert_to_security_team(severity, user, device, reason):
    """セキュリティチームにアラートを送信(Teams/Email)"""
    pass
  

実装時のハマりポイントと対策

ハマりポイント1: レガシーシステムの互換性問題

多くの企業が保有する10年以上前のシステムは、Zero Trust の認証機構(OIDC, SAML)に対応していません。 これらへのアクセスをどのように管理するかが課題です。

対策:以下の段階的アプローチをお勧めします:

  1. レガシーシステム用に「デバイス信頼ゲートウェイ」を配置
  2. ゲートウェイ経由でのアクセスのみを許可
  3. ゲートウェイで認証・デバイスコンプライアンス検証を実施
  4. 3-5年のロードマップでシステム刷新を計画

ハマりポイント2: 中断のないユーザー体験とセキュリティのバランス

Zero Trust が厳しすぎると、正規ユーザーも頻繁にブロックされ、生産性が低下します。 筆者の経験上、導入初期に「何でもブロック」すると、ユーザーから反発を受けます。

対策:段階的な展開(フェーズドロールアウト)を実施してください。


# Zero Trust 段階的展開ロードマップ

フェーズ1(1-2ヶ月): パイロット
  対象: IT部門、セキュリティチーム(50人以下)
  施策: MFA必須、デバイスコンプライアンス検証、ログ監視
  ポリシー: オブザーバーモード(ブロックなし、ログのみ記録)
  目標: 問題点を特定し、ユーザーフィードバックを収集

フェーズ2(2-3ヶ月): 部門単位での展開
  対象: Finance, HR, Legal (200-300人)
  施策: フェーズ1 + マイクロセグメント化、API認可制御
  ポリシー: エンフォースモード(ポリシー違反時はブロック)
  目標: 実務運用での課題を解決、オペレーション定着

フェーズ3(3-6ヶ月): 全社展開
  対象: 全従業員
  施策: フェーズ2 + インシデント自動対応
  ポリシー: 完全エンフォース
  目
    
K
AWS・Python・生成AIを専門とするソフトウェアエンジニア。AI・クラウド・開発ワークフローの実践ガイドを執筆しています。詳しく見る →