【書き起こし】メルコインのインフラ設計・構築と、信頼性のあるサービスをリリースするためのSREの取り組み – Masaki Iino / Takaaki Yuhara【Merpay & Mercoin Tech Fest 2023】

Merpay & Mercoin Tech Fest 2023 は、事業との関わりから技術への興味を深め、プロダクトやサービスを支えるエンジニアリングを知ることができるお祭りで、2023年8月22日(火)からの3日間、開催しました。セッションでは、事業を支える組織・技術・課題などへの試行錯誤やアプローチを紹介していきました。
この記事は、「メルコインのインフラ設計・構築と、信頼性のあるサービスをリリースするためのSREの取り組み」の書き起こしです。

@m-iino:本セッションでは、「メルコインのインフラ設計・構築と、信頼性のあるサービスをリリースするためのSREの取り組み」についてお話しします。

まずは、プレゼンターの紹介です。私はIinoと申します。2019年5月にメルチャリに参画し、インフラとバックエンド担当。2020年2月からメルペイSREチームに参加。2021年からメルコインSREのテックリードとして、メルコイン事業の立ち上げを担当しています。

@yuhara:このプレゼンの後半を担当する、Yuharaといいます。2021年からメルコインのSREチームでネットワークやインフラ周りを中心に立ち上げを担当しました。よろしくお願いいたします。

@m-iino:本セッションでは、前半と後半に分けてお話しします。前半は、メルコインに求められるセキュリティとコンプライアンスへの取り組みについて説明します。後半は、インフラの全体像と信頼性のあるサービスをリリースするための取り組みについてお話ししていきます。

それではまず、セキュリティとコンプライアンスへの取り組みについてお話しします。

メルコインとは、メルカリアプリ内でビットコインの売買ができるサービスを提供する会社です。2023年3月9日より、暗号資産交換業を開始しました。本セッション内では、メルカリアプリ内の暗号資産取引サービスを「メルコイン」としてお話しします。

そんなメルコインのインフラに求められるものとは、何でしょう。暗号資産取引所システムは、金融取引を取り扱うため、セキュリティとコンプライアンスが非常に重要な要素となります。

セキュリティについては、暗号資産取引所は、サイバー攻撃や不正アクセス、ハッキング等のリスクを抱えています。そのため、強固な情報セキュリティを有することが必要です。

コンプライアンスについては、暗号資産取引は各国での法律や規制に基づいて運用管理されているため、各国の法律や金融監督当局の規制を遵守する必要があります。

これらのセキュリティとコンプライアンスを適切に管理し、コード化することで、お客さまデータの保護と取引所の信頼性を維持することが可能です。

メルコインのセキュリティ規程や要件は、メルカリやメルペイとは異なります。

暗号資産ビジネスの特性上、さまざまなサイバー攻撃への対策を行う必要があります。また、国の規定が急に変更される場合は、即座に対応しなければなりません。そのため、メルコインは、メルカリ・メルペイとインフラを分離することで、守るべきポイントを減らし、急な規制変更にも耐えられるよう、コンパクトにすることを目指しました。

暗号資産取引所システムのセキュリティとインシデント管理には、高い水準が求められます。理想はその水準を全てのカンパニーで満たすことですが、すぐの実現は容易ではありません。例えば、インフラを分離せずメルコインをメルカリ・メルペイのインフラと同居させた場合、メルカリ・メルペイのシステム管理体制や運用に大きな影響を及ぼします。

メルカリ・メルペイで発生したインシデントをメルコインに伝播させないためでもあり、逆に攻撃される可能性が高い暗号資産取引所システムへの攻撃をメルカリ・メルペイに波及させないためでもあります。

将来的には、全てのカンパニーでメルコインと同等のセキュリティコンプライアンス基準を満たす予定です。

プロダクション環境における具体的な分離例を説明します。まず、Google Workspaceがメルコインとメルカリ・メルペイで分離されています。既存のmercari.comに対して、mercoin.comというGoogle Workspaceを用意しました。

GCP Organizationも、それぞれのWorkspaceに存在しています。しかし、Billing Accountは、共通のものを使用しています。これはメルカリがGoogleと交わした契約条件などをメルコインにも適用するためです。

複数のGCP Organizationで共通のBilling Accountを使うために、GCPのMulti Billingを使用しています。この機能は、最大で五つのOrganizationに適用することが可能です。数が限られているため、よく検討し、慎重に適用する必要があります。

開発者が誤った設定をすることで、原因が生じる可能性があります。開発者が意識せずとも、セキュリティが保証されるべきです。そして、新たにmicroservicesを追加してもセキュリティを保つべきです。そのため、メルコイン全体でSecure by defaultを目指すことになりました。

メ゙ルコインでは、メルカリグループが積み上げてきたセキュリティ機能や設計を受け継ぎつつ、1から作れる強みを生かして、初めからセキュアな状態を作り、維持することを目標としています。また、セキュリティ設定を後から追加していくのではなく、初めから使える設定を最小限にすることで、開発者が意識せずとも危険な設計をしてしまうことを防いでいます。必要に応じて部分的に例外を許可するようにしています。

GCPのOrganization Security PolicyをGCP Organization全体にかけることで、サービスが増え、新たにGCPプロジェクトを作成しても、初めから危険な設定ができないようになっています。

プロジェクト発足時からセキュリティチームと協力して、全てのOrganization Security Policyを一つずつ検討し、Organizationレベルでポリシーを適用しています。検討の際には、Googleが提供しているGoogle Cloud Security Foundations guideCIS Benchmarkの推奨事項も参考にしながら、ポリシーを作成しました。

ここで採用しているポリシーの一例を紹介します。SSH keyをGCEのMetadataに埋め込んで使うことを防止し、ブートローダーやOSの改ざんも防いでいます。GCEのデフォルトサービスアカウントへのエディター権限の付与も制限しています。また、GCSのパブリック公開も制限しています。

IAMに関しても、最小権限を設定したカスタムブラウザロールを用意し、各チームに合わせた、GCPフォルダレベルで各チームにロールを増やしています。例えば、プロダクション全体を見るSREチームには、広い範囲で最小権限を有効にし、microservicesチームには、担当するmicroservicesを束ねるチーム用のGCPフォルダーに対して最小権限を付与しています。

オペレーションなどで権限昇格が必要な際には、「Carrier」という社内製の権限昇格ツールを使って一時的な権限昇格を行います。Carrierについては、セッションの後半でも説明します。

また、Security PolicyでカバーできないものはPRCの項目に追加し、新規サービスのリリース時など、定期的にチェックを行っています。

セキュリティとコンプライアンスの観点からメルコインのインフラに対して、メルコインのチームがオーナーシップを持つ必要があります。

メルカリグループでは、Mercari SRE、Merpay SRE、Mercoin SREと、それぞれのプロダクトごとにSREチームが存在します。

それぞれのSREチームが担当するプロダクトを安定的に動かすために、インフラの開発運用や、microservicesのサポートを行います。プロダクトごとのSREとは別に、インフラ基盤の開発・運用をするPlatformチームがいます。インフラ全体のオーナーは彼らが担っています。

メルコインSREと比較するために、まずはメルペイにおけるSREについて説明します。メルペイでは、SREが開発チームのサポートをしつつ、メルペイが共通で使うシステムの開発管理を行っています。Platformチームはインフラコンポーネントの開発をしつつ、インフラ全体のオーナーでもあります。

一方でメルコインでは、SREの基本的な役割は、メルカリ・メルペイと同じですが、インフラ全体のオーナーをSREが担っています。

Platformチームにはインフラコンポーネントの開発・運用を委託する形で承認をSREが行っています。こうすることで、メルコイン組織に所属する人がメルコインのシステムを管理する体制を実現しています。

メルコインでは、バックアップを含むお客さまデータやサーバーリソースを全て日本国内に置いています。

日本国内で取り扱うことで、日本の法令と規制の遵守が容易になります。また、お客さまデータの保護指針が明確になり、管理とセキュリティ対策が容易になります。

そのため、GCPのリージョンを東京と大阪に制限しています。ただ、GCPがグローバルでのみ提供している機能は、リージョンの指定はしていません。

Organization Security PolicyのresourceLocationsをGCP Organization全体にかけることでサービスが増え、新たにGCPプロジェクトを作成しても、初めから国外でのリソース作成ができないようになっています。

ただし、必要に応じて、プロジェクト単位で他のリージョンへのリソース作成を許可することも可能です。ポリシーの管理はSREが行っているため、例外を設定するには、システム上でSREの許可が必要です。

メルコインは、お客さまの安全と信頼を確保するために独自のインフラを構築しました。これはメルカリグループから分離されており、メルコインのチームがインフラの管理を行っています。システムは日本国内で運用されており、安全な取引環境を提供しています。さらに、開発者が特別な注意を払わなくても、システムの設計主体が安全性を確保するようになっています。

@yuhara:ここからは、メルコインのインフラの全体像と信頼性のあるサービスをリリースするための取り組みについてお話しします。

まずはメルコインのアーキテクチャについてです。全てのmicroservicesはGCPを利用しており、共通のGKEクラスターの中で動いています。

microservicesはレイヤーアーキテクチャとなっており、インターネットからのリクエストを受け付けるゲートウェイサービスと、認証をつかさどるAuth Tokenサービス、各バックエンドサービスの手前に置かれるBFFとしての役割を持つAPIサービスやビジネスロジックをつかさどる各種バックエンドサービスという形で、レイヤーを構成しています。

各microservicesのワークロードは共通のGKEで動いていますが、そのサービスが利用するデータベースなどは、microservicesごとに個別のプロジェクトにわかれており、サービスオーナーであるバックエンドエンジニアチームで管理しています。

microservicesはそれぞれのプロジェクトにわかれていますが、ネットワークの側面でいうと、Shared VPCの構成をとることで、VPCに所属するリソース、GKEやGCEなどのリソースは、プロジェクトがわかれていても、共通のVPCの中で通信することができます。

またShared VPCのホストプロジェクトが、ネットワークのハブとしての位置づけになるので、そのホストプロジェクトをネットワーク管理者が管理することで、例えばVPC Firewallで、Shared VPC内の通信を制御したり、Cloud NATによって外部向けの通信をコントロールしたり、あるいはVPC内のプライベートドメインをCloud DNSで管理することができるようになっています。

メルコインでは、Secure by Defaultのポリシーに沿って、VPC FirewallでDefault Deny構成としており、必要な通信を管理者が許可する運用を行っています。

あとメルコインではGKEクラスターは用途に応じていくつかのクラスターにわかれており、コンシューマー向けのサービスに関わるアプリケーション用のクラスターと、それ以外のクラスター、例えばGitHub Actionsのself-hosted runnerを自前で管理しているので、そのためのクラスターや、社内の運用ツール用のクラスターなど、クラスターが複数にわかれています。

クラスター間で通信が必要なケースでも、Shared VPCによって、VPC内で通信が収まります。

またメルコインでは、メルカリのOrganizationとは完全に分離された独立したOrganizationとVPCの構成になっていますが、メルコインからメルカリ側のサービスと連携するケースがあります。

例えば、メルカリのユーザーIDとメルコインのユーザーIDをマッピングするために、メルカリのユーザーIDをメルコインから取得するケースです。このようなケースでは、VPCがわかれているため、一般的にはインターネットにサービスエンドポイントを公開して、インターネット経由でアクセスするか、異なるVPCをVPCピアリングでネットワークを接続する方法などが考えられます。

いずれの方法にしても、ネットワークを繋げるための設計が煩雑なため、メルカリグループとしては、異なるカンパニー間のVPCを簡単に接続する仕組みとして、Private Service Connect(PSC)を採用しています。

Private Service Connectでは、対象となるサービスをService Attachmentを使って公開したいプロジェクト(今回の例では、メルカリ側から見たメルコインの対象プロジェクト)に絞って限定公開することで、指定したプロジェクトからのみの接続を許可し、セキュアにアクセスすることが可能になります。

VPCピアリングなどは不要で、簡単にメルカリ側のサービスとの連携を実現できます。

続いて、メルコインGKEクラスターに関わる設計の一部を紹介します。メルコインのGKEクラスターはプライベートクラスターとなっています。

プライベートクラスターは、外部IPアドレスを持たない、つまりVPC内の内部IPアドレスのみを持つNodeの構成となっています。またKubernetesのAPIサーバーは、VPCの内部IPアドレスで提供されるので、Nodeや同じVPC内にいるホストからは、このプライベートエンドポイントに対して、ネットワークに閉じた形で通信できます。

またメンテナンスやオペレーションのためにインターネット上からKubernetesのAPIサーバーにアクセスするケースでは、パブリック向けのエンドポイントを特定のIPアドレスに限定して許可する形で運用を行っています。

あとはNodeが外部IPアドレスを持たないため、外向けの通信はCloud NATを経由する形になっています。

その他のメルコインのGKEで使っている機能の一例として、一つ目に、Network Policyがあります。全てのmicroservicesが一つの共通クラスターの中で、マルチテナントになっているため、microservicesネームスペースへの通信を制御するために、Network Policyを有効にしていて、デフォルトでは全てをdenyする設定としています。必要なmicroservicesのみのアクセスを許可するために、Network Policyをアップデートしていくホワイトリスト方式の運用を行っています。

続いて、Cloud DNS for GKEです。Cloud DNSを有効にしています。DNSのスコープとしては、クラスタースコープとVPCスコープという二つのモードがありますが、メルコインではVPCスコープを使ってます。VPCスコープを使うと、GKE内部のDNS名がVPC全体に伝播するので、クラスターの外のホストから直接特定のKubernetesサービスの名前を引くことができ、Ingressを経由することなく、クラスターの外からmicroservicesにアクセスできます。これはあくまで前提として、VPC FirewallやNetwork Policyで通信が許可されている場合に限ります。

あとは、Google GroupをKubernetesのRoleBindingに指定することができる機能のGoogle Group for RBACも有効にしていて、ユーザー管理をGoogle Groupと連携させたり、Workload IdentityについてはKubernetesサービスアカウントをGCPのIAMサービスアカウントと連携さして、Keyless構成を実現させています。

Istioに関しては、GKEで用意されているアドオンを使うこともできますが、メルコインではアドオンを使わずに個別にセットアップしています。アドオンだと、Googleマネージド Istioが使えるものの、バージョンの指定や、使いたい機能や設定の調整などができないため、メルコインとして使いたいバージョンや機能を指定するために、ユーザーマネージド Istioで運用しています。

Istioの用途としては、主にCanary Releaseで1%トラフィックマイグレーションを行うことや、microservices間の通信をMTLSで暗号化することなどがあげられます。

次にメルコインのmicroservicesの開発・運用の全体像を見ていきます。先ほど、全てのmicroservicesは共通のGKEクラスターの中で動いていて、ネームスペースで区切られたマルチテナントになっており、GCPもプロジェクト単位でわかれているという話をしました。これらの開発・運用方法についても紹介したいと思います。

microservicesごとに開発チームが決められており、そのチームがオーナーシップを持って運用も行います。この例では、サービスAチームはKubernetesのネームスペースA上のmicroservicesと、それに関わるGCPプロジェクト内のSpannerや、Pub/Subといったリソースの管理です。

ただし、これらの構築や運用には多くの専門的な知識やリソースの管理が必要です。限られたメンバーとスケジュールの中で、1から全てをプロビジョニングするのは大変で、メルコインとして期待する設定が行われていないといった可能性も出てきます。

SREとして、チームの開発を促進し、かつメルコインで定めた設定をプロビジョニングできるように、抽象化したモジュールを提供しています。これらを使うことで、開発者は全ての設定を一つ一つ行う必要はなく、既に標準化されたものをプロビジョニングできます。

具体的には、SpannerやPub/SubといったGCPの各種リソースだけではなく、オンコールでインシデント管理を行うために、メルコインで利用しているPagerDuty、コード管理のためのGitHub、監視に関するDatadogや一部のKubernetesのリソースに関わる設定は、Terraformで定義し、Kubernetesのワークロードに関わるリソースはCUEを使って抽象化できるようになってるので、もう少し具体的に説明していきます。

Terraformで提供しているモジュールの例としては、ここにあるようにいくつかの用途に応じて数種類あります。

microservices-starter-kitは、開発者がmicroservicesを作る際に使うキットになっています。GCPプロジェクトやKubernetesネームスペースなどが作られ、必要なIAM設定など、microservicesを作るために必要な設定が含まれています。

microservices-teams-kitは、サービスチームに関わる設定を提供していて、チームのGoogle Groupのメンバー管理や、そのチームに付与されるIAM設定、オンコールに関わるPagerDutyの設定やGitHubで使われるGitHub Teamの管理などを、これで一元管理しています。

microservices-spanner-kitは、Spanner instanceやデータベースの設定に加えて、データベースのバックアップや、Spanner autoscaler(Spanner instanceの負荷に応じてインスタンスをスケールアウトできるオートスケーラーの仕組みを独自に導入している)それらに関わる必要な設定も含めて、このキットで対応できます。

microservices-slo-kitは、そのmicroservicesのサービスレベルやSLOに応じて、Datadogの監視などの設定を行うことができるモジュールで、一つ一つ監視モニターを作らなくても良い形になっています。

Kubernetesのリソースも同様に、開発者が多くのYAMLを管理する必要があり煩雑になるため、それらを簡易化し、開発者の認知負荷を低減するために、CUEというオープンソースの言語を使って抽象化を行っています。これらによって、YAMLに比べて大幅にコードが削減されるとともに、Istioのような新しく取り入れる技術についても、開発者の負荷を軽減でき、かつメルコインとして、セキュリティや可用性の面でコントロールが利いた状態でワークロードが生成できる状態になっています。

ちなみにCUE自体はまだそれほどメジャーな言語ではないので、気になる方はこちらのブログを参照してください。

ここまで、抽象化によっていかに開発者が簡単にmicroservicesの開発・運用を行えるかというお話をしてきました。一方であまり過度に抽象化していくと、例えば他と少し異なる設定を行いたいときに対応できず使い勝手が悪かったり、またそれらを対応するために共通化しているモジュール本体を修正する必要が出て、逆にコストが高くなる側面もあります。

そのため、メルコインだけでなくて、メルカリグループも含めて、キットを提供して抽象化しつつも、直接開発者がTerraformを記述できる自由度を持たせた形で、microservicesの開発運用ができる状態になっています。

そうすると、標準化されていないリソースなども本番環境にプロビジョニングされる可能性があるので、メルコインとしてのセキュリティや可用性などの観点から、推奨する設定、あるいはやってはいけない設定といったメルコインのポリシーを守るために、CI/CDパイプライン上で、TerraformやKubernetesのコードの検証をConftestを使って行っています。

一例としては、Shared VPCに接続するためのTerraformモジュールがあります。許可されたサービスのみが接続できるように制限したいので、事前に許可されているかをチェックしたり、TerraformでVPC Firewallを設定する際に、監査などの観点からログを出力することを推奨しているため、そのチェックを行ったり、Kubernetes マニュフェストでも、コンテナが特権モードになっていたり、ホストネットワークを使用していないかなどを検証したりしています。

実際に運用を始めると、障害対応などで緊急のオペレーションが必要なケースも出てきます。対応方法として、インフラなどの構成を変更するために行動を修正してCI/CDを通すやり方もありますが、時間がかかりすぎて復旧までに時間を要してしまいます。

またはIAMの権限を取得するのも同様に、Terraformのコードから、CI/CDを通すと、権限が付与されるまでに待たないといけないため時間がかかってしまいます。このCarrierというツールは、有効期限付きの一時的な権限を、承認をもって取得できるシステムです。

基本的にはSREや開発者は本番環境への一切の変更権限を持っておらず、必要なときにのみCarrierを使って権限申請し、SREが承認した上で、権限取得する運用を行っています。これによって、申請したときの有効期限が切れた後は、自動的に権限も取り消されるので、権限の消し忘れなどもなく、統制が取られた状態で安全に運用できます。

メルコインは、セキュリティやコンプライアンスなどの側面から、メルカリとは完全に独立したGCP Organizationとして分離されています。メルコインのmicroservicesは、共通のGKEクラスターでマルチテナントを構成しており、セキュリティなどの観点でNetwork Policyなどを使って完全に他のテナントと分離した構成です。

開発者がmicroservicesのオーナーシップを持っており、SREからインフラを抽象化したツールなどを提供することでサービスの開発と運用を促進してきました。一方で課題感としては、抽象化しているツールが増えてきたことで、学習コストや開発者の認知負荷が高くなってきてるというのがあって、それらを開発解決するために、よりシンプルなインターフェイスのようなものが必要になっています。

今後、そういった課題に対しても、より良いものを取り入れて改善していけるといいなと考えております。

本日はご清聴いただきありがとうございました。

  • X
  • Facebook
  • linkedin
  • このエントリーをはてなブックマークに追加