ふとしたことで、不特定多数のユーザにssh接続環境を用意してハンズオン環境を作る際、sshログインと同時にdockerのインスタンスにアクセスさせることができれば、各ログインセッションごとに同じ環境を個別に用意できるのではないかと思ったので、やってみることにした。 (といっても、やってることは単純でsshのauthrozied_keysのcommandに docker run -it image /bin/bash を書いといてやることで、指定したイメージから個別にコンテナを起動してログインさせているだけなのだけど…) メリットとしては、例えば

  • 複数名でログインしている場合に、1名が必要なファイルを消してしまっても他のユーザへの影響が無い
  • 各ユーザに個別にログイン情報を渡さずに済む(一括で渡しておけばいい)
  • docker runでコンテナを起動させてそのままbashにログインしているだけなので、外部への通信を行えないようにできる

といったあたりだろうか…? dockerの仮想ネットワークと組み合わせてネットワークを閉じれば、簡易的なラボのようなものも作れる(かもしれない)。

逆にデメリットとして、

  • ログインして新しくファイルを作ったりした際はセッションが切れたらコンテナはexitしてしまうので、取り出す際に結構面倒そう (接続元のIPアドレスと以前の接続元のdocker idを紐付ける仕組みを作っておいて、既存のコンテナがあればdocker runかdocker startかを分岐させれば良さそうだけど、面倒だから今回はそこまでやらない。グローバルIP同じとこの場合とか考えると面倒だし)
  • 作ったコンテナはexitされる(or、Ctrl + P,Qをすればそのまま動作した状態になるだけ)なので、溜まっていくコンテナを定期的に削除してやる必要がある

あたりが考えられる。

とりあえず、今回はベースOS(及びコンテナイメージ)はCentOS 7を使うことにする。 また、一応DBサーバなどにアクセスも可能な簡易ラボっぽくしてみようと思うので、外部アクセスが行えない仮想ネットワークも作成する。 (完全に通信をさせないのであれば接続先ネットワークをnoneにしてコンテナ作ればいいけど)

1. Dockerのインストール

まず、以下のコマンドでベースとなるCentOSにdockerのインストールをする。

sudo yum install -y yum-utils device-mapper-persistent-data lvm2
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum makecache fast
sudo yum install docker-ce
sudo systemctl start docker
sudo systemctl enable docker

2. イメージの取得・カスタマイズ

dockerをインストールできたら、ssh接続ユーザがログインすることになるコンテナを作成する。 今回は面倒くさいので、既存のイメージ(今回はCentOSのオフィシャルイメージ)に最低限必要となるパッケージ入れてカスタマイズする(以下では、baseというコンテナ名でデーモンとして起動、接続している)。

docker pull centos
sudo docker run -d --name base -it centos /bin/bash
docker attach base

コンテナにログインしたら、CentOSのオフィシャルイメージにはなぜかipコマンド等が入ってないので、iprouteをインストールする。

yum install iproute

iprouteをインストールしたら、コンテナを停止させてそこからイメージを作成する。(イメージ名は「login_image」にしている)

docker commit base login_image

とりあえず、これでユーザが使用するコンテナイメージは完成。

3.仮想ネットワークの作成・設定等

次に、Docker用の仮想ネットワークを構築する。 Dockerでは、デフォルトだとホストのインターフェイスにブリッチがあるので、そこから外部のネットワークと通信が可能なのだが、今回はインターネットへの接続をさせない想定でいるので、Docker仮想ネットワークで外部ネットワークにアクセスできない環境を作り、そこに接続させるようにする。 仮想ネットワーク作成時に、以下のように--internalオプションを付与することで外部のネットワークにアクセス出来ないようにすることが可能。

docker network create -d bridge --internal --subnet 192.168.10.0/24 --gateway 192.168.10.254 docker-local

ここではやらないけど、pingやデータベースへのアクセスの練習用にMariaDBやらhttpdのイメージを取得してこのネットワークで起動させておくといいだろう。

4. ssh接続用ユーザの設定(docker run起動コマンド含む)

最後に、ユーザに公開するssh接続用ユーザの作成及び設定をする。(事前にssh用の鍵を生成しておき、公開鍵を作ってある状態とする)

useradd docker-login

sudoでdocker runだけ行えるように/etc/sudoersに以下を追記する。

docker-login ALL=(ALL) NOPASSWD: /usr/bin/docker run -it --network=docker-local*

「\~/.ssh」ディレクトリを作成してauthorized_keysに以下の内容を記述する。 (一応、Dockerのようなコンテナではfork爆弾を実行されるとホストに影響が出るので、docker run時のオプションでプロセス数は制限しておく)

command="sudo /usr/bin/docker run -it --network=docker-local --pids-limit 512 --name=$(date +%Y%m%d_%H%M%S)_test login_image" ssh-rsa AAA....

あとは、コマンドを設定した公開鍵に対応した秘密鍵でssh接続してやればそのセッションごとにコンテナを起動、接続してくれるようになる。

サービスを入れて検証作業をするとかそういったことには不向きだけど、コマンドを実際に叩いて動かしてみたりとか、スクリプトを作って動かしてみよう、といったレベルであれば問題無さそうかな。