SMARTCAMP Engineer Blog

スマートキャンプ株式会社(SMARTCAMP Co., Ltd.)のエンジニアブログです。業務で取り入れた新しい技術や試行錯誤を知見として共有していきます。

BigQueryだけでRedashから個人情報見えなくする方法解説

f:id:tkgwy:20190131220648j:plain

データエンジニアの瀧川です。

Redash使ってますか!?

Redashが出てここ数年、加速度的に導入事例が聞かれるようになり、もうスタートアップのデファクトスタンダードとも言えるのではないでしょうか。

その導入事例の中でよく聞かれるのが、 全社的に Redashを公開して、だれでもデータにアクセスできるようにしたよという話です。

確かにRedashは、クエリの蓄積・共有が容易ですし、グラフやダッシュボード機能がそのまま営業活動に使えたりと利点はたくさんあります。

ただ、ここで問題になるのが、個人情報を始めとする 一般ユーザが見ることのできないデータ をどのように制御するかだと思います。

本記事では、弊社で使っている BigQueryだけ で、個人情報をマスキングしたデータを用意し、権限設定でデータへのアクセスを制御する方法を紹介しようと思います!

目標

例として、 production データセットに users テーブルが存在し、カラムとして (id int64, email: string, created_at) を持つとします。(以下のような感じですね!)

f:id:tkgwy:20190131200920p:plain

そのときに email カラムがマスキングされたテーブルだけ参照できる common-bigquery サービスアカウントを作成できればゴールとします。

(Redashへは、作成したサービスアカウントを登録すれば、個人情報にアクセスできない)

方法

以下の手順で実施していきます。

  • 元テーブルからマスクテーブルへのコピーするクエリを作成
  • クエリを定期実行
  • サービスアカウントにアクセス権を付与
  • データセットの許可リストにサービスアカウントを追加

元テーブルからマスクテーブルへのコピーするクエリを作成

「マスキングしたいカラム以外をselect」ってどのように書いてますか?

単純にやるなら以下ですよね。

select id, created_at from production.users

しかし、BigQueryには replaceexcept というステートメントが存在して、「hogehogeなカラムだけを除く、置換する」という表現をすることができます! これを使って上のSQLを書き直すと以下のようになります。

select * except(email) from production.users

Standard SQL Query Syntax  |  BigQuery  |  Google Cloud

上記のステートメントと、UDF(User Defined Function)を使って、 production.users から email のドメイン以外をマスキングしてselectするクエリが以下になります! (UDFは複雑に見えますが、emailであれば@マークでsplitしてローカル部だけハッシュ化しているだけで、集計作業なんかでドメインを残したほうがいい場合のクエリですね)

#standardSQL
create temp function mask(str string, typ string) as (
case typ
  # emailはローカル部だけマスクし、ドメイン情報は残す
  when 'email' then (
    select format('%s@%s', to_hex(sha256(local)), domain) from (
      select split(str, '@')[safe_offset(0)] as local
           , split(str, '@')[safe_offset(1)] as domain
    )
  )
  else to_hex(sha256(str))
end
);
select * replace (mask(email, 'email') as email) from production.users

実行するとこのようになります。

f:id:tkgwy:20190131210609p:plain

クエリを定期実行

作成したクエリを実行することでコピーは作成できますが、データを更新するため定期実行する必要があります。

実環境では定期ジョブ全般はDigdagを使ってますが、最近BigQueryに実装されたScheduledQuery(β)を使ってやってみようと思います。

Scheduling queries  |  BigQuery  |  Google Cloud

WebUI上でクエリを作成し、「Save Scheduled Query」ボタンを押して、必要情報を入力したのが以下となります。

これで、1時間毎にデータが更新されるようにできました。今まで定期実行する仕組みをこちらで用意する必要があったのですが、とても便利ですね!

(BigQueryはデータセット単位でしかアクセス制御できないので、 masked_production データセットを作成してそちらでマスキングされたテーブルを管理します)

f:id:tkgwy:20190131204329p:plain

サービスアカウントにアクセス権を付与

残りの作業は、「masked_productionデータセットにのみアクセスできるサービスアカウント」を作成するだけです。

これはGCPのWebConsoleで行うのですが、ここでかなりハマるのがGCPの権限です。

GCPの権限は日本語が難しく、どれをつけるとなにができるのか直感的にわかりにくいと感じています。

今回でいうと、「BigQuery データ閲覧者」が罠で、これを付与すると無条件ですべてのデータセットが閲覧できるようになってしまいます。

なので以下の画像の通り、「BigQueryジョブユーザー」だけ付与するようにしましょう!

f:id:tkgwy:20190131210122p:plain

データセットの許可リストにサービスアカウントを追加

あとはBigQueryのWebUIから、 masked_production データセットの右の逆三角(▼)から「Share dataset」を押して、以下のように作成したサービスアカウントのEmailを「Can view」で追加すればすべて終了となります!

f:id:tkgwy:20190131211349p:plain

まとめ

この方法を使うと以下のメリットがありますね!

  • 開発やインフラ構築がいらない
  • SQLなので、マスキングの自由度高い
  • GCPの権限で完結する

ベストプラクティスとは言えないと思いますが、少しでもここで説明した機能やテクニックが参考になれば嬉しいです!