<jupyter_start><jupyter_text>IdP-proxyのセットアップ---VCノードに [IdP-proxy](https://github.com/NII-cloud-operation/CoursewareHub-LC_idp-proxy)を構築する。  はじめに  構成CoursewareHubの構成要素を以下に示します。![構成](images/cw-221-01.png)このNotebookでは上図の `IdP-proxy` を構築します。  事前に準備が必要となるものについてこのNotebookを実行するにあたって、あらかじめ準備が必要となるものについて以下に記します。* IdP-proxyのホスト名(FQDN)* IdP-proxyのサーバ証明書、秘密鍵  ディレクトリ構成このNotebookで構築するIdP-proxyのディレクトリ構成を以下に記します。 * `/srv/idp-proxy/`    * `docker-compose.yml`    * `idp-proxy-cert/` 証明書を格納するディレクトリ        - `idp-proxy.cer` SAMLの暗号化、署名に用いる証明書        - `idp-proxy.key` SAMLの暗号化、署名に用いる秘密鍵        - `idp-proxy.chained.cer` httpsのサーバ証明書        - `gakunin-signer.cer` フェデレーションのメタデータ署名の証明書    * `metadata/` メタデータを格納するディレクトリ        - `auth-proxies.xml`  操作対象の設定操作対象となるAnsibleのグループ名を指定します。  UnitGroup名IdP-proxyの構築環境となるVCPのUnitGroup名を指定します。 VCノードを作成時に指定した値を確認するために `group_vars`ファイル名の一覧を表示します。<jupyter_code>!ls -1 group_vars/<jupyter_output><empty_output><jupyter_text>UnitGroup名を次のセルに指定してください。<jupyter_code># (例)
# target_auth = 'IdPproxy'

target_auth =<jupyter_output><empty_output><jupyter_text>チェック対象となるVCノードがAnsibleによって操作できることを確認します。 Ansibleの設定ファイルの場所を環境変数に設定しておきます。<jupyter_code>from pathlib import Path
import os

cfg_ansible = Path('ansible.cfg')
if cfg_ansible.exists():
    os.environ['ANSIBLE_CONFIG'] = str(cfg_ansible.resolve())<jupyter_output><empty_output><jupyter_text>指定されたグループ名で対象となるノードが操作できることを確認します。<jupyter_code>!ansible {target_auth} -m ping<jupyter_output><empty_output><jupyter_text>管理者権限での操作ができることを確認します。<jupyter_code>!ansible {target_auth} -b -a 'whoami'<jupyter_output><empty_output><jupyter_text>パラメータの設定  ホスト名(FQDN)の指定IdP-proxyのホスト名(FQDN)を指定してください。<jupyter_code># (例)
# auth_fqdn = 'idpproxy.example.org'

auth_fqdn =<jupyter_output><empty_output><jupyter_text>学認フェデレーションCoursewareHubと連携する学認フェデレーションに関するパラメータを設定します。 次のセルで参加するフェデレーションを指定してください。<jupyter_code># (例)
# federation = 'production'  # 運用フェデレーション
# federation = 'test'        # テストフェデレーション

federation =<jupyter_output><empty_output><jupyter_text>参加するフェデレーションに応じたサーバとの連携を行います。各フェデレーションのホスト名を以下の表に示します。| | 学認DS(Discovery Service) | クラウドゲートウェイ ||-|--|--||運用フェデレーション|`ds.gakunin.nii.ac.jp`|`cg.gakunin.jp`||テストフェデレーション|`test-ds.gakunin.nii.ac.jp`|`sptest.cg.gakunin.jp`| 上記の表に示した以外のサーバを指定する場合は、次のセルのコメントを外してサーバのホスト名を設定してください。<jupyter_code># ds_fqdn = 'ds.gakunin.nii.ac.jp'     # 学認DS(Discovery Service)
# cg_fqdn = 'cg.gakunin.jp'            # クラウドゲートウェイ<jupyter_output><empty_output><jupyter_text>パラメータの保存この章で指定したパラメータの値をファイルに保存します。<jupyter_code>import yaml
from pathlib import Path

gvars_path = Path(f'group_vars/{target_auth}')
with gvars_path.open() as f:
    gvars = yaml.safe_load(f)

gvars.update({
    'auth_fqdn': auth_fqdn,
    'federation': federation,
})
if 'ds_fqdn' in vars():
    gvars['ds_fqdn'] = ds_fqdn
if 'cg_fqdn' in vars():
    gvars['cg_fqdn'] = ds_fqdn

with gvars_path.open(mode='w') as f:
    yaml.safe_dump(gvars, stream=f)<jupyter_output><empty_output><jupyter_text>group_vars ファイルの内容を表示して保存されたパラメータを確認します。<jupyter_code>!cat group_vars/{target_auth}<jupyter_output><empty_output><jupyter_text>IdP-proxy コンテナの準備  証明書の配置  サーバ証明書IdP-proxyコンテナで使用するサーバ証明書の配置を確認します。 まず、証明書を配置するディレクトリを作成します。<jupyter_code>!ansible {target_auth} -b -m file -a \
    'path={{{{idp_proxy_dir}}}} state=directory owner={{{{ansible_user}}}}'
!ansible {target_auth} -b -m file -a \
    'path={{{{idp_proxy_certs_dir}}}} state=directory owner=999 group=997'<jupyter_output><empty_output><jupyter_text>作成したディレクトリ`/srv/idp-proxy/certs`に証明書、秘密鍵を配置してください。出どころなどの情報を必要以上に残さないためにNotebookからの操作ではなく、ターミナルなどから **VCノードに ssh でログインして操作を行ってください**。配置する証明書などのファイル名は以下のようにしてください。* サーバ証明書    - `/srv/idp-proxy/certs/idp-proxy.cer`* サーバ証明書と中間CA証明書を連結したもの    - `/srv/idp-proxy/certs/idp-proxy.chained.cer`* 秘密鍵    - `/srv/idp-proxy/certs/idp-proxy.key`    - パスフレーズを無しにする sshでログインするVCノードのIPアドレスを確認します。表示されたIPアドレスに対して、ユーザ名`root`と「511-VCノード作成」のNotebookで設定したSSHの秘密鍵を指定することでVCノードにsshでログインできます。<jupyter_code>!ansible {target_auth} -m debug -a 'var=vc_ipaddress'<jupyter_output><empty_output><jupyter_text>**証明書などの配置を行った後に、これ以降の操作を行ってください。** 証明書が配置されていることを確認します。サーバ証明書の内容を表示してみます。<jupyter_code>!ansible {target_auth} -b -a \
    'openssl x509 -noout -text -in {{{{idp_proxy_certs_dir}}}}/idp-proxy.cer'<jupyter_output><empty_output><jupyter_text>秘密鍵の内容を表示してみます。<jupyter_code>!ansible {target_auth} -b -a \
    'openssl rsa -noout -text -in {{{{idp_proxy_certs_dir}}}}/idp-proxy.key'<jupyter_output><empty_output><jupyter_text>中間CA証明書を連結したサーバ証明書の内容を表示してみます。<jupyter_code>!ansible {target_auth} -b -a \
    'openssl x509 -noout -text -in {{{{idp_proxy_certs_dir}}}}/idp-proxy.chained.cer'<jupyter_output><empty_output><jupyter_text>証明書の owner, group などの値を利用環境に合わせて以下のように設定します。* owner: 999* group: 997この設定はコンテナ内では以下のように設定したことに相当します。* owner: `nginx`* group: `nginx`<jupyter_code>cert_owner = 999
cert_group = 997
!ansible {target_auth} -b -m file -a \
    'path={{{{idp_proxy_certs_dir}}}} state=directory \
    owner={cert_owner} group={cert_group}'
!ansible {target_auth} -b -m file -a \
    'path={{{{idp_proxy_certs_dir}}}}/idp-proxy.cer \
    owner={cert_owner} group={cert_group}'
!ansible {target_auth} -b -m file -a \
    'path={{{{idp_proxy_certs_dir}}}}/idp-proxy.chained.cer \
    owner={cert_owner} group={cert_group}'
!ansible {target_auth} -b -m file -a \
    'path={{{{idp_proxy_certs_dir}}}}/idp-proxy.key \
    owner={cert_owner} group={cert_group} mode=0600'<jupyter_output><empty_output><jupyter_text>メタデータ署名証明書の配置メタデータの署名を検証するための証明書を配置します。 証明書を配布しているURLを指定してください。<jupyter_code># 運用フェデレーション
# metadata_signer_url = 'https://metadata.gakunin.nii.ac.jp/gakunin-signer-2017.cer'
#
# テストフェデレーション
# metadata_signer_url = 'https://metadata.gakunin.nii.ac.jp/gakunin-test-signer-2020.cer'

metadata_signer_url =<jupyter_output><empty_output><jupyter_text>指定されたURLの証明書を配置します。<jupyter_code>!ansible {target_auth} -b -m get_url -a \
    'url={metadata_signer_url} dest={{{{idp_proxy_certs_dir}}}}/gakunin-signer.cer \
    owner={cert_owner} group={cert_group} mode=0644'<jupyter_output><empty_output><jupyter_text>配置した証明書のFingerprintを表示してみます。参考のため、証明書の fingerprintを記載しているURLを以下に示します。* 運用フェデレーション    - https://meatwiki.nii.ac.jp/confluence/display/GakuNinShibInstall/signer* テストフェデレーション    - https://www.gakunin.jp/join/test/rule<jupyter_code>!ansible {target_auth} -b -a \
    'chdir={{{{idp_proxy_certs_dir}}}} \
    openssl x509 -in gakunin-signer.cer -sha256 -fingerprint -noout'<jupyter_output><empty_output><jupyter_text>IdP-proxyコンテナのセットアップ証明書以外に IdP-proxyコンテナで必要となるファイルを準備する Ansible Playbook を実行します。 この節で実行する Playbook では以下の処理を行います。* コンテナイメージの取得* SimpleSAMLphp のcron実行のためのランダムキーの作成* メタデータディレクトリの準備ここで取得するIdP-proxyのコンテナイメージは[NII-cloud-operation/CoursewareHub-LC_idp-proxy](https://github.com/NII-cloud-operation/CoursewareHub-LC_idp-proxy)をVCP向けにカスタマイズして [VCPのコンテナレジストリ](https://harbor.vcloud.nii.ac.jp/)に格納したものです。VCPでカスタマイズした部分のソースは [./docker/app/idp-proxy](docker/app/idp-proxy/)にあります。 まず、実際に設定を変更する前にドライラン（チェックモード）でPlaybookを実行します。> ドライランではメタデータを配置するディレクトリが作成されないため、ファイルの配置でエラーとなりますがこの時点では問題ありません。<jupyter_code>!ansible-playbook -l {target_auth} -CDv playbooks/setup-idp-proxy.yml || true<jupyter_output><empty_output><jupyter_text>実際に設定変更を行います。<jupyter_code>!ansible-playbook -l {target_auth} playbooks/setup-idp-proxy.yml<jupyter_output><empty_output><jupyter_text>IdP-proxyのコンテナイメージが取得できたことを確認します。<jupyter_code>!ansible {target_auth} -m shell -a \
    '/usr/local/bin/docker images | grep idp-proxy'<jupyter_output><empty_output><jupyter_text>IdP-proxy コンテナのためにセットアップしたディレクトリの状態を確認します。<jupyter_code>!ansible {target_auth} -a 'ls -Rl {{{{idp_proxy_dir}}}}'<jupyter_output><empty_output><jupyter_text>SP検証環境のメタデータ（テストフェデレーション）テストフェデレーションのSP検証環境メタデータを取得している場合は IdP-proxyへの配置を行います。> SP検証環境のメタデータは利用申請の際に送付されてくるものなので、通常はこの時点でメタデータを取得していません。そのため**この節は実行せずにスキップしてください**。通常は、次に実行する「531-IdP-proxyを学認へ申請する」のNotebookのなかで SP検証環境のメタデータを登録します。>> この節は、既に学認への登録を済ませている IdP-proxy を再構築する場合などに実行することを想定しています。 SP検証環境のメタデータを、このNotebook環境に配置してそのファイル名を次のセルに設定してください。<jupyter_code># (例)
# sptest_metadata = './sptestcgidp-metadata.xml'

sptest_metadata =<jupyter_output><empty_output><jupyter_text>SP検証環境のメタデータをIdP-proxyに配置します。<jupyter_code>if 'sptest_metadata' in vars():
    !ansible {target_auth} -b -m copy -a \
        'src={sptest_metadata} dest={{{{idp_proxy_metadata_dir}}}}/cgidp-metadata.xml'<jupyter_output><empty_output><jupyter_text>IdP-proxyコンテナの起動  docker-compose.yml の配置`docker-compose.yml`を構築環境に配置します。 実際に配置する前に、チェックモードで確認を行います。<jupyter_code>!ansible {target_auth} -CDv -m template -a \
    'src=template/idp-proxy/docker-compose.yml dest={{{{idp_proxy_dir}}}}/docker-compose.yml backup=yes'<jupyter_output><empty_output><jupyter_text>実際に配置を行います。<jupyter_code>!ansible {target_auth} -Dv -m template -a \
    'src=template/idp-proxy/docker-compose.yml dest={{{{idp_proxy_dir}}}}/docker-compose.yml backup=yes'<jupyter_output><empty_output><jupyter_text>コンテナの起動IdP-proxyコンテナを起動します。<jupyter_code>!ansible {target_auth} -a 'chdir={{{{idp_proxy_dir}}}} \
    docker-compose up -d'<jupyter_output><empty_output><jupyter_text>コンテナが起動したことを確認します。<jupyter_code>!ansible {target_auth} -a 'chdir={{{{idp_proxy_dir}}}} \
    docker-compose ps'<jupyter_output><empty_output><jupyter_text>コンテナのログを確認します。<jupyter_code>!ansible {target_auth} -a 'chdir={{{{idp_proxy_dir}}}} \
    docker-compose logs --tail=20'<jupyter_output><empty_output><jupyter_text>設定ファイルの更新IdP-proxyコンテナのSimpleSAMLphp設定ファイル`/var/www/simplesamlphp/config/config.php`を編集し、設定内容を更新します。 まず、構築環境のIdP-proxyコンテナからSimpleSAMLphpの`config.php`をローカル環境に取得します。<jupyter_code>from tempfile import mkdtemp
from pathlib import Path
work_dir = Path(mkdtemp(dir='./tmp')).absolute()
simplesamlphp_config = work_dir / 'config.php'
!ansible-playbook -v -e simplesamlphp_config={simplesamlphp_config} -l {target_auth} \
    playbooks/fetch-idpproxy-ssp-config.yml<jupyter_output><empty_output><jupyter_text>次のセルの実行結果に表示されるリンクをクリックすることで、取得した `config.php`の内容を編集することができます。必要な項目を編集してください。技術的問い合わせ先を修正するには以下の項目を変更してください。* `technicalcontact_name`* `technicalcontact_email`> ファイルの編集後にはCtrl-Sなどで編集結果を保存してください。またSimpleSAMLphpの管理者パスワードを設定する以下の項目の設定を変更してください。* `auth.adminpassword`<jupyter_code>from notebook import notebookapp
from IPython.display import HTML
nb_conf = list(notebookapp.list_running_servers())[0]
p = Path(nb_conf['base_url']) / 'edit' / simplesamlphp_config.relative_to(nb_conf['notebook_dir'])
HTML(f'<a href={p} target="_blank">{p.name}</a>')<jupyter_output><empty_output><jupyter_text>ローカル環境で編集した設定ファイル`config.php`を実行環境のIdP-proxyコンテナに配置します。<jupyter_code>!ansible-playbook -v -e simplesamlphp_config={simplesamlphp_config} -l {target_auth} \
    playbooks/deploy-idpproxy-ssp-config.yml<jupyter_output><empty_output><jupyter_text>次のセルを実行すると表示されるリンク先を表示するとIdP-proxyのメタデータが表示されます。技術的問い合わせ先などの値が更新されていることを確認してください。<jupyter_code>print(f'https://{auth_fqdn}/simplesaml/module.php/saml/sp/metadata.php/default-sp?output=xhtml')<jupyter_output><empty_output><jupyter_text>SimpleSAMLphp設定ページにアクセスする構築が成功したことを確認するためにIdP-proxyの SimpleSAMLphp設定ページにアクセスします。 次のセルを実行すると表示されるリンク先を表示してください。<jupyter_code>print(f'https://{auth_fqdn}/simplesaml/')<jupyter_output><empty_output><jupyter_text>構築に成功していると、以下のような画面が表示されます。![SimpleSAMLphp](images/cw-521-02.png)なお、テストフェデレーションの場合、上記画面で「連携」タブを選択すると以下のようなエラーが表示されることがあります。```SimpleSAML\Error\Error: UNHANDLEDEXCEPTIONBacktrace:1 www/_include.php:17 (SimpleSAML_exception_handler)0 [builtin] (N/A)Caused by: Exception: Invalid configuration of the 'metadata.sources' configuration option: Error fetching '/var/www/simplesamlphp/metadata/xml/cgidp-metadata.xml':file_get_contents(/var/www/simplesamlphp/metadata/xml/cgidp-metadata.xml): failed to open stream: No such file or directory```これは、SP検証環境のメタデータ登録をまだ行っていないことが原因です。「531-IdP-proxyを学認へ申請する」のNotebookを実行することで、このエラーは解消されます。  メタデータの確認学認のメタデータが取得できていることを確認します。 メタデータファイルが存在していることを確認します。`gakunin-metadata/saml20-idp-remote.php` などのファイルが表示されることを確認してください。<jupyter_code>!ansible {target_auth} -m shell -a 'chdir={{{{idp_proxy_dir}}}} \
    env PATH=\$PATH:/usr/local/bin \
    docker-compose exec idp-proxy \
    find /var/www/simplesamlphp/metadata'<jupyter_output><empty_output><jupyter_text>メタデータファイルが存在していない場合は、次のセルを実行すると表示されるリンク先にアクセスしてメタデータの更新を行ってください。> メタデータの更新にはSimpleSAMLphp の管理者としてログインする必要があります。<jupyter_code>print(f'https://{auth_fqdn}/simplesaml/module.php/metarefresh/fetch.php')<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13547136279182487, 'fraction_numerical': 0.0060586477098311655, 'mean_word_length': 8.58204334365325, 'pattern_counts': {'":': 0, '<': 151, '<?xml version=': 0, '>': 157, 'https://': 10, 'lorem ipsum': 0, 'www.': 6, 'xml': 7}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '37', 'dir': 'jupyter-structured-clean-dedup', 'id': '565124', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 7096, 'n_tokens_neox': 6842, 'n_words': 462, 'path': 'CoursewareHub/notebooks/521-IdP-proxyのセットアップ.ipynb', 'repo_name': 'nii-gakunin-cloud/ocs-templates', 'size': '12379'}