2021/09/30 から、OpenSSL1.0.x でLet'sEncryptの証明書を使っているところと接続できなくなる問題とEC2での対策方法

現象

$ echo|openssl s_client -connect helloworld.letsencrypt.org:443 -servername helloworld.letsencrypt.org
Verify return code: 20 (unable to get local issuer certificate)
  • OpenSSLを使っている、curl やRuby なども影響を受ける

原因

  • Let'sEncryptの証明書チェーンは、R3 --> ISRG Root X1 --> DST Root CA X3 となっている
  • この、DST Root CA X3 が 2021/09/30 に期限切れとなった
  • トラストストアには、ISRG Root X1 と、DST Root CA X3 が入っているが、OpenSSL 1.0.x では、 証明書チェーンの中に、トラストストアにあるが、期限切れの証明書があると、検証が失敗扱いになる という挙動がある

歴史的経緯

Let'sEncrypt がルート証明書を DST Root CA X3 から ISRG Root X1 に変更しようとする流れ

  • もともとの Let'sEncrypt のルート証明書は、DST Root CA X3
  • Let'sEncrypt は、ルート証明書を ISRG Root X1 に変えようとしていた
  • しかし、古いクライアントでは、トラストストアに、ISRG Root X1 が無いため、中間証明書を DST Root CA X3ISRG Root X1 のクロスサイン証明書にしていた(これにより、どちらかがトラストストアにあれば検証が通る)
  • その後、2021/09/30 に DST Root CA X3 の期限が切れるため、ルート証明書を ISRG Root X1 だけにする動きが始まる

Android7.1 問題と苦肉の策

  • しかし、Android7.1以前のバージョンにはISRGのルート証明書が入っていないため、ルート証明書を切り替えると、Android7.1以前でLet'sEncryptの証明書が使えなくなるという問題が判明
  • で、Let'sEncryptは苦肉の策として、以下のようにルート証明書を変更するとアナウンス
R3 --> ISRG Root X1 --> DST Root CA X3
  • ルート証明書の上にルート証明書をチェーンするという荒業
  • これをすると、Android7.1以前では、ISRGがトラストストアにないため、DSTまで遡る。ここで、2021/09/30 以降は、DSTの有効期限が切れてしまうが... Android7.1では、証明書の有効期限チェックを行わない ため、問題が解決すると... 解決...?
  • ISRGをトラストストアにもつ、他のクライアントではDSTまで遡らないため、特に問題はないはずだったが...

OpenSSL 1.0.x では Android互換チェーン の検証に失敗する

  • しかし、OpenSSL 1.0.x では、上記の「Android互換チェーン」については検証が失敗扱いとなる。これは、OpenSSL1.0.xで、信頼チェーンの間に無効な証明書があって、さらにそれがトラストストアに登録済だと、検証が失敗するという挙動(仕様?)のため

👇 Let'sEncrypt による、OpenSSL 1.0.x では Android互換チェーン の検証に失敗する件の記事

community.letsencrypt.org

  • OpenSSL 1.1.0 では修正済みで、1.0.x はたくさんの脆弱性があるので、さっさとバージョンをあげようとアナウンスしている

対策

OpenSSL公式は、トラストストアにて、期限切れのDSTのルート証明書を削除するようにと、アナウンスしている

https://t.co/bL7HmxKqcr?amp=1 www.openssl.org

AWS(EC2)では、ルート証明書のyumパッケージである ca-certificates にて、上記の対応を済ませたバージョンを配布しているので、yum update ca-certificates すれば解決する

aws.amazon.com

AWSでは、さらにこちらで手動対策方法もアナウンスしている

aws.amazon.com

参考

songmu.jp

songmu.jp

www.walbrix.co.jp

今更CentOS6でRubyを検証するDocker環境がほしい時みる記事

どうしても古いままの環境をいじらざるを得ない時ありますよね...

Dockerfile

FROM centos:6

RUN \
  sed -i -e "s/^mirrorlist=http:\/\/mirrorlist.centos.org/#mirrorlist=http:\/\/mirrorlist.centos.org/g" /etc/yum.repos.d/CentOS-Base.repo &&\
  sed -i -e "s/^#baseurl=http:\/\/mirror.centos.org/baseurl=http:\/\/vault.centos.org/g" /etc/yum.repos.d/CentOS-Base.repo

RUN yum -y install \
  git \
  bzip2 \
  gcc \
  openssl-devel \
  readline-devel \
  zlib-devel

RUN git clone https://github.com/rbenv/rbenv.git ~/.rbenv
RUN git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
RUN echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
RUN echo 'eval "$(rbenv init - bash)"' >> ~/.bash_profile
RUN \
  source ~/.bash_profile && \
  rbenv install 2.7.4 && \
  rbenv local 2.7.4

RUN yum -y install wget

ポイント

  • CentOS6のサポートが終わってしまったため、リポジトリがもう無い。そのため、古いリポジトリを残してくれている vault.centos.org をリポジトリの参照先にする
  • 中に入った後、source ~/.bash_profile する必要がある。これどうすれば省略できますかね

Rails7のフロントエンドの方向性について理解したことをメモ

ざっくりまとめ

  • Rails7は、StimulusとTurboのHotwireを標準のjsとしているが、jsまわりのトレンドとは方向が異なる
  • Railsでリッチなフロントエンドをバリバリやるのは難しく、そのあたりの不満がフロントエンド側から表出している
  • Railsは(最初から)、小さいチームによるフルスタック開発のためのフレームワークと表明しており、リッチなフロントエンドをバリバリやることは目指していない

ソース

techfeed.io

👆 DHHによる、「Rails 7は、2021年以降のJavaScriptに対する3つの素晴らしい答えを出すだろう」 の翻訳記事

Railsは当初からフルスタックである。
Rails 7では、JavaScriptに3つの明確な選択肢が用意されている
Hotwireとimport mapsを使ったデフォルトの道。
人気のあるJavaScriptバンドラーの1つとの薄い統合を使った代替の道。
そして最後にフロントエンド用の別のリポジトリを使った厳格なAPIの道。
最後に、Railsを単にAPIとして使用するという選択肢もある。
それを利用するSPAは、まったく別のプロジェクトとリポジトリに置いておく。
Railsは長い間、--apiでこの道をサポートしてきて、これからもそうしていく。
小中規模のチームにはお勧めできない方法だが、フロントエンドとバックエンドの間に高い壁を設けてSPAを作ることに専念している大規模な組織の中にいる場合は、意味のある方法かもしれない。

 


 

kenzoblog.vercel.app

StimulusやHotwireなども少し学習で触りましたが、それなりに学習コストがかかるので、Rails7の上でDHHが推しているJavaScriptの書き方でやっていくと、「Railsの上ではJavaScriptが書ける」みたいな状態になりそうに思います。

DHHの推奨するRailsでのjsに特化しちゃうとキャリアが狭まりそうだよねというのはすごく分かる

 


 

blog.unasuke.com

View層においてJavaScriptのFrameworkもしくはコードの比重が増えていくとともに、バックエンドまで一気通貫で同じ言語を使用できればいいのにという思想からか、加えてRailsとモダンフロントエンドとの相性がよくないからか、Railsの出番は今後減っていくだろうという意見に対しての賛同が増えてきているのを感じている。

今のトレンドである(と思われる)リッチなUXを提供するには、Railsは無用なものになってしまうのでは? という危機感の記事

 


 

zenn.dev

Rails のフロントエンド周りは限界
Rails は文化的にパフォーマンスに対する指向を持たない
ActiveRecord の賞味期限は Rails と同じ
型による大規模化への伸びしろの有無が決定的な差になってきた

 


 

okuramasafumi.hatenablog.jp

👆 Railsはスケールしない個人開発レベルのプロジェクトで強みが活かせるというお話

スケーラビリティが不要なアプリケーションをスモールチームで開発するためのフレームワークがRails
そこ(個人開発の場)では「フロントエンドの最適化」よりも「いかに仮説を検証するか」が重要であり、Railsが提供する高速な開発が重要な意味を持ちます。Railsのエコシステムにより各種実装を省略できることもまた重要です。
Railsに欠けているものは詰まるところ「段階的なスケーラビリティ」に尽きるのではないかと私は考えています。

ぼんやりした感想

  • Railsは、SPAみたいなバリバリのjsではなく、ページの一部をちょっと動的に動かせれば(ほとんどのユースケースで)十分では? というスタンスっぽい
  • そういう意味では、一般ユーザをメインにする最近のwebサイトよりは、業務システムみたいなものの方がRails向きなのかもしれない
  • この辺の方針は理解できるし、個人や数人で全部やる系のシステムではそれで良さそう
  • ただし、StimulusとTurboのHotwireが、フロントエンドとしてのキャリアパスとしてひらけているの? といったら疑問が残るので、バリバリフロントやりたい! って人には向いてなさそう
  • フロントと、バックエンドでチームが明確に分かれてしまっている会社の場合、APIサーバとして使えば良いけど、Railsの良さは活かせないよ? というのがDHHのスタンス
  • そういう場合、Rails以外を選ぶのも良いのかもしれない
  • はてブで指摘があったけど、RailsとDockerとの相性の悪さはめっちゃ理解できる。 bundle install が手間ですよね...

フルスタックRailsを選んだ場合のチームビルドについて

  • 別にチームのキャリアパスとして、フロントエンドとバックエンドが別れてしまっている場合、フルスタックRailsを選択するのは、スピードが得られる代わりにフロントエンド側に多大な負担をかけるよなぁという気持ち
  • フルスタックRailsという選択肢が現状では、フロントエンドのキャリアを閉ざしてしまうので、福利厚生としてよろしくない
  • フルスタックRailsやるんなら、サーバサイドがキャリアの主軸で、フロントもちょこちょこいじれます! って人が良いんだろうなぁ...

自分はどうしましょう

  • なんやかんやで、Railsはまだ残り続けると思うので、それらをメンテナンスするスキルはしばらく腐らなそう。Railsやgemのバージョンアップとか。そのへんは磨き続ける
  • Rails以外のAPIを提供のトレンドを知っておきたい
  • 転職してからインフラに軸足が移りつつあるので、今の所焦燥感は無い
  • フロント側もうすこし勉強しないとな...

MacOSをスリープした時にgoogleアカウントからログアウトする方法

方法

sleepwatcher という、sleep & wakeup 時に任意のコマンドを実行するアプリを使います

また、google アカウントは、 https://accounts.google.com/Logout にアクセスすると、ログアウトできるので、スリープ時に、デフォルトブラウザで、これにアクセスさせます

sleepwatcher のインストール & 自動起動設定

brew install sleepwatcher
brew services start sleepwatcher

スリープ時に実行するスクリプトの作成

sleepwatcher は、スリープ時に ~/.sleep を実行してくれます

cat <<EOS > ~/.sleep
#!/bin/sh
open https://accounts.google.com/Logout
EOS

実行権限も忘れずに

chmod +x ~/.sleep

以上で、スリープ時にgoogleアカウントからログアウトできます

免責事項

sleepwatcher はだいぶ長いこと更新されていないので、使用は自己責任で

経緯

退勤時にgoogleアカウントからのログアウトする会社ルールができたので作ってみました

Terraform Cloud にある state を mv する方法

流れ

  • state ファイルをローカルに持ってくる
  • backend をローカルに変更
  • terraform state mv を実行
  • terraform state push を実行
  • backend を Terraform Cloud に戻す(この時に、state を overwrite する)

state ファイルをローカルに持ってくる

terraform state pull > tmp.tfstate    

backend をローカルに変更

cat << EOF > override.tf
terraform {
  backend "local" {
  }
}
EOF
$ terraform init -reconfigure
Initializing modules...

Initializing the backend...

Successfully configured the backend "local"! Terraform will automatically
use this backend unless the backend configuration changes.

terraform state mv を実行

terraform state mv -state=tmp.tfstate ...

変更されたことを確認

terraform state list -state=tmp.tfstate | grep ...

terraform state push を実行

terraform state push tmp.tfstate

backend を Terraform Cloud に戻す(この時に、state を overwrite する)

rm override.tf
$ terraform init -reconfigure
Initializing modules...

Initializing the backend...
Acquiring state lock. This may take a few moments...
Do you want to copy existing state to the new backend?
  Pre-existing state was found while migrating the previous "local" backend to the
  newly configured "remote" backend. An existing non-empty state already exists in
  the new backend. The two states have been saved to temporary files that will be
  removed after responding to this query.

  Previous (type "local"): /var/folders/12/02rv601d4kv6gmbxrzg4hzzh0000gn/T/terraform229570062/1-local.tfstate
  New      (type "remote"): /var/folders/12/02rv601d4kv6gmbxrzg4hzzh0000gn/T/terraform229570062/2-remote.tfstate

  Do you want to overwrite the state in the new backend with the previous state?
  Enter "yes" to copy and "no" to start with the existing state in the newly
  configured "remote" backend.

既存の状態を新しいバックエンドにコピーするか? と聞かれるので「yes」と回答する

リモートのstateでも、変更が維持されていることを確認

terraform state list | grep ...

独自ドメインからRoute53でCloudFrontにAレコードを設定したときに、SSL関係のエラーが出た時の対処方法

現象

独自ドメインから、Route53でCloudFrontにAレコードを設定した その後に独自ドメインから、upした画像にアクセスするとSSL関係のエラーが発生する

curl -vv https://example.com/E4Tvj0mUUAEWnW8.jpeg
*   Trying ***.***.***.***...
* TCP_NODELAY set
* Connected to example.com (***.***.***.***) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/cert.pem
  CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* error:1400410B:SSL routines:CONNECT_CR_SRVR_HELLO:wrong version number
* Closing connection 0
curl: (35) error:1400410B:SSL routines:CONNECT_CR_SRVR_HELLO:wrong version number

CloudFrontのドメイン直接の場合はupした画像を見ることはできる

原因

CloudFront側で、CloudFrontのlternate Domain Names(CNAMEs)に、独自ドメインを設定していなかった

参考

blog.serverworks.co.jp

感想

SSLのハンドシェイクで失敗するので、なにか証明書関係のエラーと思って少しハマってしまった...

サーバメンテナンスのときには、503(Service Unavailable)を返して、さらに Retry-After ヘッダー をつけておくと安心かも

まとめ

  • メンテナンスページを出す時には、503(Service Unavailable) を返す
  • Retry-After ヘッダーに復旧日時を入れておくと、復旧後に見に来てくれるようになる
  • Retry-After ヘッダーが無いまま、長期間 503 を返すと、クローラーはサーバが復旧しないと思って index を外してしまう
  • また、200404 とかを返すとクローラーがメンテナンス中であることを理解してくれない

ソース

ちょっと古い

webmaster-ja.googleblog.com

RFCの Retry-After レスポンスヘッダの解説

HTTP/1.1: Header Field Definitions