はじめに
こんにちは、研究開発部 研究開発担当の北村と市岡です。
このたびMWS Cupのスコアサーバを作ってきました。様子は以下の記事で書きましたのでぜひぜひ見てください!
https://blog.nflabs.jp/entry/2022/10/31/130107
スコアサーバはOSSのCTFdを使用してAWS上に構築をおこないました。
CTFdはその名の通りCTF用のサーバを簡単に構築できるもので、幅広く利用されています。
幅広く利用されている反面、CTFdの使い方を日本語で解説した記事って見たことが無いって思ったので、この記事ではCTFdの使い方を日本語で説明してみたいと思います。
詳細な設定については英語の公式ドキュメントを参照していただければと思います。
僕たちが英語を読むのが苦手だったのもあり、同じような境遇の方のお手伝いになればと思います。
本記事の特徴
- HTTPSでCTFdにアクセスする方法が書いてある
- データベースをRDSにした場合の設定方法が書いてある
- Basic認証の設定方法が書いてある
- CTFdのプロセス数を設定する方法が書いてある
制限
本記事では以下の点を考慮していません。
- AWSでのリソースの作成方法は書いていません。
- CTFdが使うメールサーバを用意していません。MWS CupではSlackで問い合わせを受け、パスワード再発行などは担当者が実施しました。
AWSのリソースを作成する
AWSのリソースについては概要のみを説明します。

上記の構成になるようにTerraformでリソースをデプロイしました。CTFdは上図のEC2インスタンスにインストールを行います。
最終的に以下を満たせば問題ないです。
- EC2インスタンスが外部からHTTPおよびHTTPS接続できること
- 自身がSSHでログインできること
- EC2インスタンスのシェルからRDSに接続できること
- EC2インスタンスのAMIはUbuntuを選択
- RDSはMySQLを選択
CTFdをインストール
DockerおよびDocker Composeのインストール
まずはEC2インスタンスにログインし、必要なソフトウェアをインストールします。
本記事では、CTFdをDocker Composeで起動します。このため、以下の記事を参考に、DockerおよびDocker Composeをインストールしました。
まずは、既にインストールされているパッケージを最新化します。
sudo apt update sudo apt upgrade sudo reboot
次に、再度EC2インスタンスにログインしたうえで、DockerおよびDocker Composeをインストールします。
sudo apt-get update
sudo apt-get install \
ca-certificates \
curl \
gnupg \
lsb-release
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
CTFdのダウンロード
DockerとDocker Composeをインストールできたら、CTFdの最新版をインストールします。wgetで指定するURLは、CTFdのGitHubから最新のバージョンのURLを確認して置き換えてください。
CTFdのリリース:https://github.com/CTFd/CTFd/releases
wget https://github.com/CTFd/CTFd/archive/refs/tags/3.5.0.zip sudo apt install unzip unzip 3.5.0.zip cd CTFd-3.5.0
SSL/TLS証明書の取得
情報セキュリティの学会のイベントということでSSL/TLS証明書を取得し、HTTPSで通信させることにしました。
先に参考にしたWebサイトを載せておきます。
以下を参考にCertbot を用いて、SSL/TLS証明書を取得しました。
https://medium.com/csictf/self-hosting-a-ctf-platform-ctfd-90f3f1611587
具体的な手順を説明します。
まずはCertbotをインストールし、Certbotを使って証明書を取得します。
sudo apt-get update sudo apt-get install software-properties-common sudo add-apt-repository universe sudo apt-get update sudo apt-get install certbot python3-certbot-nginx sudo systemctl stop nginx sudo systemctl disable nginx sudo certbot certonly --standalone --debug -v
上記の手順を実施することで、Let's encryptにメールアドレスが登録され、3か月後に、もうすぐ証明書が失効する連絡が来ます。3か月以上利用する場合は証明書の更新が必要です。
その後、以下の手順でNginxの設定ファイルと同じディレクトリにファイルを配置します。example.comを取得したドメインに置き換えてください。
$ pwd /home/ubuntu/CTFd-3.5.0/conf/nginx sudo cp /etc/letsencrypt/live/example.com/fullchain.pem . sudo cp /etc/letsencrypt/live/example.com/privkey.pem . sudo chown ubuntu:ubuntu fullchain.pem sudo chown ubuntu:ubuntu privkey.pem
Basic認証に必要なfileの作成
MWS CupではスコアサーバにBasic認証をかけていました。ここでBasic認証の手順も説明します。
まずはnginxのフォルダでBasic認証に必要な.htpasswdファイルを作成します。以下のコマンドで.htpasswdファイルが作れます。
$ pwd /home/ubuntu/CTFd-3.5.0/conf/nginx sudo apt install apache2-utils htpasswd -c .htpasswd "ユーザの名前"
http.confの修正
次に/home/ubuntu/CTFd-3.5.0/conf/nginx/http.confに設定を入れます。
score.example.comを実際のスコアサーバのFQDNに置き換えます。
修正した点は主に以下の4つです。
- 80番ポートから443番ポートへのリダイレクトを記述
- 80番ポートで受け入れる設定だったCTFdへのリバースプロキシの設定を443番ポートへ変更
- SSL/TLSの証明書に関する記述を追加
- Basic認証の記述を追加
最終的な設定ファイルは以下のような感じです。(http.conf)
worker_processes 4;
events {
worker_connections 1024;
}
http {
# Configuration containing list of application servers
upstream app_servers {
server ctfd:8000;
}
# HTTP通信でアクセスしたときは、HTTPSヘリダイレクト(以下5行を追加)
server {
server_name score.example.com;
listen 80;
return 301 https://$host$request_uri;
}
server {
server_name score.example.com;
# 80番ポート向けだったものを443番ポート向けに修正(以下の1行を修正)
listen 443 ssl;
# HTTPS通信用の証明書と秘密鍵(以下2行を追加)
ssl_certificate /etc/nginx/fullchain.pem;
ssl_certificate_key /etc/nginx/privkey.pem;
client_max_body_size 4G;
# Basic認証のために以下の2行を追加
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/conf.d/.htpasswd;
# Handle Server Sent Events for Notifications
location /events {
proxy_pass http://app_servers;
proxy_set_header Connection '';
proxy_http_version 1.1;
chunked_transfer_encoding off;
proxy_buffering off;
proxy_cache off;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
# Basic認証のために以下の1行を追加
proxy_set_header Authorization "";
}
# Proxy connections to the application servers
location / {
proxy_pass http://app_servers;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
# Basic認証のために以下の1行を追加
proxy_set_header Authorization "";
}
}
}
docker-compose.ymlの修正
ここまで、さまざまなファイルを作りました。これらのファイルをdockerコンテナ上にコピーするため、/home/ubuntu/CTFd-3.5.0/docker-compose.ymlを修正します。
CTFdには、docker-compose.ymlで以下の4つのサーバを立てることになっています。
- ctfd (CTFd本体)
- nginx (HTTPプロキシサーバ)
- db (データベースサーバ)
- cache (キャッシュサーバ)
今回はdbをRDSへ移行したため、dbを削除し、nginxとctfdの設定を変更しました。
修正点は以下の4つです。
- CTFdのWORKERSの数を増やす(プロセス数を増やす)
- DATABASE_URLをRDSのエンドポイントに変更する
docker-compose.ymlのdbコンテナの記述部分を削除するdocker-compose.ymlのctfdコンテナのports設定の部分を削除する(※nginxからのアクセスのみを許可するため)
WORKERSを増やすと、CTFdは複数のプロセスになるため、複数のCPUで動作するようになります。
具体的な設定内容を以下で説明します。CTFdではWORKERSの数を増やすためにランダムな文字列が必要です。以下のコマンドにより、ランダムな文字列を取ります。(ここでは、aaaaaaaaaが得られたことにします。)
dd if=/dev/urandom bs=1 count=64 2>/dev/null| md5sum | head -c 13
1.のWORKERSの数を増やすには、以下の2つを変更する必要があります。
- SECRET_KEYの追加
- WORKERSを1より大きな数値に変更(vCPUの数に一致させるとよい)
最終的にdocker-compose.ymlは以下のようになります。修正箇所の直前にコメントをかきました。
version: '2'
services:
ctfd:
build: .
user: root
restart: always
# (1箇所目)ports設定のコメントアウト(以下2行をコメントアウト)
# ports:
# - "8000:8000"
environment:
# (2箇所目) SECRET_KEYを追加 (aaaaaaaaaを上記で生成したランダムな文字列に置き換える)
- SECRET_KEY=aaaaaaaaa
- UPLOAD_FOLDER=/var/uploads
# (3箇所目) DATABASE_URLを修正(RDSのエンドポイントURL、Username、Passwordに修正)
- DATABASE_URL=mysql+pymysql://<username>:<password>@wwww.xxxxxxxxxx.ap-northeast-1.rds.amazonaws.com/ctfd
- REDIS_URL=redis://cache:6379
# (4箇所目) WORKERSを4に増やした(vCPUの個数と一致させるのがおすすめ)
- WORKERS=4
- LOG_FOLDER=/var/log/CTFd
- ACCESS_LOG=-
- ERROR_LOG=-
- REVERSE_PROXY=true
volumes:
- .data/CTFd/logs:/var/log/CTFd
- .data/CTFd/uploads:/var/uploads
- .:/opt/CTFd:ro
# (5箇所目)dbを消したため、depends_onも削除(以下2行をコメントアウト)
# depends_on:
# - db
networks:
default:
internal:
nginx:
image: nginx:stable
restart: always
volumes:
- ./conf/nginx/http.conf:/etc/nginx/nginx.conf
# (6箇所目)SSL/TLSの証明書、秘密鍵、.htpasswdの追加(以下3行を追加)
- ./conf/nginx/fullchain.pem:/etc/nginx/fullchain.pem
- ./conf/nginx/privkey.pem:/etc/nginx/privkey.pem
- ./conf/nginx/.htpasswd:/etc/nginx/conf.d/.htpasswd
ports:
- 80:80
# (7箇所目)443番ポートを追加(HTTPS追加)(以下1行を追加)
- 443:443
depends_on:
- ctfd
#(8箇所目)データベースのコメントアウト(以下14行をコメントアウト)
# db:
# image: mariadb:10.4.12
# restart: always
# environment:
# - MYSQL_ROOT_PASSWORD=ctfd
# - MYSQL_USER=ctfd
# - MYSQL_PASSWORD=ctfd
# - MYSQL_DATABASE=ctfd
# volumes:
# - .data/mysql:/var/lib/mysql
# networks:
# internal:
# This command is required to set important mariadb defaults
# command: [mysqld, --character-set-server=utf8mb4, --collation-server=utf8mb4_unicode_ci, --wait_timeout=28800, --log-warnings=0]
cache:
image: redis:4
restart: always
volumes:
- .data/redis:/data
networks:
internal:
networks:
default:
internal:
internal: true
CTFdの起動
最後に以下のコマンドでサーバを起動すると使えるようになります。
sudo docker compose up -d
おわりに
今回はCTFdの構築方法を紹介しました。CTFdを使ってイベントを開催する方々の参考になればうれしいです。
身内で勉強会をするときなどにもちょうど良いと思いますので、みなさんぜひぜひ使ってみてください!