Amazon EKS環境の特権コンテナ起動を検出するGuardDutyイベントを発生させてみた

2022.04.11

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

コンサル部のとばち(@toda_kk)です。

先日、GuardDutyがAmazon EKSに対応し、EKSクラスターにおける脅威を検出できるようになりました。

検出できる脅威のタイプ(Finding Types)のうちPrivilegeEscalation:Kubernetes/PrivilegedContainerがあります。これは、EKSクラスターにおいて特権コンテナ(Privileged Container)が起動されたことを検出するイベントです。

実際にどんなイベントが検出されるのか確認したかったので、本記事では特権コンテナの起動手順について記載します。

特権コンテナとは?

特権コンテナ(Privileged Container)とは、実行されているホストコンピューター上においてroot相当の権限を持つコンテナのことです。

具体的には、通常のコンテナプロセスはホスト上のLinux Capabilitiesが制限された状態で実行されますが、特権コンテナでは全てのLinux Capabilitiesが有効になった状態で実行されます。

rootユーザーでのコンテナ実行とは異なりますので、ご注意ください。

なお、2022年4月現在、Fargateでは特権コンテナの実行をサポートしていません。EKSで特権コンテナを実行したい場合は、EKS on EC2環境のみとなります。

Privileged containers aren't supported on Fargate.

PrivilegeEscalation:Kubernetes/PrivilegedContainerの発生条件

AWS公式ドキュメントには、下記のように記載されています。

This finding informs you that a privileged container was launched on your Kubernetes cluster using an image has never before been used to launch privileged containers in your cluster. A privileged container has root level access to the host. Adversaries can launch privileged containers as a privilege escalation tactic to gain access to and then compromise the host.

EKSクラスターにおいて、これまで特権コンテナの起動に使用されたことのないイメージを使用して特権コンテナが起動されたときに、発生するようです。

EKSにおける特権コンテナの起動

前提として、EKSクラスターはすでに作成済みとします。eksctlによるクラスター作成については、下記の記事をご参照ください。

今回はtest-eksという名前でEKSクラスターを作成しておきます。

その上で、EKSクラスターで特権コンテナを実行するためには、下記のマニフェストファイルを作成してkubectl applyします。

privileged-container.yml

apiVersion: v1
kind: Namespace
metadata:
  name: test-app

---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    name: test-app-deployment
  name: test-app-deployment
  namespace: test-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: test-app
  template:
    metadata:
      labels:
        app: test-app
    spec:
      containers:
        - image: nginx:latest
          name: test-app-container
          securityContext:
            privileged: true

Namespacetest-appおよびDeploymenttest-app-deploymentを作成するマニフェストとなっています。Deploymentでは、nginx:latestをイメージとして使用してPodを実行します。

特権コンテナとして実行するためには、spec.template.spec.containersのなかでsecurityContext.privilegedtrueで指定する必要があります。

kubectl applyコマンドを実行することで、マニフェストを適用します。

 $ kubectl apply -f privileged-container.yml
namespace/test-app created
deployment.apps/test-app-deployment created

NamespaceやDeploymentなしで単にPodだけ起動したい場合は、上記のマニフェストファイルは使わずに下記のようにkubectl runコマンドで--privilegedフラグを指定することで特権コンテナを実行できます。

$ kubectl run test-nginx --image=nginx:latest --privileged
pod/test-nginx created

GuardDutyイベントの確認

上記のマニフェストファイルをapplyすると、EKSクラスターの監査ログ(Audit)からGuardDutyが特権コンテナの実行を検知し、下記のようなJSON形式のイベントが作成されます。

下記は2022年4月現在のものになります。フォーマットなど今後変更になる可能性もあるのでご注意ください。

PrivilegeEscalation:Kubernetes/PrivilegedContainer

[
  {
    "AccountId": "123456789012",
    "Arn": "arn:aws:guardduty:ap-northeast-1:123456789012:detector/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/finding/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "CreatedAt": "2022-04-11T09:32:32.008Z",
    "Description": "A privileged container with root level access was launched on EKS Cluster test-eks. If this behavior is not expected, it may indicate that your credentials are compromised.",
    "Id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "Partition": "aws",
    "Region": "ap-northeast-1",
    "Resource": {
      "AccessKeyDetails": {
        "AccessKeyId": "ASIAXXXXXXXXXXXXXXXX",
        "PrincipalId": "",
        "UserName": "user-name",
        "UserType": "Unknown"
      },
      "EksClusterDetails": {
        "Name": "test-eks",
        "Arn": "arn:aws:eks:ap-northeast-1:123456789012:cluster/test-eks",
        "VpcId": "vpc-xxxxxxxxxxxxxxxxx",
        "Status": "ACTIVE",
        "Tags": [
          {
            "Key": "aws:cloudformation:stack-name",
            "Value": "eksctl-test-eks-cluster"
          },
          {
            "Key": "alpha.eksctl.io/cluster-name",
            "Value": "test-eks"
          },
          {
            "Key": "aws:cloudformation:stack-id",
            "Value": "arn:aws:cloudformation:ap-northeast-1:123456789012:stack/eksctl-test-eks-cluster/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
          },
          {
            "Key": "eksctl.cluster.k8s.io/v1alpha1/cluster-name",
            "Value": "test-eks"
          },
          {
            "Key": "aws:cloudformation:logical-id",
            "Value": "ControlPlane"
          },
          {
            "Key": "alpha.eksctl.io/eksctl-version",
            "Value": "0.90.0"
          }
        ],
        "CreatedAt": "2022-04-11T07:04:46.350Z"
      },
      "KubernetesDetails": {
        "KubernetesUserDetails": {
          "Username": "kubernetes-admin",
          "Uid": "aws-iam-authenticator:123456789012:XXXXXXXXXXXXXXXXXXXXX",
          "Groups": [
            "system:masters",
            "system:authenticated"
          ]
        },
        "KubernetesWorkloadDetails": {
          "Name": "test-app-deployment",
          "Type": "deployments",
          "Uid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
          "Namespace": "test-app",
          "HostNetwork": false,
          "Containers": [
            {
              "ContainerRuntime": null,
              "Id": null,
              "Name": "test-app-container",
              "Image": "nginx:latest",
              "ImagePrefix": "",
              "SecurityContext": {
                "Privileged": true
              }
            }
          ]
        }
      },
      "ResourceType": "EKSCluster"
    },
    "SchemaVersion": "2.0",
    "Service": {
      "Action": {
        "ActionType": "KUBERNETES_API_CALL",
        "KubernetesApiCallAction": {
          "RequestUri": "/apis/apps/v1/namespaces/test-app/deployments",
          "Verb": "create",
          "UserAgent": "kubectl/v1.22.4 (darwin/amd64) kubernetes/xxxxxxx",
          "RemoteIpDetails": {
            "City": {
              "CityName": "Chiyoda-ku"
            },
            "Country": {
              "CountryName": "Japan"
            },
            "GeoLocation": {
              "Lat": xx.xxxx,
              "Lon": xxx.xxxx
            },
            "IpAddressV4": "xxx.xxx.xxx.xxx",
            "Organization": {
              "Asn": "1234",
              "AsnOrg": "XXXXXXXXXX",
              "Isp": "XXXXXXXXXX",
              "Org": "XXXXXXXXXX"
            }
          },
          "StatusCode": 201
        }
      },
      "Archived": false,
      "Count": 1,
      "DetectorId": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
      "EventFirstSeen": "2022-04-11T09:32:03.976Z",
      "EventLastSeen": "2022-04-11T09:32:04.017Z",
      "ResourceRole": "TARGET",
      "ServiceName": "guardduty",
      "AdditionalInfo": {
        "Value": "{}",
        "Type": "default"
      }
    },
    "Severity": 5,
    "Title": "Privileged container with root level access launched on the EKS Cluster.",
    "Type": "PrivilegeEscalation:Kubernetes/PrivilegedContainer",
    "UpdatedAt": "2022-04-11T09:32:32.008Z"
  }
]

同じイメージでは一度しか通知されないので注意

上述の通り、脅威のタイプがPrivilegeEscalation:Kubernetes/PrivilegedContainerのイベントの発生条件は、「これまで特権コンテナの起動に使用されたことのないイメージを使用して特権コンテナが起動されたとき」です。

そのため、一度このイベントを発生させたEKSクラスターにおいて同じイメージを使用して特権コンテナを実行したとしても、GuardDutyは特権コンテナの実行を通知してくれません。

また、今回はnginx:latestで指定していましたが、別のタグを指定したとしても同様に通知されません。

発生済みのGuardDutyイベントを一度アーカイブした上で、同じイメージを使用して特権コンテナを実行しても、通知はされません。

別のEKSクラスターで同じイメージを使用して特権コンテナを実行した場合は、新たにGuardDutyイベントが発生してくれます。

つまり、あくまでも1つのEKSクラスターにおいて1つのイメージで特権コンテナが実行されたときに通知される、という点にご注意ください。

以上、コンサル部のとばち(@toda_kk)でした。