Cloudflare Zero Trust で IdP 登録をテストする (SimpleSAMLphp)



# 概要

Cloudflare Zero Trust でテスト用の IdP を連携したいことがあります。

その場合は、Okta や OneLogin の開発者用無料アカウントを作成して IDaaS を利用することもできますが、自前のディレクトリサービスと連携して多様な認証方式を試すことができる SimpleSAMLphp も選択肢になります。

SP としても振る舞える一方で IdP としても活用可能なため、今回は IdP としての機能を利用します。

>SP としての活用例はこちら：[Cloudflare Zero Trust で SaaS アプリ登録をテストする (SimpleSAMLphp) - Qiita](https://qiita.com/khayama/items/36c849bee6d53a52813d)

# SimpleSAMLphp インストール

CentOS を使います。

```shell
$ cat /etc/redhat-release 
CentOS Linux release 8.4.2105
```

事前に必要なパッケージをインストールし、サービスを起動します。

```shell
sudo dnf install -y httpd php php-xml php-json php-mbstring jq wget
sudo systemctl --now enable httpd
sudo systemctl --now enable php-fpm
```

SimpleSAMLphp をダウンロードします。

```shell
curl -s https://api.github.com/repos/simplesamlphp/simplesamlphp/releases/latest | jq '.assets[] | select(.name|match(".tar.gz$")) | .browser_download_url' | tr -d \" |  wget -qi -
```

ダウンロードしたファイルを確認します。

```shell
$ ls
simplesamlphp-1.19.6.tar.gz
```

ファイルを解凍し、中身を `/var/www/simplesamlphp` にコピーします。

```shell
tar xvzf simplesamlphp-1.19.6.tar.gz
sudo mv simplesamlphp-1.19.6/ /var/www/simplesamlphp
```

`httpd` に SimpleSAMLphp 用の設定ファイルを追加します。

```shell
cat << EOS | sudo tee /etc/httpd/conf.d/simplesamlphp.conf
Alias /simplesaml /var/www/simplesamlphp/www

<Directory /var/www/simplesamlphp/www>
   Require all granted
</Directory>
EOS
```

`httpd` を再起動し、SELinux を一時的に無効化します。

```shell
sudo systemctl restart httpd
sudo setenforce 0
```

# SimpleSAMLphp を IdP として構成

以下のように設定ファイルを変更します。

`example.com` は、自身でホストするドメインに変更してください。

`enable.saml20-idp` で IdP 機能を有効化し、`exampleauth`でユーザ名・パスワードの認証方式を許可します。

```shell
sed -i "
  s/'auth.adminpassword' => '123'/'auth.adminpassword' => 'secret'/;
  s/'enable.saml20-idp' => false/'enable.saml20-idp' => true/;
  s/'baseurlpath' => 'simplesaml\/'/'baseurlpath' => 'https:\/\/idp.example.com\/simplesaml\/'/;
  s/'language.default' => 'en'/'language.default' => 'ja'/;
  s/'exampleauth' => false/'exampleauth' => true/;
  " /var/www/simplesamlphp/config/config.php
```

`/config/authsources.php`の設定を以下のように変更します。

```shell
# コメントアウト削除
sed -i -e '103d'  /var/www/simplesamlphp/config/authsources.php
sed -i -e '85d'  /var/www/simplesamlphp/config/authsources.php
# ユーザ情報追加
sed -i "
  s/'exampleauth:UserPass',/'exampleauth:UserPass',\\
        'user1:pass1' => [\\
            'uid' => ['user1'],\\
            'email' => ['user1@example.com'],\\
            'eduPersonAffiliation' => ['member', 'admin'],\\
        ],\\
        'user2:pass2' => [\\
            'uid' => ['user2'],\\
            'email' => ['user2@example.com'],\\
            'eduPersonAffiliation' => ['member', 'developer'],\\
        ],/;
  " /var/www/simplesamlphp/config/authsources.php
```

以下の部分について、コメントアウトがなくなり、`user1` 、`user2` が追加されたことを確認します。

```php
    'example-userpass' => [
        'exampleauth:UserPass',
        'user1:pass1' => [
            'uid' => ['user1'],
            'email' => ['user1@example.com'],
            'eduPersonAffiliation' => ['member', 'admin'],
        ],
        'user2:pass2' => [
            'uid' => ['user2'],
            'email' => ['user2@example.com'],
            'eduPersonAffiliation' => ['member', 'developer'],
        ],

        // Give the user an option to save their username for future login attempts
        // And when enabled, what should the default be, to save the username or not
        //'remember.username.enabled' => false,
        //'remember.username.checked' => false,

        'student:studentpass' => [
            'uid' => ['test'],
            'eduPersonAffiliation' => ['member', 'student'],
        ],
        'employee:employeepass' => [
            'uid' => ['employee'],
            'eduPersonAffiliation' => ['member', 'employee'],
        ],
    ],
```

最後に SAML アサーションに署名する際に必要な自己証明書を作成します。

```shell
openssl req -newkey rsa:3072 -new -x509 -days 3652 -nodes -subj /C=JP/ST=Tokyo/CN=MyIdP -out /var/www/simplesamlphp/cert/server.crt -keyout /var/www/simplesamlphp/cert/server.pem
sudo chmod 644 /var/www/simplesamlphp/cert/server.pem
```

IdP（認証プロバイダ）に関するメタデータ設定は以下のファイルで確認できます。

```shell
$ cat /var/www/simplesamlphp/metadata/saml20-idp-hosted.php
<?php

/**
 * SAML 2.0 IdP configuration for SimpleSAMLphp.
 *
 * See: https://simplesamlphp.org/docs/stable/simplesamlphp-reference-idp-hosted
 */

$metadata['__DYNAMIC:1__'] = [
    /*
     * The hostname of the server (VHOST) that will use this SAML entity.
     *
     * Can be '__DEFAULT__', to use this entry by default.
     */
    'host' => '__DEFAULT__',

    // X.509 key and certificate. Relative to the cert directory.
    'privatekey' => 'server.pem',
    'certificate' => 'server.crt',

    /*
     * Authentication source to use. Must be one that is configured in
     * 'config/authsources.php'.
     */
    'auth' => 'example-userpass',

    /* Uncomment the following to use the uri NameFormat on attributes. */
    /*
    'attributes.NameFormat' => 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri',
    'authproc' => [
        // Convert LDAP names to oids.
        100 => ['class' => 'core:AttributeMap', 'name2oid'],
    ],
    */

    /*
     * Uncomment the following to specify the registration information in the
     * exported metadata. Refer to:
     * http://docs.oasis-open.org/security/saml/Post2.0/saml-metadata-rpi/v1.0/cs01/saml-metadata-rpi-v1.0-cs01.html
     * for more information.
     */
    /*
    'RegistrationInfo' => [
        'authority' => 'urn:mace:example.org',
        'instant' => '2008-01-17T11:28:03Z',
        'policies' => [
            'en' => 'http://example.org/policy',
            'es' => 'http://example.org/politica',
        ],
    ],
    */
];
```

# Cloudflare Tunnel インストール

以下のドキュメントを参考にセットアップします。

> [Set up your first tunnel · Cloudflare Zero Trust docs](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/tunnel-guide/#set-up-a-tunnel-remotely-dashboard-setup)![image-20220722005638629](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20220722005638629.png)

セットアップが完了すると、`https://idp.example.com/simplesaml` にアクセスできます。

（`example.com` が Cloudflare でホストされている必要があります。）

![image-20220603230741235](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20220603230741235.png)

# `example-userpass` のログイン確認

この段階で `user1` でログインできることを確認しておきます。

![image-20220913001813617](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20220913001813617.png)

![image-20220913001851330](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20220913001851330.png)

![image-20220913001922371](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20220913001922371.png)

![image-20220913001947170](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20220913001947170.png)

# SimpleSAMLphp の IdP メタデータを取得

以下の要領で IdP として構成できた `metadata.xml` をダウンロードします。

![image-20220912004129440](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20220912004129440.png)

![image-20220912004220176](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20220912004220176.png)

# Cloudflare Zero Trust に IdP (SimpleSAMLphp) を登録

Settings > Authentication > Login methods > Add new > Add a login method > Select an identity provider

から Generic な SAML プロバイダとして登録します。

![image-20220913002406547](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20220913002406547.png)

先ほどダウンロードした `metadata.xml` をアップロードすると、必須項目が自動で入力されます。

![image-20220912004656363](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20220912004656363.png)

Email / SAML attribute を以下のように構成して、Save します。

![image-20220913002731755](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20220913002731755.png)

# Cloudflare Access を SimpleSAMLphp に SP として登録

SimpleSAMLphp を IdP としたときに、SimpleSAMLphp からみると、Cloudflare は連携先の SP と見えるので、そのように登録します。

上記登録時のガイドにもある `https://<your-team-name>.cloudflareaccess.com/cdn-cgi/access/saml-metadata` から取得できる情報を以下のコマンドで反映できます。

```shell
sed -i "
  s/<?php/<?php\\
\$metadata['https:\/\/<your-team-name>.cloudflareaccess.com\/cdn-cgi\/access\/callback'] = [\\
    'AssertionConsumerService' => 'https:\/\/<your-team-name>.cloudflareaccess.com\/cdn-cgi\/access\/callback',\\
    'SingleLogoutService' => 'https:\/\/<your-team-name>.cloudflareaccess.com\/cdn-cgi\/access\/logout',\\
];/;
  " /var/www/simplesamlphp/metadata/saml20-sp-remote.php
```

# 認証テスト

正しく構成されたかをテストできます。

![image-20220913003301986](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20220913003301986.png)

![image-20220913001922371](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20220913001922371.png)

![image-20220913003347586](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20220913003347586.png)

# まとめ

シンプルなユーザー名・パスワードでの認証プロバイダとして SimpleSAMLphp を Cloudflare Zero Trust に連携させることができました。

また、SimpleSAMLphp には `exampleauth:UserPass` 以外にもBasic認証やディレクトリサービスとの連携、データベース照合など、他にも利用可能な認証モジュールがあるため、様々なケースでのテストに便利に使えそうです。

> [SimpleSAMLphp Authentication module](https://simplesamlphp.org/docs/stable/simplesamlphp-idp#authentication-module)
>
> [`authcrypt:Hash`](https://simplesamlphp.org/docs/contrib_modules/authcrypt/authcrypt.html)
>
> Username & password authentication with hashed passwords.
>
> [`authcrypt:Htpasswd`](https://simplesamlphp.org/docs/contrib_modules/authcrypt/authcrypt.html)
>
> Username & password authentication against .htpasswd file.
>
> [`authX509:authX509userCert`](https://simplesamlphp.org/docs/contrib_modules/authX509/authX509.html)
>
> Authenticate against a LDAP database with a SSL client certificate.
>
> `exampleauth:UserPass`
>
> Authenticate against a list of usernames and passwords.
>
> `exampleauth:Static`
>
> Automatically log in as a user with a set of attributes.
>
> [`ldap:LDAP`](https://simplesamlphp.org/docs/contrib_modules/ldap/ldap.html)
>
> Authenticates an user to a LDAP server.
>
> [`ldap:LDAPMulti`](https://simplesamlphp.org/docs/contrib_modules/ldap/ldap.html)
>
> Authenticates an user to one of several LDAP server. The user can choose the LDAP server from a dropdown list.
>
> [`sqlauth:SQL`](https://simplesamlphp.org/docs/contrib_modules/sqlauth/sql.html)
>
> Authenticate an user against a database.
>
> [`radius:Radius`](https://simplesamlphp.org/docs/contrib_modules/radius/radius.html)
>
> Authenticates an user to a Radius server.
>
> [`multiauth:MultiAuth`](https://simplesamlphp.org/docs/stable/multiauth/multiauth.html)
>
> Allow the user to select from a list of authentication sources.
>
> [`saml:SP`](https://simplesamlphp.org/docs/stable/saml/sp.html)
>
> Authenticate against a SAML IdP. Can be used for bridging.
>
> `authYubiKey:YubiKey`
>
> Authenticate with [a YubiKey ](https://www.yubico.com/products/yubikey/).
>
> [`authtwitter:Twitter`](https://simplesamlphp.org/docs/contrib_modules/authtwitter/oauthtwitter.html)
>
> Authenticate with your Twitter account using the Twitter OAuth API.
>
> [`papi:PAPI`](https://github.com/rediris-es/simplesamlphp-module-papi/blob/master/README.md)
>
> Authenticate by means of the PAPI protocol.

# 参考

- [SimpleSAMLphp Identity Provider QuickStart](https://simplesamlphp.org/docs/stable/simplesamlphp-idp)
- [SimpleSAMLphp で SAML 2.0 によるシングルサインオン (SSO) の動作を確認してみた - Qiita](https://qiita.com/noritnk/items/7ef45c845675be584a40#4-idp-%E3%81%AE%E8%A8%AD%E5%AE%9Aidp-centos-7)
- [SimpleSAMLphp で開発用の SAML ID Provider を立てる - suer のブログ](https://suer.hatenablog.com/entry/2015/11/20/141941)
- [CentOS 8でyum/dnfに失敗！ Failed to download metadata for repo 'AppStream' - Qiita](https://qiita.com/yamada-hakase/items/cb1b6124e11ca65e2a2b#4-%E6%A0%B9%E6%9C%AC%E8%A7%A3%E6%B1%BA%E7%AD%96%E3%81%AF)
- [Connect to Pydio Cells via SimpleSAML PHP | Pydio](https://pydio.com/en/docs/kb/identity-management/connect-pydio-cells-simplesaml-php)
- [SimpleSAMLphpを利用してSAML認証をセットアップする手順 #2](https://zenn.dev/uchidaryo/articles/setup-saml-simplesamlphp-2)