GKE ノード上で Linux の auditd ログを有効にする


このページでは、Containrer-Optimized OS を実行している Google Kubernetes Engine ノードで、詳細なオペレーティング システム監査ログを有効にする方法を説明します。このページでは、Cloud Logging にログを送信するように fluent-bit の Logging エージェントを構成する方法についても説明します。GKE Autopilot クラスタでは、ノードと基盤となる仮想マシン(VM)が Google によって管理されるため、Linux Auditd ロギングの有効化はサポートされていません。

オペレーティング システムの監査ロギングは、Cloud Audit LogsKubernetes 監査ログとは異なります。

概要

ノードのオペレーティング システムログには、エラー メッセージ、ログイン試行、バイナリ実行など、クラスタとワークロードの状態に関する重要な情報が記録されます。この情報を活用して、問題のデバッグやセキュリティ インシデントの調査を行うことができます。

クラスタ内の各ノードからログを収集するには、DaemonSet のスケジュールを設定できるクラスタノードごとに DaemonSet を使用して Pod を 1 つずつ実行します。この Pod によって、ホスト上に auditd ロギング デーモンが構成され、ログを Logging などのログ取り込みサービスに送信するように Logging エージェントが構成されます。

定義上、監査はイベントの後に実行されるため、ポストモーテムなセキュリティ対策となります。クラスタでフォレンジックを実行する際、多くの場合監査ログだけでは不十分です。全体的なセキュリティ戦略の一環として auditd ログの最適な使用方法を検討してください。

制限事項

このページで説明するロギング メカニズムは、GKE Standard クラスタで Container-Optimized OS を実行するノードでのみ動作します。

ロギング DaemonSet の動作の仕組み

このセクションでは、サンプルのロギング DaemonSet が動作する仕組みを説明します。この仕組みを理解することで、DaemonSet を自由に構成できるようになります。後続のセクションでは、DaemonSet をデプロイする方法について説明します。

サンプルのマニフェストで、DaemonSet と ConfigMap およびそれらを格納する名前空間のインスタンスを定義します。

この DaemonSet では、クラスタ内の各ノードにポッドがデプロイされます。この Pod には 2 つのコンテナが格納されます。1 つ目のコンテナは、Container-Optimized OS ノードで利用可能な cloud-audit-setup systemd サービスを起動する init コンテナです。2 つ目のコンテナは cos-auditd-fluent-bit で、fluent-bit のインスタンスが含まれています。これは、ノード ジャーナルから Linux の監査ログを収集して、Cloud Logging にエクスポートするように構成されています。

このサンプルのロギング DaemonSet ログでは、次のイベントがログに記録されます。

  • auditd システム構成の変更
  • AppArmor 権限チェック
  • execve()socket()setsockopt()mmap() の実行
  • ネットワーク接続
  • ユーザーのログイン
  • SSH セッションとその他すべての TTY(kubectl exec -t セッションを含む)

ロギング DaemonSet の構成

ロギング DaemonSet の構成は、cos-auditd-fluent-bit-config という ConfigMap を使って行います。提供されている例では、監査ログは Logging に送信されますが、他の宛先にログが送信されるように構成できます。

auditd は、デフォルトのロギング構成よりもかなり多くのログを生成することがあり、システム リソースを消費します。そのため、追加費用が発生する場合があります。フィルタを設定すると、ロギングのボリュームを管理できます。

ロギング DaemonSet のデプロイ

  1. 既存のクラスタを使用することも、新しいクラスタを作成することもできます。

  2. サンプルのマニフェストをダウンロードします。

    curl https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-node-tools/master/os-audit/cos-auditd-logging.yaml > cos-auditd-logging.yaml
    
  3. サンプルのマニフェストを必要に応じて編集します。DaemonSet の仕組みについては、前のセクションをご覧ください。

  4. 共通変数を初期化します。

    export CLUSTER_NAME=CLUSTER_NAME
    export CLUSTER_LOCATION=COMPUTE_REGION
    

    次のように置き換えます。

    • CLUSTER_NAME: クラスタの名前。
    • COMPUTE_REGION: クラスタの Compute Engine のリージョン。ゾーンクラスタの場合は、代わりにゾーンを使用します。
  5. ロギング Namespace、DaemonSet と ConfigMap をデプロイします。

    envsubst '$CLUSTER_NAME,$CLUSTER_LOCATION' < cos-auditd-logging.yaml \
    | kubectl apply -f -
    
  6. ロギング Pod が起動したことを確認します。マニフェストで別の Namespace を定義した場合は、cos-auditd を使用している名前空間の名前に置き換えます。

    kubectl get pods --namespace=cos-auditd
    

    Pod が実行されている場合、出力は次のようになります。

    NAME                                             READY   STATUS    RESTARTS   AGE
    cos-auditd-logging-g5sbq                         1/1     Running   0          27s
    cos-auditd-logging-l5p8m                         1/1     Running   0          27s
    cos-auditd-logging-tgwz6                         1/1     Running   0          27s
    

    クラスタのノードごとに Pod が 1 つデプロイされます。この例のクラスタには 3 つのノードが存在します。

  7. これで、Logging で監査ログにアクセスできるようになりました。ログ エクスプローラで、次のクエリを使用して結果をフィルタリングします。

    LOG_ID("linux-auditd")
    resource.labels.cluster_name = "CLUSTER_NAME"
    resource.labels.location = "COMPUTE_REGION"
    

    また、gcloud CLI を使用することもできます(結果セットが非常に大きくなる可能性があるため、--limit を使用します)。

    gcloud logging read --limit=100 "LOG_ID("linux-auditd") AND resource.labels.cluster_name = "${CLUSTER_NAME}" AND resource.labels.location = "${CLUSTER_LOCATION}""
    

ログのエクスポート

サポートされている宛先にログを転送する方法については、シンクの構成と管理をご覧ください。

クリーンアップ

auditd によるロギングを無効にするには、ロギング DaemonSet を削除してノードを再起動します。監査の構成は、有効になると同時にロックされます。この構成を変更するには、ノードの再作成が必要になります。

  1. DaemonSet、ConfigMap、およびそれらの名前空間をクラスタから削除します。

    kubectl delete -f cos-auditd-logging.yaml
    
  2. クラスタのノードを再起動します。まず、ノードが所属するインスタンス グループを取得します。

    instance_group=$(gcloud compute instance-groups managed list \
                        --format="value(name)" \
                        --filter=${CLUSTER_NAME})
    

    次に、インスタンス自体を取得します。

    instances=$(gcloud compute instance-groups managed list-instances ${instance_group} \
                   --format="csv(instance)[no-heading][terminator=',']")
    

    最後に、インスタンスを再作成します。

    gcloud compute instance-groups managed recreate-instances ${instance_group} \
       --instances=${instances}
    

次のステップ