Cookpad Summer Internship 2021 10 Day Techコースを開催しました!

f:id:fufufukakaka:20210426121451j:plain

研究開発部の深澤(@fukkaa1225)です。今年はエンジニアの立場から新卒採用も担当しています。

4月の記事で告知したサマーインターンシップのうち、10 Day Techコースを8月16日〜8月27日で開催しました。この記事ではその内容を紹介します。

3 Day Product Designコースについては、以下の記事をご覧ください。

10 Day Techコースは、前半5日間が講義形式、後半5日間が実践形式でした。 前半は技術講義とサービス開発講義の2本立てです。 後半はOJTプログラムとPBL(Project-Based Learning)プログラムのそれぞれに分かれて、サービス開発の実践に取り組みます。

昨年はオンラインのみでの開催でした。今年は前半の講義パートをオンラインのみ、後半の実践パートではオフィスに来訪されることを希望した方にはオフィスで、それ以外の方々は前半から引き続きオンラインで参加する形式を取りました。例年と同様、多くの学生の方々にご参加いただきました。本当にありがとうございました。

前半

まずは前半の講義について簡単にご紹介致します。

1日目: フロントエンド講義

初日は1時間弱ほど、イントロダクションとしてクックパッドの取り組みの紹介や自己紹介を行いました。

その後、今年の技術講義のテーマを発表しました。今年のテーマは「ミニクックパッドマートを作る」でした。クックパッドマートを題材として、クックパッドの中で使われている技術スタックを一気に学習・実践することが狙いでした。

イントロダクションを終えた後、フロントエンド講義からいよいよ技術講義がスタートしました。 2021年の春インターンでも用いた動画を見るという事前準備を前提として、午前中の1時間でクライアントサイドから見たGraphQLに関する講義を行いました。

その後、午後はミニクックパッドマートのweb画面を作ることを目標として、基礎課題・発展課題に取り組みました。

2日目: iOS講義

2日目のiOS講義は1日目に実装したミニクックパッドマートの画面を、SwiftUIで実装するという内容でした。iOS未経験の方がほとんどで、環境構築のところが難所ではあったものの、 SwiftUIを実際に触ってみて使いやすいと感じた人が多かったようです。ほとんどの人が基礎課題を完了させるところまで実装を完了させていました。

3日目: サーバサイド講義

3日目はサーバサイド講義でした。例年の講義では、APIを前半に自分たちで作ってから、その自作APIを使って後半の講義で画面を作るという流れでした。しかし、各自の進捗度合いなどによって想定仕様と微妙に異なる自作APIとなってしまい、画面を作る際に苦労してしまうことがありました。

これを踏まえて、今年はあらかじめ完成しているAPIサーバをこちらで立てて、前半に画面を作る講義を配置してAPIの仕様を把握しながら画面を作りました。その後、3日目のサーバサイド講義で、これまで使ってきたAPIを自分たちで実装してみる、という流れをとりました。

実際に作成してみるのは、GraphQLのAPIサーバです。これをRubyで実装する講義でした。また、決済を担当する別サービス(minifinancier)とのサービス間通信をgRPCで実装するなど、発展的な内容も多く盛り込まれた講義でした。非常にボリュームの多い内容で、多くの方々が苦労されていましたが、それでも何とか乗り切っていました。

4日目: インフラ講義

4日目のインフラ講義では、クックパッドにおけるSREが果たしている役割とその歴史を、実例を交えつつ紹介しました。演習パートでは、基礎課題としてTerraform・hakoを用いて、ミニクックパッドマートをデプロイした他、minifinancierをデプロイしてgRPCのサービス間通信を張る、発展課題として静的ファイルをS3+Cloudfront構成で配信するなどの課題に取り組みました。

スライド: https://static.cookpad.com/techlife/cookpad_summer_internship_2021_infra/main.pdf

補助資料

5日目: サービス開発講義

前半最終日はサービス開発講義を実施しました。午前はクックパッドのサービス開発に対する考え方や開発プロセスを座学形式で学びました。 午後は、午前で学んだことをベースにインターン生同士でチームを組み、ZoomやFigmaを活用したオンラインでのグループワークを行いました。グループワークでは、与えられたテーマを元にユーザーインタビューや価値仮説、アイデア出し、プロトタイプの作成までを一貫して実践しました。講義の終盤では実際に作成したプロトタイプをユーザーにテストしてもらい、それら結果をまとめて各チームでの成果発表を行いました。

「丸1日コードを書かない講義です」とアナウンスしたときからどんな講義なんだろう?と皆さん気になっていたようでした。実際に取り組んでみて、サービス開発について体系的に学び実践する機会がなかなかないので、貴重な良い経験ができたと好評でした。

後半

後半はPBLコースとOJTコースそれぞれに分かれての実践パートでした。

f:id:fufufukakaka:20210906103359j:plain
講師との壁打ちの様子

f:id:fufufukakaka:20210906104529j:plain
雑談していた様子

PBLでは前週のサービス開発講義の内容を元にして、サービス開発の実習を行いました。「一人暮らしの料理」に関する課題を見出し、それを解決するアプリケーションを提案、実装・デプロイしきる、という工程を5日間という短い時間でやりきるというタイトなものでした。 仮説検証、実装時の技術相談などを社員がサポートしつつ着実に進めていった結果、最終的にはほぼ全員がデプロイまでやりきり、無事に成果を発表できていました。

f:id:fufufukakaka:20210906103047j:plain
PBL成果発表の様子、 撮影:WeWork Oceangate Minatomirai

最終講評はCTOの成田、レシピ事業部部長など4名が成果物を真剣に審査しました。実際にそれで課題を解決することができているのか、技術力をどれだけアピールできているか、など複数の視点から評価を行いました。

f:id:fufufukakaka:20210906102845j:plain
講評者のCTO成田、 撮影:WeWork Oceangate Minatomirai

厳正なる審査の結果、技術観点・サービス観点から優秀だった方にはそれぞれ賞を贈らせていただきました。どちらもそれぞれ、特別な賞品を贈呈いたしました。

OJTではクックパッドの各部署に配属され、メンターの指導を受けながらサービス開発を実践してもらいました。レシピサービス、クックパッドマート、基盤系の部署などさまざまな部署に配属された後、みなさんそれぞれのタスクをやり遂げていただきました。 最終日にはPBLコースと合わせて、各自が取り組んだタスクを発表してもらいました。ほとんど全員がPRのマージ、本番環境へのデプロイまでこなしており、発表を聞いていた人全員がみなさんの偉業に驚いていました。

f:id:fufufukakaka:20210906115758j:plain
OJT成果発表の様子、 撮影:WeWork Oceangate Minatomirai

インターンシップを終えて

簡単にではありますが、10日間のサマーインターンシップを振り返させていただきました。 昨年はすべてオンラインでの開催でしたが、今年は後半の実践プログラムについてオンラインとオフィスを選択希望制にしました。昨今の情勢もあり全員にご来訪いただくことは叶わない難しい状況でしたが、恵比寿からみなとみらいに移転した新しいオフィスを、参加者の方々に体感いただく機会を設けられて良かったと感じています。 全体を通じてリモート中心の設計という点は昨年と同様であったため、Zoom、Slack、Kibelaを最大限に活用しました。また、これまでの取り組みを踏まえて、より一層双方向のコミュニケーションを意識しました。具体的にはSlackでpollやreactionによる双方向的でカジュアルなコミュニケーションを織り交ぜたり、Zoom上でブレイクアウトルームを活用したチームごとの成果発表やワークを取り入れる講義などがありました。 今回得られた知見を、次回以降の取り組みにも活かしていきたいと思います。

ノベルティ

f:id:fufufukakaka:20210906103238j:plain
ノベルティセット

f:id:fufufukakaka:20210906103300j:plain

f:id:fufufukakaka:20210906103327j:plain
オフィス招待カード

写真のノベルティセット(アメ、ラムネ、スマートフォンスタンド、マルシェバッグ、うちわ、ステッカー)を事前に送付しました。 また、全日リモート参加を選択された方には、別の機会で改めてオフィス見学に来ていただけるように、オフィス招待カードも送付させていただきました。 この他にサマーインターンシップのロゴが入ったZoomのバーチャル背景用の画像も配布しています。

まとめ

以上が、Cookpad Summer Internship 2021 10 Day Techコースの開催報告です。 ご参加いただいた皆さま、本当にありがとうございました!

今年のサマーインターンシップは終わってしまいましたが、クックパッドでは就業型インターンシップを通年で募集しています。 興味のある方はぜひご応募ください!

AWSフル活用!クッキングLiveアプリ「cookpadLive」を支える技術

メディアプロダクト開発部の長田(@osadake212)です。
私の主な仕事は、CookpadTV 株式会社のサービス開発をすることです。CookpadTV ではたくさんのサービスを同時に開発しており、今回の記事ではそのたくさんのサービスの中の一つである cookpadLive とそれを支える技術について、利用している AWS サービスを中心に紹介します。

cookpadLive チームメンバーによる、過去の発表や記事と被る箇所もあるのですが、この記事では全体を眺めることができるように紹介していきます。

cookpadLive とは

cookpadLive

cookpadLive とは、料理上手な有名人と Live 配信で一緒に料理が楽しめるクッキング Live アプリです。視聴者は Live 配信中にコメント機能を使って、料理のわかりづらいポイントを質問したり、作って欲しい料理のリクエストをすることができます。
普段あまり料理をしないユーザーも楽しめる Live 配信になっていて、 cookpadLive をきっかけに料理を作るユーザーもいます。

Live 配信中にはコメント以外にも多くの機能があります。

  • コメント・ハート・スタンプ(スタンプは有料会員であるゴールド会員限定)
  • Live 配信後半にゴールド会員だけが視聴できる スペシャルTIME
  • 広角カメラによる配信映像で Live を楽しめる スタジオ観覧モード
  • Live 配信中に料理やレシピカードを購入できる スペシャルSHOP
  • Live 配信中に出演者と生電話ができる スペシャルTALK

これらの機能は Live 配信によって取り外しが可能になっていて、企画に合わせて最適な機能を組み合わせることができるようになっています。

また Live 配信以外にも、アーカイブやスペシャル VIDEO のような機能もあります。

cookpadLive の歴史

cookpadLive は 2018年にリリースしました。リリース当時は Live 配信を視聴する機能しか備わっておらず、アプリの UI、バックエンドの構成も現在とは大きく異なっています。

特徴的な変遷を紹介すると

  • コメント配信システムを Firebase から AWS へ乗り換え
  • ユーザーが増えたことによるスパイクに耐えるための仕組みの整備
  • ゴールド会員という月額有料プランを用意し、スペシャル TIME, スタジオ観覧モードのようなゴールド会員向けの機能を実装
  • 都度課金にもチャレンジしてマイクロサービスを作ったが、うまく利用できなかったのでマイクロサービスの撤退
  • Live 配信リソースを効率よく利用するために Live 配信システムを刷新した
  • スペシャル TALK、スペシャル SHOP の機能を実装

こんな感じで、小さくリリースしてから、積極的に新しいことにチャレンジし、失敗しながらも前に進むために継続的に開発をしています。

※こちらの記事にスパイクに耐えるための仕組みの詳細について記載しているので、合わせて読むと分かりやすいです。
cookpadTV ライブ配信サービスの”突貫” Auto Scaling 環境構築

cookpadLive のシステム概要

クックパッドでは AWS を積極的に利用しています。

Rails や go などのアプリケーションサーバーは、社内で Amazon ECS を使って動かす環境が整っているので、 cookpadLive のアプリケーションサーバーもその仕組みを使って動かしています。( Dockerfile と jsonnet を書くと本番環境で動き始める素晴らしい仕組みです。*1
基本的な Web アプリケーションであれば上記の仕組みだけで十分なのですが、 cookpadLive のように映像を扱ったり、リアルタイムでなにかをしたりする場合には工夫が必要です。AWS にはさまざまなサービスがあり、 cookpadLive の新機能を実装するときには、まず AWS のサービスをうまく使うことで実現できないか、という観点で技術調査・設計・実装を進めています。

細かいところは省略しつつも、 cookpadLive システムの構成はだいたい以下のようになっています。

クックパッドには強力な開発基盤があり、さまざまな社内アプリケーションから利用できるように設計されています。
cookpadLive もその開発基盤の上で開発しており、特に認証基盤・決済基盤・DWH はその中でも重要な役割を担ってくれています。

次のセクションでは、AWS を使った特徴的な部分について紹介します。

cookpadLive のシステム的な特徴

以下の3つについて紹介します。

  1. Live 配信
  2. Live 配信中のメッセージ
  3. スペシャル TALK

1. Live 配信

Live 配信・アーカイブ生成などの映像を扱うために AWS メディアサービスを利用しており、その中の AWS Elemental MediaLive*2, AWS Elemental MediaStore*3, AWS Elemental MediaTailor*4 AWS Elemental MediaConvert*5 を利用しています。

ワークフロー

Live 配信は MediaLive -> MediaStore -> MediaTailor -> CloudFront のように構成しています。
MediaLive で配信スタジオからの RTMP Push を受け付けて、 MediaStore を destination に HLS 形式にエンコードしたものを出力させます。
また、CloudFront の手前に MediaTailor を挟んでおくことで、ゴールド会員限定のスペシャル TIME を実現できるようにしています。

アーカイブは MediaLive の Output にアーカイブ用のものを追加しており、 RTMP Push を受け付けた時に S3 を destination に MPEG2-TS 形式で出力し、Live 配信終了時にアーカイブ生成処理を実行します。
出力された ts ファイルは一度1つの ts ファイルに結合された後、 MediaConvert を使って HLS 形式にエンコードし、 CloudFront 経由で配信しています。

MediaTailor の部分が若干特殊になっているものの、一般的なワークフローで Live/アーカイブ配信を実現しています。

配信リソース管理のためのマイクロサービス

cookpadLive では配信リソースを管理するマイクロサービスを用意したのにはいくつか理由があり、その1つを紹介します。
※こちらの発表資料に詳しく記載しているので、合わせて読むと分かりやすいです。
cookpadLiveのライブ配信基盤 Cookpad Tech Kitchen #23

cookpadLive では、1配信1系統毎に MediaLive のインスタンスを立ち上げています。なので通常配信に加え、別カメラの映像を流すスタジオ観覧モードを追加するなど、1つの配信でも別系統の映像を配信したい場合は追加でインスタンスを立ち上げています。つまり、同じ時間帯に3つの配信あり、さらにそれぞれ通常・スタジオ観覧モードの2系統があった場合、6つの MediaLive のインスタンスが必要になります。また、それぞれの配信でリハーサル配信をする場合もあったりして、1日にいくつものインスタンスを必要とする場合があります。

MediaLive のインスタンスは作成してから数分〜数十分経過しないと利用可能にならないので、あらかじめ作成しておく必要があるのですが、作成タイミングによって MediaLive のインスタンス作成上限に引っかかったり、 Live 配信の開始時刻までに利用可能にならないリスクがあります。

リソース確保に伴うこれらの課題をマイクロサービスを用意して抽象化することで、 Live 配信に関するビジネスロジックの実装に集中できる環境を作りました。

2. Live 配信中のメッセージ

cookpadLive の開発では、コメント・ハート・スタンプなどのリアルタイムの情報をまとめてメッセージと呼んでいます。
Live 配信中にリアルタイムにサーバーからクライアントにメッセージを送信するために AWS AppSync を利用しています。

AppSync は GraphQL のインターフェースで AWS DynamoDB などのデータソースにアクセスすることができるサービスです。
GraphQL には3つのオペレーションがあり、クエリ・ミューテーション・サブスクリプションがあります。 cookpadLive のメッセージ配信は、 AppSync のサブスクリプションのオペレーションを使って実現しています。

クライアントが直接 AppSync を利用していないのにはいくつか理由があります。

まず1つ目は、送られたメッセージをそのままファンアウトさせるのではなく、アプリケーションサーバーである程度処理を加えたかったからです。
具体例を挙げると、なりすましが難しい形でユーザー属性をメッセージに付け加えたかったり、不適切なコメントをフィルタリングしたり、といった処理をしたかったからです。
AppSync の Resolver や datasource や Cognito などを工夫することで実現することも可能だとは思うのですが、システム全体の整合性を考えると現実的ではないと判断したので cookpadLive ではアプリケーションサーバーを経由して AppSync にミューテーションする方式を採用しました。

余談ですが、 AppSync はサーバーアプリケーションからオペレーションすることをあまり考慮しておらず、言語によっては SDK が用意されていません。なので cookpadLive では AppSync との通信部分を独自に実装しました。

2つ目の理由は AppSync への書き込み流量をサーバー側で制御したかったからです。
Live 配信は決まった時間にユーザーがいっきに集まりますし、配信の盛り上がりや企画次第ではハート・コメント・スタンプが連打され、リクエストのスパイクが起きやすいという性質があります。

AppSync に対するオペレーションの Rate limit も存在するのですが、例えばデータソースに DynamoDB を指定している場合はテーブルのキャパシティプランニングも合わせて必要になります。
サービスの成長や出演者の人気度の変化に柔軟に対応するためにも、アプリケーションサーバーを経由して AppSync に書き込みする構成にしています。

※こちらの発表資料に詳しく記載しているので、合わせて読むと分かりやすいです。
クックパッドの動画事業での AWS AppSync 活用事例

コメントの永続化

図をみると message サーバーから AppSync へ書き込むフローと、 S3 に書き込むフローにわかれている部分があるのですが、前者は Live 配信中に他ユーザーにファンアウトするためのフローで、後者はコメントデータの永続化のためのフローになっています。
シンプルに考えると、 AppSync のデータソースを DynamoDB にすればいいのではないか、と思われるかもしれないのですが、 負荷試験の結果 cookpadLive のコメントの流量で DynamoDB に書き込みをしようとすると期待するパフォーマンスがでないことがわかりました。
コメントデータはアーカイブの生成が完了したタイミングで準備ができていればよいので、パフォーマンスチューニングをするのではなく、多少遅延してもよいのでパフォーマンスを気にせず永続化できる仕組みを構築しました。(AppSync のデータソースは type: NONE を利用しています。)

※こちらの発表資料に詳しく記載しているので、合わせて読むと分かりやすいです。
アーカイブ配信でもライブ感を味わいたい / cookpad_tech_kitchen#23

余談ですが、この課題は AppSync のデータソースに Amazon Kinesis を指定できるようになると解決するので、是非 Kinesis をサポートしてほしいです。

3. Live 配信中の通話機能(スペシャル TALK)

スペシャル TALK は、Live 配信中にキャストと1対1で生電話ができる機能で、配信スタジオからは映像と音声の両方、ユーザーからは音声だけの通話ができます。
この機能を実現するために Amazon Chime と AWS AppSync を利用しています。

まずユーザーはスペシャル TALK への応募を行います。応募が揃ったら通話するそのユーザーに対して AppSync のサブスクリプションを使って、サーバーからアプリに対してイベントを送信します。アプリはこのイベントを受け取ると API を叩き Amazon Chime の接続情報を取得します。取得した接続情報をもとに Amazon Chime に接続し、接続が完了すると通話が開始される、というフローになります。

配信スタジオとの統合

システム構成ですがこの形に辿り着くまでに多くの議論を重ねました。
今まで開発したことないタイプの機能でしたし、既存の配信スタジオのマイク・スピーカー・カメラ・スイッチャーとどのように統合するのかであったり、 Live 配信の企画として成立させるためには通話以外にどういう機能が必要なのかを検討したりと、エンジニアチームだけではなく、撮影技術チーム・Live 配信ディレクターチームも巻き込んで今の形に仕上げました。

また、開発やデバッグにはとても苦労しました。 通話機能なので相手が居ないと正しく動いているかどうかが判断しづらく、離れたところで音楽を鳴らして擬似通話したり、ある程度完成したら複数人でデバッグしてみたりと、試行錯誤しながら開発をしました。

また、Amazon Chime は他の AWS リソースと違ってコンソールでリソースの操作ができず API でしか操作できなかったので、今どうなっているか、などの状態をパッと把握するのが難しいです。
この課題については現在も残っていて、チームメンバーと議論しながら解決に向けて進めている最中です。

余談ですが、結合テストについては、コロナ禍で全員リモートだったこともあり、実際の利用環境に近い形でテストすることができ、ユーザーの気持ちや問題に早く気づくことができました。

今後の予定

今回の記事では主にサーバーサイドの技術について触れました。cookpadLive では iOS・Android・FireTV のプラットフォームでアプリを展開しており、これらのアプリでも技術的な挑戦をしています。
アプリのチャレンジについては、次の機会で執筆しようと思いますので、乞うご期待ください。

cookpadLive では引き続き技術的なチャレンジをしていきます。
直近では API のパフォーマンス改善と、 JSON API を GraphQL に置き換えることを検討しています。そのうち情報発信していきますので、こちらも乞うご期待ください。

記事では書ききれなかったことも多く「もっと cookpadLive について知りたいよ」という方がいらっしゃいましたら、是非 @osadake212 までご連絡ください。

info.cookpad.com

参考記事

*1:ECS インフラの変遷 https://techlife.cookpad.com/entry/2021/08/05/114810

*2:ライブ動画処理サービスです。公式サイト: https://aws.amazon.com/jp/medialive/

*3:メディア向けに最適化された AWS ストレージサービスです。公式サイト: https://aws.amazon.com/jp/mediastore/

*4:動画ストリームにターゲット広告を個別に挿入できます。公式サイト https://aws.amazon.com/jp/mediatailor/

*5:ファイルベースの動画変換サービスです。 公式サイト: https://aws.amazon.com/jp/mediaconvert/

レガシーとなった TLS 1.0/1.1 廃止までの道のり

SRE 兼よろず屋の id:sora_h です。最近は本社移転プロジェクトをやっています。趣味は Web *1 です。

さて、クックパッドでは 2020 年 12 月に TLS 1.0 および TLS 1.1 (以後 "Legacy TLS") を廃止しました。

Legacy TLS は RFC 7457 でまとめられているような既知の脆弱性の存在などから、Chrome, Firefox といった主要ブラウザを含め各所でのサポートが打ち切られつつあります。また、現在では IETF においても Legacy TLS は deprecated と RFC 8996 にて宣言されました。  

クックパッドでもセキュリティ対策およびレガシーな技術と向き合う一環で廃止を進めました。我々は歴史の長いサービスも提供しているため、古い Android や Internet Explorer などからのアクセスもありましたが、トラフィック傾向や各種ベンダーによるサポート状況を見ながら慎重に進めていきました。

全サービスでの廃止にあたっては関わる人数や影響範囲も大きくなるため、丁寧に進める必要があります。それはモチベーションの整理から新しい TLS 設定の検討といった下準備、design doc の作成とステークホルダーへの提案、そして実際の廃止作業といった短くない道のりを辿りました。本稿ではこの一連のプロセスについて振り返ります。

廃止のモチベーション

まず、Legacy TLS を廃止したいモチベーションとしては下記が挙げられます。

  • セキュリティ上のリスク: Legacy TLS は RFC 7457 に挙げられているように既知の脆弱性が存在する。その上、新たに深刻な脆弱性が発見された場合のリスクは低くない。
  • コスト最適化: 一部サービスは非 SNI サポートに有償オプション *2 を必要としている。これは TLS 1.2 以上を前提とすることで、クライアントの SNI サポートも前提とできるため、Legacy TLS 無効化によりそのオプションを廃止できる。
  • 最新の技術やサービスを利用できない潜在的なリスク: TLS 1.2 以上や SNI を前提とする技術やサービスはこれから増え続けていくと考えられる。

特にセキュリティ上のリスクは現状よりも今後新たな脆弱性が発見された際のリスクを高く評価しました。2017 年に完全 HTTPS 化を行った際の理由でも触れられていますが、我々はユーザーさんにセキュアなサービスを提供したいと考えています。

その一環として、2014 年に公開された SSL 3.0 の POODLE 攻撃に対する対応を振り返ります。クックパッドでは脆弱性情報の公開後、速やかに SSL 3.0 を無効化しました。しかし、当時のトラフィック状況では唐突にサポートを打ち切るには時期尚早で、ユーザーさんへの影響が想定以上に発生してしまいました。そのため、再度有効化の上あらためて無効化に向けて動く対応を行ったことがあります。

この POODLE の教訓から、今後 Legacy TLS に重大な脆弱性が新たに見つかった時、我々は迅速にユーザー影響なしに無効化できるのか、という疑問が発生しました。セキュアなサービスを提供し続けることを考えれば無効化はせざるを得ませんが、一方で脆弱性の対応により突然クックパッドのサービスを利用できなくなってしまうユーザーさんの発生も避けたいです。そのため、早期に準備して Legacy TLS の廃止を進めるべきだと考えました。  

また、最新の技術やサービスが利用できないことも大きな足枷となります。特にクックパッドのグローバル向けサービスでは Fastly をサイト全体の CDN として利用しており、Fastly がサービス全体での Legacy TLS 廃止を進めていたこと、また TLS 1.3 と Legacy TLS が排他だったのは大きな決め手でした *3

そして実トラフィックを確認すると、Legacy TLS の利用率は 2017 年で 3% だったところ廃止を提案した 2020 年 8 月頃では 0.5% まで減少していました。

また、同じ頃にクライアント (ブラウザ) でも Legacy TLS のサポートを打ち切る計画 *4 があり、徐々に無効化され始めていました *5。これらも廃止を後押しする理由となります。

廃止のための準備

まずは前節で述べた理由を元に社内ブログへ所信表明を投稿しました。廃止のためにはエンジニアリングチームを含めビジネスサイドのステークホルダーの説得、またサポートチームの協力を得る必要があります。まずはやっていき宣言を発出した後、準備を整えて協力や意思決定を貰いに行くことにします。

トラフィック状況のモニタツールを用意

一言で廃止すると言っても、クックパッドは複数のサービスを提供していて、システムはその数以上に存在します。

Legacy TLS の利用状況についても、 Internet Explorer や古い Android からのトラフィックが存在しないような歴史の浅いサービスから、そうではないサービス、はたまた toB 向けに提供していて Chrome, Firefox, Edge といったモダンブラウザの割合が少ないサービスまで存在し、全体で一気に廃止するというのは良い判断ではありません。

そこでまずは SRE で状況を把握するため、また最終的にはエンジニアリングチームが各々判断できるようにするため、各システムのトラフィック状況をモニタするための社内ツール TLSitrep *6 を作成しました。

https://twitter.com/sora_h/status/1285189591096410112  TLSitrep のスクリーンショット

TLSitrep では週次で ELB ログを集計し、その結果を閲覧できるようになっています。これはほぼ全てのシステムが AWS 上で稼動しロードバランサーとして ELB を利用していて、また全 ELB のアクセスログを Amazon Athena でクエリできるようテーブルとパーティションを自動で維持してくれる社内システムが存在しており、サクッと実装することができて便利でした。

新しい TLS 設定ポリシーと移行ガイドの作成

次に、廃止後に設定する cipher suite の方針などを決定しました。TLS 1.2/1.3 で利用することができる cipher suite から、Mozilla の Server Side TLS ポリシー, CRYPTREC GL-3001-3.0.1 *7, NIST SP 800-52 Rev. 2 等を参考に検討します。具体的には下記のように定義しました。

  • Modern TLS: TLS 1.2+, AEAD (AES-GCM, ChaCha20-Poly1305), Forward Secrecy (TLS 1.2: ECDHE, 1.3: any)
  • Moderate TLS: TLS 1.2, 非 AEAD, Forward Secrecy
  • Legacy TLS: (Insecure TLS を除く) TLS 1.0/1.1, 非 AEAD, 非 Forward Secrecy
  • Insecure TLS: SSL 3.0 以下 or AES/ChaCha20-Poly1305以外 or AEAD/HMAC-SHA256,384以外

ただし、実際には ALB では規定のポリシーの中から選択することになる他、CloudFront など CDN でも同様となるため、この基準をそれにマッピングすると下記の通りです:

  • Modern: ELBSecurityPolicy-FS-1-2-Res-2019-08
  • Moderate (推奨): ELBSecurityPolicy-TLS-1-2-2017-01
  • Legacy: ELBSecurityPolicy-2016-08

TLSitrep においてもこの基準で集計しています。そして、変更した際のインパクトを把握しつつ移行先のポリシーがサジェストされるようにしました:

f:id:sora_h:20210819052222p:plain
図: 表示される移行先ポリシーの提案
f:id:sora_h:20210819052420p:plain
図: Cipher Suite 単位のアクセス傾向

また、ポリシーの策定にあたっては実際のクライアントからの接続可否と、影響の大きさを調査するため、 testssl.sh を用いて実際に各種 security policy を設定した ALB にテストを行い、念の為に実際の古い Windows や IE からもテストを行います。

実際のところ、ALB デフォルトの ELBSecurityPolicy-2016-08 から ELBSecurityPolicy-TLS-1-2-2017-01 へ移行した場合のインパクトは下記の通りとなりました:

  • Windows: 2009 年以前の PC は接続不可 (Windows Vista 以前)。
  • macOS: 2013 年 10 月以前は接続不可 (macOS 10.8 以前)。ただし同年リリースの Chrome/Firefox から TLS 1.2 が有効なので 10.8 以前でも OK の場合あり。
  • Android: 2013 年以前は接続不可 (Android 4.4.2 以前)。
  • iOS: 2011 年以前は接続不可 (iOS 5)。

iOS/Android 向けアプリ版ともに影響を受ける端末はすでにサポート対象外ですが、やはり実際のトラフィックでは初期の Android 4.x 系や古い Internet Explorer からのアクセスが影響範囲として目立つことが分かりました *8

また、前述のようにシステムによって傾向が違うことも明らかになりました。例えば cookpad storeTV の関連システムでは販売店舗等からのアクセスが多いためか、古い Internet Explorer や OS など Legacy TLS や非 FS/AEAD cipher suite の利用率が他と比べて目立っていたなどが挙げられます。

説明と説得のための design doc の作成

各所へ説明するため、モチベーションや移行手段、新しい TLS 設定について記載した design doc を作成しました *9。この時点で、社内のセキュリティチームからもレビューを貰っています。

筆が乗ってしっかりした文章になってしまった *10 ため、最終的には事業部から「ここまでやってもらったらやるだけですね」などと評価されたようで、ちゃんと書いてよかったなと思っています。

また、国内他社事例などもできる限り調査して現状を記載しました。その際、 Yahoo! JAPAN さんの廃止などはかなり参考にさせていただきました。

f:id:sora_h:20210819052657p:plain
図: 用意した design doc の ToC と冒頭部分

アナウンスと説得

前節で用意した design doc を元に筆者が主体的にエンジニアリングチームやステークホルダーへ提案、意思決定を仰ぎました。

幸いにも Legacy TLS のトラフィックレートが十分低下しており、そして design doc でリスクと利点を説明、その他の準備でサービスチームの作業も最低限にしたことからスムーズに受け入れてもらえました。また、自分が動かずとも doc を抱えて他チームのマネージャが意思決定者まで話を持っていってくれる、事業側のエンジニアリングチームが実際の影響ユーザー数の算出を行ってくれるといった協力を貰う事ができたので、備えて良かったなと感じます。

cookpad.com ドメインでの廃止作業

無事に廃止が決まったため、残るは設定の移行作業となります。ここまでくれば技術的にはやるだけです。

基本的に design doc 上で合意済みの対応方針と移行方法をベースに全社へアナウンスをし、各チームに対応を一任しました。また、新規システムがデフォルトで利用する TLS 設定もこのタイミングで切り替えました。

その結果、速やかに無効化されていったようです (筆者はそれを毎週確認しているだけでした)。TLSitrep が変更先の設定を提案するようにした他、ポリシーも分かりやすく提示したため、変更作業としてはアナウンス通りに ALB 設定変更のデプロイで済むことがほとんどでした。前述のように廃止については受け入れられていたため、スムーズに廃止が進行しました。

そして、関わるチーム数が多い cookpad.com ドメインおよび PC およびスマートフォンブラウザ版クックパッド (以後 "レシピサービス") については筆者が実作業も担当しました。この節では以降、レシピサービスにおける Legacy TLS 廃止について説明します。

対象のユーザーさんへ警告を表示するための仕組み

まず、レシピサービスが他サービスと比較して大きなユーザー影響が見込まれたため、ユーザーさんへの告知が必要でした。

クックパッドのサービスは全て常時 HTTPS となっており、 Legacy TLS 廃止後は非対応の環境から完全に接続できなくなります。そのため、実際に接続できなくなるユーザーさんに対して、サポート外になる警告を表示しました。

具体的には、Legacy TLS 廃止後の SecurityPolicy を設定した ALB と CloudFront distribution を用意して、CloudFront への接続に失敗した場合 ALB へ接続試行、その結果を元に警告を表示する JavaScript を準備しました。

 

f:id:sora_h:20210819052810p:plain
図: 警告のイメージ (実際にリリースした際は廃止日時が記載されていました)

この検証作業や前述の SecurityPolicy 接続テストの一環で Windows XP/IE6 や Vista/IE7 の環境も構築してみたんですが、Windows Update さえ実施できず本当に何もできない感じだったのが記憶に残っています。最新のパッチまで当ててたらもう少し何か出来たりするのかな.........。

サポートチームとの連携

以上の変更を抱えてサポートチームへも相談し、文言や問合せ等の対応方針を検討しました。ここでも最初の design doc で背景を理解してもらうのがスムーズに進み、やはり文章は便利だなという気持ちが強まります。

グローバルチームとの連携

cookpad.com ドメインはクックパッドのグローバル向けサービスと共有しているため、このドメインの Legacy TLS 廃止にあたってはグローバル側のサービスチームとも連携が必要でした。

こちらは歴史も浅く Web フロントエンドが古いプラットフォームでそもそも動かなかったりする他、iOS/Android アプリについても日本国内版に比べ古い OS のサポートを早期に打ち切っている関係で背景の説明をするまでもなく合意を得ることができました。

なお、日本国外からの cookpad.com ドメインへのアクセスは CDN として Fastly を経由するようになっているため、Fastly 側での設定変更を行いました。Fastly は CloudFront ほど柔軟な設定はなく、基本的に cipher suite についてはお任せとなります。TLS 1.0/1.1 を無効化し 1.2/1.3 のみとなった設定を準備しました。

Legacy TLS の無効化

告知から一定期間置いて、順次 Legacy TLS を無効化する設定をデプロイしました。念の為ブラウザ版で表示している告知へ誘導するため  iOS/Android 版クックパッドアプリで利用されている API から先に無効化を進めましたが、幸い大きな混乱はなく廃止完了となりました。

cookpad.com ドメインにおける廃止が終わる頃には、他システムでも既に廃止が完了していたため、cookpad.com での廃止を以てクックパッドが提供するほぼ全てのサービス *11で Legacy TLS の廃止が完了したことになります。

まとめ

f:id:sora_h:20210819052858p:plain
図: Qualys SSL Labs にて A を獲得することができた様子 
  廃止から半年以上経過しますが、社内外どちらも大きな混乱はありませんでした。ビジネスサイド含め複数のステークホルダーやチームと連携する必要がありましたが、丁寧にリスクを説明できるようにし、サービスチームの対応コストも下げることによってスムーズに受け入れてもらうことができました。また、ユーザーさんからの反応も想定より小さいものとなったようです。

そして、このプロジェクトで用意した TLSitrep については維持し、ALB の SecurityPolicy が更新された場合速やかに新しい推奨設定を検討できるようにしています。直近では ALB の TLS 1.3 サポート *12 、非 AEAD/FS を許容する TLS 1.2 only の policy が来ないかな、などど思いながら過ごしています。

最後に繰り返しとなりますが、レガシーな環境や設定の存在はサービス提供者とユーザーさん双方のリスクとなるだけでなく新しい技術の足枷となりかねません。クックパッドは先に述べたように歴史の長いサービスで、サーバーサイドからクライアントサイドまでそれが起きやすい環境です。そんなクックパッドではレガシーな環境に立ち向かいながら新しい技術や industry standard へ積極的に追従する仲間を募集しています。 https://cookpad.jobs

謝辞

本プロジェクトは複数のチームの協力によって成り立ちました。また、特に古い環境向けの JavaScript をサクッと書いてくれた id:hokaccha 、TLS 設定や対応方針のレビューをしてくれたセキュリティチームの id:kani_b と  id:mztnex (@m_mizutani) にこの場を借りて感謝します。

*1:I-DIntent to ship, crbug.com, chromium-review, standards-positions などを眺めること

*2:例: CloudFront の dedicated IP address オプション、プロジェクト当時存在した Fastly の shared/dedicated certificate オプション

*3:Fastly は 2016 年からサービス全体での Legacy TLS 廃止を進めていますが、現時点でもまだ既存のユーザーに対する完全な廃止はされていないようです。

*4:打ち切りの宣言: Chrome, Firefox, IE/Edge, Safari

*5:打ち切りの様子: Chrome, Firefox

*6:TLS + Sitrep; situation report

*7:2020年7月公開、タイムリーにリリースされていて便利

*8:プロジェクト当時、ブラウザ版でも Android 4.x のサポートは終了しているが Internet Explorer は引続きサポートしている状況でした

*9:実際には平行して書いていました

*10:Google Docs A4 で 13 ページ、15,000 文字 / TLS 設定の方針なども記載したため、実際にステークホルダーが読むべきところはその半分くらい

*11:本稿執筆現在、フィーチャフォン向けサービスでの Legacy TLS 提供が残っています...。

*12:CloudFront には来たのに無い...

/* */ @import "/css/theme/report/report.css"; /* */ /* */ body{ background-image: url('https://cdn-ak.f.st-hatena.com/images/fotolife/c/cookpadtech/20140527/20140527163350.png'); background-repeat: repeat-x; background-color:transparent; background-attachment: scroll; background-position: left top;} /* */ body{ border-top: 3px solid orange; color: #3c3c3c; font-family: 'Helvetica Neue', Helvetica, 'ヒラギノ角ゴ Pro W3', 'Hiragino Kaku Gothic Pro', Meiryo, Osaka, 'MS Pゴシック', sans-serif; line-height: 1.8; font-size: 16px; } a { text-decoration: underline; color: #693e1c; } a:hover { color: #80400e; text-decoration: underline; } .entry-title a{ color: rgb(176, 108, 28); cursor: auto; display: inline; font-family: 'Helvetica Neue', Helvetica, 'ヒラギノ角ゴ Pro W3', 'Hiragino Kaku Gothic Pro', Meiryo, Osaka, 'MS Pゴシック', sans-serif; font-size: 30px; font-weight: bold; height: auto; line-height: 40.5px; text-decoration: underline solid rgb(176, 108, 28); width: auto; line-height: 1.35; } .date a { color: #9b8b6c; font-size: 14px; text-decoration: none; font-weight: normal; } .urllist-title-link { font-size: 14px; } /* Recent Entries */ .recent-entries a{ color: #693e1c; } .recent-entries a:visited { color: #4d2200; text-decoration: none; } .hatena-module-recent-entries li { padding-bottom: 8px; border-bottom-width: 0px; } /*Widget*/ .hatena-module-body li { list-style-type: circle; } .hatena-module-body a{ text-decoration: none; } .hatena-module-body a:hover{ text-decoration: underline; } /* Widget name */ .hatena-module-title, .hatena-module-title a{ color: #b06c1c; margin-top: 20px; margin-bottom: 7px; } /* work frame*/ #container { width: 970px; text-align: center; margin: 0 auto; background: transparent; padding: 0 30px; } #wrapper { float: left; overflow: hidden; width: 660px; } #box2 { width: 240px; float: right; font-size: 14px; word-wrap: break-word; } /*#blog-title-inner{*/ /*margin-top: 3px;*/ /*height: 125px;*/ /*background-position: left 0px;*/ /*}*/ /*.header-image-only #blog-title-inner {*/ /*background-repeat: no-repeat;*/ /*position: relative;*/ /*height: 200px;*/ /*display: none;*/ /*}*/ /*#blog-title {*/ /*margin-top: 3px;*/ /*height: 125px;*/ /*background-image: url('https://cdn-ak.f.st-hatena.com/images/fotolife/c/cookpadtech/20140527/20140527172848.png');*/ /*background-repeat: no-repeat;*/ /*background-position: left 0px;*/ /*}*/