Ranger の カスタムマスキングポリシーの定義方法

# この記事について

Hadoopクラスタのリソースに対するアクセス制御を行う Ranger では、テーブルの列に対するマスキングポリシーを指定することができます。

マスキングポリシーには、プリセットで「Redact」というパターンがあり、これは英語をXに、数字をNに変換するものです。

このパターンが、プリセットの中では唯一、以下の三拍子が揃っていて大変便利です。

- 文字列型に適用できる
- 変換前のデータの雰囲気がなんとなくわかる（文字列の長さがそのまま保たれるから）
- 空欄の項目と値が入っている項目の区別ができる（HashはNullの項目にも何らかの値を入れてしまう）

しかし、Redact では全角文字が変換の対象にならないため、日本語の項目が全見えになってしまうという問題があります。

日本語を含む項目をいい感じにマスクするには、カスタムポリシーを設定する必要があります。しかし、書き方をわかりやすくガイドしたドキュメントがなかなか見つからずにつまづいたので、ここにいくつかサンプルを載せておきます。

# カスタムマスキングポリシーの定義方法

Ranger のマスキングポリシーの「Custom」を選択すると、入力欄が出てきます。
この中に、マスキングルールを定義します。

![Screen Shot 2023-11-16 at 23.10.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587845/9719df6f-f3bd-e8ca-1cd9-c6bd033ed3e7.png)

# カスタムのマスキングルールの例

日本語項目に対して、よく使いそうなものを置いておきます。

## すべての文字を「●」にする

```SQL
regexp_replace({col},".","●")
```

例：
もとの文字列：東京都中央区銀座1-1-1
変換後の文字列：●●●●●●●●●●●●●

## 最初の三文字をそのまま残し、残りを「●」にする

```SQL
CONCAT(regexp_extract({col}, '^(.{3})', 1), regexp_replace(regexp_extract({col}, '^.{3}(.+)$', 1), '.', '●'))
```

例：
もとの文字列：東京都中央区銀座1-1-1
変換後の文字列：東京都●●●●●●●●●●


## 👆今はここまで👆

すみません。もっと他に使えそうなものを調べたら、都度追記します。

# カスタムのマスキングルールを自前でアレンジするときのコツ

## カスタムルールをアレンジするには

上記の例を参考に、正規表現や、Impala が使っている String Function を駆使すれば、思いどおり（というか、書いたとおり）のマスキングルールを適用できます。

https://impala.apache.org/docs/build/asf-site-html/topics/impala_string_functions.html#string_functions__regexp_extract

## カスタムルールをアレンジするコツ

カスタムルールをアレンジする際は、直接 Ranger にルールを記述する前に、まず以下の手順を踏むことをおすすめします。

なぜこの方法がおすすめなのかは後述します。

### おすすめの手順 Step1

まずHueなどのクエリエディタで以下のクエリを実行します。

```SQL
SELECT 
　マスクしたい項目, 
  CAST(Rangerに書こうとしているマスキングルール as STRING) 
  from 対象のテーブル
```

たとえば customer というテーブルの name という項目に、「最初の２文字を残し、残りを●にする」というカスタムのマスキングポリシーを適用したいとします。

その場合は、Hueのエディタなどで以下のクエリをまずたたきます。

```SQL
SELECT 
  -- マスクしたい項目
  name, 
  -- CAST句の中にマスキングルールを入れたもの
  CAST(CONCAT(regexp_extract(name, '^(.{2})', 1), regexp_replace(regexp_extract(name, '^.{2}(.+)$', 1), '.', '●')) as STRING) 
  from customer;
```

うまくいけば、こんな結果が返ってくるはずです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587845/c047fa66-c2b0-cec4-fbab-b69b9a6165e5.png)

### おすすめの手順 Step2

Step1によって、

- 文法エラーが出ないこと
- 想定どおりのマスキング結果になること

が確認できたら、たたいたSQLの `CAST()` 句の中をRangerにコピーします。
その際、列の名前を {col} に変更します。

```SQL:Ranger にコピペする際の変更の例

-- もとのCAST句の中身
CONCAT(regexp_extract(name, '^(.{2})', 1), regexp_replace(regexp_extract(name, '^.{2}(.+)$', 1), '.', '●')

-- Ranger にコピーする場合
CONCAT(regexp_extract({col}, '^(.{2})', 1), regexp_replace(regexp_extract({col}, '^.{2}(.+)$', 1), '.', '●')

```

# 上記の手順を踏むのがおすすめな理由

上記の手順を踏むのがおすすめな理由は、一言で言うと、Rangerに直接ルールを定義すると、編集・テストともにしづらいからです。

## カスタムルールをアレンジするときに、おそらく必ず遭遇する問題

Ranger の画面にいきなりカスタムルールを定義しようとすると、以下の問題に遭遇すると思います。

- 入力欄が小さい
    - 単純に、非常に入力しづらい
    - 長いルールだと、自分が書いたルールの全体を画面上で見渡せない
    
- Rangerでは文法チェックをしてくれない
    - 文法のエラーがあっても、RangerのルールはSaveできてしまう
    - Ranger の画面上では、文法のハイライトなどもしてくれない
    - 定義したルールにエラーがあると、クエリエンジンで該当のテーブルを select した際に、SQLのエラーとして表示される
    - こんな感じです⏬
    - ![Screen Shot 2023-11-16 at 23.29.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/587845/2924338c-920b-0385-4449-db157802ad28.png)

- Ranger のルールが反映されるまでに少し時間差がある＆どのタイミングでルールが反映されたかがUI上ではわからない

上記の理由から、Rangerに直接ルールを定義しようとすると、非常にテストがしづらいです。

そのため、まずはクエリでテストをして、正しい構文を作った上でRangerに転記することをおすすめします。

# カスタムマスキングポリシーが機能する仕組み

最後に、カスタムマスキングポリシーが機能する仕組みを参考までに。

※ソースをちゃんと読んだわけではなく、挙動から推測した仕組みです。

- マスキングポリシーを定義すると、該当の項目を含む SELECT 文をかけた際に、該当の項目に対して裏で以下の処理がかかることにより、マスキングがかかる。

```SQL
SELECT CAST(変換ルール as STRING)
```

- 変換ルールは、以下の文法に則って定義することができる。

https://impala.apache.org/docs/build/asf-site-html/topics/impala_string_functions.html#string_functions__regexp_extract


- Ranger のマスキングポリシーは、列単位で指定する
    - つまりRanger は、定義されたルールがどの列に適用するためのものかをわかっている

- Ranger のカスタムルールを記載するときは、{col} と記載すると、Ranger（またはRangerが連携しているクエリエンジン）が {col} の部分をルール適用対象の列の名前に変換してくれる

# さいごに

この記事の内容は以上です。

お役に立った場合は、「いいね」やストックをしていただけると励みになります。
誤りを見つけた場合は、コメントでお知らせください。