Akatsuki Hackers Lab | 株式会社アカツキ(Akatsuki Inc.)

Akatsuki Hackers Labは株式会社アカツキが運営しています。

AWS上の fluentd から BigQuery への認証に Workload Identity を利用する

この記事では、AWS の EC2 や ECS 上で動作する fluentd から Workload Identity を利用してBigQueryにログを送る方法を紹介します。

背景

AWS から BigQuery にアクセスする際、従来はサービスアカウントキーを利用して認証を行なっていました。しかし、サービスアカウントキーは厳重な管理が必要です。これに対して、Workload Identity を利用すれば、管理が必要なキー自体をなくすことができ、運用の手間を軽減することができます。

先日 googleauth gem 1.5 がリリースされ、Ruby からも AWS からのWorkload Identity による認証をすることが可能になりました。
rubygems.org

早速これを利用して、AWS上のEC2やECSで動作する fluentd から BigQuery にデータ送信する際の認証方法を Workload Identity にしてみます。

Workload Identity の設定

下記のドキュメントに従って、AWS のロールと GCP のサービスアカウントの紐付けを行います。
あらかじめ作成したEC2のインスタンスプロファイルに割り当てたロール、またはECSのタスクロールを、GCP上のBigQueryへのアクセス権限をつけたサービスアカウントに紐付けます。
cloud.google.com

詳しい手順は省きますが、本ブログの下記の記事でもコンソールを利用した設定方法を紹介しています。
hackerslab.aktsk.jp

fluentd のセットアップと動作テスト

Docker を利用して fluentd を動作させます。下記は最小限のサンプルですので、実際には要件に応じて buffer や fluent-bigquery-plugin の設定が必要です。
Workload Identity 用の認証情報構成ファイル(JSON)を、Dockerfile と同ディレクトリに workload-identity.json として配置してください。
なお、この認証情報構成ファイルはあくまでも設定ファイルであって認証情報ではないので、サービスアカウントキーと違ってより気軽に扱うことができますので、下記でも Docker イメージ内に単純にCOPYして配置しています。

Dockerfile

FROM fluentd:latest
USER root
RUN apk add --no-cache --update --virtual .build-deps build-base ruby-dev \
   && fluent-gem install fluent-plugin-bigquery googleauth_aws_container_credential_provider \
   && fluent-gem sources --clear-all \
   && apk del .build-deps \
   && rm -rf /tmp/* /var/tmp/* /usr/lib/ruby/gems/*/cache/*.gem
COPY fluent.conf /fluentd/etc/
COPY workload-identity.json /home/fluent/.config/gcloud/application_default_credentials.json
USER fluent
CMD ["-r", "googleauth_aws_container_credential_provider"]

※ ビルド時に googleauth gem 1.5.0以降が導入されたことを確認してください。
※ googleauth_aws_container_credential_provider は、ECSで動作させる際に必要になります。詳細は後述します。

fluent.conf

<source>
  @type forward
  port 24224
</source>

<match data.*>
  @type bigquery_insert
  @id insert

  auth_method application_default
  project your-project-name  # 適宜設定してください
  dataset your_dataset_name  # 適宜設定してください
  table ${tag[1]}
  fetch_schema true

  <buffer tag>
  </buffer>
</match>

これをdocker buildして、Workload Identity に紐付けたロールを持つインスタンスプロファイルを割り当てた EC2 インスタンス上、またはタスクロールを持つ ECS タスクとして起動します。port 24224 でデータを受信できるようにしておいてください。そして、 fluent-cat 等を利用して、

echo '{"field1":123,"field2":"test_value"}' | \
  fluent-cat -h <fluentdのアドレス> data.<テーブル名>

のようにデータを送信すると、テーブル名に指定した BigQuery テーブルにそのデータが挿入されるはずです!


ただし注意点として、googleauth 1.5.0 の時点では IMDSv2 にうまく対応できないバグがあるようです。EC2で試す際は IMDSv1 が使えるように設定し、認証情報構成ファイル作成の際にも --enable-imdsv2 をつけない (つけてしまった場合はJSONから imdsv2_session_token_url キーを削除する )必要があります。
IMDSv2 の使用 - Amazon Elastic Compute Cloud

ECSタスクロールからの認証情報の取得について

さて、ここまで ECS でも動作すると書いてきましたが、実際には素の状態の googleauth はECSのタスクロールから認証情報を取得することができません。
EC2 ではインスタンスメタデータサービス (IMDS) のエンドポイント http://169.254.169.254/latest/meta-data/ を利用して認証情報を取得します。しかし、ECSのタスクロールの場合は http://169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI というエンドポイントを利用して取得します。アクセスの手順も異なるので、たとえ認証情報構成ファイルのエンドポイントを書き変えても対応できません。
これは Ruby の googleauth gem だけに限らず、他言語の認証ライブラリでも同様のようです。
しかし他言語で回避策が見つけられており、タスクロール用のエンドポイントから認証情報を取得して環境変数にセットした状態でライブラリを呼べば良いことが分かっています。

参考:
aws fargate - connection error from aws fargete to gcp bigquery by using Workload Identity - Stack Overflow
Workload Identity連携でAWS(EC2/ECS/EKS)からサービスアカウントキーなしでBigQueryにアクセスする

ただし、環境変数では認証トークンが期限切れになる恐れがあります。Ruby では Module#prepend を利用してパッチを当てられるので、これを利用して googleauth が認証情報を取得しようとするタイミングでタスクロールから認証情報を取得して返却させるのが確実でしょう。
これを簡単に実現できるように、 googleauth_aws_container_credential_provider という gem を作成しました。
rubygems.org
github.com


最初のDockerfileのように、 gem install し、fluentd の -r オプションで読み込ませるだけでECSタスクロールに対応させることができるようになっています。
なお、 googleauth gem に動的パッチを当てるという内容上、今後の googleauth のバージョンアップで内容が変わると利用できなくなる可能性がある点は注意が必要です。

まとめ

EC2やECSのタスクロールを利用して、 fluentd から BigQuery へデータ送信する際に Workload Identity で認証する方法を紹介しました。
特に、現時点では EC2 では IMDSv2 対応、ECS ではタスクロール対応に注意が必要であり、その回避策を説明しました。
クラウド間のフェデレーションは仕組み自体は複雑になりがちですが、セキュアな運用がより簡単に行えるようになることを期待しています。