2022-03-01
ICTSC 2021 冬の陣に参加した
2/25, 26 で開催された、学生限定のトラブルシューティングコンテスト「ICTSC」にサークルのチームで参加してきました。結果は 2300pt 中 1250pt を獲得し、20 チーム中 10 位でした。問題が 17 問出題されて解いていくという CTF に似た形式です。
このイベントは、入社先で内定者ハッカソンをやったときに、チームメンバーが教えてくれたのがきっかけで知りました。こんな楽しいイベントもっと早く知りたかった…
解いた問題
17 問中 5 問解きました。
3 ドッカーフィルターブロッカー
docker(docker-compose)で動いているアプリがあり、そのアクセスを localhost (つまり 127.0.0.1)に限定するという問題でした。docker-compose.yml の ports をいじるというのが想定解のようでしたが、アクセスをフィルターしなきゃ!の一心で取り組んだ結果、iptables を使用したブロックに辿り着きました。
wiki には
Linux カーネル 2.4 以降では、Netfilter というパケット処理のためのフレームワークをもっており、これの設定を操作するツールが iptables である。
とありました。ubuntu では iptables をラッパーした ufw が用いられていたり、centos8 や新しい debian では nftables というまた別の新しいやつが使われているらしい。
$sudo iptables -nL
で一覧が見れて、ポート 8080 番の設定がなかったので
$ sudo iptables -A INPUT -p tcp --dport 8080 -j REJECT
を入れました。
それと、永続化もしたんですが、今振り返ると nftables で永続化操作してたっぽい。けどちゃんとされてました。中身は実は nftables だったのかな?
7 なんで繋がらない!?
隣のルーターのループバックアドレスまでのルーティングが分からないので何かしらで経路情報を手に入れましょう(スタティックルーティングは禁止)という問題でした。
OSPF の設定が既に入っていて、MTU やバージョンが合っていないことで動いていないらしかったんですが残念ながらそれに全く気付かず、「ただダイナミックルーティングすればいいのか?それでいいの?」と思いながらただ RIP を入れました。
1 つ目のルーター
[edit]
$ set protocols rip interface eth0
2 つめのルーター
[edit]
$ set protocols rip interface eth0
[edit]
$ set protocols rip redistribute connected
redistribute connected
のところが大事でした。
ところで、問題の条件に示された ping を通すだけだと、厳密には rip neighbor や hostA を passive-interface にするだけで可能です。
8 Nginx が展開されない
k8s の問題でした。k8s は全然対策ができておらず、2 日目の朝に Qiita の記事「独学 Kubernetes コンテナ開発の基本を最速で理解する」を読んで完全に理解した状態で臨みました。
まず kubetl get pods
などでエラーを確認したところ、unbound な PersistentVolumeClaims があるらしいことが分かりました。
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 47s (x4118 over 2d20h) default-scheduler 0/2 nodes are available: 2 pod has unbound immediate PersistentVolumeClaims.
そこで(懸命にぐぐった結果)、上記の Claims が満足するような PersistentVolume を作成することで、解決しました。具体的には、yaml を書いて kubectl apply しました。
nginx の pods が動き始めましたが、まだだめでした。k8s クラスタの外部から(ひとつ、又は複数の)pods にアクセスする場合、ClusterIP か NodePort か LoadBalancer が必要で、今回は LoadBalancer が設定されていましたが、
LoadBalancer Service を解釈してくれるコントローラーが Kubernetes クラスタにデプロイされている必要があるのと、クラスタ外にロードバランサが要るのと、そのロードバランサがコントローラから設定可能なものでないといけないと、使用するハードルが高い。 基本的には EKS とか GKE とかのマネージド Kubernetes で使われる想定になっている。
そんな LoadBalancer Service をオンプレ Kubernetes でも手軽に使えるようにしてくれるのが MetalLB。 MetalLB を Kubernetes クラスタにデプロイすると、LoadBalancer Service にクラスタ外からアクセス可能な仮想 IP アドレスを割り振ってくれる。
引用:https://www.kaitoy.xyz/2020/10/31/metallb/
とのことだったので、metallb というものを導入して全てが解決されました。
k8s のこと少ししか知りませんでしたが、設定ファイルを apply するだけで全部自動でいい感じに動いてくれて、すげえなーと思いました。
また、pods や service を眺めている時に Calico という、pods 間のネットワーク繋げてくれる CNI を見つけ、これの設定でやるんだろうな~と勘違いをして時間を消費していました。
9. ping が通らない(0 点)
サーバーが二つのルーターを挟んで設置してあり、NAT を入れてね!という問題でした。
どっち向きに NAT(source NAT)するのか良く分からず、二つのルーターで NAT を対向させる形にしてみたら 0 点でした。全然分からないので解説待ちです…
NAT の設定不備を直す、みたいな簡潔なひとこと解説でしたが、同じ向きに二重 NAT ということだったのかな…?
不備だったとしたら、多分インターフェイスが間違ってました。
15. Ansible が動かない
メンバーと一緒に解きました。
$ ansible-playbook setup.yaml
を実行して、出てきたエラーをひとつひとつググっていって解決しました。
そして ansible が動いた後に、以下のエラーが出てきてました。
/var/log/nginx/error.log
2022/02/26 11:16:17 [emerg] 4387#4387: directive "listen" is not terminated by ";" in /etc/nginx/sites-enabled/default:2
これの port_num が埋め込まれていない?となったので
nginx-template.yml
server {
listen default_server;
listen [::]: default_server;
ので、ググったところ vars を埋め込むには template というのを使えばいいことが分かり、setup.yaml を修正して AC でした。
16 無限クリック
アプリを指定して開くと普通に見えたので、その拡張子の開くアプリのデフォルト設定だなとすぐ分かりました。
GUI で設定できました。(~/.config/mimeapps.list
にもその記述がありました。)
一番簡単だったかなと思います。なんなら 2 段 SSH の向こうにポートフォワーディングをして VNC を繋ぐ方が初めてで難しかったです。
まとめと感想
一桁順位を目指していましたが、ギリギリ達成できず悔しかったです。
実はこのイベントのために対策会をサークルで主催し、ハンズオンをやってました(別の記事にします)。それの資料作りやハンズオン環境構築を通して技術力を深めることができ、またイベント駆動開発ができました。イベントっていいね!
おわり