docker上にRedmineとSamba4 Active directory認証環境を構築

# docker環境で Samba4 Active Directory認証(以下AD認証)を使用してRedmineにログインする。

以前、[docker上にRedmineとopenLDAP認証環境を構築](http://qiita.com/ir-shin1/items/12d0dbea40d1f1f06747)を行ったが、少し発展させてAD認証にチャレンジしたので、その時のメモを残す。

(2017/09/17追加)[Back up and Restoring a Samba AD DC](https://wiki.samba.org/index.php/Back_up_and_Restoring_a_Samba_AD_DC)を参考にバックアップ方法を追加

## 環境

  * CentOS7.3 (VMWare Fusion上にゲストOSとして構築)
  * Docker 1.12.6 (yumリポジトリのものを使用)
  * docker-compose 1.9.0 (yum epelリポジトリのものを使用)
  * Redmine redmine:3.4.2 (docker hubよりpull)
  * DB postgres:9.6.3 (docker hubよりpull)
  * Samba4 sonohara/samba4-ad:latest  (docker hubよりpull)
  * LDAPブラウザ JXplorer JXv3.3.1.2

いつものように、dockerのイメージはlatestではない最新のタグを使用する。Samba4にはタグが付与されていなかったので、latestを使用する。(Versionを確認すると 4.5.3 を使用している)
pullの数が多い(みんながダウンロードしている?)ので、pitkley/samba-ad-dc を試してみたが、winbinddのエラーが出て上手く繋がらなかったため、sonohara/samba4-adを使用する。

本来ならば、ADの管理ツールを使用するのだが、OSX上で利用できるAD管理ツールを探すのが面倒だったので、すぐに見つかったLDAPブラウザ(JXplorer)を利用する。

## 1. dockerイメージの取得

```
$ docker pull sonohara/samba4-ad:latest
$ docker pull redmine:3.4.2
$ docker pull postgres:9.6.3
```

## 2. docker設定

ネットワークは、今後gitlab、mattermostととの連携を考えているので、個別に専用のネットワークをdocker networkコマンドで作成する。

```
$ docker network create redmine_network
$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
1361f0cf0a0c        bridge              bridge              local               
.....
ea5779e11ae6        redmine_network     bridge              local          
```

(2017/09/03 削除 コンテナ内のDNSは 127.0.0.11 となっている)
~~~後ほど定義で出てくる DNS_FORWARD には、ネットワークのホスト側のIPを記述する必要があり、ホスト側のIPは以下のコマンドでdockerコンテナ側でGatewayとして見える。~~~

```
$ docker network inspect --format='{{.IPAM.Config}}' redmine_network
[{172.18.0.0/16  172.18.0.1/16 map[]}]
```

データ永続化のための領域(logとsambaの設定)を作成する。SELinuxを有効にしている場合は、dockerコンテナ内からアクセスできるようにコンテキストを設定する必要がある

```
$ mkdir log samba files db
$ chcon -t svirt_sandbox_file_t log samba files db
```

前回の[docker上にRedmineとopenLDAP認証環境を構築](http://qiita.com/ir-shin1/items/12d0dbea40d1f1f06747)のymlをベースに変更を加える。

```:docker-compose.yml
version: '2'

services:
  addc:
    image: sonohara/samba4-ad:latest
    container_name: addc_sv
    environment:
      DOCKER_DEBUG: 0
      DNS_FORWARD: 127.0.0.11
      DNS_DOMAIN: projectx.local
      AD_PASSWORD: PASS0rd123
      AD_REALM: projectx.local
      AD_DOMAIN: PROJECTX
    ports:
      - "53:53/tcp" # DNS(tcp)
      - "53:53/udp" # DNS(udp)
      - "139:139"
      - "389:389"
      - "445:445"
      - "636:636"
    volumes:
      - ./samba:/var/lib/samba
      - ./log:/var/log/samba
    networks:
      - redmine_network

  redmine:
    image: redmine:3.4.2
    container_name: redmine_sv
    environment:
      REDMINE_DB_PASSWORD: rdpassword
    ports:
      - "80:3000"
    links:
      - "postgres:postgres"
      - "addc:ldap"
    volumes:
      - ./files:/usr/src/redmine/files
    networks:
      - redmine_network

  postgres:
    image: postgres:9.6.3
    container_name: postgres_sv
    environment:
      POSTGRES_PASSWORD: rdpassword
      POSTGRES_USER: redmine
    volumes:
      - ./db:/var/lib/postgresql/data
    networks:
      - redmine_network

networks:
    redmine_network:
        external: true
```

## 3. 起動

```
$ docker-compose up -d
Creating postgres_sv
Creating addc_sv
Creating redmine_sv
```

## 4. ADの設定

### 4.1 ユーザの登録

```
$ docker exec -ti addc_sv samba-tool user list
Administrator
krbtgt
Guest
$ docker exec -ti addc_sv samba-tool user create yamada.tarou test1Pass \
  --use-username-as-cn \
  "--mail-address=yamada.tarou@test.com" --given-name=山田 --surname=太郎
User 'yamada.tarou' created successfully
$ docker exec -ti addc_sv samba-tool user create suzuki.hanako test1Pass \
  --use-username-as-cn \
  "--mail-address=suzuki.hanako@test.com" --given-name=鈴木 --surname=花子
User 'suzuki.hanako' created successfully
$ docker exec -ti addc_sv samba-tool user list
Administrator
yamada.tarou
suzuki.hanako
krbtgt
Guest
```

```
samba-tool user create yamada.tarou test1Pass \
   --use-username-as-cn \
   "--mail-address=yamada.tarou@test.com" \
   --given-name=山田  --surname=太郎
```

上記のコマンドパラメータは、ADには以下のように登録されている。
(2017/09/02) --use-username-as-cn を追加することで、cnにユーザ名を設定

 * sAMAccountName:	yamada.tarou
 * ~~~cn:	山田 太郎   ⇒ これで一意性をとっているので、重複しないようにする必要がある。~~~
 * cn:	yamada.tarou
 * mail: yamada.tarou@test.com
 * sn:	太郎
 * givenName:	山田

## 4.2 LDAPブラウザ(JXplorer)での確認

JXplorerを起動し、登録した情報を確認する。JXplorerから確認はできるが、変更・修正方法については不明。submitを押してもエラーになる。
AD認証情報のメンテナンスは、WindowsのAD管理ツールに任せることにする。

<img width="1030" alt="JXplorer001.png" src="https://qiita-image-store.s3.amazonaws.com/0/137664/9412b2e1-c72f-f4b8-eb56-15c525cd6a5c.png">

以下のパラメータでログインする。

 * ホスト:192.168.45.131   ※ VMware上のゲストのIPアドレス
 * ポート:389
 * プロトコル:LDAPv3
 * ベースDN:DC=projectx,DC=local
 * Level:User+Password
 * UserDN:CN=Administrator,CN=Users,DC=projectx,DC=local
 * Password:PASS0rd123     ※ docker-compose.ymlのAD_PASSWORDで定義した値

<img width="1040" alt="JXplorer002.png" src="https://qiita-image-store.s3.amazonaws.com/0/137664/0158b6fe-d06d-8198-9c6f-4ef4759ed650.png">

先に登録した情報を確認する。

<img width="1047" alt="JXplorer003.png" src="https://qiita-image-store.s3.amazonaws.com/0/137664/703c8e56-e911-9602-e545-09476a045683.png">

## 5. Redmineの設定

### 5.1 Redmineログイン

ホストPCからVMWareゲスト(http://192.168.45.131) にアクセスし、ユーザadmin、パスワードadminでログインする。パスワード変更画面になるので、adminのパスワードを変更する。

![1redmine01.png](https://qiita-image-store.s3.amazonaws.com/0/137664/ee4c4e1c-a3af-ecd5-9820-d5e79c01c276.png)

### 5.2 新しい認証方式の追加

「管理」⇒「LDAP認証」⇒「新しい認証方式」で設定方式の追加を行う。

 * 名称:ADDC
 * ホスト:ldap ※ docker-compose.ymlのlinksで定義したホスト名
 * ポート:389
 * アカウント:PROJECTX\Administrator     ※ ドメイン名はdocker-compose.ymlのAD_DOMAINで定義した値
 * パスワード:PASS0rd123     ※ docker-compose.ymlのAD_PASSWORDで定義した値
 * ベースDN:CN=Users,DC=projectx,DC=local

![1redmine02.png](https://qiita-image-store.s3.amazonaws.com/0/137664/e6ae2df9-c69d-ab40-bfe1-b98ed85a597d.png)

あわせてユーザーを作成:チェック

   * ログインIDの属性:sAMAccountName
   * 名の属性:givenName
   * 姓の属性:sn
   * メールアドレスの属性:mail

作成ボタンを押し、新しい認証方式を登録する。登録後「テスト」ボタンを押し、ADと接続できることを確認する。

![1redmine03.png](https://qiita-image-store.s3.amazonaws.com/0/137664/3a6b7c99-15db-3a83-6250-39b815c34c35.png)

### 5.3 ログアウトし、LDAPで登録したユーザ(yamada.tarou)でログイン

「あわせてユーザーを作成」をチェックしているので、Redmineに登録していないユーザは自動的に登録される。

![1redmine04.png](https://qiita-image-store.s3.amazonaws.com/0/137664/998930dd-ab03-bf09-0ca5-0970bc67c97e.png)


### 5.4 既存ユーザのパスワード認証先の変更

管理者でRedmineにログイン後、管理->ユーザ->ログインIDを選択で画面を開き、認証-認証方式を「内部」から「ADDC」に変更すれば、LDAP認証に変わる。

![1redmine05.png](https://qiita-image-store.s3.amazonaws.com/0/137664/4a53b366-a620-a3f6-92ab-cf7edbf49a2e.png)

これで、Active Directoryのパスワードを含む情報の変更がopenLDAPより簡単に出来れば、当初の目的はかなえられる。
後は、今考えている gitlabなどのサービスとSSOで連携が出来ればベストなのだが。

## 6. テーマ・プラグインを追加

素のRedmineを使用するのではもったいないので、テーマ・プラグインをインストールするスクリプトを作成。本当は、Dockerfile を作成してイメージを作成するべきなのだろうがお手軽にスクリプトにした。

```bash:create-redmine.sh
#!/usr/bin/env bash

REDMINE=redmine_sv

set -x

## 必要なパッケージを追加
docker exec ${REDMINE} apt-get -y update
docker exec ${REDMINE} apt install -y unzip ghostscript fonts-ipaexfont

docker exec ${REDMINE} mkdir -pm 755 /home/redmine
docker exec ${REDMINE} chown redmine.redmine /home/redmine

docker exec ${REDMINE} bash -c 'ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime'

docker exec ${REDMINE} bash -c 'gem install bundler'

docker exec ${REDMINE} bash -c 'chown redmine.redmine /usr/src/redmine/Gemfile.lock*'


## テーマインストール
docker exec -u redmine ${REDMINE} bash -c 'cd /usr/src/redmine/ ; git clone git://github.com/farend/redmine_theme_farend_fancy.git public/themes/farend_fancy'

## プラグインインストール

# チケットテンプレートプラグイン
docker exec -u redmine ${REDMINE} bash -c 'cd /usr/src/redmine/plugins ; git clone -q -b 0.1.6 https://github.com/akiko-pusu/redmine_issue_templates.git'

# Redmine サイドバー オン・オフプラグイン
docker exec -u redmine ${REDMINE} bash -c 'cd /usr/src/redmine/plugins ; git clone -q https://github.com/bdemirkir/sidebar_hide.git'

# Redmine View Custom
docker exec -u redmine ${REDMINE} bash -c 'cd /usr/src/redmine/plugins ; git clone -q https://github.com/onozaty/redmine-view-customize.git view_customize'

# クリップボードイメージアップロードプラグイン
docker exec -u redmine ${REDMINE} bash -c 'cd /usr/src/redmine/plugins ; git clone -q https://github.com/peclik/clipboard_image_paste.git'

# Messengerプラグイン
docker exec -u redmine ${REDMINE} bash -c 'cd /usr/src/redmine/plugins ; git clone -q https://github.com/alphanodes/redmine_messenger.git redmine_messenger'

# GibHub hook Plugin
docker exec -u redmine ${REDMINE} bash -c 'cd /usr/src/redmine/plugins ; git clone -q https://github.com/koppen/redmine_github_hook.git'

docker cp EasyGanttFree.zip ${REDMINE}:/usr/src/redmine/plugins/.
docker exec -u redmine ${REDMINE} bash -c 'cd /usr/src/redmine/plugins ; unzip EasyGanttFree.zip'

docker cp redmine_agile-1_4_4-light.zip ${REDMINE}:/usr/src/redmine/plugins/.
docker exec -u redmine ${REDMINE} bash -c 'cd /usr/src/redmine/plugins ; unzip redmine_agile-1_4_4-light.zip'

docker cp redmine_checklists-3_1_6-light.zip ${REDMINE}:/usr/src/redmine/plugins/.
docker exec -u redmine ${REDMINE} bash -c 'cd /usr/src/redmine/plugins ; unzip redmine_checklists-3_1_6-light.zip'

docker cp redmine_work_time-0.3.4.zip ${REDMINE}:/usr/src/redmine/plugins/.
docker exec -u redmine ${REDMINE} bash -c 'cd /usr/src/redmine/plugins ; unzip redmine_work_time-0.3.4.zip'

docker exec ${REDMINE} bash -c 'cd /usr/src/redmine/plugins ; bundle install'

docker exec -u redmine ${REDMINE} bash -c 'cd /usr/src/redmine/plugins ; RAILS_ENV=production bundle exec rake redmine:plugins:migrate'

docker restart ${REDMINE}
```

以下の手順でプラグインをインストールする。

```
$ ./create-redmine.sh 2>&1 | tee run.log
```

## 7. Samba4情報のバックアップ・リストア (2017/09/17変更)

[Back up and Restoring a Samba AD DC](https://wiki.samba.org/index.php/Back_up_and_Restoring_a_Samba_AD_DC)で使用している [samba_backup](https://git.samba.org/?p=samba.git;a=blob;f=source4/scripting/bin/samba_backup) コマンドは  tdbbackup コマンドを呼び出しているが、使用しているコンテナのイメージには入っていない。
tdbbackup コマンドは、処理の流れをみるとsambaがオープンしているだろうデータベースファイル XXX.tbl を整合性を保持したまま XXX.tbl.bak を作成するコマンドのようだ。

バックアップ時にサービスを止めても良い方針を考えているので、サービスを止めて、バックアップ、サービス再開で行くことにする。バックアップ時にサービスを止めてはいけない環境ならば、先にセカンダリADを考えるべきだろう。

samba_backup を見ると、privateとetcとsysvolをバックアップしているので、バックアップ対象とする。
また、バックアップ・リストアについては、オーナー・パーミッションなどが合わせるのが大変なため、バックアップ・リストア用のコンテナを作成して実行する。

### 7.1 バックアップ

使用しているsamba4のイメージが ENTRYPOINT で起動コマンドをしているため、単純にdocker runでコマンドを指定しても先に ENTRYPOINT が実行される。そこで、ENTRYPOINT をbash に変更してバックアップを行うようにしている。

```bash:samba-ad_backup.sh
#!/usr/bin/env bash

BACKUP=$PWD/backup
set -x
mkdir -p ${BACKUP}
chcon -t svirt_sandbox_file_t ${BACKUP}

# LDAPサービスを停止
docker stop ldap_sv

# バックアップ実行
docker run --rm \
           --entrypoint="/bin/bash" \
           --volume ${BACKUP}:/backup \
           --volumes-from ldap_sv:ro \
           sonohara/samba4-ad:latest \
    -c "cd /var/lib/samba ; tar zcf /backup/samba$(date +%Y%m%d%H%M%S).tar.gz \$(cd /var/lib/samba ; find private sysvol -type f -o -type l )"

# LDAPサービスを起動
docker start ldap_sv
```

### 7.2 リストア

```bash:samba-ad_restore.sh
#!/usr/bin/env bash

BACKUP=$PWD/backup
backupfile="$1"
date=$(date +%Y%m%d%H%M%S)

# バックアップファイルチェック
if [ \! -f ${BACKUP}/${backupfile} ] ; then
  backupfile=$(basename "$1")
  if [ \! -f ${BACKUP}/${backupfile} ] ; then
    echo "not found backup file $1"
    exit 1
  fi
fi

set -x

if mkdir samba/samba.${date} ; then
  # LDAPサービスを停止
  docker stop ldap_sv

  # リストア実行 
  docker run --rm \
             --entrypoint="/bin/bash" \
             --volume ${BACKUP}:/backup:ro \
             --volumes-from ldap_sv \
            sonohara/samba4-ad:latest \
     -c "cd /var/lib/samba ; mv * samba.${date}/. ; tar xf /backup/${backupfile}"

  # LDAPサービスを起動
  docker start ldap_sv

  mv samba/samba.${date} .
else
  echo "mkdir error"
  exit 1
fi
```


# 参考

[開発環境の認証を改善して Redmineを社内標準にした話](https://www.slideshare.net/ryousoda/redmine-69559249)
[sAMAccountNameをキーとして、OpenLDAPとActiveDirectoryを検索する](http://qiita.com/ryouma_nagare/items/bcda4c372347ed83fe7c)
[RedmineでのLDAP認証(ActiveDirectory)設定方法](https://yoshinorin.net/2016/04/03/Redmine-LDAP/)
[Docker コンテナ・ネットワークの理解](http://docs.docker.jp/engine/userguide/networking/dockernetworks.html)