GuardDuty EKS Runtime Monitoringの導入
EKS Runtime Monitoring
3月30日、Amazon GuardDuty EKS ランタイムモニタリングの一般提供についてお知らせします。30 件以上のセキュリティの検出結果からランタイムの脅威を検出して EKS クラスターを保護できます。新しい EKS ランタイムモニタリングは、ファイルアクセス、プロセス実行、ネットワーク接続など、個々のコンテナランタイムアクティビティの可視化を追加するフルマネージド EKS アドオンを使用しています。
ランタイムモニタリングは、オペレーティングシステムレベルのイベントを監視および分析して、環境内の特定の AWS ワークロードにおける潜在的な脅威を検出するのに役立ちます。ランタイムモニタリングは、以前は Amazon Elastic Kubernetes Service (Amazon EKS) リソースでのみ利用可能でしたが、GuardDuty は現在、ランタイムモニタリング機能を拡張して、Amazon Elastic Container Service (Amazon ECS) および Amazon Elastic Compute Cloud (Amazon EC2) リソースの脅威検出を提供しています。
大ざっぱにいえばEKS Audit Log Monitoringがコントロールプレーン担当で、(EKS) Runtime Monitoringがデータプレーン担当になる。
料金
vCPUの数に対して課金されるほか、VPCエンドポイントを用意することになるため、その料金が別途かかる。またDaemonSetをデプロイするためEC2の料金が増える可能性がある。
エージェントコンテナのresourcesはこんなもん
使用開始にあたって決めること
GuardDutyにDaemonSetの管理を任せるか、自分で管理するかを選択する。任せると、EKSアドオンの作成(と更新)、VPCエンドポイントの作成が自動的に行われる。
※任せる設定でEKS Runtime Monitoringを利用開始後、利用停止(無効化した)場合、EKSアドオンもVPCエンドポイントも自動的に削除される(無意味にお金がかかり続けることはない)
任せない場合EKSアドオンの作成(と更新)、VPCエンドポイントの作成を自分で行う。
EKSクラスターとアドオンはTerraformでIaC化されている環境のため、今回は自分で管理することにした。
有効化
AWS Organizationsを利用しているため、GuardDuty管理アカウントからメンバーアカウントに対して有効化する例を載せる。
GuardDuty > Accounts
自分で管理することにしたためmanage agent automatically
は有効化しない。
※現時点ではTerraformプロバイダーがメンバーアカウントのdetector管理に対応していないため手動でコンソールから有効化している
EKSアドオンとVPCエンドポイントの作成
Terraformのサンプル
data "aws_caller_identity" "caller" {}
data "aws_region" "current" {}
resource "aws_vpc_endpoint" "eks_runtime_monitoring" {
vpc_id = var.vpc_id
service_name = "com.amazonaws.${data.aws_region.current.name}.guardduty-data"
vpc_endpoint_type = "Interface"
subnet_ids = var.subnet_ids
security_group_ids = var.security_group_ids
private_dns_enabled = true
policy = data.aws_iam_policy_document.eks_runtime_monitoring.json
}
data "aws_iam_policy_document" "eks_runtime_monitoring" {
statement {
actions = ["*"]
resources = ["*"]
effect = "Allow"
principals {
type = "*"
identifiers = ["*"]
}
}
statement {
actions = ["*"]
resources = ["*"]
effect = "Deny"
principals {
type = "*"
identifiers = ["*"]
}
condition {
test = "StringNotEquals"
variable = "aws:PrincipalAccount"
values = [data.aws_caller_identity.caller.account_id]
}
}
}
VPCエンドポイントに付与するポリシーやセキュリティグループの要件は以下を参照
resource "aws_eks_addon" "guardduty_agent" {
cluster_name = var.cluster_name
addon_name = "aws-guardduty-agent"
addon_version = "v1.2.0-eksbuild.1"
resolve_conflicts = "OVERWRITE"
}
EKS Runtime Monitoringを有効化のうえアドオンを作成するとこうなる。
amazon-guardduty
Namespaceにaws-guardduty-agent
DaemonSetができている。
PriorityClassも作成され、それなりの優先度を持っているが、description
とpreemptionPolicy
にある通り自分より低優先度のPodを押しのけることはしない。
※EKS Runtime Monitoringの有効化前にアドオンを作成するとこうなる(EKS Runtime Monitoringがまだ使えないというだけでクラスターの運用に支障はない)
検出結果(一例)
datadog-agentのprocess-agentコンテナ(およびagentコンテナ)に対してPrivilegeEscalation:Runtime/DockerSocketAccessedが検出された。
調査
/var/run/docker.sock
と書いてあるが、その時点でクラスターではKubernetes 1.26が実行されていたため、すでにcontainerdに移行済みだった。
docker.sockの謎
Session Managerでノードに入ってみると/var/run/docker.sock
は存在したがソケットではなくディレクトリだった。
中身はない。
このディレクトリが何者なのかの疑問は解消できなかった。このissueが関係あるかもしれない。
なんにしろソケットの存在確認(checkSocketExists
)のときに失敗するため、通信には使われないはず。
Datadogのコンテナの/host/var/run
にはノードの/var/run
がマウントされている。
ノードには/var/run/containerd/containerd.sock
が存在し、Datadogコンテナの/host/var/run/containerd/containerd.sock
に同じものがある。
なので実際の通信はcontainerd.sock
を通じて発生していると考えた。
この通信はContainerdインテグレーションに必要なものであるため、抑制ルールを作成して自動的にアーカイブすることにした。
抑制ルールを作成すると以後同じ条件の検出結果は自動的にアーカイブされるようになる。
対応(抑制ルールの作成)
すべてのクラスターでDatadog Agentはdatadog
Namespaceにデプロイしているため、datadog
Namespaceで検出されたDockerSocketAccessed
は抑制するルールにする。
resource "aws_guardduty_filter" "datadog_dockersocketaccessed" {
rank = 4
detector_id = aws_guardduty_detector.ap_northeast_1.id
action = "ARCHIVE"
name = "datadog-DockerSocketAccessed"
finding_criteria {
criterion {
field = "resource.kubernetesDetails.kubernetesWorkloadDetails.namespace"
equals = ["datadog"]
}
criterion {
field = "type"
equals = ["PrivilegeEscalation:Runtime/DockerSocketAccessed"]
}
}
}
field
の書き方はここを見る(Filter attributes
の表)。
※rank
はproviderの必須argument(v5.31.0現在)ですが、AWS APIでは必須ではありません。
おまけ:抑制ルール例
Argo CDによるRole/RoleBinding作成・変更への警告を抑制
resource "aws_guardduty_filter" "argocd_rbac" {
rank = 5
detector_id = aws_guardduty_detector.ap_northeast_1.id
action = "ARCHIVE"
name = "argocd-rbac"
finding_criteria {
criterion {
field = "resource.kubernetesDetails.kubernetesUserDetails.username"
equals = [
# in-clusterな操作のusername
"system:serviceaccount:argocd:argocd-application-controller",
# remote clusterへの操作のusername
# https://argo-cd.readthedocs.io/en/stable/operator-manual/declarative-setup/#eks
"iam-role-name"
]
}
criterion {
field = "type"
equals = [
"PrivilegeEscalation:Kubernetes/AnomalousBehavior.RoleCreated",
"PrivilegeEscalation:Kubernetes/AnomalousBehavior.RoleBindingCreated"
]
}
}
}
criteriaの仕様
Each filter criteria attribute is evaluated as an AND operator. Multiple values for the same attribute are evaluated as AND/OR.
criterion
同士はANDで、equals
内のそれぞれはORです。
Discussion