Apple Touch ID Keyboard を使ったパスワードレス認証

| 7 min read
Author: shigeki-shoji shigeki-shojiの画像

弊社では隔月で有志によるハッカソンを開催しています。

1 月のハッカソンで、私は年が明けてすぐに購入した「Appleシリコン搭載Macモデル用Touch ID搭載Magic Keyboard - 英語(US)」を、昨年公開した記事「WebAuthn でパスワードの無い世界へ」の通りに利用することをテーマに参加しました。

試してみたところ、いくつか課題が見つかりました。

旧記事の通りに進めようとした場合の課題は次の通りです。

  • Apple シリコンに対応した最新の Keycloak をインストールできない。
  • 最新と古いバージョン間でパスワードレス認証を有効にする画面が (微妙に) 異なる。

さらに今回は Kubernetes で動作するようにしたいとも考えました。

Information

旧記事「WebAuthn でパスワードの無い世界へ」では、Keycloak のコンテナイメージを Docker Hub から取得していました。しかし、最新の Keycloak コンテナイメージは Quay.io で公開されています。

この記事で紹介する Helm チャートのイメージの指定も Docker Hub ではなく Quay.io から pull するようになっています。

Keycloak

#

Keycloak は SAML の Identity Provider (IdP) としてあるいは OpenID Connect (OIDC) の OpenID Provider (OP) として使用できる認証プロダクトです。クラウド環境やオンプレミス環境で使用可能です。

前提

#

動作確認に使用した環境は次の通りです。

インストール

#

Keycloak のインストール

#

Helm チャートを使ってインストールします (ArtifactHUB)。

この記事では Rancher Desktop に同梱されている Ingress である traefik を使用します。

そのため SSL/TLS 証明書が必要になります。

この記事では証明書を Let's Encrypt で取得します。

certbot

#

Homebrew を使って certbot をインストールします。

brew install certbot

証明書生成

#

次のコマンドを実行します。

sudo certbot certonly --manual --preferred-challenges dns

ドメイン名を入力します。所有するドメイン名が example.com であれば、*.example.com のように入力すると便利です。

Please enter in your domain name(s) (comma and/or space separated)  (Enter 'c'
to cancel):

ドメイン名の所有を確認するために、DNS に TXT レコードの追加が要求されます。

表示された指示に従って DNS (Route 53 等) に TXT レコードを追加します。

_acme-challenge.example.com TXT "<表示された値>"

DNS にレコードを追加してから、それがローカル環境で認識されるまで少し時間がかかるので、追加後しばらく待ってから Enter キーを押してください。

成功すると、この例であれば /etc/letsencrypt/live/example.com ディレクトリに証明書ファイルが生成されます。

Helm コマンドを使ったインストール

#

Helm チャートリポジトリにあるオリジナルの values.yaml に若干変更が必要です。

オプション、Ingress を有効にするための変更を加えた values.yaml ファイルを GitHub リポジトリに置いています。takesection/keycloak-install を clone してください。

git clone https://github.com/takesection/keycloak-install.git
cd keycloak-install

certbot で生成されたファイルをクローンした keycloak-install にコピーします。

sudo cp /etc/letsencrypt/live/example.com/fullchain.pem /etc/letsencrypt/live/example.com/privkey.pem ./

tls-secret を作成します。

kubectl create secret tls tls-secret --cert=fullchain.pem --key=privkey.pem

values.ymlの編集

#

values.yml から local-values.yml をコピーしてください。

cp values.yml local-values.yml

local-values.yml の298行目、306行目にある ingress の設定を、証明書のドメイン名に合わせて編集します。例えば、使用するドメイン名が keycloak.example.com であれば、次のようになります。

  # List of rules for the Ingress
rules:
-
# Ingress host
host: '{{ .Release.Name }}.example.com'
# Paths for the host
paths:
- path: /
pathType: Prefix
# TLS configuration
tls:
- hosts:
- keycloak.example.com
secretName: "tls-secret"

Helm チャートのリポジトリを追加します。

helm repo add codecentric https://codecentric.github.io/helm-charts

helm コマンドを使ってインストールします。

helm install keycloak --values=local-values.yml codecentric/keycloak  

Keycloak の初期設定

#

port-forward で localhost でアクセスできるようにします。

kubectl port-forward svc/keycloak-http 8080:80

ブラウザを使って http://localhost:8080/auth/ にアクセスして、管理者のユーザ名とパスワードを設定します。

Create ボタンをクリックします。

パスワードレス認証フローの設定

#

Administration Console のリンクをクリックして、Username or emailPassword には、それぞれ先に設定した管理者のユーザ名、パスワード を入力して Sign In します。

新しい Realm を作成するため、左上の Master のあたりにマウスを置いて「Add realm」ボタンをクリックします。

Add realm の Name に passengers と入力し、「Create」ボタンをクリックします。

左側にある Authentication をクリックします。

Flows の設定

#
  1. Flows で Browser を選択し、右にある「Copy」ボタンをクリックします。

  1. 新しい名前として WebAuthn Browser と入力し、「Ok」ボタンをクリックします。

  1. WebAuthn Browser Forms の下にある「Username Password Form」、「WebAuthn Browser Browser - Conditional OTP」、「Condition - User Configured」と「OTP Form」の右にある Actions から Delete を選んで削除します。

  1. WebAuthn Browser Forms の右にある ActionsAdd execution をクリックして、Provider から Username Form を選択して「Save」ボタンをクリックします。

  1. WebAuthn Browser Forms の右にある ActionsAdd flow をクリックして AliasPassword Or Two-factor を入力して「Save」ボタンをクリックします。このフローは REQUIRED に設定します。

  1. Password Or Two-factor の右にある ActionsAdd execution をクリックして、Provider から WebAuthn Passwordless Authenticator を選択して「Save」ボタンをクリックします。このフローは ALTERNATIVE に設定します。

  1. Password Or Two-factor の右にある ActionsAdd execution をクリックして Provider から Password Form を選択して「Save」ボタンをクリックします。このフローは ALTERNATIVE に設定します。

ここまでの設定で WebAuthn Browser は次のようになります。

Bindings

#

Bindings タブをクリックして Browser FlowWebAuthn Browser を選択して「Save」ボタンをクリックします。

Required Actions

#

Required Actions タブをクリックして「Register」ボタンをクリックし、Required Action に Webauthn Register Passwordless を選択して「Ok」ボタンをクリックします。

WebAuthn Passwordless Policy

#

WebAuthn Passwordless Policy タブをクリックします。

この画面では、次のように入力して「Save」ボタンをクリックします。

項目名
Relying Party Entity Name keycloak
Signature Algorithms ES256
Relying Party ID 構築した keycloak の DNSName
Attestation Conveyance Preference none
Authenticator Attachment platform
Require Resident Key No
User Verification Requirement discouraged
Timeout 0
Avoid Same Authenticator Registration OFF
Acceptable AAGUIDs

試してみましょう

#

左側の Manage にある Users をクリックします。

「Add user」ボタンをクリックします。

「Username」、「Email」、「First Name」、「Last Name」を入力し「Save」ボタンをクリックします。

Credentials タブをクリックします。

Set Password にパスワードを入力し「Set Password」ボタンをクリックします。

認証情報の登録

#

kubectl get ingress で表示されたホスト名とIPアドレスを /etc/hosts ファイルに設定します。

https://{ホスト名}/auth/realms/passengers/account に Chrome ブラウザでアクセスします。

  1. 「Sign In」ボタンをクリックします。

  2. Username or email に作成したユーザの Username か Email を入力して「Sign In」ボタンをクリックします。

  3. Password を入力して「Sign In」ボタンをクリックします。

    • Password の変更が求められたら、変更します。

  1. リンク Signing In をクリックします。

  2. PasswordlessSecurity Key のリンク Set up Security Key をクリックします。

  1. 「Register」ボタンをクリックします。

  1. デバイスに Touch ID が登録されます。

パスワードレスでログイン

#

Sign Out して、もう一度 Sign In をクリックします。

Password を入力する画面の下のリンク Try Another Way をクリックします。

リンク Security Key をクリックします。

「Sign in Security Key」ボタンをクリックして、Touch ID で認証します。

おわりに

#

昨年記事を書いた時点では Apple 社のブラウザ Safari 以外ではパスワードレス認証ができなかったと記憶しています。この記事にある通り、今では Google Chrome ブラウザでも Touch ID に対応したパスワードレス認証ができています。

豆蔵デベロッパーサイト - 先週のアクセスランキング
  1. 基本から理解するJWTとJWT認証の仕組み (2022-12-08)
  2. Docker+Wasm で WASM をコンテナとして実行する (2023-01-25)
  3. 自然言語処理初心者が「GPT2-japanese」で遊んでみた (2022-07-08)
  4. 直感が理性に大反抗!「モンティ・ホール問題」 (2022-07-04)
  5. Nuxt3入門(第4回) - Nuxtのルーティングを理解する (2022-10-09)
  6. AWS認定資格を12個すべて取得したので勉強したことなどをまとめます (2022-12-12)
  7. Jest再入門 - 関数・モジュールモック編 (2022-07-03)
  8. ORマッパーのTypeORMをTypeScriptで使う (2022-07-27)
  9. Nuxt3入門(第8回) - Nuxt3のuseStateでコンポーネント間で状態を共有する (2022-10-28)
  10. Nuxt3入門(第1回) - Nuxtがサポートするレンダリングモードを理解する (2022-09-25)