シングルサインオンサービスKeycloakとGitLabを連携する

# TL;DR

* SSOサービスKeycloakと，プロジェクトリポジトリGitLabを連携させる方法を説明します
    * Keycloakが，Dockerコンテナで稼働している状況で進めます
    * GitLab-CEの[Omnibus Package](https://docs.gitlab.com/omnibus/)を使用します
    * [KeycloakをGrowiと連携する記事](https://qiita.com/myoshimi/items/f26cf3f179602a12a5ac)も参考にしてください

# 手順

* Keycloakで使用中のRealmに，gitlab用のClientを追加して連携します
    * Realmは，登録されたユーザ，グループを共通に利用する複数のClientをまとめるものです
    * [Growiとの連携](https://qiita.com/myoshimi/items/f26cf3f179602a12a5ac)の記事で，Realmの作成を行っているので，参考にしてください
* GitLabにSAML認証の設定をします

# KeycloakにGitLab用Clientを作成する

## Clientの作成

* Keycloakの管理者コンソールにログインします
* GitLabと連携したいRelamを選び，"Clients"から"Create"をクリックします
    * ![01_createClient.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309617/91865de1-fab0-5d9d-0081-5e9c3c8cbf1f.jpeg)
* "Client ID"に適当な名前（この記事では"gitlab"にしました）を入力し，"Save"します
    * ![02_clientID.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309617/68b2eb9e-9575-9210-52a1-babdf90295c4.jpeg)
* 後述の説明にしたがって，各タブに設定をします
    * Settingsタブ，Rolesタブ，Mappersタブで設定を記述します

## Settigsタブ

* 表の通り設定します
    * GitLabのホスト名，ドメイン名は，適切なものに変更してください
    * 修正の必要がある項目と，ONにしている部分だけを抜粋しています

| 設定名                     | 設定値                                                                                    |
| -------------------------- | ----------------------------------------------------------------------------------------- |
| Client ID                  | gitlab            |
| Enabled                    | ON                |
| Client Protocol            | saml              |
| Include AuthnStatement     | ON                |
| Sign Documents             | ON                |
| Sign Assertions            | ON                |
| Signature Algorithm        | RSA_SHA256        |
| SAML Signature Key Name    | KEY_ID            |
| Canonicalization Method    | EXCLUSIVE        |
| Client Signature Required  | ON               |
| Force POST Binding         | ON               |
| Front Channel Logout       | ON          |
| NAME ID Format             | persistent  |
| Root URL                   | GitLabのURL(e.g. ```https://gitlab.example.com```)              |
| Valid Redirect URIs        | GitLabのURL以下の領域 (e.g. ```https://gitlab.example.com/users/auth/saml/callback```  |
| Master SAML Processing URL | ログイン後のコールバックURL (e.g. ```https://gitlab.example.com/users/auth/saml/callback```) |
| IDP Initiated SSO URL Name | GitLabのFQDN(e.g. ```gitlab.example.com```) |

* さらに，"Fine Grain SAML Endpoint Configuration"を展開して，以下の設定を行います

| 設定名                                      | 設定値                                                                                     |
| ------------------------------------------- | ------------------------------------------------------------------------------------------ |
| Assertion Consumer Service POST Binding URL | ログイン後のコールバックURL (e.g. ```https://gitlab.example.com/users/auth/saml/callback```) |

## Rolesタブ

* Rolesタブで，"Add Role"をクリックします
* Role Nameに，Client IDに```:external```を結合した文字列を設定します
    * ![03_roles.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309617/09754975-b6cf-d388-f268-a97890db2bd8.jpeg)
    * ![04_rolesAfter.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309617/576d60f7-fbd5-25e0-8305-cb252526025f.jpeg)



## Mappersタブ

* Mappersタブで，GitLabのユーザ情報として必要な情報と，keycloakで管理しているユーザ情報を紐づけます
* "Create"ボタンをクリックして，以下の表の通り，マッピングする5つのエントリを追加します
    * ![05_mapper.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309617/b758b26a-ca6f-a4ef-f281-f515cf8dee4f.jpeg)
    * まず"Mapper Type"のドロップダウンリストからTypeを選択すると，入力が必要となるフォームが表示されます
    * first_nameとlast_nameのエントリの，Friendly Nameは，{First|Last}とNameの間に半角スペースが1文字分入っているので，注意してください
        * ![06_name.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309617/11ad1c3f-349c-eb16-4e59-633463ea1d23.jpeg)

| Name       | Mapper Type   | Property  | Friendly Name | SAML Attribute Name | SAML Attribute NameFormat |
| ---------- | ------------- | --------- | ------------- | ------------------- | ------------------------- |
| name       | User Property | Username  | Username      | name                | Basic                     |
| email      | User Property | Email     | Email         | email               | Basic                     |
| first_name | UserProperty  | FirstName | First Name    | first_name          | Basic                     |
| last_name  | UserProperty  | LastName  | Last Name     | last_name                | Basic                     |

| Name  | Mapper Type | Role attribute name | Friendly Name | SAML Attribute NameFormat | Single Role Attribute |
| ----- | ----------- | ------------------- | ------------- | ------------------------- | --------------------- |
| roles | Role list   | roles               | Roles         | Basic                     | ON                    |

# Gitlabの設定

## IDP認証フィンガープリントの作成

* 以下のような，Realmを指定したURLにアクセスすると，Realmの情報を見ることができます

```
https://sso.example.com/auth/realms/dev/protocol/saml/descriptor
```

* ```<dsig:X509Certificate>```タグ内の，```MII〜```で始まる文字列をコピーします
* 以下のようなgitlab-sso.pemファイルを作成します

```
-----BEGIN CERTIFICATE-----
<コピーした文字列>
-----END CERTIFICATE-----
```

* ```openssl```コマンドを使用して，フィンガープリントを計算します

```bash
openssl x509 -sha1 -fingerprint -noout -in gitlab-sso.pem
SHA1 Fingerprint=AA:BB:CC:DD:EE:AA:BB:CC:DD:EE:AA:BB:CC:DD:EE
```
* ```SHA1 Fingerprint=```に続く文字列をコピーします

## docker-compose.yml

* Dockerhubにある，Gitlab-ceのOmnibus Packageを使い，docker-compose.ymlファイルを作成します
    * ymlに直書きせず，envファイルなどに外出ししたほうが良いです
    * ```ports```や```volumes```ディレクティブの値は，環境に応じて適当に変更してください
* environmentディレクティブに，SAMLの設定を追加します
* 注目点は，```gitlab_rails['omniauth_providers']```内の```args```キーの値です
    * ```assertion_consumer_service_url```: gitlabのコールバックURL
    * ```idp_cert_fingerprint```: 前節で作成したフィンガープリント
    * ```idp_sso_target_url```: ClientのSettingsタブで設定した"IDP Initiated SSO URL Name"の位置に書かれています
        * ![07_IDP.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309617/0a0a246c-0095-7993-7197-03229b685c99.jpeg)
    * ```issuer```: Client ID
    * 適宜，URLなどは環境に合わせて記載してください

```docker
version: '2'

services:

# ....<snip>.....
# リバースプロキシの設定など
# ....<snip>.....

  gitlab:
    restart: always
    image: gitlab/gitlab-ce:latest
    ports:
      - "10022:22"
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        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',
            args: {
                assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
                idp_cert_fingerprint: 'AA:BB:CC:DD:EE:AA:BB:CC:DD:EE:AA:BB:CC:DD:EE:AA:BB:CC:DD:EE',
                idp_sso_target_url: 'https://sso.example.com/auth/realms/dev/protocol/saml/clients/gitlab.example.com',
                issuer: 'gitlab',
                name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
             },
             label: 'SAML Login' # optional label
         }]
    volumes:
      - ./srv/docker/gitlab/logs:/var/log/gitlab
      - ./srv/docker/gitlab/data:/var/opt/gitlab
```

## コンテナの立ち上げと動作確認

* ```docker-compose up -d```コマンドで，gitlabを立ち上げます
* 立ち上がったら，```https://gitlab.example.com/```にアクセスして，初期管理パスワードの変更画面が表示されることを確認します
    * ![08_InitialView.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309617/0879fadc-86d9-ac76-56ef-043641038c6b.jpeg)
* 初期パスワードを変更すると，ログイン画面が現れることを確認します
    *![09_Login.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309617/502e6fbb-8151-eaff-5e85-2a43e30c4dfb.jpeg)
* "SAML Login"をクリックすると，Keycloakのログイン画面に遷移しますので，当該Realmに登録されたユーザでログインを試みます
    * ![10_SSO.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309617/c1f96e39-7763-f932-b161-a04099e369b0.jpeg)
* GitLabにログインできれば成功です
    * ![11_Gitlab.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309617/ca8f89c4-85ad-d509-9704-b81429891f44.jpeg)

# 参考

* [OSSなシングルサインオンサービスKeycloakをdockerで立ち上げる](https://qiita.com/myoshimi/items/7e9f1de7373427233880)
* [シングルサインオンサービスKeycloakとWikiシステムGrowiをSAML連携する](https://qiita.com/myoshimi/items/f26cf3f179602a12a5ac)
* [Omnibus GitLab documentation](https://docs.gitlab.com/omnibus/)
* [GitLab: Use Keycloak as SAML 2.0 OmniAuth Provider](https://edenmal.moe/post/2018/GitLab-Keycloak-SAML-2-0-OmniAuth-Provider/)
* [Dockerhub gitlab/gitlab-ce
](https://hub.docker.com/r/gitlab/gitlab-ce/)