
SSH/Telnet honeypot среднего уровня взаимодействия, созданный с помощью Cowrie, Loki, Promtail и Grafana - развернутый на DigitalOcean через Terraform с конвейером валидации GitLab CI.
Стек хонейпота SSH/Telnet, развернутый на DigitalOcean droplet с помощью Terraform. Атаки фиксируются Cowrie, сохраняются в Loki и визуализируются в Grafana с живой картой мира источников атак.
honeypot/
├── cowrie/
│ └── etc/
│ ├── cowrie.cfg # Cowrie honeypot configuration
│ └── userdb.txt # Accepted and rejected fake credentials
├── geoip/
│ └── .gitkeep # Placeholder - MMDB files are gitignored
├── grafana/
│ ├── provisioning/
│ │ ├── dashboards/
│ │ │ ├── dashboards.yml # Provisioning: dashboard provider
│ │ │ └── honeypot-dashboard.json # Pre-built Attack Monitor dashboard
│ │ └── datasources/
│ │ └── loki.yml # Auto-provisioned Loki datasource
│ └── grafana.ini # Grafana server settings
├── loki/
│ └── config.yml # Loki single-binary config and retention
├── promtail/
│ └── config.yml # Promtail scrape and GeoIP pipeline
├── scripts/
│ ├── geoip-update.sh # Download or refresh GeoIP database
│ └── setup-firewall.sh # Host UFW rules for honeypot ports
├── terraform/
│ ├── templates/
│ │ ├── cloud-init.yaml.tftpl # Droplet first-boot script (Terraform-templated)
│ │ └── env.tftpl # .env lines embedded via Terraform
│ ├── backend.tf # Terraform backend config
│ ├── main.tf # Droplet, SSH key, firewall, cloud-init
│ ├── outputs.tf # IPs and helpful post-apply values
│ ├── terraform.tfvars.example # Example variable values (copy to terraform.tfvars)
│ ├── variables.tf # Terraform input variables
│ └── versions.tf # Terraform and provider version constraints
├── .env.example # Example environment file for manual setup
├── .gitignore # Ignored paths and files
├── .gitlab-ci.yml # CI/CD pipeline: fmt, validate, Checkov
├── docker-compose.yml # Docker Compose file for the honeypot stack
├── LICENSE # GPLv2 license
├── manual-deployment.sh # Legacy VM bootstrap without Terraform
└── README.md # Project documentation
## Аппаратные требования
> Примечание: Эти требования основаны на тарифе Basic Droplet от DigitalOcean по состоянию на май 2026 года и являются минимальными для работы проекта.
- Провайдер: DigitalOcean
- Тариф: Basic Droplet — 1 Intel vCPU
- ОЗУ: 1 ГБ (+2 ГБ swap)
- Хранилище: 35 ГБ NVMe SSD
- ОС: Ubuntu 24.04 LTS
## Установка и настройка
>Примечание: После установки рекомендуется открыть новый терминал и проверить, что вы всё ещё можете подключиться по SSH на `ADMIN_SSH_PORT` (по умолчанию: 2022), прежде чем закрывать исходную сессию.
### Развертывание с помощью Terraform (рекомендуется)
1. Создайте API-токен DigitalOcean с правами на чтение и запись:
- Войдите в DigitalOcean и перейдите в Account > API > Tokens > Generate New Token.
- Назовите токен (например, «Cowrie Honeypot») и выберите разрешения «Full Access».
- Нажмите «Generate Token» и скопируйте значение токена в надёжное место (вы больше не сможете его увидеть).
2. Создайте пару SSH-ключей на локальной машине и скопируйте путь к открытому ключу.
3. Перейдите в каталог `terraform`, затем скопируйте и отредактируйте файл с переменными:
> Примечание: `do_token`, `ssh_public_key_path` и `grafana_admin_password` должны быть настроены как минимум в `terraform.tfvars` перед применением.```bash
cd terraform
cp terraform.tfvars.example terraform.tfvars
Примечание: Terraform должен быть установлен на вашем локальном компьютере. Инструкции см. в Руководстве по установке Terraform.```bash terraform init # Initialize Terraform and download providers terraform apply
5. Если тестирование - переразвернуть с заменой:```bash
terraform apply -replace="digitalocean_droplet.honeypot"
### Ручное развёртывание (устаревшее)
1. Создайте droplet DigitalOcean с указанными выше требованиями к оборудованию и вашим SSH-ключом.
2. Подключитесь по SSH к droplet или используйте веб-консоль DigitalOcean и выполните следующие команды:```bash
ssh root@<your-droplet-ip> # If using DigitalOcean web console, skip this command
git clone https://gitlab.com/Oseguera12/cowrie-honeypot-digitalocean.git /opt/honeypot
cd /opt/honeypot
cp .env.example .env
nano .env
bash manual-deployment.sh
Примечание: По умолчанию Terraform записывает состояние в
terraform/terraform.tfstateна вашем локальном компьютере. Этот файл содержит конфиденциальные выходные значения (IP капли, пароль Grafana, отпечаток SSH-ключа) и никогда не должен быть закоммичен..gitignoreпокрывает*.tfstateи*.tfstate.*.
Риски локального состояния:
apply могут повредить файлДля всего, что выходит за рамки личной лаборатории, переключитесь на удаленный бэкенд. terraform/backend.tf содержит закомментированную конфигурацию DigitalOcean Spaces (совместимую с S3).
Чтобы включить удаленный бэкенд:
terraform.tfvars): ```bash
export AWS_ACCESS_KEY_ID=
export AWS_SECRET_ACCESS_KEY=
backend "s3" в terraform/backend.tf и укажите имя вашего бакета и endpoint региона.terraform init -migrate-state, чтобы перенести существующее локальное состояние в Spaces..gitlab-ci.yml запускает три задания при каждом пуше в одной стадии validate:
Примечание:
terraform:fmtиterraform:validateблокируют конвейер при ошибке.checkov:scanнастроен сallow_failure: true, поскольку некоторые результаты являются преднамеренными компромиссами. Подавляйте конкретные приемлемые результаты с помощью встроенных комментариев# checkov:skip=CKXXX, а не отключайте задание полностью.
CKV_DIO_4 («Убедитесь, что входящий трафик брандмауэра не широко открыт») срабатывает один раз для всего ресурса digitalocean_firewall. Он подавляется одним комментарием # checkov:skip=CKV_DIO_4:, размещённым внутри блока ресурса в terraform/main.tf. В таблице ниже документировано, почему каждый открытый порт является намеренным.
flowchart TB internet((Internet))
subgraph tf["Terraform"] fw[DigitalOcean Cloud Firewall] droplet[Ubuntu 24.04 droplet] fw --> droplet end
subgraph compose["Docker Compose on droplet"] cowrie["Cowrie honeypot — SSH on port 22, Telnet on port 23"] promtail[Promtail with GeoIP labels] loki[Loki log store] grafana["Grafana — host :3000"] cowrie -->|JSON logs from ./data/cowrie-logs| promtail --> loki --> grafana end
internet -->|22/23 honeypot| fw internet -->|Admin SSH :2022| fw internet -->|Grafana :3000| fw droplet --> compose
## Наблюдения
Данные, собранные за 5 дней развертывания в реальных условиях (с 2026-05-05 по 2026-05-09):
| Метрика | Значение |
|---------------------------|----------|
| Всего подключений | 41,700 |
| Попыток входа | 15,400 |
| Успешных входов | 868 |
| Выполнено команд | 836 |
| Загружено файлов | 6 |
| Уникальных стран-источников | 106 |
### Страны с наибольшим количеством атак
| Страна | Подключения |
|-----------------|-------------|
| Германия | 9,768 |
| Нидерланды | 9,110 |
| США | 7,706 |
| Великобритания | 3,858 |
| Сингапур | 1,770 |
| Бельгия | 1,422 |
### Шаблоны учетных данных
Наиболее часто используемое имя пользователя — `root` с 3866 попытками, за ним следуют `admin` (728) и `user` (494), что отражает нацеленность автоматических сканеров на учетные данные по умолчанию и известные сервисные учетные записи. Самым распространенным паролем был `123456` (1480 попыток), затем `123` и `12345`, что соответствует инструментам для перебора по словарю.
### Поведение атакующего внутри фиктивной оболочки
868 попыток входа успешно прошли с использованием фиктивного набора учетных данных. Из этих сессий было выполнено 836 команд. Самой частой командой была `uname -s -v -n -r -m` (360 выполнений) — стандартная команда для снятия отпечатка системы, выполняемая автоматизированными скриптами пост-эксплуатации для идентификации целевой ОС и архитектуры перед развертыванием полезной нагрузки. Среди других наблюдаемых команд были `export HISTFILE=/dev/null` для отключения журналирования истории оболочки и `export HISTSAVE=/dev/null`, что указывает на активные попытки атакующих скрыть свои следы даже внутри системы, которую они считали скомпрометированной.
### Ключевой вывод
Объем автоматического сканирующего трафика — 41 700 подключений за 5 дней из 106 стран — подтверждает, что любой общедоступный SSH-сервис сталкивается с постоянными попытками перебора в течение нескольких часов после обнаружения. Поведенческая модель немедленного запуска `uname` с последующими командами подавления истории соответствует автоматизированным фреймворкам пост-эксплуатации, работающим с минимальным участием человека.
## Использование
### Использование дашборда Grafana
> Примечание: учетные данные дашборда задаются в terraform.tfvars или .env (для ручного развертывания)
Дашборд можно открыть по адресу:```
http://<your-droplet-ip>:3000
Вход с admin / <GRAFANA_ADMIN_PASSWORD>.
cowrie/etc/userdb.txt - содержит принятые учетные данные для honeypot.
В этом разделе подробно описаны решения, принятые в ходе разработки этого проекта, и возникшие проблемы. Он служит отражением процесса разработки проекта и извлеченных уроков. Перейдите к Security Considerations, если вы хотите только узнать, как пользоваться проектом.
Почему облачный хостинг?
Почему DigitalOcean?
Почему Terraform?
manual-deployment.sh, предназначена для пользователей, не знакомых с Terraform или предпочитающих не использовать его. Этот путь требует создания droplet, подключения к нему, клонирования репозитория и запуска скрипта. Terraform позволяет быстрее итерировать: редактируйте кодовую базу и переразвертывайте без повторения каждого ручного шага с локальной машины. Это также упрощает разрушение инфраструктуры и начало с чистого листа. Если проект вырастет из одного honeypot в honeynet, Terraform масштабируется более чисто, чем ручное развертывание или только легаси-скрипт.Почему Cowrie?
Почему Loki?
Почему Grafana?
Почему Promtail?
Почему GeoIP?
scripts/geoip-update.sh: без учетной записи или ключа API, что упрощает развертывание для любого, кто клонирует репозиторий. Встроенный этап GeoIP в Promtail читает локальный MMDB-файл и добавляет метки для панели Geomap в Grafana.Пошаговый обзор того, что происходит при настройке honeypot с помощью Terraform или скрипта ручного развертывания.
На вашей машине:
terraform/terraform.tfvars: токен API, путь к открытому ключу SSH, пароль Grafana, URL/ветку репозитория, опционально manage_do_firewallterraform init: установите провайдера DigitalOcean локальноterraform apply: Terraform строит план, затем создает или обновляет ресурсыВ DigitalOcean:
droplet_image, droplet_size, region и т.д.user_data устанавливается в сгенерированный cloud-init: при первой загрузке ВМ получает административный SSH-порт, repo_url / repo_branch и копию сгенерированного .env в кодировке base64 (пароль Grafana и ADMIN_SSH_PORT из env.tftpl)manage_do_firewall истинно):
terraform/main.tf)На droplet cloud-init выполняется автоматически:
package_update / package_upgrade, затем установка перечисленных пакетов (curl, git, ufw, …). На раннем этапе загрузки write_files создает /root/honeypot.env (сгенерированный Terraform env.tftpl в base64: пароль Grafana, ADMIN_SSH_PORT и т.д.)runcmd (порядок в terraform/templates/cloud-init.yaml.tftpl): установка бэкендов iptables / ip6tables в legacy/swapfile, fstab, swappiness)Внутри Docker Compose:
/ready на порту 3100 внутри контейнера; на хосте только 127.0.0.1:3100)depends_on в docker-compose.yml), затем запускаютсяdata/cowrie-logs для PromtailПользователь создает ВМ, подключается по SSH и запускает скрипт из клонированного репозитория.
manual-deployment.sh делает следующее:
.envapt update и apt upgradeufw и iptablessshd на ADMIN_SSH_PORT и отключение ssh.socketscripts/setup-firewall.shscripts/geoip-update.sh и ежемесячный crondocker compose pull / up -d, затем скрипт ожидает проверку работоспособности Loki и Grafana и выводит сводкуРассмотренные решения:
Решение:
Компромиссы:
Извлеченные уроки:
docker compose up завершался ошибкой, потому что порт 22 уже использовался и не мог быть привязан Cowrie.Рассмотренные решения:
sshd был неправильно настроен или прослушивал не тот портРешение:
sshd перемещается на ADMIN_SSH_PORT (по умолчанию 2022) и перезапускается первым, затем ssh.socket останавливается и отключается, чтобы освободить порт 22 для привязки Docker к Cowrie. Правила UFW применяются после обоих шагов, чтобы разрешить новый административный порт.Компромиссы:
Извлеченные уроки:
ssh.socket — это systemd-юнит сокета, который резервирует порт 22 для активации SSH по требованию. Он должен быть остановлен и отключен до того, как Docker сможет привязать порт хоста 22 для Cowrie. Если он все еще активен, docker compose up завершается ошибкой «address already in use».GeoIP-функциональность
Grafana HTTPS
Функциональность прокси-сервера
GNU General Public License Version 2.0 (GPLv2) Полный текст лицензии см. в файле LICENSE.
| Job | Tool | Назначение |
|---|
terraform:fmt | hashicorp/terraform:1.8 | Форматирование: ошибка, если файл требует terraform fmt |
terraform:validate | hashicorp/terraform:1.8 | Проверка конфигурации без обращения к DigitalOcean |
checkov:scan | bridgecrew/checkov:latest | Ошибки конфигурации IaC в коде Terraform |
| Check ID | Resource | Finding | Decision |
|---|
CKV_DIO_4 | digitalocean_firewall.honeypot — входящий SSH для администратора | Порт SSH для администратора открыт на 0.0.0.0/0 | Принято — ограничение до фиксированного IP непрактично для портативной лаборатории; рекомендовано в продакшене |
CKV_DIO_4 | digitalocean_firewall.honeypot — порт 22 входящий | Порт 22 открыт на 0.0.0.0/0 | Намеренно — это поверхность SSH-ловушки; ограничение источника лишает смысла |
CKV_DIO_4 | digitalocean_firewall.honeypot — порт 23 входящий | Порт 23 открыт на 0.0.0.0/0 | Намеренно — поверхность Telnet-ловушки; та же логика, что и для порта 22 |
CKV_DIO_4 | digitalocean_firewall.honeypot — порт 3000 входящий | Grafana HTTP открыт на 0.0.0.0/0 | Принято для доступности лаборатории — известное ограничение описано в Соображения безопасности; производственные развертывания должны ограничить доступ до известного IP-адреса или использовать прокси через HTTPS на порту 443 |
| Панель | Описание |
|---|
| Карта атак мира | Геокарта со слоями тепловой карты и маркеров, показывающая происхождение каждого соединения |
| Всего подключений | Количество входящих сессий honeypot за выбранный промежуток времени |
| Попытки входа | Общее количество попыток подбора учетных данных |
| Успешные входы | Атакующие, которые совпали с учетными данными userdb.txt |
| Выполненные команды | Команды оболочки, выполненные внутри поддельной оболочки |
| Загруженные файлы | Вредоносное ПО/скрипты, захваченные через wget/curl |
| Скорость подключения | Временной ряд: подключения/с, неудачные входы/с, успешные/с |
| Самые популярные имена пользователей | Наиболее часто используемые SSH-имена пользователей |
| Самые популярные пароли | Наиболее часто используемые пароли |
| Самые популярные команды | Наиболее часто выполняемые команды оболочки |
| Атаки по странам | Таблица подключений по странам |
| Последние события | Живой поток логов последних событий |
| Загрузки файлов | Таблица каждого файла, который атакующий пытался загрузить |
systemctl enable --now dockersshd на ADMIN_SSH_PORT; отключение ssh.socket, чтобы порт хоста 22 был свободен для Cowriegit clone из repo_url / repo_branch в /opt/honeypot (должен включать docker-compose.yml и конфигурации).env на диске: перемещение /root/honeypot.env в /opt/honeypot/.env (режим 600)scripts/setup-firewall.sh (UFW для административного SSH, 22, 23, 3000)scripts/geoip-update.sh (DB-IP City Lite в geoip/); добавление ежемесячного cron для того же скриптаdata/cowrie-logs и data/cowrie-dl с правами, которые ожидает Compose/opt/honeypot, docker compose pull, затем docker compose up -d