📜

SadServers解説#18 "Lisbon": etcd SSL cert troubles

2024/05/21に公開

https://ja.wikipedia.org/wiki/リスボン

問題概要

シナリオ

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を取得するコマンドを実行し、エラーメッセージを確認しましょう。
どうしても通信が通らなければ、ポートやファイアウォールの状態、サーバの状態などを確認していきましょう

解決の手順を表示する
  1. サーバーからキーfooを取得するコマンドを実行し、エラーメッセージに従って問題に対処する
  2. etcdサーバーの状態を確認する
  3. ポートやファイアウォールの状態を確認する

 

ヒント

一部、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の値が取得できました!

 

問題一覧はこちら

https://zenn.dev/comf_nakamura/articles/sadservers_sitemap

Discussion