LINEヤフー Tech Blog

LINEヤフー株式会社のサービスを支える、技術・開発文化を発信しています。

Admission Webhookを用いてKubernetesベースのPaaSを拡張する

こんにちは。先日まで、Private PaaSを提供している部署でインターンシップを行っていた岡部です。

インターンに参加した本部では、社内のアプリケーションエンジニア向けの開発者基盤を提供しています。とくに、私の所属していた部署では、KubernetesベースのPaaSを提供しています。 本記事では、KubernetesのAdmission Webhookを活用した、より良い基盤作りに向けた取り組みの一部を紹介いたします。

(参加したインターンシップの詳細は、こちらページをご覧ください。KubernetesベースのPlatform Engineeringに挑戦

社内の開発者向けPaaSの紹介

私がインターンとして参加した部署では、社内の開発者向けのアプリケーションプラットフォーム(以後PaaS: Platform as a Service)を提供しています。このPaaSは、Kubernetesクラスタ上に構築されており、CustomResourceDefinition(以後CRDと略記)やAdmission Webhookを用いて独自の拡張が行われています。社内の開発者はPaaSを利用し、コンテナイメージと数十行程度のマニフェストファイルを用意するだけで、簡単にアプリケーションのデプロイ・運用を行えます。端的に言えば、AWS App Runner、Google Cloud Runに近いサービスを社内向けに提供しています。

PaaSを用いると、以下のようなマニフェストファイルを作成し、アプリケーションをコンテナイメージとしてコンテナレジストリにあらかじめ登録すれば、簡単にデプロイを行えます。

apiVersion: paas.example.com/v1
kind: App
metadata:
  name: hello-world
  namespace: my-project
spec:
  service:
    autoscale:
      maxReplicas: 10
      minReplicas: 2
    template:
      spec:
        containers:
        - name: nginx
          image: registry.example.com/hello-world:latest
          ports:
          - containerPort: 8080

実際には、作成したマニフェストをapp.yamlのような名前で保存し、kubectlに近いコマンドを発行すればデプロイを行えます。

$ paasctl apply -f app.yaml
app.paas.example.com/hello-world created

社内のアプリケーション開発者は、PaaSを用いることで、コア機能の実装に集中できます。

これらの取り組みは ヤフーにおけるKubernetesを活用したPlatform Engineeringの取り組み という記事でより詳しく紹介されています。合わせてご覧ください。

課題と解決策

ヤフーでは、個人情報を取り扱うサービスが多くあります。そのため特定のKubernetesクラスタ上にアプリケーションをデプロイする際には、L7レイヤでの認証認可を強制したいという要望があります。 ヤフーでは認証認可用のSidecarが提供されており、アプリケーション開発者がそれぞれで認証認可を実装する必要がありません。社内で提供しているPaaSでは、アプリケーションに特定のラベルを付与することでSidecarをインジェクトできる仕組みがあります。

そこで、KubernetesのAdmission Webhookを利用して、アプリケーションに特定のラベルが付与されているかチェックすることで、L7レイヤーでの認証認可を強制できると考えました。

KubernetesのAdmission Webhookとは

先ほど紹介した通り、社内で提供されるPaaSはKubernetesをベースに構築されています。Kubernetesを拡張する方法はいくつかあり、とくに代表的なものとしては、CRDや、Admission Webhook(脚注1)のようなものが挙げられます。

Admission Webhookとは、クライアントからKubernetes API Serverへのリクエストが行われた際に、特定の処理を発火させられる拡張機能です。

とくにAdmission Webhookには、

  • Validating Webhook
  • Mutating Webhook

と呼ばれる二種類のWebhookが存在します。

Validating Webhookは特定のリソースに対する特定のオペレーションが行われる際に、リクエストの検証を行います。具体的には App  CREATE するオペレーションを行う際に、.spec.service.autoscale.maxReplicas が100以下だと検証・実現できます。

一方、Mutating Webhookは、特定のリソースに対する特定のオペレーションが行われる際に、リクエスト内容を変更できます。例としては App  CREATE するオペレーションを行う際に、.spec.service.autoscale.maxReplicas が100以上であれば、100に書き換えることができます。

とくにMutating Webhookは、Istioで用いられるサイドカーインジェクション(脚注2)として広く使われています。

これらのAdmission WebhookはHTTPによる通信を行えて、admissionregistration.k8s.io/v1 で定められたスキーマに沿ったJSONのやりとりができればいいので、好きな言語・フレームワークを用いて実装できます。

参考: Webhook request and response(外部サイト)

※脚注1: 厳密には、KubernetesのAPI Serverは主に認証認可とAdmission Control と呼ばれる2つの役割を担当しています。Admission WebhookはAdmission Controlのフローの一部分ですが、本記事ではこの両者を厳密に区別しないで進めます。
※脚注2: Pod作成時に自動的にistio-proxyをサイドカーとして同梱させる仕組み

ヤフーにおける認証・認可基盤

社内には多くのアプリケーションが存在し、それぞれがAPIによって連携しています。当然、連携にあたっては認証認可基盤が必要で、これは旧Yahoo! Inc.が開発したAthenzというシステムによって実現されています。本筋から離れてしまうので、詳しくは紹介しませんが、いわゆるRBACによってアクセス可能なリソースを制限しています。

社内のPaaSではAthenzをサイドカーとしてコンテナ内に同梱させるので、アプリケーション・サービス間の認証認可を実現しています。これはIstioのサイドカーインジェクションと近い仕組みと考えるとわかりやすいかもしれません。もちろん、すべてのサービスで認証認可が必要なわけではないので、Athenzサイドカーの同梱有無をマニフェストのラベルによって表現します。これは、以下のマニフェストの .metadata.labels.athenz.example.com/inject のようなラベルで簡単に表現できます(秘密保持の観点から、ラベル名は実際とは異なります)

apiVersion: paas.example.com/v1
kind: App
metadata:
  name: hello-world
  namespace: my-project
  labels:
    athenz.example.com/inject: "true"
spec:
  service:
    autoscale:
      maxReplicas: 10
      minReplicas: 2
    template:
      spec:
        containers:
        - name: nginx
          image: registry.example.com/hello-world:latest
          ports:
          - containerPort: 8080

特定のラベルが付与されていることを確認し、サイドカーインジェクションが自動的に行われます。

PaaSへの応用

あらためてここまでの話をまとめると、以下の通りです。

  • 社内向けにPaaSを提供する上で、特定のクラスタ上で認証認可を必須にしたい要件がある
  • Kubernetesには、API Serverに特定の処理が飛んだ時にだけリクエストを変異・検証するための拡張機能が存在する
  • ヤフーではAthenzと呼ばれる認証認可基盤が用いられており、サイドカーインジェクションによってコンテナに注入されている
  • Athenzによるサイドカーインジェクションは、マニフェストに特定のラベルを付与することで、デプロイ時に自動的に行われる

この問題を解決するためには、デプロイ時にマニフェストを確認し、デプロイを許可するか判断するWebhookを実装すればいいわけです。もう少し具体的に書くと、特定のクラスタに対してAppリソースのCREATE, UPDATEオペレーションが行われた際に、マニフェストの.metadata.labels.athenz.example.com/injectフィールドが"true"になっていることを検証し、オペレーションを許可するか判断することで、Athenzサイドカーの同梱を強制できます。

このようにAdmission Webhookを使用すれば、組織固有の問題を解決できます。

まとめ

本記事では、開発者基盤におけるKubernetesの拡張事例を紹介しました。社内に多くの独自基盤を持っており、これらはKubernetesの拡張機能であるCRDやAdmission Webhookと高い親和性を持っていることを紹介しました。とくに、Admission Webhookは実装が比較的容易であるため、Kubernetesを運用しているさまざまな組織での応用ができると思います。

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

ここまでは取り組んできた内容について紹介しました。最後にインターンシップの感想をお伝えできればと思います。

最初に驚いたのは、なんといっても超大規模基盤のスケールに圧倒されました。多数のコンポーネントが歯車のようにかみ合うことで、インフラが構成されていることを感じました。日本国内でもトップクラスのアクセス数を誇るYahoo! JAPANのサービスを支えるインフラ、開発者基盤に触れられたのは、大変貴重な経験になりました。

同時に、組織や基盤、インフラが属人化されていないことも印象に残りました。社内には丁寧なレビューやドキュメントを残すことが文化の一つとして根付いており、コードやドキュメントをチーム全体で所有しているように感じました。サービスや組織をスケールするためには重要なことだろうとは思っていましたが、自分の想像以上に徹底されていて驚くばかりでした。

また、社員のみなさまや関係者の方々に多くのサポートをしていただきました。とくに自分はあれこれお願いをすることや、基本的なことを質問することも多かったのですが、その度に快諾し、手厚いサポートをしていただきました。とくに、業務で書くコードの書き方について丁寧なコードレビューを受けられたのは、非常に良い経験となりました。社内、チーム全体でこのような雰囲気と文化が形成されているように感じ、快適に業務を進められました。この場を借りて、あらためて感謝いたします。

メンターからの一言

本インターンにて岡部さんのメンターをしていた中村です。今回のインターンでは、想定難易度としては少し難しいWebhookを作成していただきました。 完了想定は約2週間だったのですが、約1か月という長期のインターンであることと、慣れない環境での作業であるため、2週間で完了できなくても問題ないと想定していました。 しかし、岡部さんたちの理解力・開発力がとても素晴らしく、完了想定の2週間でしっかり完了できていました。 後半にも弊社だからこそ触れられるタスクにも着手していただき、非常にいい経験になったかなと思います。

私個人としてはメンター以外ではほとんどサポートはできませんでしたが、いろいろな社員の方と話していろんな刺激を受けたかと思います。 本インターンで得た経験や刺激を今後活かせていただけたらと思います。1か月間お疲れさまでした!本当にありがとうございました!

参考資料