セキュリティ要件の高いシステムにNew Relicを導入できるのか検証してみた

こんにちは、NTTドコモの矢吹です。
本記事は [New Relic Advent Calendar 2021](https://qiita.com/advent-calendar/2021/newrelic)の18日目の投稿です。
ドコモでも[NTTドコモ R&D Advent Calendar 2021](https://qiita.com/advent-calendar/2021/nttdocomo)を開催していますので、よければこちらにも目を通していただけると幸いです。

## はじめに

私のチームでは、ドコモの大規模データをストリーム処理するETLシステムをAWS上に構築しています。EKS上に多くのアプリケーションを展開していますが、システムの運用・監視を行うにあたって、ログの用途やシステムのコンポーネントによってログの収集・可視化の方法が異なっていることが課題でした。具体的には、以下のような状況です。

- サービス監視用として、処理遅延や欠損などに関するメトリクスをCloud Watchで確認する
- システムリソースの監視には、Prometheusで収集したJMXメトリクス等を、Cloudwatch、Firehoseと経由してLambdaで変換した上でS3に保存し、AthenaとQuick Sightを用いて可視化する
- アプリケーションログはFluentbit等でElasticserachに送信・ログの保管を行い、必要に応じてログの検索やKibanaでの可視化を行う


このような散逸するテレメトリデータのための運用・保守をしていくことはかなり大変です。そのため、New RelicのようなオブザーバビリティのSaaSを導入し、テレメトリデータの一元管理を行うとどれくらい運用が楽になるのかは非常に気になっていました。
一方、我々のシステムは機密性の高いデータを扱っている都合上、セキュリティ基準は非常に高く設定されており、気軽にインターネット経由でログの送信などは行えません。
そこで「厳格なセキュリティ要件を満たしつつ、New Relicを導入することは可能なのか？」というところに焦点を当てて、検証を行っていきたいと思います。

### 導入にあたってのセキュリティ要件

New Relicを導入するには、

- ログを保管するストレージは暗号化されていること
- 通信経路が暗号化されていること

といった基本的な項目はもちろん満たしている必要があります。こちらについては、[New Relic側で対策がなされている](https://newrelic.com/jp/blog/how-to-relic/new-relic-security)ようです。

これに加えて、私たちのシステムでは下記のような要件を満たす必要があります。

- ログを送信する際はAgent側で送信するデータのフィルタリングが可能なこと
- New Relicに保存したログに不正なデータ含まれていないか監査できること

### 本稿の主題
このようにログの送信に関しては連携のハードルが高いため、まずはログ以外のメトリクスのみに絞ってNew Relicに集約する方法について考えます。ということで、本稿では「いかにログを出力せずにメトリクスだけをNew Relicに送信するか」という謎テーマで検証をしてきた内容についてまとめたいと思います。
（ログのフィルタリングや監査については現在進行形で検証を進めているため、共有する機会があればそこで共有します）

## メトリクスの連携
以下の種別毎にメトリクス連携する方法を見ていきます。

- AWSサービスのメトリクス
- K8sクラスターのメトリクス
- アプリケーションのメトリクス

### AWSサービスのメトリクス
Cloud Watchで見れるようなAWSサービス毎のメトリクスやカスタムメトリクスを連携します。基本的には[AmazonCloudWatch Metric Streams](https://docs.newrelic.com/jp/docs/infrastructure/amazon-integrations/aws-integrations-list/aws-metric-stream/) を用いるのが簡単です。
下図のように、AWSの各種サービスのメトリクスをCW Metric Streams -> Kinesis Firehose -> New Relicという構成でデータ連携を行なってくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552099/a596e93d-6801-755e-5b69-2f636349f577.png)
設定はNew Relic向けにCW Metric Streams、Kinesis Firehoseを作成するだけです。AWSサービスのメタデータも取得して表示したい場合はNew Relic向けのAWS Configなどの読み取り権限のあるRoleを作成してください。

#### CW Metric Streams, Kinesis Firehoseの作成
[New RelicがCfnを用意](https://nr-downloads-main.s3.amazonaws.com/cloud_integrations/aws/cloudformation/MetricStreams_CloudFormation.yml)してくれているので適切なパラメータを設定して実行するだけでOKです。New Relicに送信したくないカスタムメトリクス等がある場合は、[AWS::CloudWatch::MetricStream](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-cloudwatch-metricstream.html)に対してフィルター（IncludeFilters/ExcludeFilters）を手動で追加すると良さそうですね。

以上、AWS Metricsについては問題なく連携できそうです。

### K8sクラスターのメトリクス
K8sクラスターのイベントやノード・コンテナのリソース使用率などを取得します。
Guided InstallでKubernetesを選択し、収集するデータを選択することでセットアップ用のHelmコマンドもしくは、K8s yamlを生成してくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552099/ab4b9afb-6dd1-08a7-eb83-36830daaaa78.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552099/90e984cc-8404-fcf8-a627-cc1bf88c2bad.png)

ここで、Gather Log dataやPixieのオプションなどを選択するとLogを収集・送信するコンテナも起動してしまうので、メトリクスのみに絞りたい場合は外す必要があります。あとは生成されたyamlを実行すればNamespaceの作成からメトリクス収集用のPodの展開まで一気に行なってくれます。

### （余談）我々のシステムにおける課題
yamlを実行する際に、パブリックのコンテナレジストリからImageをPullして実行する必要がありますが、我々のシステムはセキュリティポリシー上インターネットからのインバウンド通信を完全にシャットダウンしています。そのため、K8s Integrationに必要な大量のコンテナイメージをプライベートレジストリ（ECR）に移した上で該当のyamlのimage名を全て書き換える必要があり、これはなかなか大変です。必要なコンテナイメージが全てPublic ECRやquay.ioなどにホストされていれば、先日発表された[ECRのPull Through Cache](https://aws.amazon.com/jp/blogs/aws/announcing-pull-through-cache-repositories-for-amazon-elastic-container-registry/)で解決できるかもしれないので、New Relicさんぜひご検討をお願いします・・・！！

### アプリケーションのメトリクス
最後にアプリケーションのメトリクスです。Kinesis Streamsを用いてストリーム処理を行うシステムである都合上、Kinesis Consumer Library (KCL)を活用するために基本的にJavaでアプリケーションを開発しています。JMXメトリクスが取得できれば良いので、[JMX Monitoring Integration](https://docs.newrelic.com/jp/docs/infrastructure/host-integrations/host-integrations-list/jmx-monitoring-integration/)を試してみました。ですが、こちらについては我々の環境ではうまく動作させることができませんでした。（Infrastructure agentのcontainer版にはjmx integration機能がありませんし、k8s版もドキュメントがなかったので、それらしく設定してみたもののダメでした。）

APMでもJMX含めた詳細なメトリクスを取得できるのでこちらについても試してみました。[Install New Relic Java agent for Docker](https://docs.newrelic.com/docs/apm/agents/java-agent/additional-installation/install-new-relic-java-agent-docker/)に記載の通りにNew Relic Agentをダウンロード＆解凍して起動時にエージェントを指定するだけなので、こちらもセットアップは簡単ですね。
起動するとJVMのメトリクスはきちんと表示できるようになりました。
![image (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552099/a632d590-18d7-2527-6611-307644c198d4.png)

カスタムメトリクスをAPMで収集・可視化したい場合はMBeanにメトリクスを登録し、収集するようにすれば良さそうです。こちらについてはまだ試せていないので今後取り組んで行きたいと思います。
https://docs.newrelic.com/jp/docs/apm/agents/java-agent/custom-instrumentation/java-agent-custom-jmx-instrumentation-yaml/

また、JFRの機能を有効化することで、ブラウザから遠隔でプロファイラーを起動することもできます。（環境変数: NEW_RELIC_JFR_ENABLED =trueとすることで有効化）
VisualVMやMission Controlを使わずともパフォーマンス解析ができるのでとても良いですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552099/d716781c-c89f-ec27-4077-30074fe54b0c.png)

アプリケーションのメトリクスについてはAPMを使う限りはログも送信されてしまいそうな気はしますが、まだ調査できていないので引き続き検証は続けていこうと思います。
（とはいえ、ここまで便利なのでログを適切に扱う方法を確立してAPMを活用していく方に振っていきたい。。CodeStreamも便利そうなので試してみたいし・・）

## まとめ
New Relicにログを送らずにメトリクスだけ送りたいというNew Relicの良さを殺してしまうような内容で試してきた結果についてまとめてみました。
ここまで触ってきての所感として、総じてセットアップが簡単に行えるし、メトリクスを一箇所に集約できるだけでもかなり運用が楽になりそうだと感じました。とはいえ、ログも含めた全ての情報を集約し、全てのテレメトリーデータを関連付けて分析できるようにするというのが本来の価値だと思うので、そこに向けた取り組みもしっかりと行っていこうと思います。

- Agentからログを送信する際に正規表現などでフィルターをかけた上で送信する
    - → ログはサイドカーコンテナのfluent-bitからフィルターをかけて送信する
- New Relic上の保存されたログに対して正規表現に引っかかるログをカウントし、ダッシュボード化する
    - → Logsに対してNRQLで正規表現のクエリを発行し、ダッシュボード化する

など、ある程度ログ対策の道筋が見えてきたので、こちらもまとまり次第どこかで共有できればと思います。