「direnv」を使ってプロジェクトディレクトリごとに環境変数が自動的に設定されるようにする

2023-05-07Bash

はじめに

AWSの環境構築系のツール( aws-cli とか Terraform )を使って複数のAWSアカウントを使い分けていると、
「環境変数はどっちのアカウントのものを利用していたっけ?」となることが多くなってきました。

アプリケーション毎に利用するアカウントが決まっている場合、アプリケーションディレクトリに cd コマンドで移動したタイミングで環境変数が自動的にセットされるととても便利です。

ぴったりなツールとして direnv というものがありましたので紹介します。

direnvとは?

ディレクトリ毎に環境変数を定義して、そのディレクトリがカレントになった時だけ環境変数を有効/無効にしてくれるツール。開発中のアプリ毎に環境変数を変えたい時に重宝します。

リポジトリは以下になります。

direnvはシェル用の環境切り替えツールです。

これにより、 ~/.bashrc~/.profile ファイルのようなグローバルな設定ファイルにアプリケーション個別の環境設定情報を記載する必要がなくなります。

  • プロジェクトディレクトリ配下の設定ファイルから環境変数をロードされる。
  • プロジェクトディレクトリ内のどのディレクトリにいても、これが適用される。
  • プロジェクトディレクトリ内から抜けた場合は環境変数をアンロードされる。
  • 「bash」、「zsh」、「tcsh」、「fish」、および「elvish」に対応。

direnvは最近あちこちで導入され始めている Go言語 で作成されています。

検証環境

すでに僕のmacOS上にインストールされていたため、Dockerで検証用のクリーンな環境を用意して検証を行いました。
(Dockerがなくても利用には全く問題がありません。)

# CentOS7環境をDockerで立ち上げる
$ docker run --rm -it centos:centos7 bash

利用したCentOS7環境は以下の通り。

$ uname -moi
x86_64 x86_64 GNU/Linux

$ bash -version
GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu)

前提条件

  • Gitが利用できる環境であること
    • インストール時に必要

インストール方法

Unix系OSの場合

まずは事前に「Go言語」を使えるようにしておきましょう。
( もちろんすでにインストール済みの場合は不要です。 )

$ sudo yum install epel-release

$ yum install -y golang

Go がインストールできたら、「direnv」のコードを取得してビルドします。

$ git clone https://github.com/direnv/direnv

$ cd direnv

$ make

$ sudo make install

macOSの場合

Homebrewを利用しているのであれば以下のコマンドでインストールできます。

$ brew install direnv

確認

インストールできたか確認してみましょう。
以下のようにバージョンが表示されていればインストールが完了です。

$ direnv --version
2.19.2

セットアップ

~/.bashrc ファイルの最後に次の行を追加します。
これによりシェル起動時に direnv の便利機能が利用できるようになります。

echo 'eval "$(direnv hook bash)"' >> ~/.bashrc

これで、次回のインタラクティブシェル起動時から有効となります。
現在起動中のインタラクティブシェルにも適用しておきましょう。

$ . ~/.bashrc

使い方

サンプルのプロジェクトフォルダを作成しましょう。

$ mkdir testdir && cd testdir

ここで環境変数 X の値を確認しておきます。まだこの環境変数は存在しないことがわかります。

# 何も出力されない
$ echo $X

プロジェクトフォルダ内だけで利用したい環境変数がある場合は .envrc というファイルを作成し、 export コマンドで公開してやります。
注意点として .envrc の構文はどんなインタラクティブシェルを使っていたとしても Bash 方式で記述しなければならないという点です。
(注意と言っても、普通は export コマンドの使い方なんてどのシェルでも同じですよね。)

$ cat <<'EOF' > .envrc
export X=123
EOF

direnv: error .envrc is blocked. Run `direnv allow` to approve its content.

いきなりエラーメッセージが表示されたと思います。

direnv.envrc をブロックしたよ文句を言っています。
これは、移動したディレクトリ配下(あるいはその親・祖先ディレクトリ)にある .envrc ファイルを自動的にロードしないようにするためのセキュリティメカニズムです。

この機能がなかった場合、 git pull あるいはtarアーカイブを展開したディレクトリに cd したタイミングで環境変数が自動的にセットされるため、セキュリティリスクがありますね。

読み込んで問題のない .envrc ファイルだと確信できた場合のみ、 direnv allow を実行します。
これによりこのプロジェクトディレクトリの .envrc ファイルがブロックされなくなります。

$ direnv allow
direnv: loading .envrc
direnv: export +X

.envrc ファイル内に定義されている環境変数 X が追加されました。

試しに値を確認してみましょう。

$ echo $X
123

確かにセットされています。

ここで別のディレクトリに移動してから環境変数 X の値を確認してみるとどうでしょう。

$ cd
direnv: unloading

# 何も出力されなくなる
$ echo $X

もう一度 testdir に移動してみます。

$ cd testdir
direnv: loading .envrc

$ echo $X
123

プロジェクトディレクトリから cd すると自動的にアンロードされます。

(注意点) && でつなげて移動と当時に変数参照した場合は見えてしまいます。

# プロジェクトディレクトリにいる
$ pwd
/root/testdir

# 移動と同時に変数参照すると見える
$ cd && echo $X
123
direnv: unloading

# 変数参照できない
$ echo $X

便利な使い方1:PATH環境変数を設定

更に便利な使い方ができます。

プロジェクトディレクトリ配下に bin が置かれており、これにユーティリティツールが格納されていることがあります。
PATH に追加したいのであれば、下記のように環境変数を設定します。

$ cat <<'EOF' >> .envrc
export PATH=./bin:$PATH
EOF

または、ショートカットで指定できます。

$ cat <<'EOF' >> .envrc
PATH_add bin
EOF

※変更すると、再度 .envrc がブロックされます。必要に応じて direnv allow してやりましょう。

便利な使い方2:環境変数を削除

環境変数を追加するだけではなく、 unset コマンドを使って削除することもできます。

$ cat <<'EOF' >> .envrc
unset USER
EOF

ひとこと

このファイルをリポジトリに追加し、Githubにpushしてしまうと環境変数に設定したパスワード等が漏れてしまいます。
AWSのキー情報なども同様ですね。
誤ってコミットしてしまい、クラックされるというお話を聞いたことがあります。(僕は今の所経験はないです。)

.envrcをリポジトリにコミットしないように注意しましょう。

2023-05-07Bash