続 LINE 社内用 NPMパッケージの管理戦略
みなさんこんにちは。UIT Front-end Dev7チームの吉澤です。主にUITが扱う社内サービスやミドルウェアの開発/運用などを行っています。またDev7チームにはLIFF(LINE Front-end Framework)というLINEが使っているフレームワークの開発をしているメンバもいます。他のUITのチームとは一風変わった特徴的なチームです。
このチームの業務の1つにUITが管理しているPrivate npm registryの拡張、関連機能開発/運用があります。実はこれに関連した全社的にnpmが使えなくなるという障害が2021/2/15にLINE社内で発生していました。今回はその障害について話しながら私たちUITが管理しているPrivate npm registryについての話を書きます。
Private npm registryについて
npm(node package manager)に関して改めて説明の必要はない気がしますが、Private npm registryって何だろう?という疑問は浮かぶかもしれません。文字通りnpm, incが管理している公式のregistryとは別に自分たちでnpmのregistryをホスティングしているという話になります。
LINEでは開発で利用している 2つの npm registry が存在します。1つは全社的にpackage repositoryとして利用している Sonatype Nexus(以下Nexus)で提供されるもの、もう1つはこの記事で取り上げるVerdaccioというOSSを用いたPrivate npm registry(以下Verdaccio)です。後者は私たちのチームでホスティングして運用しています。
Private npm registryに関してのメリットとしては次のようなことが挙げられます。
- private packageの管理がしやすくなること
- registry.npmjs.orgへ送ったリクエストのレスポンスをcacheできること
- リバースプロキシを導入することで任意のロジックが仕込めること
それぞれのメリットについて順に解説します。
まず、1に関してですが、公式のnpmでもprivate packageは作成することができます。しかし人数の増減や権限管理など細かいことを考えると自前でPrivate npm registryをホスティングした方が効率的です。特に権限管理に関しては私たちの運用上問題になることが多いです。導入当時Nexusの権限管理の仕組みが私たちが要件として求める水準のものが提供されておらず、新たに別にVerdaccioを私たちがホスティングするようになったという背景があります。Verdaccio導入に関しての経緯は過去にpodcastで話をしております。もしよろしければこちらのリンクから参照ください。
続いて2に関してですが、Private npm registryを使うことで不要なリクエストを公式のregistryであるregistry.npmjs.orgに送る必要がなくなります。Private npm registryが一度取得したpackageをcacheとして持っておくためです。基本的にPrivate npm registryを使うと以下のイメージのようにリクエストが処理されることになります。
最後に3に関してですが、npmクライアントが送っているリクエストを仲介するサーバが作れるので様々な処理を行うことができます。例えばバージョンごとのnpmクライアントの利用率を集計したり、セキュリティのインシデントが発生したパッケージがダウンロードされたか確認したりなどができます。これについては最後の展望の方で、もう少し深く掘り下げて記述できればと思います。
続いて、実際にUITで起きたある事例を紹介します。
事件発生(2021/2/15)までの構成について
npmのオプションにregistryがあります。このオプションは利用するregistryを指定することができます。.npmrcに記述すると以下のような形になります。
# .npmrc
registry=https://your-registry.com
Private npm registryを利用する場合、使いたいregistryのURLをこのオプションに指定することになります。ちなみにデフォルトは公式のnpm registryであるhttps://registry.npmjs.org/になります。
事件発生までLINE社内でPrivate npm registryの利用は必須ではありませんでした。そのためPrivate npm registryを利用しないプロジェクトも数多く存在し、多くのリクエストがLINEからregistry.npmjs.orgに送られていました。
ここで以下の図をご覧ください。
LINE社内のPrivate Cloudから送られるリクエストは設定を変更しない限り外部から見ると1つのIPアドレスになります(上記の図で言うとyyy.yyy.yyy.yyy)。大量のリクエストがこのIPから公式のnpm registryであるregistry.npmjs.orgに送られた結果、害意のあるアドレスとnpmに判断されてbanされてしまいました。このIPアドレスから送られるリクエストが全て403で返却されるようになってしまい、Private Cloud内の大半のVMからpackageのインストールなどが行えなくなりました。このIPアドレスを利用していたサーバは各種CIやアプリケーションサーバなど多岐に渡り、障害が解決するまでの間、npmに依存したリリースやデプロイが停止するという事態に発展しました。
対策について
幸いなことに全社的に利用しているNexusは別のIPアドレスを利用していたためbanの影響は受けていませんでした。そのためbanを解除してもらうまでの暫定対応としてNexusをregistryとして使用してもらうことになりました。
最終的にbanは無事解除してもらえましたが、次また同じ問題が発生しないとは限りません。本格的な対策を練る必要がありました。この問題は大量のリクエストを特定のアドレスから公式のnpm registryに送ったことが原因になります。そこでPrivate npm registryの社内での利用を必須にすることで、不要なリクエストをLINEのPrivate Cloudから発信しないようにしました。上の「Private npm registryについて」の2で述べたようにPrivate npm registryは一度取得したパッケージをcacheとして持ちます。Private npm registryを使わない場合と比較して、はるかにリクエスト数を減らすことができるのです。