SadServers解説#22 "Lisbon": etcd SSL cert troubles
問題概要
シナリオ
etcd SSL証明書の問題
問題詳細
https://localhost:2379
で実行されているetcdサーバーがあります。このサーバーからキーfoo
の値を取得してください。例えば、コマンドetcdctl get foo
またはcurl https://localhost:2379/v2/keys/foo
を実行します。
解決判定
Check My Solution
ボタンをクリックしてください。
解答が正解かどうか、コマンドプロンプト上で確認することも可能です。次のコマンドを実行して、以下と同じ出力が得られた場合は正解です。
$ etcdctl get foo
bar
問題解決の方針
【表示する】
サーバーから値が取得できないという問題に対処する課題です。
まずは、サーバーからキーfoo
を取得するコマンドを実行し、エラーメッセージを確認しましょう。
どうしても通信が通らなければ、ポートやファイアウォールの状態、サーバの状態などを確認していきましょう
解決の手順を表示する
- サーバーからキー
foo
を取得するコマンドを実行し、エラーメッセージに従って問題に対処する - etcdサーバーの状態を確認する
- ポートやファイアウォールの状態を確認する
ヒント
一部、SadServers公式のヒントを改変しています。
ヒント1
まずは、サーバーからキーfoo
を取得するコマンドを実行し、エラーメッセージに従って問題に対処しましょう。
実行コマンド1
$ etcdctl get foo
Error: client: etcd cluster is unavailable or misconfigured; error #0: x509: certificate has expired or is not yet valid: current time 2025-05-21T11:46:16Z is after 2023-01-30T00:02:48Z
error #0: x509: certificate has expired or is not yet valid: current time 2025-05-21T11:46:16Z is after 2023-01-30T00:02:48Z
error #0: x509: certificate has expired or is not yet valid: current time 2025-05-21T11:46:16Z is after 2023-01-30T00:02:48Z
エラー #0: x509: 証明書が期限切れか、まだ有効ではありません: 現在の時刻 2025-05-21T11:46:16Z は 2023-01-30T00:02:48Z の後です。
現在の時刻が2025年?OSの日時を見てみます。
$ date
Wed May 21 11:47:17 UTC 2025
OSの日時が未来になってしまっていますね。
本来はOSの日時設定を正しくしてから、証明書を更新するべきだと思いますが、今回は証明書が使えればいいので、OSの日時を2023/1/30よりも前にしてしまいましょう。
実行コマンド2
date
コマンドの-s
オプションで、OSの日時設定を変更することができます。
$ sudo date -s "2023/1/20"
Fri Jan 20 00:00:00 UTC 2023
OSの日時設定を変更することができました。
ヒント2
再び、キーfoo
の値を取得してみましょう。
$ etcdctl get foo
Error: client: response is invalid json. The endpoint is probably not valid etcd cluster endpoint.
$
$ curl https://localhost:2379/v2/keys/foo
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.18.0</center>
</body>
</html>
レスポンスが返ってきているので、etcdサーバは起動しているようですが、404 Not Found
が出てしまっていますね…
ポートの状態やファイアウォールなどの状態を確認してみましょう。
実行コマンド1
まずはポートの状態を見てみましょう。
$ ss -natup
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
udp UNCONN 0 0 0.0.0.0:68 0.0.0.0:*
udp UNCONN 0 0 [fe80::86a:77ff:fef0:1eeb]%ens5:546 [::]:*
tcp LISTEN 0 4096 127.0.0.1:2379 0.0.0.0:*
tcp LISTEN 0 4096 127.0.0.1:2380 0.0.0.0:*
tcp LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
tcp LISTEN 0 511 0.0.0.0:443 0.0.0.0:*
tcp TIME-WAIT 0 0 127.0.0.1:443 127.0.0.1:55340
tcp TIME-WAIT 0 0 127.0.0.1:43024 127.0.0.1:2379
tcp LISTEN 0 4096 *:6767 *:* users:(("sadagent",pid=568,fd=7))
tcp LISTEN 0 4096 *:8080 *:* users:(("gotty",pid=567,fd=6))
tcp LISTEN 0 128 [::]:22 [::]:*
tcp ESTAB 0 0 [::ffff:172.31.44.56]:8080 [::ffff:172.31.16.109]:52378 users:(("gotty",pid=567,fd=7))
うーむ、2379番ポートは空いているようですね。
実行コマンド2
次に、ファイアウォールの状態を確認してみましょう。
$ sudo iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy DROP)
target prot opt source destination
DOCKER-USER all -- anywhere anywhere
DOCKER-ISOLATION-STAGE-1 all -- anywhere anywhere
ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED
DOCKER all -- anywhere anywhere
ACCEPT all -- anywhere anywhere
ACCEPT all -- anywhere anywhere
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain DOCKER (1 references)
target prot opt source destination
Chain DOCKER-ISOLATION-STAGE-1 (1 references)
target prot opt source destination
DOCKER-ISOLATION-STAGE-2 all -- anywhere anywhere
RETURN all -- anywhere anywhere
Chain DOCKER-ISOLATION-STAGE-2 (1 references)
target prot opt source destination
DROP all -- anywhere anywhere
RETURN all -- anywhere anywhere
Chain DOCKER-USER (1 references)
target prot opt source destination
RETURN all -- anywhere anywhere
特に通信を遮断するような設定も入っていませんね…。一応、filter
テーブルだけでなくnat
テーブルも見ておきましょう。
$ sudo iptables -t nat -L
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
DOCKER all -- anywhere anywhere ADDRTYPE match dst-type LOCAL
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
REDIRECT tcp -- anywhere anywhere tcp dpt:2379 redir ports 443
DOCKER all -- anywhere !ip-127-0-0-0.us-east-2.compute.internal/8 ADDRTYPE match dst-type LOCAL
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all -- ip-172-17-0-0.us-east-2.compute.internal/16 anywhere
Chain DOCKER (2 references)
target prot opt source destination
RETURN all -- anywhere anywhere
よく見てみると、OUTPUTチェインに、2379番ポートに関する怪しい設定2379が入っています。
2379番ポートへの通信を443番ポートに転送する設定が入っています。
この設定が悪さをしていたようですね。
ヒント3
iptablesのnat
テーブルに記載されている、2379番ポートへの通信を443番ポートに転送する設定を解除しましょう。
実行コマンド
iptablesの設定を削除するには、-D
オプションを使います。
$ sudo iptables -D OUTPUT 1
$ sudo iptables -t nat -L
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
DOCKER all -- anywhere anywhere ADDRTYPE match dst-type LOCAL
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
DOCKER all -- anywhere !ip-127-0-0-0.us-east-2.compute.internal/8 ADDRTYPE match dst-type LOCAL
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all -- ip-172-17-0-0.us-east-2.compute.internal/16 anywhere
Chain DOCKER (2 references)
target prot opt source destination
RETURN all -- anywhere anywhere
再び、キーfoo
の値を取得してみましょう。
$ etcdctl get foo
bar
$ curl https://localhost:2379/v2/keys/foo
{"action":"get","node":{"key":"/foo","value":"bar","modifiedIndex":4,"createdIndex":4}}
キーfoo
の値が取得できました!
「いきなり問題を解き始めても調べるばかりになってしまう…」 「やりたいことが分かっても、コマンドが分からない…」 という方は、下記の記事でLinuxのコマンドを復習してから、SadServersの問題に取り掛かってみてはいかがでしょうか。
問題一覧はこちら
Discussion