LESSON 40分

ストーリー

佐藤CTO
認証・認可をしっかり設計しても、ネットワークが穴だらけでは意味がない

佐藤CTOがネットワーク構成図を指しました。

佐藤CTO
ゼロトラストでは、ネットワーク上の位置を信頼しない。つまり内部ネットワークでも暗号化と検証が必要だ
あなた
マイクロセグメンテーションですね。サービスごとにネットワークを分離する
佐藤CTO
その通り。さらにWAF、VPC設計、Kubernetesのネットワークポリシーまで。多層的にネットワークを守る方法を見ていこう

マイクロセグメンテーション

従来のネットワークセグメンテーションとの違い

観点従来のセグメンテーションマイクロセグメンテーション
粒度サブネット/VLAN単位ワークロード/Pod単位
制御対象南北トラフィック(外→内)東西トラフィック(内部間)も含む
ポリシーIPアドレスベースアイデンティティ/ラベルベース
変更頻度低い(ハードウェア依存)高い(ソフトウェア定義)
スケーラビリティハードウェアに制限オートスケールに追従

Kubernetes Network Policy

# 注文サービスのネットワークポリシー
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: order-service-netpol
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: order-service
  policyTypes:
    - Ingress
    - Egress
  ingress:
    # API Gatewayからのみ受信許可
    - from:
        - podSelector:
            matchLabels:
              app: api-gateway
        - namespaceSelector:
            matchLabels:
              name: monitoring
          podSelector:
            matchLabels:
              app: prometheus
      ports:
        - protocol: TCP
          port: 8080
        - protocol: TCP
          port: 9090  # メトリクス用
  egress:
    # 注文DB(PostgreSQL)への接続のみ
    - to:
        - podSelector:
            matchLabels:
              app: order-db
      ports:
        - protocol: TCP
          port: 5432
    # 決済サービスへの通信
    - to:
        - podSelector:
            matchLabels:
              app: payment-service
      ports:
        - protocol: TCP
          port: 8080
    # 外部DNS
    - to:
        - namespaceSelector: {}
          podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - protocol: UDP
          port: 53
        - protocol: TCP
          port: 53
---
# デフォルト拒否ポリシー(全通信をブロック)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress

VPCアーキテクチャ設計

セキュアなVPC構成

graph TD
    subgraph VPC["VPC: 10.0.0.0/16"]
        subgraph Public["Public Subnet (10.0.1.0/24, 10.0.2.0/24)"]
            ALB["ALB/NLB"]
            NAT["NAT GW"]
            Bastion["Bastion"]
        end
        subgraph PrivateApp["Private Subnet - App (10.0.10.0/24, 10.0.11.0/24)"]
            SvcA["ECS/EKS<br/>Service A"]
            SvcB["ECS/EKS<br/>Service B"]
            SvcC["ECS/EKS<br/>Service C"]
        end
        subgraph PrivateData["Private Subnet - Data (10.0.20.0/24, 10.0.21.0/24)"]
            RDS[("RDS Primary")]
            ES[("ElasticSearch")]
            Redis[("Redis Cluster")]
        end
    end

    ALB --> SvcA
    ALB --> SvcB
    ALB --> SvcC
    SvcA --> RDS
    SvcB --> ES
    SvcC --> Redis

    classDef publicSn fill:#198754,stroke:#146c43,color:#fff
    classDef privateSn fill:#0d6efd,stroke:#0a58ca,color:#fff
    classDef dataSn fill:#f5a623,stroke:#c47d10,color:#fff

    class ALB,NAT,Bastion publicSn
    class SvcA,SvcB,SvcC privateSn
    class RDS,ES,Redis dataSn

セキュリティグループの設計

// CDKでのセキュリティグループ設計例
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as cdk from 'aws-cdk-lib';

export class SecureVpcStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string) {
    super(scope, id);

    const vpc = new ec2.Vpc(this, 'SecureVpc', {
      maxAzs: 2,
      subnetConfiguration: [
        { name: 'Public', subnetType: ec2.SubnetType.PUBLIC, cidrMask: 24 },
        { name: 'Private-App', subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS, cidrMask: 24 },
        { name: 'Private-Data', subnetType: ec2.SubnetType.PRIVATE_ISOLATED, cidrMask: 24 },
      ],
    });

    // ALBセキュリティグループ(最外層)
    const albSg = new ec2.SecurityGroup(this, 'AlbSg', {
      vpc,
      description: 'ALB - HTTPS only',
      allowAllOutbound: false,
    });
    albSg.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(443), 'HTTPS from internet');

    // アプリケーションセキュリティグループ
    const appSg = new ec2.SecurityGroup(this, 'AppSg', {
      vpc,
      description: 'App - ALB only',
      allowAllOutbound: false,
    });
    appSg.addIngressRule(albSg, ec2.Port.tcp(8080), 'From ALB only');

    // データベースセキュリティグループ(最内層)
    const dbSg = new ec2.SecurityGroup(this, 'DbSg', {
      vpc,
      description: 'DB - App only',
      allowAllOutbound: false,
    });
    dbSg.addIngressRule(appSg, ec2.Port.tcp(5432), 'PostgreSQL from App only');

    // VPCフローログの有効化(監査用)
    vpc.addFlowLog('FlowLog', {
      destination: ec2.FlowLogDestination.toCloudWatchLogs(),
      trafficType: ec2.FlowLogTrafficType.ALL,
    });
  }
}

WAF(Web Application Firewall)

WAFルールの設計

ルールカテゴリ目的設定例
レート制限DDoS / ブルートフォース防止同一IPから5分間に1000リクエスト
SQLインジェクションDB攻撃防止SQLiパターンの検出とブロック
XSSクロスサイトスクリプティング防止スクリプトタグの検出
Geo制限地域ベースのアクセス制御特定国からのアクセスをブロック
Bot管理悪意のあるボットの排除既知のBot IPリストとの照合
カスタムルールアプリ固有の保護特定パスへのアクセス制限
// AWS WAF v2 ルール定義(CDK)
import * as wafv2 from 'aws-cdk-lib/aws-wafv2';

const webAcl = new wafv2.CfnWebACL(this, 'WebAcl', {
  scope: 'REGIONAL',
  defaultAction: { allow: {} },
  visibilityConfig: {
    cloudWatchMetricsEnabled: true,
    metricName: 'WebACLMetric',
    sampledRequestsEnabled: true,
  },
  rules: [
    {
      name: 'RateLimit',
      priority: 1,
      action: { block: {} },
      statement: {
        rateBasedStatement: {
          limit: 1000,
          aggregateKeyType: 'IP',
        },
      },
      visibilityConfig: {
        cloudWatchMetricsEnabled: true,
        metricName: 'RateLimitRule',
        sampledRequestsEnabled: true,
      },
    },
    {
      name: 'AWSManagedRulesSQLi',
      priority: 2,
      overrideAction: { none: {} },
      statement: {
        managedRuleGroupStatement: {
          vendorName: 'AWS',
          name: 'AWSManagedRulesSQLiRuleSet',
        },
      },
      visibilityConfig: {
        cloudWatchMetricsEnabled: true,
        metricName: 'SQLiRule',
        sampledRequestsEnabled: true,
      },
    },
    {
      name: 'AWSManagedRulesXSS',
      priority: 3,
      overrideAction: { none: {} },
      statement: {
        managedRuleGroupStatement: {
          vendorName: 'AWS',
          name: 'AWSManagedRulesKnownBadInputsRuleSet',
        },
      },
      visibilityConfig: {
        cloudWatchMetricsEnabled: true,
        metricName: 'XSSRule',
        sampledRequestsEnabled: true,
      },
    },
    {
      name: 'LoginRateLimit',
      priority: 4,
      action: { block: {} },
      statement: {
        rateBasedStatement: {
          limit: 100,
          aggregateKeyType: 'IP',
          scopeDownStatement: {
            byteMatchStatement: {
              searchString: '/api/auth/login',
              fieldToMatch: { uriPath: {} },
              textTransformations: [{ priority: 0, type: 'LOWERCASE' }],
              positionalConstraint: 'STARTS_WITH',
            },
          },
        },
      },
      visibilityConfig: {
        cloudWatchMetricsEnabled: true,
        metricName: 'LoginRateLimit',
        sampledRequestsEnabled: true,
      },
    },
  ],
});

TLS / 証明書管理

TLS設定のベストプラクティス

項目推奨設定避けるべき設定
プロトコルTLS 1.3(最低TLS 1.2)SSL 3.0, TLS 1.0, TLS 1.1
暗号スイートAES-256-GCM, ChaCha20RC4, DES, 3DES
鍵長RSA 2048bit以上 / ECDSA 256bit以上RSA 1024bit
証明書ACM / Let’s Encrypt 自動更新手動管理、期限切れリスク
HSTSmax-age=31536000; includeSubDomainsHSTSなし
// Node.js / Express でのTLS設定
import https from 'https';
import fs from 'fs';

const tlsOptions: https.ServerOptions = {
  key: fs.readFileSync('/etc/ssl/private/server.key'),
  cert: fs.readFileSync('/etc/ssl/certs/server.crt'),
  ca: fs.readFileSync('/etc/ssl/certs/ca.crt'),

  // TLS 1.2以上のみ許可
  minVersion: 'TLSv1.2',

  // 強力な暗号スイートのみ使用
  ciphers: [
    'TLS_AES_256_GCM_SHA384',
    'TLS_CHACHA20_POLY1305_SHA256',
    'TLS_AES_128_GCM_SHA256',
    'ECDHE-RSA-AES256-GCM-SHA384',
    'ECDHE-RSA-AES128-GCM-SHA256',
  ].join(':'),

  // サーバー側の暗号スイート優先順位を使用
  honorCipherOrder: true,
};

const server = https.createServer(tlsOptions, app);

DNS セキュリティ

対策説明実装方法
DNSSECDNS応答の改ざん防止Route 53 DNSSEC signing
DNS over HTTPS (DoH)DNS通信の暗号化CloudflareのDNS (1.1.1.1)
Split-horizon DNS内部/外部で異なるDNS応答Route 53 Private Hosted Zone
DNS Firewall悪意のあるドメインへのアクセス防止Route 53 Resolver DNS Firewall

まとめ

ポイント内容
マイクロセグメンテーションワークロード単位でネットワークを分離、東西トラフィックも制御
K8s Network PolicyPod単位のIngress/Egressルール、デフォルト拒否が基本
VPC設計Public/Private/Isolated の3層、セキュリティグループで最小権限
WAFレート制限、SQLi/XSS防止、マネージドルールの活用
TLSTLS 1.3推奨、証明書の自動更新、HSTSの設定

チェックリスト

  • マイクロセグメンテーションの概念と従来のセグメンテーションとの違いを説明できる
  • Kubernetes NetworkPolicy を記述できる
  • セキュアなVPC構成(3層アーキテクチャ)を設計できる
  • WAFルールの設計と実装方法を理解した
  • TLSのベストプラクティスを適用できる

次のステップへ

次は「データ保護」を学びます。暗号化(at rest / in transit)、KMS/Vault、PII保護、GDPRなど、データ中心のセキュリティを身につけましょう。


推定読了時間: 40分