Прим. переводчика: автор статьи предлагает реализацию honeypot'а («приманки») на основе виртуального кластера Kubernetes, чтобы обнаруживать попытки взлома K8s-инфраструктуры. Также в статье рассматриваются отличия низкоинтерактивных и высокоинтерактивных приманок.

Если не вдаваться в детали, главная задача приманок — соблазнять злоумышленников, отвлекая от реальных целей, и попутно собирать информацию об их деятельности. Сегодня мы попытаемся создать такую приманку с помощью vcluster и Falco.

Изображение из оригинальной статьи Sysdig
Изображение из оригинальной статьи Sysdig

В первой части серии речь пойдет о том, как собрать простую SSH-ловушку для выявления атак, направленных на среду исполнения.

Почему именно приманки

Приманки, или honeypot'ы, могут моделировать практически любой тип цифровых активов, включая приложения, системы, сети, устройства IoT, компоненты SCADA и многое другое. Их сложность варьируется от так называемых honeytoken'ов — отдельных файлов, дополненных соответствующим инструментарием, до honeynets — разветвленных сетей, включающих множество систем и инфраструктурных компонентов.

Приманки подобного типа очень полезны для сбора оперативной информации, поскольку позволяют командам и исследователям, специализирующимся на безопасности, получить представление об инструментах, методах и процедурах злоумышленников, а также выступают основой для индикаторов компрометации* в различных инструментах безопасности.

* Прим. переводчика

Indicators of compromise, IoCs — артефакты, наблюдаемые в сети или в операционной системе, которые с высокой степенью достоверности указывают на вторжение.

Приманки можно классифицировать по уровню сложности: высокоинтерактивные и низкоинтерактивные.

Отличия приманок с разными уровнями сложностями

Низкоинтерактивные приманки — аналог утиного манка в мире инструментов для безопасности. Для их запуска не требуются значительные ресурсы. При этом они, как правило, способны только на базовые действия — например, могут выдавать относительно реалистичный баннер в ответ на запросы на стандартный порт. Обычно этим дело и ограничивается. Такая приманка может заинтересовать злоумышленника при сканировании портов и служб, но отсутствие какой-либо иной активности на принимающей стороне, скорее всего, не увлечет его надолго. Кроме того, низкоинтерактивные приманки не позволяют получить представление о том, что именно делает злоумышленник. Они не обеспечивают достаточной области атаки, с которой тот мог бы взаимодействовать.

Если низкоинтерактивные приманки — это утиные манки, то высокоинтерактивные приманки — это полноценные подсадные утки. Они гораздо лучше заманивают злоумышленников, однако существует риск потерять «утку» в процессе. Высокоинтерактивные приманки часто представляют собой реалистичные системы с реальными работающими приложениями. Они оснащены дополнительными инструментами для тщательного отслеживания вредоносной активности. Это позволяет проследить всю цепочку действий злоумышленников, идентифицировать используемые эксплойты, а также получить копии загружаемых инструментов, двоичных файлов, используемых учетных данных и т. д. С точки зрения сбора полезной информации все это замечательно. Однако не следует забывать, что в руки злоумышленников передается реальный актив, и необходимо тщательно следить за тем, что они с ним делают.

Одна из главных проблем высокоинтерактивных приманок — изоляция атакующего от остального окружения. В случае приманок, построенных с использованием инструментов контейнеризации, таких как Kubernetes, следует внимательно следить за тем, чтобы атакующий не получил доступ к частям кластера, отвечающим за работу приманки. Также нельзя открывать доступ к инструментарию для наблюдения за приманкой и управления ею. Это непростая задача. Частью притягательности приманки приходится жертвовать, защищая ее критические компоненты от доступа злоумышленников. Другими словами, приходится следить за всем, что злоумышленник может использовать для нацеливания на сам кластер или на инструментарий для наблюдения, либо создавать обходные пути для предотвращения нежелательного вмешательства.

Виртуальные кластеры спешат на помощь

Виртуальные кластеры работают поверх основного кластера Kubernetes. Схема позволяет запускать множество виртуальных кластеров. Каждый такой кластер будет находиться в обособленной среде, без какой-либо возможности связаться с другими виртуальными кластерами или с хост-кластером.

Изоляция позволяет раскрывать ключевые внутренние элементы виртуального кластера — ничто не будет указывать, что этот кластер работает поверх другого. Можно раскрывать элементы инфраструктуры Kubernetes, инструменты обслуживания и другие компоненты, не опасаясь за судьбу кластера.

Архитектура vcluster’а
Архитектура vcluster’а

Существуют различные проекты виртуальных кластеров, которые можно использовать для организации приманки. Среди них vcluster выглядит, пожалуй, наиболее перспективно. Кроме того, проект отличается хорошей поддержкой. Ребята из vcluster очень дружелюбны и отзывчивы, обязательно зайдите и поздоровайтесь с ними в Slack'е!

Создаём приманку на vcluster

В этом разделе мы развернем простую приманку с помощью vlcuster. Специально ограничимся базовым примером. Впрочем, он будет хорошим фундаментом, на котором можно строить любые дальнейшие эксперименты.

Нам потребуются следующие инструменты с указанными минимальными версиями:

  • Minikube v1.26.1;

  • Helm v3.9.2;

  • kubectl v1.25.0;

  • vcluster 0.11.2.

Пошаговая установка приманки на базе vcluster и Falco

Прежде всего необходимо установить исполняемый файл vcluster:

$ curl -s -L "https://github.com/loft-sh/vcluster/releases/latest" | sed -nE 's!.*"([^"]*vcluster-linux-amd64)".*!https://github.com\1!p' | xargs -n 1 curl -L -o vcluster && chmod +x vcluster;
1 curl -L -o vcluster && chmod +x vcluster;
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100 36.8M  100 36.8M    0     0  10.4M      0  0:00:03  0:00:03 --:--:-- 11.2M
$ sudo mv vcluster /usr/local/bin;
$ vcluster version
vcluster version 0.11.2

Разворачиваем локальный кластер Kubernetes

Создать кластер можно множеством способов. В нашем случае мы воспользуемся Minikube.

Примечание:

Нам подходят драйверы virtualbox, qemu или kvm2 для Minikube, но не драйвер none. Falco не сможет правильно развернуть свой драйвер, если использовать none.

Кроме того, поскольку используется драйвер virtualbox, развертывание необходимо проводить на реальном оборудовании. Драйвер не будет работать в виртуальной машине, в инстансе EC2 и аналогичных средах.

Давайте создадим кластер. После запуска команды start minikube несколько минут будут собираться все нужные компоненты:

$ minikube start --vm-driver=virtualbox
????  minikube v1.26.1 on Ubuntu 22.04
✨  Using the virtualbox driver based on user configuration
????  Starting control plane node minikube in cluster minikube
????  Creating virtualbox VM (CPUs=2, Memory=6000MB, Disk=20000MB) ...
????  Preparing Kubernetes v1.24.3 on Docker 20.10.17 ...
    ▪ Generating certificates and keys ...
    ▪ Booting up control plane ...
    ▪ Configuring RBAC rules ...
    ▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5
????  Verifying Kubernetes components...
????  Enabled addons: storage-provisioner
????  Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default

Добавляем в приманку инструментарий Falco

Теперь нужно установить Falco:

$ helm repo add falcosecurity https://falcosecurity.github.io/charts
"falcosecurity" has been added to your repositories
$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "falcosecurity" chart repository
Update Complete. ⎈Happy Helming!⎈
$ helm upgrade --install falco --set driver.loader.initContainer.image.tag=master --set driver.loader.initContainer.env.DRIVER_VERSION="2.0.0+driver" --set tty=true --namespace falco --create-namespace falcosecurity/falco
Release "falco" does not exist. Installing it now.
NAME: falco
LAST DEPLOYED: Thu Sep  8 15:32:45 2022
NAMESPACE: falco
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
Falco agents are spinning up on each node in your cluster. After a few
seconds, they are going to start monitoring your containers looking for
security issues.
No further action should be required.
Tip: 
You can easily forward Falco events to Slack, Kafka, AWS Lambda and more with falcosidekick. 
Full list of outputs: https://github.com/falcosecurity/charts/tree/master/falcosidekick.
You can enable its deployment with `--set falcosidekick.enabled=true` or in your values.yaml. 
See: https://github.com/falcosecurity/charts/blob/master/falcosidekick/values.yaml for configuration values.

На запуск Pod'а с Falco уйдет несколько минут. Проверить его состояние и просмотреть журналы, чтобы убедиться, что все идет гладко, можно с помощью kubectl:

$ kubectl get pods -n falco -o wide
NAME          READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED NODE   READINESS GATES
falco-zwfcj   1/1     Running   0          73s   172.17.0.3   minikube   <none>           <none>
$ kubectl logs falco-zwfcj -n falco
Defaulted container "falco" out of: falco, falco-driver-loader (init)
Thu Sep  8 22:32:47 2022: Falco version 0.32.2
Thu Sep  8 22:32:47 2022: Falco initialized with configuration file /etc/falco/falco.yaml
Thu Sep  8 22:32:47 2022: Loading rules from file /etc/falco/falco_rules.yaml:
Thu Sep  8 22:32:47 2022: Loading rules from file /etc/falco/falco_rules.local.yaml:
Thu Sep  8 22:32:48 2022: Starting internal webserver, listening on port 8765

Собираем всё вместе и создаем виртуальный кластер

Теперь необходимо создать пространство имен для виртуального кластера в основном и развернуть в нем виртуальный:

$ kubectl create namespace vcluster
namespace/vcluster created
$ vcluster create ssh -n vcluster
info   Detected local kubernetes cluster minikube. Will deploy vcluster with a NodePort & sync real nodes
info   Create vcluster ssh...
info   execute command: helm upgrade ssh https://charts.loft.sh/charts/vcluster-0.11.2.tgz --kubeconfig /tmp/3673995455 --namespace vcluster --install --repository-config='' --values /tmp/641812157
done √ Successfully created virtual cluster ssh in namespace vcluster
info   Waiting for vcluster to come up...
warn   vcluster is waiting, because vcluster pod ssh-0 has status: ContainerCreating
done √ Switched active kube context to vcluster_ssh_vcluster_minikube
- Use `vcluster disconnect` to return to your previous kube context
- Use `kubectl get namespaces` to access the vcluster

Устанавливаем SSH-приманку

Виртуальный кластер готов. Теперь в нем можно создать незащищенный SSH-сервер и использовать его в качестве мишени.

Для этого воспользуемся специальным небезопасным Helm-чартом SSH-сервера от sourcecodebox.io. Учетные данные для этого сервера — root/THEPASSWORDYOUCREATED.

$ helm repo add securecodebox https://charts.securecodebox.io/
"securecodebox" has been added to your repositories
$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "falcosecurity" chart repository
...Successfully got an update from the "securecodebox" chart repository
Update Complete. ⎈Happy Helming!⎈
$ helm install my-dummy-ssh securecodebox/dummy-ssh --version 3.14.3
NAME: my-dummy-ssh
LAST DEPLOYED: Thu Sep  8 15:53:15 2022
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
Demo SSH Server deployed.
Note this should used for demo and test purposes.
Do not expose this to the Internet!

Изучаем разные контексты

Итак, внутри виртуального кластера теперь у нас работает некий сервис. Давайте рассмотрим два различных контекста.

Примечание:

Контекст в Kubernetes — это набор параметров для доступа к определенному кластеру. Переключение контекста меняет всё окружение для команд вроде kubectl с одного кластера на другой.

Сперва давайте взглянем на все ресурсы, существующие в кластере, с точки зрения виртуального кластера:

$ kubectl get all --all-namespaces
NAMESPACE     NAME                                READY   STATUS    RESTARTS   AGE
kube-system   pod/coredns-6ffcc6b58-h7zwx        1/1     Running   0          m26s
default       pod/my-dummy-ssh-f98c68f95-vwns   1/1     Running   0          m1s
NAMESPACE     NAME                   TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                  AGE
default       service/kubernetes     ClusterIP   10.96.112.178   <none>        443/TCP                  m26s
kube-system   service/kube-dns       ClusterIP   10.97.196.120   <none>        53/UDP,53/TCP,9153/TCP   m26s
default       service/my-dummy-ssh   ClusterIP   10.99.109.0     <none>        22/TCP                   m1s
NAMESPACE     NAME                           READY   UP-TO-DATE   AVAILABLE   AGE
kube-system   deployment.apps/coredns        1/1     1            1           m26s
default       deployment.apps/my-dummy-ssh   1/1     1            1           m1s
NAMESPACE     NAME                                      DESIRED   CURRENT   READY   AGE
kube-system   replicaset.apps/coredns-6ffcc6b58        1         1         1       m26s
default       replicaset.apps/my-dummy-ssh-f98c68f95   1         1         1       m1s

Видна обычная инфраструктура Kubernetes, а также Pod и сервис my-dummy-ssh, запущенные в пространстве имен default. Обратите внимание, что ресурсы Falco не отображаются, поскольку последний установлен в хост-кластере и не виден из виртуального кластера.

Теперь давайте переключим контексты, отключившись от виртуального кластера. Это вернет нас к контексту хост-кластера:

$ vcluster disconnect
info   Successfully disconnected from vcluster: ssh and switched back to the original context: minikube

Если теперь попросить kubectl еще раз вывести список ресурсов, картина будет совсем иной:

$ kubectl get all --all-namespaces
NAMESPACE     NAME                                                READY   STATUS    RESTARTS   AGE
falco         pod/falco-zwfcj                                     1/1     Running   0          5m
kube-system   pod/coredns-d4b75cb6d-ttwdl                        1/1     Running   0          4m
kube-system   pod/etcd-minikube                                   1/1     Running   0          4m
kube-system   pod/kube-apiserver-minikube                         1/1     Running   0          4m
kube-system   pod/kube-controller-manager-minikube                1/1     Running   0          4m
kube-system   pod/kube-proxy-dhg9v                                1/1     Running   0          4m
kube-system   pod/kube-scheduler-minikube                         1/1     Running   0          4m
kube-system   pod/storage-provisioner                             1/1     Running   0          4m
vcluster      pod/coredns-6ffcc6b58-h7zwx-x-kube-system-x-ssh    1/1     Running   0          1m
vcluster      pod/my-dummy-ssh-f98c68f95-vwns-x-default-x-ssh   1/1     Running   0          5m
vcluster      pod/ssh-0                                           2/2     Running   0          1m
NAMESPACE     NAME                                   TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                  AGE
default       service/kubernetes                     ClusterIP   10.96.0.1       <none>        443/TCP                  4m
kube-system   service/kube-dns                       ClusterIP   10.96.0.10      <none>        53/UDP,53/TCP,9153/TCP   4m
vcluster      service/kube-dns-x-kube-system-x-ssh   ClusterIP   10.97.196.120   <none>        53/UDP,53/TCP,9153/TCP   1m
vcluster      service/my-dummy-ssh-x-default-x-ssh   ClusterIP   10.99.109.0     <none>        22/TCP                   5m
vcluster      service/ssh                            NodePort    10.96.112.178   <none>        443:31530/TCP            1m
vcluster      service/ssh-headless                   ClusterIP   None            <none>        443/TCP                  1m
vcluster      service/ssh-node-minikube              ClusterIP   10.102.36.118   <none>        10250/TCP                1m
NAMESPACE     NAME                        DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
falco         daemonset.apps/falco        1         1         1       1            1           <none>                   5m
kube-system   daemonset.apps/kube-proxy   1         1         1       1            1           kubernetes.io/os=linux   4m
NAMESPACE     NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
kube-system   deployment.apps/coredns   1/1     1            1           4m
NAMESPACE     NAME                                 DESIRED   CURRENT   READY   AGE
kube-system   replicaset.apps/coredns-d4b75cb6d   1         1         1       4m
NAMESPACE   NAME                   READY   AGE
vcluster    statefulset.apps/ssh   1/1     1m

Видны ресурсы Falco и ресурсы SSH-инсталляции из виртуального кластера. На этот раз они отображаются как работающие в пространстве имен vcluster на хост-кластере.

Испытываем приманку

Наконец у нас все готово! Давайте сделаем какую-нибудь гадость, чтобы сработало правило Falco, и посмотрим, что из этого получится.

Сымитировать реальное вторжение нам помогут три терминальных окна.

Терминал 1

В первом окне мы настроим проброс портов, открыв SSH-сервер для локальной машины. Окно должно оставаться открытым, чтобы SSH-сессия оставалась активной.

kubectl port-forward svc/my-dummy-ssh 5555:22

Эта команда откроет сервис на 127.0.0.1, порт 5555. Теперь нужно убедиться, что для этого окна используется контекст vcluster. Если используется контекст для основного кластера, переключиться на нужный можно с помощью команды vcluster connect ssh -n vcluster:

$ kubectl port-forward svc/my-dummy-ssh 5555:22
Forwarding from 127.0.0.1:5555 -> 22
Forwarding from [::1]:5555 -> 22

Терминал 2

В этом окне мы подключимся по SSH к сервису, который только что открыли на порту 5555. Учетные данные: root/THEPASSWORDYOUCREATED:

$ ssh -p 5555 root@127.0.0.1
The authenticity of host '[127.0.0.1]:5555 ([127.0.0.1]:5555)' can't be established.
ED25519 key fingerprint is SHA256:eLwgzyjvrpwDbDr+pDbIfUhlNANB4DPH9/0w1vGa87E.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '[127.0.0.1]:5555' (ED25519) to the list of known hosts.
root@127.0.0.1's password: 
Welcome to Ubuntu 16.04.6 LTS (GNU/Linux 5.10.57 x86_64)
 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage
The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

Подключившись по SSH, мы теперь мечтаем сделать какую-нибудь гадость, чтобы сработало правило Falco. Например, можно посмотреть /etc/shadow:

root@my-dummy-ssh-7f98c68f95-5vwns:~# cat /etc/shadow
root:$6$hJ/W8Ww6$pLqyBWSsxaZcksn12xZqA1Iqjz.15XryeIEZIEsa0lbiOR9/3G.qtXl/SvfFFCTPkElo7VUD7TihuOyVxEt5j/:18281:0:99999:7:::
daemon:*:18275:0:99999:7:::
bin:*:18275:0:99999:7:::
sys:*:18275:0:99999:7:::
sync:*:18275:0:99999:7:::
<snip>

Терминал 3

В этом окне будем просматривать логи от Pod'а Falco:

$ kubectl logs falco-zwfcj -n falco
23:22:26.726981623: Notice Redirect stdout/stdin to network connection (user=root user_loginuid=-1 k8s.ns=vcluster k8s.pod=my-dummy-ssh-7f98c68f95-5vwns-x-default-x-ssh container=cffc68f50e06 process=sshd parent=sshd cmdline=sshd -D terminal=0 container_id=cffc68f50e06 image=securecodebox/dummy-ssh fd.name=172.17.0.1:40312->172.17.0.6:22 fd.num=1 fd.type=ipv4 fd.sip=172.17.0.6)
23:22:27.709831799: Warning Sensitive file opened for reading by non-trusted program (user=root user_loginuid=0 program=cat command=cat /etc/shadow file=/etc/shadow parent=bash gparent=sshd ggparent=sshd gggparent=<NA> container_id=cffc68f50e06 image=securecodebox/dummy-ssh) k8s.ns=vcluster k8s.pod=my-dummy-ssh-7f98c68f95-5vwns-x-default-x-ssh container=cffc68f50e06

Видно множество строк вида Notice Redirect stdout/stdin to network connection — результат проброса портов. Кроме того, есть сообщения с Warning Sensitive file opened for read by non-trusted program — результат нашей попытки прочитать /etc/shadow.

Вот оно! Это Falco сигнализирует о том, что кто-то копается в вещах, не предназначенных для его глаз, подключившись к нашей приманке через SSH. И все это происходит внутри виртуального кластера vcluster, который, в свою очередь, работает в хост-кластере.

Убираем за собой

Убрать за собой беспорядок или начать все сначала (если дела пойдут настолько плохо) можно в несколько команд: удалите Falco и сервер SSH, разберитесь с Minikube и очистите временные файлы:

$ helm delete falco --namespace falco; helm delete my-dummy-ssh --namespace default; minikube delete --all -purge; sudo rm /tmp/juju*
release "falco" uninstalled
release "my-dummy-ssh" uninstalled
????  Deleting "minikube" in virtualbox ...
????  Removed all traces of the "minikube" cluster.
????  Successfully deleted all profiles
[sudo] password for user:

Стойте, это еще не все!

Виртуальные кластеры чрезвычайно перспективны для исследований в области безопасности в целом и для организации приманок в частности. Область, несомненно, интересная для наблюдения, как для будущих разработок, так и с точки зрения применения этих инструментов технологической отраслью.

В этой статье мы заложили хорошее начало, хотя многое еще можно отшлифовать и улучшить.

Следите за нашими публикациями — в следующей части этой серии мы добавим механизм реагирования на базе Falco Sidekick, запустим новые приманки во втором виртуальном кластере и подкрутим их настройки, сделав более безопасными.

P.S.

Читайте также в нашем блоге:

Комментарии (1)


  1. ZeroBot-Dot
    29.10.2022 11:12
    +1

    Спасибо. Нашли мне занятие на выходные )