
Cowrie、Loki、Promtail、Grafanaを使用して構築された中程度の対話型SSH/Telnetハニーポット - GitLab CI検証パイプラインを使用してTerraform経由でDigitalOcean上にプロビジョニング。
Terraformを使用してDigitalOceanのドロップレット上にデプロイされたSSH/Telnetハニーポットスタック。攻撃は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
## ハードウェア要件
> 注意: これらの要件は2026年5月時点のDigitalOcean Basic Dropletプランに基づくもので、プロジェクトを実行するための最小要件です。
- プロバイダー: DigitalOcean
- プラン: Basic Droplet - 1 Intel vCPU
- RAM: 1 GB (+2 GB スワップ)
- ストレージ: 35 GB NVMe SSD
- OS: Ubuntu 24.04 LTS
## インストールとセットアップ
> 注意: インストール後は、新しい端末を開いて `ADMIN_SSH_PORT` (デフォルト: 2022) でまだSSH接続できることを確認してから、元のセッションを閉じることをお勧めします。
### Terraform によるデプロイ (推奨)
1. 読み取り/書き込み権限を持つDigitalOcean APIトークンを作成します:
- DigitalOceanにログインし、Account > API > Tokens > Generate New Token に移動します。
- トークンに名前を付け(例: "Cowrie Honeypot")、"Full Access"権限を選択します。
- "Generate Token"をクリックし、トークンの値を安全な場所にコピーします(後で確認できなくなります)。
2. ローカルマシンでSSH鍵ペアを作成し、公開鍵のパスをコピーします。
3. `terraform`ディレクトリに移動し、変数ファイルをコピーして編集します:
> 注意: 適用前に `terraform.tfvars` で少なくとも `do_token`、`ssh_public_key_path`、`grafana_admin_password` を設定する必要があります。```bash
cd terraform
cp terraform.tfvars.example terraform.tfvars
注: Terraform がローカルマシンにインストールされている必要があります。手順については、Terraform Installation Guide を参照してください。```bash terraform init # Initialize Terraform and download providers terraform apply
5. テスト中の場合 - 置き換えで再デプロイ:```bash
terraform apply -replace="digitalocean_droplet.honeypot"
### 手動デプロイメント(レガシー)
1. 上記のハードウェア要件とあなたのSSHキーを備えたDigitalOceanドロップレットを作成します。
2. ドロップレットにSSH接続するか、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=
terraform/backend.tf 内の backend "s3" ブロックのコメントを解除し、バケット名とリージョンエンドポイントを入力します。terraform init -migrate-state を実行して、既存のローカルステートを Spaces に移行します。.gitlab-ci.yml は、プッシュのたびに単一の validate ステージで 3 つのジョブを実行します。
注:
terraform:fmtとterraform:validateは失敗するとパイプラインをブロックします。checkov:scanはallow_failure: trueに設定されています。これは一部の検出結果が意図的なトレードオフであるためです。ジョブ全体を無効にするのではなく、許容できる特定の検出結果については、インラインの# checkov:skip=CKXXXコメントで抑制してください。
CKV_DIO_4(「ファイアウォールの受信が完全に開いていないことを確認」)は、digitalocean_firewall リソース全体に対して 1 回発生します。これは terraform/main.tf のリソースブロック内に配置された単一の # checkov:skip=CKV_DIO_4: コメントで抑制されています。以下の表は、各開放ポートが意図的である理由を示しています。
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` で 3,866 回、次いで `admin` (728 回)、`user` (494 回) であり、デフォルト認証情報や既知のサービスアカウントを標的とする自動スキャナの存在が確認された。最も多いパスワードは `123456` (1,480 回) で、`123`、`12345` がそれに続き、辞書ベースのブルートフォースツールに典型的なパターンを示している。
### 偽シェル内での攻撃者の行動
偽の認証情報セットに対して 868 件のログイン試行が成功した。これらのセッションのうち、836 件のコマンドが実行された。最も多いコマンドは `uname -s -v -n -r -m` (360 回実行) であり、これはペイロード展開前に標的のOSとアーキテクチャを識別するために自動化された侵害後スクリプトにより実行される標準的なシステムフィンガープリンティングコマンドである。その他に観測されたコマンドには、シェル履歴ログを無効にする `export HISTFILE=/dev/null` や `export HISTSAVE=/dev/null` が含まれており、攻撃者が自分たちが侵害したと信じているシステム内でも積極的に痕跡を隠そうとしていることが示された。
### 重要な洞察
自動化されたスキャントラフィックの量 — 5日間で106カ国から41,700件の接続 — は、公開されているSSHサービスが暴露から数時間以内に常にブルートフォース攻撃にさらされることを確認している。すぐに `uname` を実行し、続いて履歴抑制コマンドを実行する行動パターンは、人間の関与を最小限に抑えて動作する自動化された侵害後フレームワークと一致している。
## 使用方法
### Grafanaダッシュボードの利用
> 注:ダッシュボード認証情報は terraform.tfvars または .env(手動デプロイの場合)に設定されています。
ダッシュボードには以下のアドレスでアクセスできます。```
http://<your-droplet-ip>:3000
admin / <GRAFANA_ADMIN_PASSWORD> でログインします。
cowrie/etc/userdb.txt - ハニーポットで許可される認証情報が含まれています。
このファイルを編集して、ハニーポットの認証情報を調整してください。
許可されたログインにより、攻撃者はすべてのコマンドが記録される偽装シェルにドロップされます。
拒否されたエントリは、失敗した試行として記録されます。
このセクションでは、本プロジェクトの開発中に下された判断と直面した問題について詳しく説明します。これは、プロジェクトの開発プロセスと学んだ教訓を振り返る役割を果たします。プロジェクトの使用方法だけを知りたい場合は、セキュリティに関する考慮事項にスキップしてください。
なぜクラウドホスティングなのか?
なぜDigitalOceanなのか?
なぜTerraformなのか?
manual-deployment.sh は、Terraformに詳しくない、または使用したくないユーザー向けです。この方法では、ドロップレットをプロビジョニングし、接続し、リポジトリをクローンし、スクリプトを実行する必要があります。Terraformを使用すると、コードベースを編集して再デプロイする際に、ローカルマシンから各手動ステップを繰り返すことなく、より迅速な反復が可能になります。また、インフラを解体して最初からやり直すのも簡単です。プロジェクトが単一のハニーポットからハニーネットへと成長する場合、Terraformは手動プロビジョニングや従来のスクリプトだけよりもクリーンにスケールします。なぜCowrieなのか?
なぜLokiなのか?
なぜGrafanaなのか?
なぜPromtailなのか?
なぜGeoIPなのか?
scripts/geoip-update.sh を介してDB-IP City Liteを使用しています。アカウントやAPIキーは不要で、リポジトリをクローンする誰でも簡単にデプロイできます。Promtailの組み込みGeoIPステージはローカルのMMDBファイルを読み取り、Grafana Geomapパネルのラベルを追加します。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に設定される: 初回起動時にVMは管理SSHポート、git repo_url / repo_branch、生成された .env(Grafanaパスワードと env.tftpl からの ADMIN_SSH_PORT)のbase64エンコードコピーを取得するmanage_do_firewall がtrueの場合のみ):
terraform/main.tf を参照)ドロップレット上では、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 をレガシーバックエンドに設定/swapfile、fstab、swappiness)Docker Compose内:
/ready;ホスト上では 127.0.0.1:3100 のみ)docker-compose.yml の depends_on)、その後起動するdata/cowrie-logs に書き込み、Promtailがそれを読み取るユーザーがVMを作成し、SSHで接続し、クローンしたリポジトリからスクリプトを実行します。
manual-deployment.sh は以下を行います:
.env をロードし検証apt update & apt upgradeufw と iptablessshd を ADMIN_SSH_PORT で起動し、ssh.socket を無効化scripts/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 を停止・無効にして、DockerがCowrie用にポート22をバインドできるようにする。UFWルールは両方のステップの後に適用され、新しい管理ポートを許可する。トレードオフ:
学んだ教訓:
ssh.socket はsystemdソケットユニットであり、オンデマンドのSSHアクティベーションのためにポート22を予約しています。DockerがCowrie用にホストポート22をバインドできるようにするには、これを停止して無効にする必要があります。これがアクティブなままの場合、docker compose up は「address already in use」で失敗します。GeoIP機能
Grafana HTTPS
プロキシサーバー機能
GNU General Public License Version 2.0 (GPLv2) 完全なライセンステキストは LICENSE ファイルを参照してください。
| ジョブ | ツール | 目的 |
|---|
terraform:fmt | hashicorp/terraform:1.8 | フォーマット: いずれかのファイルが terraform fmt を必要とする場合に失敗します |
terraform:validate | hashicorp/terraform:1.8 | DigitalOcean に問い合わせずに設定の妥当性を検証します |
checkov:scan | bridgecrew/checkov:latest | Terraform コード内の IaC の設定ミスをチェックします |
| チェック ID | リソース | 検出結果 | 判断 |
|---|
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 に制限するか、ポート 443 で HTTPS 経由のプロキシを使用する必要があります。 |
| パネル | 説明 |
|---|
| Attack World Map | すべての接続の発信元を示す、ヒートマップとマーカーレイヤーを重ねたジオマップ |
| Total Connections | 選択した時間範囲における受信ハニーポットセッションの数 |
| Login Attempts | 認証情報に対する総ブルートフォース試行回数 |
| Successful Logins | userdb.txt の認証情報と一致した攻撃者数 |
| Commands Executed | 偽装シェル内で実行されたシェルコマンド数 |
| Files Downloaded | wget/curl で取得されたマルウェア・スクリプト数 |
| Connection Rate | 時系列グラフ: 接続数/秒、ログイン失敗数/秒、成功数/秒 |
| Top Usernames | 最も試行されたSSHユーザー名 |
| Top Passwords | 最も試行されたパスワード |
| Top Commands | 最も実行されたシェルコマンド |
| Attacks by Country | 国別の接続テーブル |
| Recent Events | 最新イベントのライブログストリーム |
| File Downloads | 攻撃者が取得しようとしたすべてのファイルのテーブル |
systemctl enable --now dockersshd を ADMIN_SSH_PORT で起動; ssh.socket を無効にして、ホストポート22をCowrie用に解放git clone を repo_url / repo_branch から /opt/honeypot へ(docker-compose.yml と設定ファイルを含む必要あり).env: /root/honeypot.env を /opt/honeypot/.env に移動(モード600)scripts/setup-firewall.sh(管理SSH、22、23、3000に対するUFW)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