# カスタムスクリプトでシークレットを使用する方法

Treasure Dataでは、シークレット情報を環境変数内に隠すことをお勧めします。このベストプラクティスにより、他の人がシークレット情報にアクセスできるコードを誤ってプッシュすることを避けられます。

## ローカル環境でPython仮想環境を作成する

Pythonは、独自のサイトディレクトリを持つ軽量な仮想環境を作成するための[venv](https://docs.python.org/3/library/venv.html)を提供しています。または、[pip](https://pypi.org/project/pip/)を使用して同じ環境を作成することもできます。

## 依存関係のインストール

1. [gist](https://gist.github.com/chezou/d0a0fc62007af4d808752e78b31ae694)に移動します。
2. 以下をダウンロードします：


* requirements.txt
* constraints.txt


コマンドラインからの例：


```bash
$ python -m venv .venv
$ source .venv/bin/activate
(.venv)$ pip install -r requirements.txt -c constraints.txt
```

1. venv仮想環境を使用すると、ローカル環境で同じパッケージを使用して開発できます。


このアプローチでは、オペレーティングシステムの不一致は解決されません。例えば、Debianで実行されている本番環境と、WindowsまたはmacOS Xの開発環境では、[apt-get](https://linux.die.net/man/8/apt-get)のようなOS依存のコマンドを実行するときにエラーが発生する可能性があります。

## PythonでTreasure ワークフローをテストする

ローカル環境でワークフロー全体を実行したい場合は、Digdagを代替として使用できます。

Treasure ワークフローはDigdagと同じではありません。

## Pythonオペレーターにパラメータを渡す

py>オペレーターにパラメータを渡す方法は以下のとおりです：

* [Digdag変数](https://docs.digdag.io/workflow_definition.html#using-variables)
* [カスタムスクリプトでシークレットを使用する方法](/ja/products/customer-data-platform/data-workbench/workflows/customscript/how-to-use-secrets-in-custom-scripts)
* [環境変数](/ja/products/customer-data-platform/data-workbench/workflows/customscript/how-to-use-secrets-in-custom-scripts)


## Digdag引数の例

py_scripts/examples.pyという名前のPythonスクリプトが以下のようにあると仮定します：


```python examples.py
def print_arg(msg):
    print(f"Message is {msg}")
```

以下の例のように、simple_with_argタスクからmessage引数を渡すことができます：


```yaml
+simple_with_arg:
  py>: py_scripts.examples.print_arg
  msg: "Hello World"
  docker:
    image: "<image_name>:<version>"
```

複数の引数を渡すには、関数に引数を追加し、Digdag引数にも追加します。

Digdag引数をPythonにシームレスに渡すことができますが、キーワード引数`**kwargs`を使用すると、意図しない変数が渡される可能性があります。例えば、Docker変数は辞書（`{"image": "..."}`など）として渡される可能性があります。Treasure Dataでは、Python関数で明示的な引数を使用することをお勧めします。

Digdagとpy>オペレーター間で意図しない競合が発生する可能性があります。以下のようにDigdag変数を設定したと仮定します：


```yaml
_export:
  td:
    database: my_db

+simple_with_arg2:
  py>: py_scripts.examples.print_arg_td
  msg: "Hello World"
  docker:
    image: "<image_name>:<version>"
```

以下のようにtd引数を持つPython関数print_arg_tdを使用します：


```python examples.py
def print_arg_td(msg, td=None):
    print(f"'msg' is {msg} and 'td' is {td}")
```

エクスポートされたtd変数は常に渡されるため、td変数は決して_None_であってはなりません。例えば、`{"database": "my_db"}`が渡される変数になるはずです。これにより、辞書と文字列のような型の不一致が発生する可能性があります。Treasure Dataでは、Digdagの予約済み引数の使用を避け、代わりにtd変数を使用することをお勧めします。例：

* td.endpoint
* td.apikey
* td.use_ssl
* td.proxy.enabled
* td.proxy.host
* td.proxy.port
* td.proxy.password
* td.proxy.user


Digdagは、例えば文字列から整数のように、意図しない型に変換する場合があります。Treasure Dataでは、Python関数内で型を評価または明示的に変換することをお勧めします。

参照：[https://docs.digdag.io/workflow_definition.md#using-variables](https://docs.digdag.io/workflow_definition#using-variables)

## 環境変数

環境変数は、py>オペレーターにパラメータを渡すもう1つのオプションです。環境変数は、安全な情報やシークレットを渡すのに適しています。

シークレットと環境変数には8192文字の制限があります。

例えば、Treasure Dataにsimple_with_envタスクがある場合：


```yaml
+simple_with_env:
  py>: py_scripts.examples.print_env
  _env:
    MY_ENV_VAR: "hello"
  docker:
    image: "<image_name>:<version>"
```

os.environを通じてMY_ENV_VARにアクセスします。例：


```python
import os

def print_env():
    print(f'Env var is {os.environ["MY_ENV_VAR"]}')
```

シークレット情報を使用する必要がある場合、例えばTreasure APIキーやAWSシークレットキーなどの場合、環境変数を使用することが重要です。

Digdagにはシークレット情報を保存する機能があります。td workflow secretsサブコマンドを実行すると、シークレットはDigdagまたはTreasure ワークフローデータベースに保存されます。

![](/assets/image-20200806-204756.9fc55842c4daafea33f4066ea224fcd85694b1485eb124cd6df0a3aca34abe7b.142841d8.png)

td.apikeyという名前のシークレットを設定したと仮定します。このシークレットはpy>オペレーターに渡すことができます。例：


```yaml
+simple_with_env2:
  py>: py_scripts.examples.access_td
  _env:
    TD_API_KEY: ${secret:td.apikey}
  docker:
    image: "<image_name>:<version>"
```

py_scripts/examples.pyは以下のようになります：


```python
import os

def access_td():
    apikey = os.environ["TD_API_KEY"]
    # Do awesome execution
```

通常のDigdag引数からシークレットを渡そうとすると、シークレットはシークレットDBから取得されません。例えば、以下のようなタスクがある場合：


```yaml
+simple_with_env_ng:
  py>: py_scripts.examples.access_td_ng
  apikey: ${secret:td.apikey}
  docker:
    image: "<image_name>:<version>"
```

代わりに以下のスクリプトを使用する必要があります：


```python
def access_td_ng(apikey):
    print(apikey)
    # Always shows "${secret:td.apikey}" insted of actual API key like "1234/XXXX"
```

## Digdag変数

PythonスクリプトでDigdag変数を読み取りたい場合は、以下の例のようにDigdag.env.paramsを使用できます：


```python
def read_workflow_env(msg):
    import digdag
    print(digdag.env.params["my_msg"])
```

import Digdagコマンドは、スクリプトがDigdag py>オペレータータスクとして実行されている場合にのみ実行できます。インポートエラーを回避したい場合は、以下のように「try-except構文」を記述する必要があります：


```python
try:
  import digdag
  digdag.env.store({"feature_query": feature_query})
except ImportError:
  pass
```