🤧

wgetでs3への接続がエラーになる件

2023/08/31に公開

事象

wgetでAWSのS3からデータを取得する際、突如 403 Forbidden エラーが発生するようになりました。
そもそもwgetコマンドとは

要因

TLSv1.1以前のプロトコルではs3へ接続できなくなっていることが要因でした。
https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/network-isolation.html

以下で要因判明・解消までの流れを詳しく説明していきます。

エラー内容

$ wget --no-check-certificate https://XXX.s3-ap-northeast-1.amazonaws.com/file/test.csv -O /tmp/test.csv
--16:28:42--  https://XXX.s3-ap-northeast-1.amazonaws.com/file/test.csv
           => `/tmp/test.csv'
XXX.s3-ap-northeast-1.amazonaws.com をDNSに問いあわせています... xx.xx.xx.xx, xx.xx.xx.xx, xx.xx.xx.xx, ...
XXX.s3-ap-northeast-1.amazonaws.com|xx.xx.xx.xx|:443 に接続しています... 接続しました。
警告: XXX.s3-ap-northeast-1.amazonaws.com の証明書の検証エラーです: certificate signature failure
HTTP による接続要求を送信しました、応答を待っています... 403 Forbidden
16:28:42 エラー 403: Forbidden。

ログを確認する限り、
httpsで接続

証明書の検証エラー

--no-check-certificateのオプションを使用しているので、httpで再接続
--no-check-certificateオプションとは:sslエラーを無視してデータを取得できるオプション
※今まではここで取得できていた。

403: Forbiddenのエラーが発生

という流れです。

今回--no-check-certificateのオプションを使用しており、
SSLのエラーは無視されるようになっているので証明書の検証エラーについては一旦置いておきます。

また、今回何度もwgetコマンドを叩いていると5回に1回位の割合でファイルの取得に成功することが特徴としてありました。

調査

エラー内容で検索するも、--no-check-certificateのオプションで解消するよ!という内容の記事ばかり。。
今回は元々--no-check-certificateオプションをつけているのでこちらは要因ではなさそうです。

curlで対象のURLを叩いてみる

curl: (60) SSL certificate problem, verify that the CA cert is OK. Details:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
More details here: http://curl.haxx.se/docs/sslcerts.html

curl performs SSL certificate verification by default, using a "bundle"
 of Certificate Authority (CA) public keys (CA certs). The default
 bundle is named curl-ca-bundle.crt; you can specify an alternate file
 using the --cacert option.
If this HTTPS server uses a certificate signed by a CA represented in
 the bundle, the certificate verification probably failed due to a
 problem with the certificate (it might be expired, or the name might
 not match the domain name in the URL).
If you'd like to turn off curl's verification of the certificate, use
 the -k (or --insecure) option.

接続元サーバのルート証明書が古いという内容のよう。
ルート証明書の期限を確認してみたところ、期限が切れたのは数年前でした。
これはこれで後ほど更新が必要ですが、今回の事象が出始めたのはここ1,2ヶ月なので、直接的な要因とは考えずらいです。

s3への接続でサポートされているのはTLSv1.2以降

接続先(s3)に何か問題・変更があるのでは?と考え、「wget s3 403 Forbidden」で検索をかけてみました。

すると、s3への接続にはTLS1.2以上が必要であることがAWSからのドキュメントにより判明しました。

ネットワークを経由した Amazon S3 へのアクセスは、AWS が発行する API を介して行われます。クライアントは Transport Layer Security (TLS) 1.2 をサポートしている必要があります。
https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/network-isolation.html

更に、以下ページよるとTLS1.2以降に限定されるのは2023年6月~とのことで、エラーが発生し始めた時期とも辻褄が合います。
https://aws.amazon.com/jp/blogs/security/tls-1-2-required-for-aws-endpoints/

解消

wgetで使うプロトコルを指定する!

--secure-protocolオプションでwgetで接続時に使用するプロトコルの指定ができます。
ところが、TLSv1_2「無効な値」とのこと。

$ wget --secure-protocol=TLSv1_2 https://XXX.s3-ap-northeast-1.amazonaws.com/file/:443
wget: --secure-protocol: `TLSv1_2'は無効な値です。

wgetの--helpオプションよりプロトコルで選択できる値を確認。
選択可能なのはTLSv1まで。TLSv1_2の記載はありません。

$ wget --help | grep -A 2 secure-protocol
       --secure-protocol=PR     セキュアプロトコルを選択する (auto, SSLv2, SSLv3, TLSv1)
       --no-check-certificate   サーバ証明書を検証しない
       --certificate=FILE       クライアント証明書として FILE を使う

wgetのバージョンが低すぎる

wgetのバージョンが1.17である他のサーバだとTLSv1_2を指定できたので、バージョンアップが必要だと判明します。

$ wget -V
GNU Wget 1.10.2 (Red Hat modified)

Copyright (C) 2005 Free Software Foundation, Inc.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

以下は参考訳です。法的には上の英文に従います。

このプログラムは有用と思われますが無保証です。
商業性や特定の目的に合致するかの暗黙の保証もありません。
詳細はGNU一般公用使用許諾をご覧下さい。

wgetのバージョンアップ

参考にしたのは以下の手順。
https://mgng.mugbum.info/1400

TLSv1_2が選択できるようになりました!

$ wget --help | grep -A 2 secure-protocol
       --secure-protocol=PR        choose secure protocol, one of auto, SSLv2,
                                     SSLv3, TLSv1, TLSv1_1, **TLSv1_2** and PFS
       --https-only                安全な HTTPS のリンクだけたどる
--
                                   Use with care. This option overrides --secure-protocol.
                                   The format and syntax of this string depend on the specific SSL/TLS engine.

バージョンアップしたのち、--secure-protocol=TLSv1_2のオプションをつけてwgetを実行したところ、403 Forbiddenエラーが出なくなりました!
※そもそもwgetのバージョンがTLS1.2に対応していないことが要因だったので、--secure-protocol=TLSv1_2のオプション無しでも接続できるようになりました。

$ wget --no-check-certificate --secure-protocol=TLSv1_2 https://XXX.s3-ap-northeast-1.amazonaws.com/file/test.csv
--2023-08-31 18:08:43--  https://XXX.s3-ap-northeast-1.amazonaws.com/activecore/test.csv
XXX.s3-ap-northeast-1.amazonaws.com をDNSに問いあわせています... xx.xx.xx.xx, xx.xx.xx.xx, xx.xx.xx.xx, ...
XXX.s3-ap-northeast-1.amazonaws.com|xx.xx.xx.xx|:443 に接続しています... 接続しました。
警告: XXX.s3-ap-northeast-1.amazonaws.com の証明書(発行者: `CN=Amazon RSA 2048 M01,O=Amazon,C=US')の検証に失敗しました:
  発行者の権限を検証できませんでした。
HTTP による接続要求を送信しました、応答を待っています... 200 OK
長さ: 50669 (49K) [text/plain]
`test.csv' に保存中

test.csv          0%[                       ]       0  --.-KB/s               test.csv        100%[======================>]  49.48K  --.-KB/s 時間 0.006s   

2023-08-31 18:08:43 (7.57 MB/s) - `test.csv' へ保存完了 [50669/50669]

株式会社アクティブコア

Discussion