SnowflakeでManaged Account に、dbtで作成したTableをシェアする。

## Managed Account とは？
- プロバイダーアカウント（自分が利用しているSnowflakeアカウント）から、子分のリーダーアカウント（読み取り専用アカウント）を作成できる
- （読み取り専用じゃないアカウントも作成できそうな雰囲気はあるが、絵的にも、日本語サイトもリーダーアカウントになっているので、きっと今は読み取り専用しか作れなさそう）

https://docs.snowflake.com/ja/user-guide/data-sharing-reader-create
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12298/f0c22c5f-9d2f-63f1-2fe1-c7b57156fb14.png)

### 何がうれしいか？
- たとえば、協業他社にデータを毎日送る必要があるときとか、ファイルを送るの面倒だし、自社環境を使ってもらうにはセキュリティに問題がある（Public DBがそのまま見られたりする）ので、会社単位とかでアカウントを作成しておけばいいのでは。
アカウントが完全に別になるので、セキュアでよいです。
例）プロバイダーアカウント（自社）: XX99999
┗ リーダーアカウント（A社用）：YY88888
┗ リーダーアカウント（A社用）：ZZ77777

### 費用はどうなるのか
- プロバイダーアカウントがリーダーアカウントの費用を全部持ちます。
- 読み取り専用とはいえ使い放題状態なので、リーダーアカウントのコストは確認しておく必要があります。

### その他注意事項
- リーダーアカウントはAdmin画面のアカウント一覧に出てこないので、存在を忘れないようにしないといけない。

## Managed Account 作成方法
### リーダーアカウントの作成
- SQLで作成する場合は↓こちら。
https://docs.snowflake.com/ja/user-guide/data-sharing-reader-create#creating-and-managing-reader-accounts-using-sql
- プロバイダーアカウントのterraformからも作成できます。
```hcl
resource "snowflake_managed_account" "account_a" {
  ## nameは大文字のみOK、プロバイダーアカウントが複数ある場合、プロバイダーアカウントが別でも、同じ名前は使えません。
  name           = "MANAGED_ACCOUNT_A_COMPANY" 
  admin_name     = "admin"
  admin_password = "secret"
  type           = "READER"
  comment        = "A managed account."
##  cloud,region,locatorはプロバイダーアカウントに準拠するので不要
##  cloud          = "aws"
##  region         = "us-west-2"
##  locator        = "managed-account"
}
```
 https://registry.terraform.io/providers/Snowflake-Labs/snowflake/0.90.0/docs/resources/managed_account

 #### 作成されたリーダーアカウントの情報を取得する。
 ```sql
 USE ROLE ACCOUNTADMIN;
SHOW MANAGED ACCOUNTS;
 ```
name, cloud, region, locator, created_on, url, account_locator_url, is_reader, comment, region_group が表示されるので、`locator` `account_locator_url`を記録しておく。

### 共有の作成と権限の付与
- shareとdatabase role を作成して、既存のshareしたいDBとSCHEMAに割り当てる。
- 共有したいテーブルに権限付与する。
```sql
create share share_a;
use database db_a;
create database role db_a.a_role;
grant usage on datbase db_a to database role db_a.a_role;
grant usage on schema schema_a to database role db_a.a_role;
grant usage on database db_a to share share_a;
grant database role db_a.a_role to share share_a;

## アカウントを共有に追加する
alter share share_a add accounts = YY88888;

## テーブルに権限付与
grant select on table table_a to database role db_a.a_role;
```

https://docs.snowflake.com/ja/user-guide/data-sharing-provider


### リーダーアカウントにAdmin loginして、各種設定をする。
- `account_locator_url`へ、`admin_name`と`admin_password`で、ログインしたら、公式↓見ながら、ロール、ユーザー、リソースモニター、ウェアハウス、シェア用データベースを作成し、権限をつける。
- データベース作成とPublicへの権限付与のSQLはこんな感じ。
```sql
use role ACCOUNTADMIN;
CREATE DATABASE db_a FROM SHARE XX99999.share_a;
grant imported privileges on database db_a to role public;
```


https://docs.snowflake.com/ja/user-guide/data-sharing-reader-config

- 弊社は上記にNetwork Policy (IP制限)を追加しました。

### リーダーアカウントに Public login してみる。
- ログインできて、共有されたテーブルのデータをSELECTできればOK。


## dbtで作成したTableの権限の再設定
- dbtで作成したTableはreplaceになるので、dbt build のタイミングでShare設定が消えるので、Taskとかでdbt build後に走るよう設定しておく
```sql
create or replace task db_a.schema_a.task_grant_table_a
  SCHEDULE = 'USING CRON 30 03 * * * Japan'
  USER_TASK_MANAGED_INITIAL_WAREHOUSE_SIZE = 'XSMALL'
  AS
    grant select on table db_a.schema_a.table_a to database role db_a.a_role;

ALTER TASK db_a.schema_a.task_grant_table_a RESUME;
```