GitLab Mattermost でダブルSSOしてみた

本記事は、[GitLab Contribute 2019 recap (Meetup Tokyo #17)](https://gitlab-jp.connpass.com/event/129245/) の [ダブルSSOで始めるGitLab Mattermost](https://speakerdeck.com/ymasaoka/start-gitlab-mattermost-with-double-sso) に関する補足記事です。
※Windows AD は今回用意できなかったので、代わりに [Keycloak](https://www.keycloak.org/) 使ってやります。


# はじめに

Docker Compose を使って、GitLab と GitLab Mattermost、Keycloak を構築、GitLab と GitLab Mattermost を Keycloak 認証で使えるようにしてみます。


# Contents

- [環境情報](#環境情報)
    - [GitLab](#gitlab)
        - [GitLab のインストール](#gitlab-インストール)
    - [GitLab Mattermost](#gitlab-mattermost)
        - [GitLab Mattermost のインストール](#gitlab-mattermost-インストール)
    - [Keycloak](#keycloak)
        - [Keycloak のインストール](#keycloak-インストール)
- [GitLab と Keycloak の SSO 設定](#gitlab-と-keycloak-の-sso-設定)
    - [Keycloak 設定](#keycloak-設定)
        - [Client 設定](#client-設定)
        - [Mappers 設定](#mappers-設定)
    - [GitLab 設定](#gitlab-設定)
- [Keycloak 認証での Mattermost ログイン](#keycloak-認証での-mattermost-ログイン)


# 環境情報

- **OS**：OS X 10.14.5
- **Docker Desktop**：2.0.0.3
- **Docker**：18.09.2
- **Docker Compose**：1.23.2


# 環境準備

## GitLab

### GitLab インストール

GitLab Community Edition のコンテナ環境を作成します。

```yaml:docker-compose.yaml
version: '3'

services:
  gitlab:
    image: 'gitlab/gitlab-ce:latest'
    container_name: 'gitlab-ce'
    hostname: 'localhost'
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'http://localhost:8929'
        gitlab_rails['gitlab_shell_ssh_port'] = 10022
    ports:
      - '8929:8929'
      - '10022:22'
      - '10080:80'
      - '10443:443'
    volumes:
      - './srv/gitlab/config:/etc/gitlab'
      - './srv/gitlab/logs:/var/log/gitlab'
      - './srv/gitlab/data:/var/opt/gitlab'
```

```bash
$ ls -al /Users/ymasaoka/docker/gitlab-ce/
drwxr-xr-x  4 ymasaoka  staff  128  6 10 12:35 .
drwxr-xr-x  6 ymasaoka  staff  192  6  9 21:02 ..
-rw-r--r--@ 1 ymasaoka  wheel  682  6 10 12:33 docker-compose.yaml
drwxr-xr-x  2 ymasaoka  staff   64  6 10 12:35 srv

$ docker-compose up -d
# 実行ログを確認したい場合
docker-compose logs -f
```

正常に GitLab が稼働したら、初回ログイン設定を行います。
http://localhost:8929 にアクセスします。
root ユーザーのパスワード変更を要求されるので、パスワードを更新します。

<img width="1042" alt="firstLoginGitLab.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348116/b2a78ab0-5aa4-e3e7-0dc5-adf86f1f4da2.png">

パスワード更新に成功すると、ログイン画面に遷移するので、先ほど更新したパスワードを使用して root ユーザーでログインします。

<img width="1440" alt="loginGitLab.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348116/e31b25ac-f3d3-c2c0-318d-afbca92a16d2.png">


## GitLab Mattermost

## GitLab Mattermost インストール

先ほど構築した GitLab の環境に、GitLab Mattermost を追加インストールします。

GitLab コンテナを停止します。

```bash:
$ docker-compose stop
```

先ほど作成した docker-compose.yaml に、以下の行を追加します。

```yaml:docker-compose.yaml
version: '3'

services:
  gitlab:
    image: 'gitlab/gitlab-ce:latest'
    container_name: 'gitlab-ce'
    hostname: 'localhost'
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'http://localhost:8929'
        gitlab_rails['gitlab_shell_ssh_port'] = 10022
        mattermost_external_url 'http://localhost:8001' # 追加
    ports:
      - '8001:8001' # 追加
      - '8929:8929'
      - '10022:22'
      - '10080:80'
      - '10443:443'
    volumes:
      - './srv/gitlab/config:/etc/gitlab'
      - './srv/gitlab/logs:/var/log/gitlab'
      - './srv/gitlab/data:/var/opt/gitlab'
```

docker-compose.yaml を更新したら、コンテナを再起動します。

```bash
$ docker-compose up -d
```

起動したら、http://localhost:8001 にアクセスし、Mattermost のログイン画面に移動します。
[GitLab Single Sign-On] を選択します。

<img width="1440" alt="loginMattermost.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348116/1ca74690-1785-e1f0-aa8e-56ebb22a7628.png">

選択後、GitLab のサインイン画面に遷移するので、先ほど同様、root ユーザーでサインインします。

<img width="1042" alt="loginGitLabRoot.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348116/4fee4444-47dc-bf19-c6a5-63b9e573f14c.png">

ログインすると、GitLab Mattermost からの認証許可確認画面が表示されるので、[Authorize] を選択します。

<img width="1440" alt="authAppMattermost.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348116/e916f0f0-47a5-9cec-15c6-048aca0e71bf.png">

選択後、Mattermost のチーム作成画面が表示されます。
チームを作成する場合は [Create a new team] を選択してください。
\(今回は、チームを作成せずに、[Go to System Console] を選択します。\)
GitLab アカウントで正常に GitLab Mattermost にログインできることを確認してください。

<img width="1440" alt="firstUserLoginMattermost.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348116/30ef2892-31c1-7df3-3815-4fd935dbcda8.png">

<img width="1440" alt="consoleMattermost.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348116/f694297e-51c5-91b1-7098-0ca22f2b8fcd.png">


## Keycloak

### Keycloak インストール

認証先となる Keycloak のコンテナ環境を作成します。

```yaml:docker-compose.yaml
version: '3'

services:
  postgres:
      image: postgres
      volumes:
        - ./postgresql/data:/var/lib/postgresql/data
      environment:
        POSTGRES_DB: keycloak
        POSTGRES_USER: keycloak
        POSTGRES_PASSWORD: password

  keycloak:
      image: jboss/keycloak
      environment:
        DB_VENDOR: POSTGRES
        DB_ADDR: postgres
        DB_DATABASE: keycloak
        DB_USER: keycloak
        DB_SCHEMA: public
        DB_PASSWORD: password
        KEYCLOAK_USER: admin
        KEYCLOAK_PASSWORD: Pa55w0rd
        # Uncomment the line below if you want to specify JDBC parameters. The parameter below is just an example, and it shouldn't be used in production without knowledge. It is highly recommended that you read the PostgreSQL JDBC driver documentation in order to use it.
        #JDBC_PARAMS: "ssl=true"
      ports:
        - 8080:8080
      depends_on:
        - postgres
```

```bash
$ ls -al /Users/ymasaoka/docker/keycloak-docker/
drwxr-xr-x   7 ymasaoka  staff    224  6 15 14:58 .
drwxr-xr-x   6 ymasaoka  staff    192  6 15 14:57 ..
drwxr-xr-x  13 ymasaoka  staff    416  6 15 14:57 .git
-rw-r--r--   1 ymasaoka  staff  11357  6 15 14:57 LICENSE
-rw-r--r--   1 ymasaoka  staff     81  6 15 14:57 README.md
-rw-r--r--   1 ymasaoka  staff    909  6 15 14:57 docker-compose.yaml

$ docker-compose up -d
```
起動したら、http://localhost:8080/auth にアクセスします。
Welcome to Keycloak が表示されるので、[Administration Console] を選択します。

<img width="1440" alt="welcome2Keycloak.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348116/f4f06a63-9c68-aa3b-26a0-847254514388.png">

Keycloak のログイン画面が表示されます。
先ほどの docker-compose.yaml の中で **KEYCLOAK_USER** と **KEYCLOAK_PASSWORD** に設定した値を使用して、Keycloak にログインします。

<img width="1440" alt="loginKeycloak.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348116/72d202f2-6d08-b72b-6816-9ab4138560c3.png">

ログインに成功すると、Master Realm の画面を確認できるはずです。

<img width="1440" alt="realmMaster.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348116/fd900764-c692-1dfb-4bbc-95fc0dd33dd0.png">


# GitLab と Keycloak の SSO 設定

構築した Keycloak のユーザー情報を使用して、GitLab にログインできるように設定します。

## Keycloak 設定

認証に使用したい Realm に移動します。
\(今回は Master を使用します。\)

### Client 設定

[Configure] -> [Clients] -> [Create] より、GitLab 用の新しい Client を追加します。

<img width="1440" alt="defaultClient.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348116/6891e47f-f4a6-af42-87e6-663cd10cc161.png">

以下の内容を入力し、設定を保存します。

- **Client**：http://localhost:8929
- **Client Protocol**：saml

<img width="1440" alt="addNewClientGitLab.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348116/05bd3da9-935b-ce9e-9e68-0212d71def61.png">

新しく作成した Client に追加の設定を行います。
以下の内容を入力し、設定を保存します。

- **Name**：GitLab
- **Include AuthStatement**：ON
- **Sign Documents**：ON
- **Force POST Binding**：OFF
- **Front Channel Logout**：OFF
- **Name ID Format**：persistent
- **Root URL**：http://localhost:8929
- **Valid Redirect URL**：http://localhost:8929/*
- **Base URL**：/
- **Master SAML Processing URL**：http://localhost:8929/users/auth/saml/callback
- **IDP Initiated SSO URL Name**：http://localhost:8929
- **Assertion Consumer Service POST Binding URL**：http://localhost:8929/users/auth/saml/callback

<img width="1440" alt="clientSetting1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348116/e8d31b0c-8108-aac5-37cc-cec341796ab3.png">

<img width="1440" alt="clientSetting2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348116/5f9d8f5c-d11e-cd60-71f7-814f4a98db8d.png">

<img width="1440" alt="clientSetting3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348116/dbb18390-1967-892d-a7ce-b34fd39ba540.png">

### Mappers 設定

[Configure] -> [http://localhost:8929] -> [Mappers] に移動します。

<img width="1440" alt="defaultMapper.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348116/da357428-fbd1-0588-2595-96639dd5568e.png">

[Create] より、新しく Mapper を登録します。

- Email
    - **Name**：email
    - **Mapper Property**：User Property
    - **Property**：Email
    - **Friendly Name**：Email
    - **SAML Attribute Name**：email
    - **SAML Attribute NameFormat**：Basic
    - **Single Role Attribute**：ON
- First_Name
    - **Name**：first_name
    - **Mapper Property**：User Property
    - **Property**：FirstName
    - **Friendly Name**：First Name
    - **SAML Attribute Name**：first_name
    - **SAML Attribute NameFormat**：Basic
    - **Single Role Attribute**：ON
- Last_Name
    - **Name**：last_name
    - **Mapper Property**：User Property
    - **Property**：LastName
    - **Friendly Name**：Last Name
    - **SAML Attribute Name**：name
    - **SAML Attribute NameFormat**：Basic
    - **Single Role Attribute**：ON
- Username
    - **Name**：username
    - **Mapper Property**：User Property
    - **Property**：UserName
    - **Friendly Name**：User Name
    - **SAML Attribute Name**：name
    - **SAML Attribute NameFormat**：Basic
    - **Single Role Attribute**：ON
- Roles
    - **Name**：roles
    - **Mapper Property**：Role List
    - **Role attribute name**：roles
    - **Friendly Name**：Roles
    - **SAML Attribute NameFormat**：Basic
    - **Single Role Attribute**：ON


<img width="1440" alt="mapperEmail.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348116/6e7d060c-baff-cc40-aac2-4c2cca2b60f0.png">

<img width="1440" alt="mapperFirstName.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348116/dd83e00a-e39f-8e90-07e0-b4ce962a4e8f.png">

<img width="1440" alt="mapperLastName.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348116/f374fdc8-8114-0424-f574-51c218604910.png">

<img width="1440" alt="mapperUsername.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348116/2092a0ff-df00-6a0a-692f-3d57a548d5b1.png">

<img width="1440" alt="mapperRoleList.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348116/0399cee5-5b3f-5cc7-3d79-f422d0b679a6.png">

### RS256 確認

Keycloak で発行された証明書の情報を確認します。

[Configure] -> [Realm Settings] -> [Keys] -> [Active] に移動します。
[RS256] の行にある [Certificate] を選択します。

<img width="1440" alt="realmSettingsKeys.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348116/d84177c5-e41a-c90c-a320-ae9dec7d96dc.png">

証明書の文字列を確認します。

![rs256Certificate.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348116/908ebfe7-55af-c39d-9a3b-9f4c8545692f.png)


## GitLab 設定

GitLab コンテナを停止します。

```bash:
$ docker-compose stop
```

docker-compose.yaml の GITLAB_OMNIBUS_CONFIG に値を追加します。

```yaml:docker-compose.yaml
version: '3'

services:
  gitlab:
    image: 'gitlab/gitlab-ce:latest'
    container_name: 'gitlab-ce'
    hostname: 'localhost'
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'http://localhost:8929'
        gitlab_rails['gitlab_shell_ssh_port'] = 10022
        mattermost_external_url 'http://localhost:8001'
        # 以下を新規に追加
        gitlab_rails['omniauth_enabled'] = true
        gitlab_rails['omniauth_allow_single_sign_on'] = ['saml']
        gitlab_rails['omniauth_block_auto_created_users'] = false
        gitlab_rails['omniauth_auto_link_saml_user'] = true
        gitlab_rails['omniauth_providers'] = [
          {
            name: 'saml',
            label: 'Keycloak Login',
            groups_attribute: 'roles',
            args: {
              assertion_consumer_service_url: 'http://localhost:8929/users/auth/saml/callback',
              idp_sso_target_url: 'http://localhost:8080/auth/realms/master/protocol/saml', # Realm を別にしている場合はmasterの部分を書き換える
              issuer: 'http://localhost:8929',
              idp_cert: '-----BEGIN CERTIFICATE-----
                MII..... 
                -----END CERTIFICATE-----', # MII...の部分は先ほど確認した証明書の値
              name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
              attribute_statements: {
                first_name: ['first_name'],
                last_name: ['last_name'],
                name: ['name'],
                username: ['name'],
                email: ['email']
              }
            }
          }
        ]
    # 追加ここまで
    ports:
      - '8001:8001'
      - '8929:8929'
      - '10022:22'
      - '10080:80'
      - '10443:443'
    volumes:
      - './srv/gitlab/config:/etc/gitlab'
      - './srv/gitlab/logs:/var/log/gitlab'
      - './srv/gitlab/data:/var/opt/gitlab'
```

docker-compose.yaml を更新したら、コンテナを再起動します。

```bash
$ docker-compose up -d
```

GitLabのログイン画面にアクセスします。
[Keycloak Login] の項目が追加されていることを確認します。

<img width="1440" alt="loginGitLabWithKeycloak.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348116/8af5acc2-9121-2ec5-b00e-f8989cf2b1b9.png">


# Keycloak 認証での Mattermost ログイン

http://localhost:8001 にアクセスし、Mattermost の画面から GitLab -> Keycloak の順に画面遷移し、ログインを試みます。

![loginDoubleSSO.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348116/1cb28243-704e-7020-770c-4053fd69f7d4.gif)


#  参考情報

- [SAML SSOでGitLabやMattermostにログインする](https://int128.hatenablog.com/entry/2017/12/22/205244)
- [GitLab: Use Keycloak as SAML 2.0 OmniAuth Provider](https://edenmal.moe/post/2018/GitLab-Keycloak-SAML-2-0-OmniAuth-Provider/)
- [Keycloakで認可サービスを試してみよう［前編］](https://www.atmarkit.co.jp/ait/articles/1904/03/news003.html)
- [GitLab Single Sign-On - Mattermost Docs](https://docs.mattermost.com/deployment/sso-gitlab.html)
- [LDAP - GitLab Documentation](https://docs.gitlab.com/ee/administration/auth/ldap.html)