DoS 攻撃とは?

SHARE:

サービス拒否(DoS: Denial-of-Serviceとは、マシンやネットワークを遮断して対象のユーザーがアクセスできないようにすることを目的とした攻撃です。そのため DoS 攻撃では、ターゲットに大量のトラフィックや情報を送信してクラッシュを引き起こします。金銭的な利益が目的でこの手の活動が行われることはそう多くありません。DoS 攻撃をしかける攻撃者は雇われていたり、報酬を受け取っていたりする場合はありますが、その動機は単に Web アプリケーションやサービスを利用する必要がある正当なユーザーを妨害することです。

この記事では、攻撃が Kubernetes に与える影響、セキュリティ侵害の兆候の見極め方、攻撃を防止するためのクラウドネイティブツールなど、DoS 攻撃について知っておくべき情報をくまなく説明します。

Kubernetes における DoS 攻撃

DoS Kubernetes クラスターの外の問題、つまり、外部の IP アドレスが脅威の発生元であると考えられがちですが、脆弱性があると組織内部が発生元となることもあります。実は、すべての DoS 攻撃が意図的なものとは限りません。攻撃の中には、誤ったデプロイ構成により API に大量の不正なリクエストが送信され、それが原因でノードの負荷が高くなる場合があります。

Kubernetes では DoS 攻撃に一般とは少々異なる方法で対処します。たとえば、AWS などのクラウドプラットフォームでオートスケーリングのサービスを実行しているとしましょう。このサービスでは、トラフィックの増加に合わせてリソースが追加されます。つまり、予期しないトラフィックが大量に発生すると自動的にスケールアップされます。これが、Kubernetes がコンテナワークロードのオーケストレータとして選択される主な理由の 1 つであり、技術的には DoS 攻撃に対する保護の強化につながります。一方で、この設計には固有の問題があります。

容量が十分にあれば、トラフィックの急増に応じてワークロードが拡張されます。しかし、オンプレミスのデータセンターでクラウドネイティブのワークロードを運用している場合など、容量に余裕がない場合には、システムが最大負荷に達してクラッシュすることになります。

クラスターをオートスケールするようなサービスを利用していれば、容量が上限に近づいたら新しいノードをプロビジョニングできます。すると、ここでまた別の問題が発生します。アプリケーションを運用するだけで、不要なリソースに対して料金を支払わなくてはなりません。新しいノードを稼働させるプロセスが原因で、AWS に対する全体的な支出が増加することになります。そのため、AWS の料金が急増してコントロールできなくなることを防ぐために、ハードの制限と強制ポリシーを適用することが重要です。

Kubernetes DoS 攻撃の兆候を見極める方法

まず、Kubernetes Container Network InterfaceCNI)プラグインから始めるとよいでしょう。CNI プラグインには、Project CalicoCiliumWeavenet など種類がいくつかあります。CNI プラグインは、コンテナ化されたワークロードからのすべての Web リクエスト(North-South または East-West トラフィック)を処理する役割を担っています。CNI プラグインがなければ、Kubernetes ではネットワーク接続を確立できません。

このアクティビティは、通常 IPTables で確認できます。または、eBPF を使用してトラフィックリクエストを追跡できます。ただし、トラフィックの量をより正確に把握するには、Prometheus Grafana などイベントを集約するツールにデータを送信して、関連するレポートを作成する必要があります。他にも、Sysdig Secure を使用すれば、Kubernetes API サーバーが大量のインバウンドトラフィックを受信しているかどうかを把握できます。また、受信したデータと、コンテナ名や特定のしきい値の超過などのメタデータを関連付けることも可能です。

Pod outbound traffic

Kubernetes 環境で DoS 攻撃に備えるには

1. ワークロードのレート制限を構成する
従来、Kubernetes 環境では、レート制限はクラスターに対する外部ユーザーからのリクエスト数を制限するためにイングレス階層に適用されます。これに加え、クラスター内で実行されるマイクロサービスアプリのワークロード間にレート制限を適用することも検討する必要があります。また、該当する場合はサービスメッシュやイングレスコントローラに対してもレート制限を構成して、DoS 攻撃の原因となるワークロード間の接続の異常な急増を防ぐことができます。この対処法により、クラスター内の 1 つのノードで帯域幅が過剰に消費されるのを防ぐことができます。

レート制限については、Traefik Proxy で制限を全体的に定義できます:

apiVersion: traefik.containo.us/v1alpha1
    kind: Middleware
    metadata:
      name: prod-rate-limit
    spec:
      rateLimit:
        average: 30
        burst: 50
    Code language: JavaScript (javascript)

2. 負荷テストを実行して、アプリケーションがどの程度適切に拡張されているかを把握する ステージングクラスターにアプリケーションをデプロイして、トラフィック処理することをお勧めします。分散型 DoSDDoS)攻撃の場合、テストは若干難しくなります。この攻撃では、多数の異なる IP アドレスから一斉にトラフィックが送信されますが、これに対処できるサービスはほとんどありません。 Speedscale を使用して呼び出しをキャプチャし、接続時にやり取りされる情報を把握する必要があります。Speedscale をお持ちでない場合は、こちらから無料のトライアルに登録し、speedctl をダウンロードしてください。

sh -c "$(curl -Lfs https://downloads.speedscale.com/speedctl/install)"Code language: JavaScript (javascript)
3. Calico または Cilium NetworkPolicy フレームワークの eXpress Data PathXDP)を活用する

XDP を使用すると、パケット処理パイプラインの初期段階で潜在的に不正なパケットを破棄できます。こうすることで、DoS/DDoS から保護できると考えられます。カーネル NIC(ネットワークインターフェイスカード)ハードウェアとドライバは、XDP のオフロードオプションをサポートします。XDP はソフトウェアスタックの下位層でベアメタルのパケットを処理することで、プログラム性を損なうことなく、最適な処理速度を実現します。

apiVersion: projectcalico.org/v3
    kind: GlobalNetworkPolicy
    metadata:
      name: dos-mitigation
    spec:
      selector: apply-dos-mitigation == 'true'
      doNotTrack: true
      applyOnForward: true
      types:
      - Ingress
      ingress:
      - action: Deny
        source:
          selector: dos-deny-list == 'true'
Code language: JavaScript (javascript)

さらに、ネットワークポリシーを使用して、Pod 間の通信を制限できます。攻撃者が特定の Pod のアクセス権を入手した場合でも、その Pod が他のクラスターから切り離されていれば、攻撃者はラテラルムーブメントを実行できません。

外部の脅威

外部公開アプリを使用している場合は、第三者がアプリケーションのロジックを悪用する手段を見つける可能性が高くなります。アプリケーションをエアギャップし、インターネットに公開していない場合でも、クラウドのネットワークポリシー構成が不適切であれば、内部にまったく新しい攻撃ベクトルが突如として発生する可能性があります。

Kubernetes には構成ミスのあるコードを修正する機能はありませんが、クラウドネイティブの技術を学ぶことで、アプリケーションのセキュリティ上の脆弱性による損害を抑えることができます。次に示す対策をとることで、セキュリティ侵害を受けた 1 つのコンポーネントから全面的な DDoS 攻撃への発展を防ぐことができます:

ネットワークポリシー

ネットワークポリシーを使用して、Pod 間の通信を制限します。攻撃者が特定の Pod のアクセス権を入手した場合でも、その Pod が他のクラスターから切り離されていれば、攻撃者はそれ以上攻撃できません。 

apiVersion: projectcalico.org/v3
    kind: GlobalNetworkPolicy
    metadata:
      name: deny-app-policy
    spec:
      namespaceSelector: has(projectcalico.org/name) && projectcalico.org/name not in {"kube-system", "calico-system", "calico-apiserver"}
      types:
      - Ingress
      - Egress
      egress:
      すべてのネームスペースで DNS Pod との通信を許可 
      - action: Allow
        protocol: UDP
        destination:
          selector: 'k8s-app == "kube-dns"'
          ports:
          - 53
Code language: JavaScript (javascript)

上記の例では、デフォルトでトラフィックを拒否する動作がシステム以外の Pod すべてに適用されます。このポリシーでは kube-dns へのアクセスも許可され、DNS ルールをすべてのポリシーで複製する必要がないため、各 Pod のポリシーをシンプルにできます。

各ワークロードのセキュリティ構成を監査する

Falco のようなツールを使用すると、ユーザーがコンテナに root でアクセスしていないこと、ユーザーが制限のあるホストネットワークへのアクセス権を持っていないこと、その他安全でない可能性がある構成が存在しないことを確認できます。


  - macro: container
    condition: container.id != host
  - macro: spawned_process
    condition: evt.type = execve and evt.dir=<
  - rule: run_shell_in_container
    desc: a shell was spawned by a non-shell program in a container. Container entrypoints are excluded.
    condition: container and proc.name = bash and spawned_process and proc.pname exists and not proc.pname in (bash, docker)
    output: "Shell spawned in a container other than entrypoint (user=%user.name container_id=%container.id container_name=%container.name shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline)"
    priority: WARNING
Code language: JavaScript (javascript)

ゼロから作成されたイメージを使用して構築する

攻撃者の主な目的は、脆弱なイメージを利用して通信することです。攻撃者は脆弱なイメージを利用してシステムコールを実行できなければ、攻撃することができません。 

パイプラインで脆弱なイメージが実行されていなければ、攻撃者はこうしたイメージを利用できません。本番環境で安全なイメージの運用を徹底する方法の 1 つが、Open Policy AgentOPA)のようなアドミッションコントローラの使用です。次の例では、「Pet」のオーナーのみが「Pet」の情報を更新できます。さらに、JSON Web TokenJWT)が付与されている従業員のみが、すでに引き取られたペットを表示できます:


package kubernetes.admission
    import future.keywords
    deny contains msg if {
        input.request.kind.kind == "Pod"
        some container in input.request.object.spec.containers
        image := container.image
        not startswith(image, "hooli.com/")
        msg := sprintf("image '%s' comes from untrusted registry", [image])
}Code language: JavaScript (javascript)

内部関係者による脅威

すでに説明したとおり、すべての脅威が組織の外で発生するわけではありません。 

単なるコードの不適切な構成についてはすでに触れましたが、クラスターへの SSH アクセス権を持ち、会社に不満を抱く従業員がデータを流出させたり、強制的にシステムを停止させたりする可能性があります。適切な統制がなされておらず、元従業員が SSH キーを使用してコントロールプレーンのノードに引き続きアクセスできるケースも考えられます。大企業であれ、IT サービスを提供する中小企業であれ、内部関係者による脅威を防止する手段を講じることは重要です。また、早い段階でセキュリティ上のベストプラクティスを構築することも大切です。そのために最適なのは、Kubernetes ロールベースのアクセス制御RBAC)を利用することです。

ロールベースのアクセス制御

内部関係者による脅威の防止に最も重要なのは、資格情報を共有しないことです。それぞれのユーザーに対して、独自の ServiceAccount Kubernetes のユーザープロファイル)を付与する必要があります。すると、RBAC を使用して Kubernetes における ServiceAccount の権限の範囲を制限できます。最悪のシナリオは、すべてのユーザーが同じ ServiceAccount 資格情報のアクセス権を使用して、クラスターを操作することです。ある従業員が退職してから組織内部で脅威が発生した場合に、誰がクラスターに対する変更を行ったのかを特定できません。また、ユーザーの権限を無効化することもできません。ユーザーの権限を無効化すると、組織全体の業務を停止することになり、チームに対して新しい ServiceAccount を構成しなければならなくなります。各ユーザーの操作を監査し、クラスター内の処理を実行したユーザーを明確にするには、ユーザーごとに権限を設定しなければなりません。 

クラスターを操作するユーザーごとに資格情報をプロビジョニングしたら、権限を最小限にするという原則に従うことが重要です。Kubernetes には、RBAC が標準搭載されており、ユーザーごとに実行できる操作を管理できます。つまり、ジョブの実行に必要なリソースへのアクセス権や操作権限を、個人単位で付与できるのです。このようにすることで、悪意のある従業員のケースだけでなく、単なるミスを防止することもできます。

Google GKE AWS EKS といった Kubernetes のマネージドサービスでは、ID およびアクセス管理(IAM)のプロファイル、Kubernetes の資格情報があらかじめ用意されている場合があります。rbac-manager のようなオープンソースプロジェクトも、RBAC の構成をシンプルにし、管理しやすくするのに役立ちます。たとえば以下のように定義すると、ネームスペース「default」の Role で、Pod への読み取りアクセス権を付与できます:


    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      namespace: default
      name: pod-reader
    rules:
    - apiGroups: [""] # "" はコア API グループを指します
      resources: ["pods"]
      verbs: ["get", "watch", "list"]
    Code language: JavaScript (javascript)

Falco を使用する場合のベストプラクティス

こうしたあらゆるオープンソースのツールを、Kubernetes での DoS 攻撃の防止に活用できますが、デジタルフォレンジック & インシデントレスポンス(DFIRのルールを必ず設定することが重要です。Falco を使用するとセキュリティ侵害の兆候を察知し、今後起こりうる DoS 攻撃の対策を講じることができます。

  • セキュリティ侵害されたワークロードからの予期しないアウトバウンド接続を検出する:
    Falco
    を使用してネットワークを監視し、Elasticsearch によるデフォルト以外のポートを使用したアウトバウンドトラフィックを検出する例を以下に示します:

  - macro: outbound
    condition: syscall.type=connect and evt.dir=< and (fd.typechar=4 or fd.typechar=6)
  - macro: elasticsearch_cluster_port
    condition: fd.sport=9300
  - rule: elasticsearch_unexpected_network_outbound
    desc: outbound network traffic from elasticsearch on a port other than the standard ports
    condition: user.name = elasticsearch and outbound and not elasticsearch_cluster_port
    output: "Outbound network traffic from Elasticsearch on unexpected port (connection=%fd.name)"
    priority: WARNING
  Code language: JavaScript (javascript)
  • 制限されたネームスペースからのアウトバウンド接続を監視する
    外部から内部ネットワーク(rfc1918)への接続を監視できます。大半の企業が日常的に行っている通信であり、次のような独自のマクロおよびルールを定義して監視できます:
  • 
    - macro: outbound_corp
        condition: >
            (((evt.type = connect and evt.dir=<) or
            (evt.type in (sendto,sendmsg) and evt.dir=< and
            fd.l4proto != tcp and fd.connected=false and fd.name_changed=true)) and
            (fd.typechar = 4 or fd.typechar = 6) and
            (fd.ip != "0.0.0.0" and fd.net != "127.0.0.0/8") and
            (evt.rawres >= 0 or evt.res = EINPROGRESS))
    - list: k8s_not_monitored
        items: ['"green"', '"blue"']
    - rule: kubernetes outbound connection
        desc: A pod in namespace attempted to connect to the outer world
        condition: outbound_corp and k8s.ns.name != "" and not k8s.ns.label.network in (k8s_not_monitored)
            output: "Outbound network traffic connection from a Pod: (pod=%k8s.pod.name namespace=%k8s.ns.name srcip=%fd.cip dstip=%fd.sip dstport=%fd.sport proto=%fd.l4proto procname=%proc.name)"
        priority: WARNING
      Code language: JavaScript (javascript)
    • アウトバウンド接続に対して信頼されたドメインと信頼されていないドメインを指定する:
      次の例では、信頼されているドメイン名(sysdig.comgithub.comgoogle.com)のリストを定義しています。この信頼されているドメイン名で名前解決できない IP アドレスにネットワーク接続すると、ポリシーが適用されます。Falco で許可/拒否するドメインなどを指定するのに便利な方法です。
    
        - list: trusted_domains
        - rule: Unexpected outbound network connection
          desc: Detect outbound connections with destinations not on allowed list
          condition: >
            outbound
            and not (fd.sip.name in (trusted_domains))
          output: Unexpected Outbound Connection
            (container=%container.name
            command=%proc.cmdline
            procpname=%proc.pname
            connection=%fd.name
            servername=%fd.sip.name
            serverip=%fd.sip
            type=%fd.type
            typechar=%fd.typechar
            fdlocal=%fd.lip
            fdremote=%fd.rip)
        priority: NOTICE
        Code language: JavaScript (javascript)

    まとめ

    クラウドネイティブツールと Kubernetes は透明性とオープンソースのプラットフォームを基盤として構築されています。この記事でご紹介した例を、DoS インシデントの原因となりかねない攻撃ベクターについて、あるいは DoS 攻撃の防止に役立つ無料のオープンソースツールを理解するのにお役立てください。

    DoS の防止に万能な方法はありません。したがって、コンテナのライフサイクルを通じてリスクを継続的に監視する必要があります。さらに、以下の対策も必要です:

    • ネットワークポリシーとして、ゼロトラストアーキテクチャを取り入れます。 
    • 脆弱性データベースを最新の状態に維持して、既知の脆弱性を検出します。
    • CI/CD パイプラインの初期段階で構成をスキャンし、環境が拡大しても、コンテナセキュリティのベストプラクティスに従い続けるようにします。

    レート制限は必須の対策です。イングレスコントローラのレート制限だけでなく、コンテナ内のリソースを制限することもできます。クラウドプロバイダにかかる過剰な支出を抑えるには、たとえば AWS アカウントで請求に関する制限とクォータを設定することが考えられます。 

    緩和対策に加えて、セキュリティ侵害の原因となるパターンや行動を特定することも重要です。Falco C2 サーバーからの既知の不正な IP アドレスへの接続、安全が保証されていない IP アドレス/FQDN への接続、アプリケーションアーキテクチャの基本設計から逸脱したポートやプロトコルを使用した接続について、アラートを生成できます。これらのテクノロジを使用するには、クラウドネイティブテクノロジを活用して DoS 攻撃を防御する方法について十分に理解しておく必要があります。