LoginSignup
33
24

More than 3 years have passed since last update.

【MongoDB】MongoDBのDockerコンテナ起動時に認証用ユーザーを作成する

Last updated at Posted at 2019-07-15

MongoDBのDockerコンテナを使って開発を行う際に本番環境での使用も考えて、アプリケーションやターミナルから接続する時に認証するように設定しました。
コンテナを起動してからコマンドでの設定やShell Scriptを自作してやるのはスマートでないと思い色々調べていると、公式のイメージが初期データを挿入できるように作られていました。その方法と裏で何をしているのかを調べたので備忘録として書いておきます。

環境

認証用ユーザーの作成方法

ユーザーを作成するJavaScript

createUser.js
const user = {
  user: 'staff',
  pwd: 'staff_password',
  roles: [{
    role: 'readWrite',
    db: 'test'
  }]
};

db.createUser(user);

このスクリプトによって、ユーザー名staff、パスワードstaff_passwordtestDBのreadWrite権限が付与されたユーザーが作成されます。ちなみにロールは複数付与することができます。
MongoDBに接続にはmongo test -u staff -p staff_passwordコマンドを実行します。

認証の有効化

MongoDBは

MongoDB does not enable access control by default. You can enable authorization using the --auth or the security.authorization setting.

と書かれている通り、デフォルトでは認証・認可は有効化されていません。認証用のユーザーを作ったところで認証・認可を有効にしないと意味がありません。
有効にする方法は、引用文に書かれているように--authコマンドオプションを使用するか、コンフィグのsecurity.authorizationenabledにする2通りあります。

Dockerfile

認証用ユーザーを起動時に作成するためには、createUser.jsを/docker-entrypoint-initdb.d下に配置する必要があります。
そして、認証・認可を有効化したDockerfileは以下のようになります。

FROM mongo:4.1-bionic
COPY createUser.js /docker-entrypoint-initdb.d/
EXPOSE 27017
CMD ["mongod", "--auth"]

docker-entrypoint.shのカラクリ

MongoDBのDockerイメージではコンテナ起動時にdocker-entrypoint.shが実行されて初期データが挿入されます。そのShell Scriptが何をやっているのかを説明していこうと思います。

rootユーザーの生成

環境変数にMONGO_INITDB_ROOT_USERNAMEMONGO_INITDB_ROOT_PASSWORDが設定されているとrootユーザーが作成されます。このrootユーザーはroleがrootとなっており、全てのリソースにアクセスできるようになっています。なので、rootユーザーが必要ない状況であれば作成しない方がいいです。

以下がrootユーザーを生成している該当箇所です。

docker-entrypoint.sh
mongo=( mongo --host 127.0.0.1 --port 27017 --quiet )

if [ "$MONGO_INITDB_ROOT_USERNAME" ] && [ "$MONGO_INITDB_ROOT_PASSWORD" ]; then
    rootAuthDatabase='admin'
    "${mongo[@]}" "$rootAuthDatabase" <<-EOJS
    db.createUser({
        user: $(_js_escape "$MONGO_INITDB_ROOT_USERNAME"),
        pwd: $(_js_escape "$MONGO_INITDB_ROOT_PASSWORD"),
        roles: [ { role: 'root', db: $(_js_escape "$rootAuthDatabase") } ]
    })
    EOJS
fi
変数 説明
$mongo mongo --host 127.0.0.1 --port 27017 --quiet localhostの27017でリッスンしているMongoDBに接続するためのコマンド
$rootAuthDatabase admin adminというデータベース

スクリプトでは、adminデータベースにユーザー名がMONGO_INITDB_ROOT_USERNAME、パスワードがMONGO_INITDB_ROOT_PASSWORD、ロールがrootであるユーザーを作成しています。

初期データの挿入

初期データを挿入するためには、それ用のShell ScriptかJavaScriptを書く必要があります。この2つ以外のスクリプトであると無視されます。
挿入用スクリプトが/docker-entrypoint-initdb.dに配置されていれば、スクリプトが実行されます。もちろん他のディレクトリに配置したら実行されません。←当たり前ですねw

前置きはこの辺にしてdocker-entrypoint.shの中身を見ていきましょう。
注) 行番号は説明のため1から連番にしてありますが、本物のソースコードの行番号と違います。

docker-entrypoint.sh
1  export MONGO_INITDB_DATABASE="${MONGO_INITDB_DATABASE:-test}"
2
3  for f in /docker-entrypoint-initdb.d/*; do
4   case "$f" in
5       *.sh) echo "$0: running $f"; . "$f" ;;
6       *.js) echo "$0: running $f"; "${mongo[@]}" "$MONGO_INITDB_DATABASE" "$f"; echo ;;
8       *)    echo "$0: ignoring $f" ;;
9   esac
10  echo
11  done

1行目

操作対象となるDBを環境変数MONGO_INITDB_DATABASEに格納してエクスポートしています。デフォルトではtestというDBが対象となっています。

3行目

/docker-entrypoint-initdb.d下にある全てのスクリプトを実行できるようにfor文で回しています。なので、実行内容ごとにスクリプトを分けて複数のスクリプトを/docker-entrypoint-initdb.dに配置することも可能です。1つのスクリプトにごちゃごちゃいろんなことを書かずに済みますね。

5行目

Shell Scriptを実行しています。.はスクリプトを読み込んで実行するという意味です。sourceコマンドと同様の役割を果たします。

6行目

JavaScriptを実行します。mongoコマンドには

You can specify a .js file to the mongo shell, and mongo will execute the JavaScript directly.

とあるようにJavaScriptを直接実行できる機能があります。わざわざnodeコマンドとかで実行している訳ではありません。
${mongo[@]}はrootユーザーの作成のところでも出てきましたが、mongo --host 127.0.0.1 --port 27017 --quietを指しています。

最後に

これで、初期データを挿入する方法とそのからくりがわかったと思います。
開発の場面では接続用のユーザーを作成したり、テストデータを挿入する時などに役に立つと思います。初期データを挿入できるのはMongoDBだけでなく、MySQLやPostgreSQLなどでも可能です。
便利な機能を使って環境構築は楽に素早く行って、メインの開発に注力していきましょう!
それでは:wave:

参考資料

33
24
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
33
24