Jeopardy形式のCTF大会の問題サーバーのフレームワークとして有名なCTFdというものがありまして、それをAWS上でビルドして公開するまでの手順をまとめます。多分一番基本的なやり方をしていると思う。
細かいチューニングは経験がないので研究途中です…この知識で十分とは思いませんが、この通りにやるといつでもCTF大会を開催できる!?かもしれない(保証はしません)そんな記事です。
参考にさせていただいたページ
準備
ドメインを買う
持ってる人はいらないですが、持ってない人はドメインを買いましょう。こだわらなければ1年1円から買えます。今回私はお名前.comで買いました。

WEB上の画面からぽちぽちやるだけなので難しくないと思います。個人なら.netとか.siteとか.xyzとかが安くて良いかもしれない。お好みでどうぞ。ドメイン名によって値段が違いますので色々比べてみるとよさそうです。

ドメイン名を決めて申し込もうとすると、サーバーの申込みをしましょう!お忘れではないですか?!サーバを追加する必要がありますよ!って繰り返しオススメされますが、今回はAWSを使うので無慈悲に「利用しない」を選びます。

購入後にメールアドレスの認証を求められることがあるらしいので、メールがきたらポチッとします。
AWSのアカウントつくる
これも持ってる人はいらないですが、初めてでもぽちぽちやるだけなので難しくないと思います。手順がわかりやすく書いてあるので見ながらやりましょう。無料アカウントで良いです。
EC2インスタンスを起動させる
多分一番オーソドックスと思われる構成でつくってみたいと思います。右上でリージョンを選ぶ。普通に日本(アジアパシフィック(東京) )を選んでますがこれってなんか違うの?

左上の検索窓にec2と入力してサービスを呼び出す。

インスタンスを起動をクリック。
インスタンスを起動
適当に名前をつけて、Ubuntuを選択して、インスタンスタイプはとりあえずt2.microを選びました(大会として運営するならもっと良いインスタンス選んだほうがいいのかもしれない、わからん。このへんはもうちょっと研究が必要だと思う)
マシンイメージは22系も選べるけど20.04を選ぶ(22だとうまく動かなかった)

キーペア(ログイン)
キーを作っていない場合はキーペアの作成をクリックして適当に名前つけてキーペアを作成します。名前はなんでもよいですが、後からサーバに接続するときにわかりやすい名前がいいのではないでしょうか。作成するとsshでサーバにログインするときに使う鍵ファイルがダウンロードできます。(.pemでダウンロードしました)

ダウンロードしてきた鍵を.sshディレクトリに移動させて権限つけておきます。
# 鍵を標準の置き場所に移動させる
┌──(nmz㉿kali)-[~]
└─$ mv ~/Downloads/<キーペア名>.pem ~/.ssh/
# 権限つけておく
┌──(nmz㉿kali)-[~]
└─$ chmod 600 ~/.ssh/<キーペア名>.pem
ネットワーク設定
ネットワークの設定のとこ。注意書きにある通りSSHのソースは自分のIPアドレスからだけに制限しておくと良い気がします。なんかあっても怖いし。あとインターネットからのHTTPS/HTTPトラフィックを許可する。

ストレージを設定
ストレージを設定(デフォルトのまま)してインスタンスを起動をクリック。

少し待つとインスタンスが起動して実行中の表示になる。
SSHでテスト接続する
起動したインスタンスのパブリックIPアドレスを確認する

キーペアのところでダウンロードしてきた鍵を使って接続してみる。
デフォルトのユーザー名はubuntu(ec2-userではないので注意←これでちょっとハマった…)
# 鍵を指定してssh接続
┌──(nmz㉿kali)-[~]
└─$ ssh -i .ssh/<キーペア名>.pem ubuntu@<IPアドレス>
つながることを確認したら作業用ユーザー作っておく
# ctfユーザーを作る
ubuntu@ip-XXX-XXX-XXX-XXX:~$ sudo adduser ctf
Adding user `ctf' ...
Adding new group `ctf' (1001) ...
Adding new user `ctf' (1001) with group `ctf' ...
Creating home directory `/home/ctf' ...
Copying files from `/etc/skel' ...
New password:
Retype new password:
passwd: password updated successfully
Changing the user information for ctf
Enter the new value, or press ENTER for the default
Full Name []:
Room Number []:
Work Phone []:
Home Phone []:
Other []:
Is the information correct? [Y/n] Y
# 作ったユーザーにsudoつける
ubuntu@ip-XXX-XXX-XXX-XXX:~$ sudo gpasswd -a ctf sudo
Adding user ctf to group sudo
# ユーザー変更
ubuntu@ip-XXX-XXX-XXX-XXX:~$ su ctf
Password:
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.
ubuntu@ip-XXX-XXX-XXX-XXX:/home/ubuntu$ cd ~
Elastic IPの設定
さっき確認したインスタンスのIPアドレスは、再起動のたびに変わることがあります。それをいい感じに固定してくれるサービスです。
参考にさせていただいたページ
検索ボックスでipとかで検索してElastic IPの機能を呼び出します。

Elastic IPアドレスを割り当てるをクリックする。
AmazonのIPv4アドレスプールが選択されていることを確認して、そのまま割り当てをクリック。

割り当てが成功したらアクション>Elastic IPアドレスの関連付け
インスタンスとプライベートIPアドレスは、さっき起動させたEC2サーバのものを入力する。カーソルを合わせると選択肢が出てくるのでぽちっと選ぶだけ。

※Elastic IPは基本的には無料ですが。この関連付けをやっとかないと課金されるらしいです。リソースの無駄遣いに厳しいAmazon。
これでIPアドレスが割り当てられたIPv4アドレスに変わりました。念の為新しいIPアドレスにSSHでログインできるかもう一回試してみましょう。
DNSの設定
IPアドレス直打ちでも接続はできますがDNSを設定してドメイン名でアクセスできるようにしてみます。せっかく買ったし。
参考にさせていただいたページ
Route53の設定
検索ボックスでrouteとかで検索してDNSサービスのRoute53を呼び出す。

ホストゾーンの作成をクリック。
準備のところで買ったドメイン名を入力する。サブドメイン使いたい場合も、このとき入力するのはドメイン名だけです。入力したらもっかいホストゾーンの作成をクリック。

NSレコードの値/トラフィックのルーティング先ってところにネームサーバのアドレスが4つ表示されるのでどっかにメモしておきます。このドメインを管理しているDNSサーバはこれだよって意味です。

お名前.comの設定
お名前.com Naviにログインします
TOPに移動して、設定したいドメインの初期設定(2回め以降はその他)クリック

ネームサーバーの選択のところでその他のサービスを選び、さっきコピーしたネームサーバのアドレスを入力する(4つめはプラスマークを押すと入力できます)確認>OKで設定できる。

※インターネットの環境により、反映完了まで24時間から72時間かかる場合があります。
だそうです。
Aレコードの作成
Aレコードを設定するとDNSサーバさんがこのドメインのIPアドレスはこれだよーってそれにそって回答してくれます。DNSたちに自分の存在を知らしめてやりましょう。AWSのRoute53に戻って、ホストゾーンの詳細画面でレコードを作成をクリック

サブドメインを使いたい場合はこのレコード名のところにサブドメイン名を入れます。使いたくなければ別に空欄で良いです。あと値のところにさっきのElastic IPで割り当てられたIPアドレスを入れて、レコードタイプがAになっていることとシンプルルーティングになってることを確認してレコードを作成。

設定ができてるか確認する
DNSが浸透したら(浸透言うな!)nslookupコマンドででRoute53のネームサーバが返ってくるようになるのでそしたら完了。
nslookup -type=NS <ドメイン名>

うまくいってれば設定したドメイン名でssh接続できるようになってるはず。
┌──(nmz㉿kali)-[~]
└─$ ssh -i ~/.ssh/<キーペア名>.pem ubuntu@<ドメイン名>
CTFdのインストール
とりあえずCTFdのマニュアルどおりにやってみる。
# とりあえずアップデート
ctf@ip-XXX-XXX-XXX-XXX:~$ sudo apt update
ctf@ip-XXX-XXX-XXX-XXX:~$ sudo apt upgrade
<略>
# CTFdをクローン
ctf@ip-XXX-XXX-XXX-XXX:~$ git clone https://github.com/CTFd/CTFd.git
Cloning into 'CTFd'...
remote: Enumerating objects: 14427, done.
remote: Counting objects: 100% (1501/1501), done.
remote: Compressing objects: 100% (917/917), done.
remote: Total 14427 (delta 871), reused 972 (delta 550), pack-reused 12926
Receiving objects: 100% (14427/14427), 25.91 MiB | 11.83 MiB/s, done.
Resolving deltas: 100% (8935/8935), done.
# pip入ってなかったのでインストール
ctf@ip-XXX-XXX-XXX-XXX:~$ sudo apt install python3-pip
# CTFdディレクトリにprepareシェルが準備されているので実行
ctf@ip-XXX-XXX-XXX-XXX:~$ cd CTFd
ctf@ip-XXX-XXX-XXX-XXX:~/CTFd$ ./prepare.sh
<略>
# 足りないぽい?のでrequirementsも実行
ctf@ip-XXX-XXX-XXX-XXX:~/CTFd$ pip install -r requirements.txt
<略>
Successfully installed zope-event zope-interface
# docker-compose入れる
ctf@ip-XXX-XXX-XXX-XXX:~/CTFd$ sudo apt install docker-compose
<略>
# docker-compose.ymlが準備されているのでビルド
ctf@ip-XXX-XXX-XXX-XXX:~/CTFd$ sudo docker-compose build
<略>
Successfully tagged ctfd_ctfd:latest
# Dockerイメージの確認
ctf@ip-XXX-XXX-XXX-XXX:~/CTFd$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ctfd_ctfd latest c294d6814f49 28 seconds ago 654MB
python 3.9-slim-buster 975c845dddf2 2 days ago 118MB
# このまま上げてもWARNINGが出るので言われるままにアップグレード
ctf@ip-XXX-XXX-XXX-XXX:~/CTFd$python3 -m pip install --upgrade pip
<略>
# 一応再起動
ctf@ip-XXX-XXX-XXX-XXX:sudo reboot
<しばし待ってもう一度sshでログインする>
# パイルダーオーン!
ctf@ip-XXX-XXX-XXX-XXX:~/CTFd$ sudo docker-compose up
<略>
ちょっと待ってからブラウザで http://<ドメイン名>/setup に接続しにいくとCTFdがたちあがってる。Dockerってすごいなあ(小並感)

SSL化する
この時点では保護されてない通信って表示される。内輪の大会なら別に良いのかもしれないけどどかっこ悪いのでhttpsで接続できるようにしたいですよねー(いや格好の問題でもないか…)

参考にさせていただいたページ
Certificate Managerの設定
今まであまり気にしてなかったのですがAWSには証明書を発行してくれるサービスもちゃんとあるんですね…いい時代になったものです…(年寄り)
検索ボックスでacmとか入力してCertificate Managerを呼び出す。

証明書のリクエスト

パブリック証明書をリクエスト

サブドメインでも使えるように完全修飾ドメイン名のところに、取得したドメイン名の頭にワイルドカードをつけたものをいれとく。推奨らしいのでDNS検証にします。リクエストをクリック

CNAMEレコードの作成
DNSサーバの情報は、原則としてドメインの管理者しか変更することができないので、認証局が指定したCNAMEレコードを設定することで私がドメインの管理者です!って証明します。DNSサーバも認証局もどっちもAmazonなのでちょっと自作自演ぽい感じがします(気のせい)
証明書をリクエストすると保留中の検証って状態になってるはずなので、IDのところをクリックする。

Route 53でレコードを作成をクリック

レコードを作成をクリック

しばらくするとステータスが発行済みになります(ステータスがかわるまで15分くらいかかったので手順間違ってるのかと思った、落ち着いてお茶でも飲みましょう)

ALB(Application Load Balancer)の設定
ロードバランサーっていうのはサーバの負荷を分散してくれるやつ〜って思ってたんだけど、HTTPSで転送されるデータの暗号化と復号をしてくれる役割もあるんだそうな。だからリクエストの受付係として置いておくことでサーバさん的には自分で暗号のことを考えなくて良くなるってことでしょうか。ちなみに少しお金がかかるようです。まあ良さそうなので置いていきましょう。
検索ボックスにalbとか入力してロードバランサーを呼び出す。

ロードバランサーの作成をクリック
今まで日本語化されてたのに突然英語に…Application Load BalancerをCreateします。

Basic configration
名前をつける(あとから変更できないそうです)

Network mapping
VPCの設定はデフォルトで良さそう。Mappingsのところは上から2つにチェックを入れる。

Security groups
Create new security groupでセキュリティグループをつくる。セキュリティグループは要するにファイアウォールの設定のことだと思う。
ルールを追加から80と443は全て受け付けるようにして、名前は適当につけてセキュリティグループを作成。

くるくるの矢印マークをクリックすると今設定したセキュリティグループが選択できるようになるので選ぶ。デフォルトのグループはバツをクリックして消しておく。

Listeners and routing
まずCreate target groupでターゲットグループをつくる。ターゲットグループっていうのはロードバランサがどのサーバに対してどういう通信をするか決めてるもの。
名前つけてNext

available instancesに作ったグループが出てくるのでチェック入れてInclude as pending belowをクリック。下の枠に設定が移動するのでその状態でCreate target group

ALBの画面に戻ってセキュリティグループと同じようにぐるぐる矢印クリックして今作ったターゲットグループを選択する。あとHTTPSも追加する。

あとは一番下までスクロールしてCreate load balancer

Aレコードの編集
DNSサーバのAレコードを編集して、ドメインにリクエストがあったときにロードバランサーさんを答えてもらうようにします。
もう一度Route53に戻ってホストゾーンの一覧からドメイン名をクリックする

Aレコードにチェックを入れてレコードの編集をクリック

エイリアスのトグルをオンにするとプルダウンが3つ出てくるので
- Application Load BalancerとClassic Load Balancerへのエイリアス
- ロードバランサーのあるリージョン
- さっき設定したロードバランサー
を選んで保存をクリック

数分待ってからブラウザでhttps://<ドメイン名>にアクセスしにいくとちゃんと鍵マークがついてる。Amazonが認証局になってることを確認。

HTTPで接続してきたときにHTTPSにリダイレクトさせる
ついでなのでHTTPで繋いでくる人は優しく誘導してあげましょう。せっかくSSL設定したし(せっかくとかではない)
参考にさせていただいたページ
ロードバランサーの画面でリスナータブを開いてHTTP:80のルールの表示/編集

左上のプラスマークをクリックしてルールの挿入

条件の設定(この辺は引用元のクラメソさんの記事見たほうがいいです)して保存

ルールが追加されました

ブラウザからhttp://<ドメイン名>にアクセスしてhttps://〜にリダイレクトされることをたしかめましょう!

以上です。お疲れ様でした!
まとめ
インフラ素人AWSド素人なのですがなんとか構築できました。ほんとにド素人なので「この設定よくない」とかあったら教えていただけるととても嬉しいです。ちなみにここで上げてるCTFdは落としてるので普段は繋がりません。たまに社内とかで遊ぶときに上げるかもしれんけど。攻撃しないでください。ぼくは悪いスライムじゃないよぷるぷる
これで問題さえあればいつでもCTFの大会ができるぞ!多分!問題さえ!あればね?!?!(だれか一緒にやりませんか)