EKS:Fargateから始めるハニポ生活


こちらはAWS Containers Advent Calendar 2020の5日目の記事です。

ハニーポットとは、あえて外部から攻撃を受けることで最近の攻撃のトレンドや手法を見てみよう!という目的で構築されるサーバのことです。このハニーポット、運用をするにはハニポサーバそのものの整備だけではなくサーバで受けたログを収集し解析を行う解析基盤の整備です。

今回はハニーポットをAWS/EKS上に構築することで運用コストを抑えてみようというお話しです。
しかしせっかくのre:Inventの直後アドベントカレンダーですので、最近話題になっているAWS Fargateと先日のre:Inventで話題に上がったFargate上のログをfluentbitで収集する機構を用いてログの集約を行う環境を整えていこうと思います。

構成

今回のハニポは下記のような構成で構築しました。(fluentdではなくfluentbitの間違いですorz)
OSレイヤ以下のメンテナンスは極力したくないため & 新しいもの触りたいということで今回はAWS Fargateを利用します。

基本的に攻撃者にはALB経由で攻撃を行ってもらい、IngressでHTTPのポートを割り振ってPodでアクセスログをキャプチャしていく構成です。またログDBのバックエンドとしてElasticsearchかCloudWatchLogsで悩みましたが、お仕事で今後使う予定のCloudWatchLogsを利用することにしました。

ハニポとしてはWOWHoneypotを利用します。ただしオリジナルにはDockerコンテナ周りの設定が含まれていないため、今回はForkしたオレオレWOWHoneypotを利用することにします。

構築

環境構築

こちらに従って構築していきます。
https://aws.amazon.com/jp/blogs/containers/fluent-bit-for-amazon-eks-on-aws-fargate-is-here/

適当な踏み台サーバ上に、みなさん大好きawscli/elsctlをインストールしておきます。実際にはVPCの設定は細かく設定する必要がありますが、いったんサクッとeksctl側の設定に任せることにします。

cluster.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
  name: honeypot
  region: eu-west-2
  version: "1.18"

cloudWatch:
  clusterLogging:
    enableTypes: ["*"]

iam:
  withOIDC: true

fargateProfiles:
  - name: kube-system
    selectors:
      - namespace: kube-system
  - name: wowhoneypot
    selectors:
      - namespace: wowhoneypot
$ eksctl create cluster -f ./cluster.yaml

20分程度すると環境ができあがっています。環境が立ち上がったら.kubeconfigに認証情報を保存してkubectl get pods --all-namewspacesを叩いてCoreDNSのPodが立ち上がっていることを確認します。

$ aws eks update-kubeconfig --name honeypot
$ kubectl get pods  --all-namespaces
$ kubectl create ns wowhoneypot

上記の構築でFargateProfileを一緒に作成されています。FargateProfileはKubernetesのNamespaceリソースとラベルを用いて指定することが可能ですが、今回はNamespaceリソースにだけ割り当てます。これによりwowhoneypotnamespaceに作成されたPodはすべてFargate上に起動するようになります。

ログ収集用IAM Policyの作成

アプリログをfluentbitが拾ってCloudWatch Logsへ投げ込む際に、FargateからCloudWatch Logsのリソースへアクセスする必要があります。そこでCloudWatch Logsへのアクセスを行うためのIAM Policyを作成し、Fargateの実行ロールへアタッチします。

permission.json
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
      "Action": [
        "logs:CreateLogStream",
        "logs:CreateLogGroup",
        "logs:DescribeLogStreams",
        "logs:PutLogEvents"
      ],
    "Resource": "*"
  }]
}
# 先のCloudWatch LogsへアクセスするためのPolocyを作成する
$ aws iam create-policy \
        --policy-name FluentBitEKSFargate \
        --policy-document file://permissions.json 

# FargateProfileのExecutionRoleを取得する
# RoleNameではなくARNが渡されるので注意
$ aws eks describe-fargate-profile \
        --cluster-name honeypot \
        --fargate-profile-name wowhoneypot \
        --query fargateProfile.podExecutionRoleArn

# 作成したPolicyをRoleにアタッチする
$ aws iam attach-role-policy \
        --policy-arn arn:aws:iam::123456789012:policy/FluentBitEKSFargate \
        --role-name eksctl-honeypot-cluster-FargatePodExecutionRole-XXXXXXXXXX

EKS自体の環境構築はここでいったん完了です。

WOWHoneypotの改修

ハニーポット本体となるWOWHoneypotの改修ポイントとして下記の4点が必要です。

  • ログのフォーマット
    • jsonなどの構造化データに変更する
  • 環境変数による設定の注入
    • WOWHoneypotは独自のconfigフォーマットを用いている
  • Client ipaddressの変更
    • masterブランチではリクエストヘッダーのHostのIPアドレスをClientIPとしている
  • Dockerfileの作成

特に今回はHTTPのエンドポイントとしてALBを利用するため、ClientIPの表示をヘッダーのX-Forwarded-Forの値に変更する必要があります。

ということでざっくり再実装したものがこちらのリポジトリ > https://github.com/RyuSA/WOWHoneypot

マニフェストの作成

aws-observabilitynamespaceを作成して、namespaceへ適切なラベルを貼るとfluentbitによるログ転送が有効になります。
https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/fargate-logging.html

fluentd-config.yaml
kind: Namespace
apiVersion: v1
metadata:
  name: aws-observability
  labels:
    aws-observability: enabled
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: aws-logging
  namespace: aws-observability
  labels:
    k8s-app: fluentbit-cloudwatch
data:
  output.conf: |
    [OUTPUT]
        Name cloudwatch_logs
        Match *
        region us-east-2
        log_key log
        log_group_name /app/honeypot
        log_stream_name wowhoneypot
        auto_create_group On

そしてDeploymentとServiceを作成します。

deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: wowhoneypot
  namespace: wowhoneypot
  labels:
    app: wowhoneypot
    type: honeypot
spec:
  replicas: 1
  selector:
    matchLabels:
      app: wowhoneypot
  template:
    metadata:
      labels:
        app: wowhoneypot
    spec:
      containers:
        - name: wowhoneypot
          image: ryusa/wowhoneypot:1.4
          imagePullPolicy: Always
          resources:
            requests: {}
            limits:
              cpu: 100m
              memory: 64Mi
          securityContext:
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            capabilities:
              drop:
                - ALL
          env:
            - name: "PORT"
              value: "8080"
          ports:
            - containerPort: 8080

ここまで確認できたら動作確認をしておきましょう。

$ kubectl -n wowhoneypot port-forward wowhoneypot-XXX-YYY 8080:8080
$ curl localhost:8080/debug
$ kubectl -n wowhoneypot logs wowhoneypot-XXX-YYY

ALBのプロビショニング

Fargate上のPodへNodePortを指定することはできず、LoadBalancerとしてはALBを利用するほかありません。そこでIngressとしてALB Controllerをデプロイしエンドポイントとします。

まずはEKSがALBを構築するためのIAM Policyを作成します。

$ curl -o iam-policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.9/docs/examples/iam-policy.json
$ aws iam create-policy --policy-name ALBIngressControllerIAMPolicy --policy-document file://iam-policy.json

IAM Policy作成後、今後はIAM Policyに紐つけるためのServiceAccountを作成しPolicyと紐付けを行います。

$ kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.9/docs/examples/rbac-role.yaml
$ eksctl create iamserviceaccount \
        --region us-east-2 \
        --name alb-ingress-controller \
        --namespace kube-system \
        --cluster honeypot \
        --attach-policy-arn arn:aws:iam::123456789012:policy/ALBIngressControllerIAMPolicy \
        --override-existing-serviceaccounts \
        --approve

あとはALBのプロビショニングを担当するALB Controllerをデプロイするだけです。ただしALB ControllerのマニフェストにはAWS環境について記載する箇所があるため注意が必要です。

$ curl -o alb-ingress-controller.yaml https://raw.githubusercontent.com/kubernetes-sigs/aws-alb-ingress-controller/v1.1.9/docs/examples/alb-ingress-controller.yaml

# 下記をそれぞれコメント解除して記載する
# --cluster-name
# --aws-vpc-id
# --aws-region
$ vim alb-ingress-controller.yaml
$ kubectl create -f alb-ingress-controller.yaml -n kube-system

ALB ControllerがRunning Stateになった状態で、ALBをプロビショニングしましょう!

ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: "endpoint"
  namespace: "wowhoneypot"
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 8080}, {"HTTP": 80}]'
spec:
  rules:
    - http:
        paths:
          - path: /*
            backend:
              serviceName: wowhoneypot
              servicePort: 8080

Ingressの作成が完了するまでやや時間がかかるので、AWSコンソールで構築状況を確認するかdigコマンドでIPが降ってくることを確認しておくと良いと思います。

LoadBalancerの作成が完了するとCloudWatchLogsにアクセスがポコポコ来るようになります。

完走した感想

1週間ほどハニポを放置してみましたが、定常的に5req/min程度の攻撃を観測することができ、某VPSのレンタルサーバでハニポを運用していた時よりアクセス数が多いかな?といった印象でした。(AWSのIPレンジとかで集中していたりするのかな?)
TCPレイヤの攻撃も見たかったのですが、EKS FargateはL4レイヤのLBに対応しておらず今回は断念しました。しかし同じ手法を使えばマネージドノードグループを利用することでTCPレイヤの攻撃も観測することができると思います。