Cloud ComposerとSecret ManagerでAirflowをセキュアにSlack連携する

この記事は、Merpay Tech Openness Month 2023 の18日目の記事です。

はじめに

メルペイでBackend Engineerをしている@champonです。
普段はApache Airflow(以下、Airflowと呼ぶ)を用いた与信枠計算パイプラインの運用をしています。
この記事では、Cloud Composer(以下、Composerと呼ぶ)を用いたAirflowからSlack通知を行う実装例について紹介します。

AirflowにおけるSlack連携

メルペイの与信枠計算では、データパイプラインとしてComposerを用いたマネージドなAirflowを採用しています。Airflowでは、有向グラフ上に定義したタスクを順次実行していくワークフロー(DAG)を構築することができます。自分のチームでは、Airflowを運用する上で主にアラートの用途として、DAGが失敗したときにSlackに通知が送られるようにしています。これにより、DAGの失敗にチーム全員が気付けるようになり、またより早く修正対応に取り組むことができるため、総合的に運用コストを下げることができます。

以降では、AirflowのSlack連携において、Secret Managerを導入したよりセキュリティの高い実装例について記載します。

Secret Managerについて

Secret Managerは、APIキーなどの機密性の高いシークレットデータを暗号化して保存することができるGoogle Cloud Platform(以下、GCPと呼ぶ)上のサービスです。シークレットデータのバージョニングも行えるため、汎用性高く使用することができます。

さて、Slack連携をするためにはSlackで発行したトークンが必要になります。このトークンは機密性の高い情報であるため、露出した場所に保管するのはリスクがあります。例えば、Composerでは環境変数を設定することができますが、設定した値はGCPコンソール上で直接確認できるようになっています。該当するGCP Projectのコンソールにアクセスできるユーザーは限られてはいますが、暗号化されてない上に露出した形で保管されているのは良くないです。

また、環境変数への設定はシークレットデータのローテーションにおいても不都合が生じます。万が一シークレットデータが漏洩してしまった場合、以前まで使っていたシークレットデータを失効し、新しいものに設定する必要があります。しかし、Composerでは環境変数の更新に際してComposer環境が再起動されます。Composer環境の再起動には数十分の時間を要するため、開発の遅延やスケジュール実行との競合などが発生する恐れがあります。

そこで、SlackのAPIトークンをSecret Managerで管理することで、Composerと切り離した形で運用することができ、より安全かつ柔軟性を高めることができます。

Cloud ComposerからSecret Managerにアクセスする

ComposerからSecret Managerにアクセスするには、terraformにおいて以下のように定義し、Composerのサービスアカウントに対してRoleを付与します。

resource "google_service_account" "composer_service_account" {
  project      = “my-project”
  account_id   = "composer-service-account"
  display_name = "A service account for composer"
}

resource "google_secret_manager_secret" "slack_api_token" {
  project   = “my-project”
  secret_id = "slack-api-token"
}

resource "google_secret_manager_secret_iam_member" "composer_service_account_is_secret_accessor_to_slack_api_token" {
  project   = “my-project”
  secret_id = google_secret_manager_secret.slack_api_token.secret_id
  role      = "roles/secretmanager.secretAccessor"
  member    = "serviceAccount:${google_service_account.composer_service_account.email}"
}

Secret Managerからシークレットデータを取得するためには、GCPのClient Libraryを用いることで実現可能です。Pythonでは、SecretManagerServiceClientのaccess_secret_versionメソッドを用いてSecretのIDおよびVersionを指定することで、シークレットデータを取得できます。

client = secretmanager_v1beta1.SecretManagerServiceClient()
name = client.secret_version_path(“my-project”,”slack-api-token”,”latest”)
response = client.access_secret_version(name=name)
secret_data = response.payload.data.decode(“utf-8”)

AirflowではPythonOperatorを使用することでPythonでDAGのタスクを実装できるため、タスク単位でAPIトークンを取得してSlack通知を行うことも可能です。

Airflow Connectionを使う方法

先の節では、GCP Client Libraryを用いてSecret Managerからシークレットデータを取得しました。しかし、Airflow Connectionという機能を用いることで、Secret ManagerとAirflowを直接連携できます。

まず、Airflow ConnectionでSecret Managerをbackendにするために、terraformにおいてgoogle_composer_environmentのairflow_config_overridesを設定する必要があります。また、Slack通知との連携を行うためのパッケージを別途インストールするようにします。

resource “google_composer_environment” “my_composer” {
  config {
    software_config {
      airflow_config_overrides = {
        secrets-backend = "airflow.providers.google.cloud.secrets.secret_manager.CloudSecretManagerBackend"
      }

      pypi_packages = {
        apache-airflow-providers-slack = ""
      }
    }
  }
}

※基本的な設定項目は省略しています

また、Airflow Connectionを使用するためには、Secret ManagerのSecret IDのprefixを’airflow-connections’に指定する必要があります。

resource "google_secret_manager_secret" "slack_api_token" {
  project   = “my-project”
  secret_id = "airflow-connections-slack_api_token"
}

次に、Secret ManagerにJSONフォーマットでデータをアップロードします。

{
  “conn_id”: “slack_api_token”,
  “conn_type”: “slack”,
  “password”: “<YOUR SLACK API TOKEN>”
}

※JSONフォーマットを使用する場合はapache-airflow>=2.3.0である必要があります。代わりにURIフォーマットも使用可能です
※conn_idはSecret IDからprefixを取ったものとなります

あとは、SlackAPIPostOperatorを用いて、Slack通知を行うOperatorを簡単に実装することができます。

from airflow.providers.slack.operators.slack

slack = SlackAPIPostOperator(
    task_id=”slack-notification”,
    channel=”#test-channel”,
    conn_id=”slack_api_token”,
    text=”Hello World”,
)

まとめ

本記事では、Composerで構築したAirflowにおいて、Secret Managerを用いたSlack連携の実装例について紹介しました。GCPのドキュメントを読むとAirflow Connectionを用いる方法が推奨されていますが、同じSecretを別のサービスにも用いておりSecret IDを変更したくない(後からprefixを付けたくない)等の理由があれば、より柔軟に対応できるClient Libraryを用いる方法が良いかもしれません。

明日は @youxkeiさんと@fivestarさんの記事です。引き続きお楽しみください。

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