docker-registry に認証/アクセス制限を追加する nginx-docker-registry を公開しました

TL;DR (3行で)

  • 公式の docker-registry には認証がない
  • ngx_mruby で Basic認証とアクセス制限をかけるスクリプトを書いた
  • Docker イメージを nagachika/nginx-docker-registry で公開

動機

どうもこのごろ猫も杓子も Docker で食傷気味ですね。しかし最近わたしも Docker 使うようになってしまいました。

Docker のイメージを保存する Docker Registry はオープンソースになっていて、Private Docker Registry を立てるのは非常に簡単にできます。使いかたを解説した記事もたくさんあります。

https://github.com/docker/docker-registry

しかしこの docker-registry には認証やアクセス制限の機能がないため*1、どこからでもアクセスできるようなところに立てると誰でもイメージを push/pull できてしまいます。認証については公式の DockerHub の index endpoint に委譲するか、独自にやる時は docker-registry のフロントに reverse proxy を立ててそこでやってね、というのが公式のスタンスのようです。

nginx を使って docker-registry に Basic 認証をかける方法を解説した記事は前例があります。

認証付きのDocker Private registryを立てる | SOTA

もう一歩進んで、ユーザ毎の namespace へのアクセスを制限できるようにしたいと思います。
また複数のユーザが利用できるようにするため、認証情報の設定をラクにしたいというニーズもあります。

実現したいのは以下のようなことです

  • Basic 認証をかける
    • 認証情報は DB などのストレージから取得させる
  • ユーザアカウント毎に dokcer push/pull できるネームスペースを制限する
    • ユーザ名 userA の時は userA/app1 のような名前のみアクセスできる
  • SSL 対応

実現方法

nginx でこうしたちょっと複雑なことを実現するために ngx_mruby を利用することにしました。

https://github.com/matsumoto-r/ngx_mruby

ngx-mruby からは Redis を利用することができるというのをきいたことがあったので、認証情報の取得先として Redis を使うことができるだろうと思ったのと、なにより ruby で書けるので nginx の設定の書きかたやモジュール群の機能について詳しくなくてもなんとかなるだろうという目論見でした。実際には nginx のフェーズについても多少は知らないといけないことはありましたが…それでも他のモジュールを組み合わせてなんとかするのよりは(自分にとっては)楽ができたと思います。

認証情報は Redis に格納して mruby スクリプトで読み込むようにしました。Basic 認証とアクセス制御を mruby で実装しています。
またリクエストを転送する docker-registry のアドレスの情報も Redis に格納してそこから読み取るようにしました。これは nginx.conf で upstream の設定をすることもできるのですが、転送先のサーバを認証したユーザ毎に振り分ける(そうすることでイメージのストレージをユーザ毎に独立させる)というのもやりたいと思っているので、redis から取得する作りにしています。
SSL 対応は nginx の ssl module を利用しています。

ngx-mruby の作者の @matsumotory さんには、Dockerfile の pull request を取り込んで頂いたり、Twitter でつぶやいていたらすぐに必要な module の組み込みをしてくださったりといろいろ助けて頂きました。ありがとうございます。

使いかた

リポジトリhttps://github.com/nagachika/nginx-docker-registry に公開しています。

また Docker イメージも DockerHub で公開しています。 https://registry.hub.docker.com/u/nagachika/nginx-docker-registry/

簡単に使いかたを README.md に Quick Start として書きました。

ちょっと解説を追加すると、Quick Start では転送先の docker-registry*2と、ストレージの redis も同じ docker ホスト上で動かすケースにしています。お試し用ということで redis や registry のストレージはコンテナ削除と同時に消えます。永続化が必要ならそのあたりは適宜 volume 設定なり外部サービスを使うなりやってください。転送先のアドレスも redis に設定するようにしているので redis-cli で入れておく必要があります。
また認証情報ですが、redis には password はとりあえず salt をかけて SHA1 Digest したものを格納するようにしています。redis へのアクセス制限はしっかりする必要があると思います。もちろん salt は実際には固有の推測されない文字列を使ってくださいね。そのへんは説明してないけど察してくれると期待している…。

あとは docker push してみるだけなのですが、Quick Start では SSL の証明書はオレオレ証明書を作っているので、このままだと docker コマンドは失敗します。
認証付きのDocker Private registryを立てる | SOTA を参考に証明書を docker デーモンの起動するノードに登録しなくてはいけません。あと docker login とかイメージ名にアドレスを含める方法とか…このあたりもいずれ簡単に Quick Start に追記したいと思います。boot2docker 使ってると証明書は VM 内に追加しないといけないとかアドレスが異なるとか、環境毎に対応したドキュメント書くのが面倒でしてね…。

なにか問題をみつけたらフィードバックお願いします。

*1:正確には DockerHub の index と連携する機能はある、らしい。しかし独自の認証を追加するのは別にする必要がある

*2:Docker のイメージ名は単に registry なんですよね。よく忘れる