🐶

Kerberos 認証を理解する

2024/06/26に公開

はじめに

Kerberos 認証をちゃんと理解しないまま利用していたため、とある環境構築の案件でとてもハマってしまいました。次に同じ失敗をしないためにも、基礎を学ぶことが大切だと思うので、お勉強してみることにしました。

この記事でやること

  • Kerberos 認証に関する知識の整理
  • Kerberos 認証のデモ環境を構築
  • Kerberos 認証でサーバーに接続するために必要な作業の説明

Kerberos 認証に関する知識の整理

Kerberos とは?

Kerberos は、ネットワーク認証プロトコルのひとつであり、これによりネットワーク内のクライアントとサーバー間で安全な通信を実現することが可能になります。
クライアント、サーバー、および KDC(Key Distribution Server)の3つから構成され、KDC から発行されるチケットにより、安全な通信とシングルサインオン(SSO)を実現することができます。

Kerberos 認証の流れ


Kerberos 認証では、上図の流れで認証プロセスを進めます。
その際、2種類のチケットを使います。

  1. TGT(Ticket Granting Ticket): ユーザーがログインするときに取得するチケット。他のサービスにアクセスするためのチケットを取得する際に使われる。
  2. Service Ticket: ユーザーが特定のサービスにアクセスするために必要なチケット。

Kerberos 認証の構成要素と用語

Realm

Realm は認証管理ドメインを示します。Realm は Kerberos サーバー(KDC) によって管理されます。
ユーザー/サービスは、その Realm の認証サーバーと secret (password/key) を共有する場合のみ、その Realm に属します。

Realm の主な役割は以下です。

  • 認証ドメインの定義: ユーザーやサービスがどの KDC によって管理されるかを示す。
  • 信頼関係(トラスト)の設定: 異なる Realm 間で信頼関係(トラスト)が設定されている場合、ユーザーは自分の Realm 外のリソースにアクセスできる。

Principal

Principal は、Kerberos がチケットを割り当てることができる一意の ID です。
この記事を書いてる段階で主要バージョンである Kerberos V5 での Principal の形式は以下のとおりです。

primary/instance@REALM
  • primary: ユーザーの場合、ユーザ名。nfs などのサービスになることもある。host という単語になることもある。
  • instance: instance は、user principal の場合は optional になるが、service principal の場合は必須。service principal の場合、instance に指定する hostname は FQDN で指定する必要がある。
  • REALM: Realm のとこで説明した内容と同じ。慣習的には大文字で書く。

有効な Principal Name は以下のようなものがあります。

jdoe
jdoe/admin
jdoe/admin@CORP.EXAMPLE.COM
nfs/host.corp.example.com@CORP.EXAMPLE.COM
host/corp.example.com@CORP.EXAMPLE.COM

Kerberos 認証のデモ環境の構築

実際に手を動かしたほうが理解が早いので、Kerberos 認証を試せるデモ環境を構築して、基本的な操作方法を試してみたいと思います。
ここでは、クライアントからサーバーへ Kerberos 認証を使った接続ができるようになるまでに必要な手順を記録しています。

Docker のインストール

好きな方法で Docker をインストールします。
https://www.docker.com/get-started/

Docker Container を立ち上げる

https://github.com/rea9r/demo-kerberos-auth にデモ環境を用意しました。
以下のコマンドを実行して、必要なコンテナを全て立ち上げます。

docker-compose up --build

KDC でやること

kadmin で Principal のリストを出力

KDC のコンテナに接続して bash を実行します。

docker exec -it kerberos-kdc /bin/bash

kadmin を使って、Kerberos Database 内に存在する全ての Principal のリストを確認してみます。

kadmin.local -q "listprincs"
result
[root@kerberos-kdc /]# kadmin.local -q "listprincs"
Authenticating as principal root/admin@EXAMPLE.COM with password.
K/M@EXAMPLE.COM
kadmin/admin@EXAMPLE.COM
kadmin/changepw@EXAMPLE.COM
kadmin/kerberos-kdc@EXAMPLE.COM
kiprop/kerberos-kdc@EXAMPLE.COM
krbtgt/EXAMPLE.COM@EXAMPLE.COM
noPermissions@EXAMPLE.COM

kadmin は Kerberos V5 管理システムへのコマンドラインインターフェースです。kadmin.local とすることで、Kerberos Database に直接アクセスします。

kadmin で Principal を新しく追加

kadmin.local -q "addprinc -randkey host/service-server@EXAMPLE.COM"
result
[root@kerberos-kdc /]# kadmin.local -q "addprinc -randkey host/service-server@EXAMPLE.COM"
Authenticating as principal root/admin@EXAMPLE.COM with password.
WARNING: no policy specified for host/service-server@EXAMPLE.COM; defaulting to no policy
Principal "host/service-server@EXAMPLE.COM" created.

kadmin で Service Principal と keytab を作成

次に、 service-server のコンテナにデプロイする必要がある Service Principal の keytab ファイルを作成します。

kadmin.local -q "ktadd -k /service.keytab host/service-server@EXAMPLE.COM"
result
[root@kerberos-kdc /]# kadmin.local -q "ktadd -k /service.keytab host/service-server@EXAMPLE.COM"
Authenticating as principal root/admin@EXAMPLE.COM with password.
Entry for principal host/service-server@EXAMPLE.COM with kvno 2, encryption type aes256-cts-hmac-sha1-96 added to keytab WRFILE:/service.keytab.
Entry for principal host/service-server@EXAMPLE.COM with kvno 2, encryption type aes128-cts-hmac-sha1-96 added to keytab WRFILE:/service.keytab.
Entry for principal host/service-server@EXAMPLE.COM with kvno 2, encryption type des3-cbc-sha1 added to keytab WRFILE:/service.keytab.
Entry for principal host/service-server@EXAMPLE.COM with kvno 2, encryption type arcfour-hmac added to keytab WRFILE:/service.keytab.
Entry for principal host/service-server@EXAMPLE.COM with kvno 2, encryption type camellia256-cts-cmac added to keytab WRFILE:/service.keytab.
Entry for principal host/service-server@EXAMPLE.COM with kvno 2, encryption type camellia128-cts-cmac added to keytab WRFILE:/service.keytab.
Entry for principal host/service-server@EXAMPLE.COM with kvno 2, encryption type des-hmac-sha1 added to keytab WRFILE:/service.keytab.
Entry for principal host/service-server@EXAMPLE.COM with kvno 2, encryption type des-cbc-md5 added to keytab WRFILE:/service.keytab.

kadmin で User Principal と keytab を作成

次に、service-server 上で利用する User Principal を追加します。
ここでのユーザー名は、service-server のコンテナ上のユーザー名と同じである必要があります。
ここでは、ユーザー名として krb5user を使用します。

kadmin.local -q "addprinc -randkey krb5user"
result
[root@kerberos-kdc /]# kadmin.local -q "addprinc -randkey krb5user"
Authenticating as principal root/admin@EXAMPLE.COM with password.
WARNING: no policy specified for krb5user@EXAMPLE.COM; defaulting to no policy
Principal "krb5user@EXAMPLE.COM" created.
Principal 追加後の listprincs も確認しておく
[root@kerberos-kdc /]# kadmin.local -q "listprincs"
Authenticating as principal root/admin@EXAMPLE.COM with password.
K/M@EXAMPLE.COM
host/service-server@EXAMPLE.COM
kadmin/admin@EXAMPLE.COM
kadmin/changepw@EXAMPLE.COM
kadmin/kerberos-kdc@EXAMPLE.COM
kiprop/kerberos-kdc@EXAMPLE.COM
krbtgt/EXAMPLE.COM@EXAMPLE.COM
krb5user@EXAMPLE.COM
noPermissions@EXAMPLE.COM
kadmin.local -q "ktadd -k /krb5user.keytab krb5user@EXAMPLE.COM"
result
[root@kerberos-kdc /]# kadmin.local -q "ktadd -k /krb5user.keytab krb5user@EXAMPLE.COM"
Authenticating as principal root/admin@EXAMPLE.COM with password.
Entry for principal krb5user@EXAMPLE.COM with kvno 2, encryption type aes256-cts-hmac-sha1-96 added to keytab WRFILE:/krb5user.keytab.
Entry for principal krb5user@EXAMPLE.COM with kvno 2, encryption type aes128-cts-hmac-sha1-96 added to keytab WRFILE:/krb5user.keytab.
Entry for principal krb5user@EXAMPLE.COM with kvno 2, encryption type des3-cbc-sha1 added to keytab WRFILE:/krb5user.keytab.
Entry for principal krb5user@EXAMPLE.COM with kvno 2, encryption type arcfour-hmac added to keytab WRFILE:/krb5user.keytab.
Entry for principal krb5user@EXAMPLE.COM with kvno 2, encryption type camellia256-cts-cmac added to keytab WRFILE:/krb5user.keytab.
Entry for principal krb5user@EXAMPLE.COM with kvno 2, encryption type camellia128-cts-cmac added to keytab WRFILE:/krb5user.keytab.
Entry for principal krb5user@EXAMPLE.COM with kvno 2, encryption type des-hmac-sha1 added to keytab WRFILE:/krb5user.keytab.
Entry for principal krb5user@EXAMPLE.COM with kvno 2, encryption type des-cbc-md5 added to keytab WRFILE:/krb5user.keytab.

keytab ファイルを各コンテナにコピー

Service Principal と User Principal の追加ができたら、keytab ファイルを各コンテナにコピーします。

service.keytab を service コンテナにコピー
docker cp kerberos-kdc:/service.keytab ./service.keytab
docker cp ./service.keytab service-server:/etc/krb5.keytab
krb5user.keytab を client コンテナにコピー
docker cp kerberos-kdc:/krb5user.keytab ./krb5user.keytab
docker cp ./krb5user.keytab client-server:/etc/krb5.keytab

KDC の /etc/hosts の修正

service-server の IP Address を確認
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' service-server
client-server の IP Address を確認
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' client-server
/etc/hosts に追記
172.18.0.2 kerberos-kdc
# 以下を追記
172.18.0.3 client-server
172.18.0.4 service-server

service-server での設定

コンテナに接続

service-server コンテナに接続
docker exec -it service-server /bin/bash

/etc/ssh/sshd_config の修正

service-server が SSH の認証で Kerberos チケットを受け入れられるようにするには、/etc/ssh/sshd_config で次の構成を有効にする必要があります。

/etc/ssh/sshd_config
# GSSAPI を使用した認証を有効にする
GSSAPIAuthentication yes
# セッション終了時に GSSAPI クレデンシャルをクリーンアップする
GSSAPICleanupCredentials yes
  • GSSAPI 認証は、Kerberos のようなセキュアな認証メカニズムを提供するために使用されます。これを有効にすることで、クライアントは GSSAPI ベースの認証プロトコル(例えば Kerberos)を使用して SSH で接続できるようになります。
  • これでパスワードを送信することなく、チケットベースのセキュアな認証を行うことができます。

/etc/krb5.conf の修正

/etc/krb5.conf を修正して、KDC の接続先などを指定します。

/etc/krb5.conf
[libdefaults]
    default_realm = EXAMPLE.COM
    forwardable = TRUE
[realms]
    EXAMPLE.COM = {
            kdc_ports = 88
            kadmind_port = 749
            kdc = host.docker.internal
            admin_server = host.docker.internal
    }
[domain_realm]
        host.docker.internal = EXAMPLE.COM

krb5user の作成

krb5user の作成
adduser krb5user

これで service-server は krb5user の Kerberos チケットベースのログインを受け入れる準備が整いました。

client-server での設定

コンテナに接続

client-server コンテナに接続
docker exec -it client-server /bin/bash

/etc/hosts の修正

client から接続したい server の情報を /etc/hosts に追記します。

/etc/hosts に追記
# 以下を追記
172.18.0.4 service-server

/etc/ssh/ssh_config の修正

client 側が SSH の認証で Kerberos チケットを利用できるようにするために/etc/ssh/ssh_config で次の構成を有効にします。

/etc/ssh/sshd_config
# GSSAPI を使用した認証を有効にする
GSSAPIAuthentication yes

/etc/krb5.conf の修正

client 側も /etc/krb5.conf を修正して、KDC の接続先などを指定します。

/etc/krb5.conf
[libdefaults]
    default_realm = EXAMPLE.COM
    forwardable = TRUE
[realms]
    EXAMPLE.COM = {
            kdc_ports = 88
            kadmind_port = 749
            kdc = host.docker.internal
            admin_server = host.docker.internal
    }
[domain_realm]
        host.docker.internal = EXAMPLE.COM

Client から色々試してみる

kinit で Kerberos チケットの初期化

これで kinit を使用して Kerberos チケットを初期化できるようになりました。

kinit で Kerberos 認証を行い、チケットを取得
kinit krb5user -k -t /etc/krb5user.keytab

kinit コマンドがエラー無しで返された場合、クライアント側は krb5.conf に基づいて KDC に正常にアクセスできたことを意味します。User Principal の TGT チケットを初期化できた状態になります。

klist で keytab ファイルの内容を確認

klist を使用できるかを確認してみます。

klist で keytab ファイルの内容をリスト表示する
klist -kte
result
[root@client-server /]# klist -kte
Keytab name: FILE:/etc/krb5.keytab
KVNO Timestamp           Principal
---- ------------------- ------------------------------------------------------
   2 06/19/2024 12:56:28 krb5user@EXAMPLE.COM (aes256-cts-hmac-sha1-96)
   2 06/19/2024 12:56:28 krb5user@EXAMPLE.COM (aes128-cts-hmac-sha1-96)
   2 06/19/2024 12:56:28 krb5user@EXAMPLE.COM (des3-cbc-sha1)
   2 06/19/2024 12:56:28 krb5user@EXAMPLE.COM (arcfour-hmac)
   2 06/19/2024 12:56:28 krb5user@EXAMPLE.COM (camellia256-cts-cmac)
   2 06/19/2024 12:56:28 krb5user@EXAMPLE.COM (camellia128-cts-cmac)
   2 06/19/2024 12:56:28 krb5user@EXAMPLE.COM (des-hmac-sha1)
   2 06/19/2024 12:56:28 krb5user@EXAMPLE.COM (des-cbc-md5)

Kerberos チケットを使用して SSH 接続

Kerberos チケットを使用して、パスワードを必要とせずに SSH 接続できることを確認します。

Kerberos チケットを使って SSH 接続
ssh krb5user@service-server
result
[root@client-server /]# ssh krb5user@service-server
The authenticity of host 'service-server (172.18.0.4)' can't be established.
ECDSA key fingerprint is SHA256:t+yaqZfgauI2ZMAWd3gF3bzHhoLyJU55wI/X/ePJ630.
ECDSA key fingerprint is MD5:c6:a4:cb:15:3f:34:03:de:da:73:07:36:ad:58:7e:f9.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'service-server,172.18.0.4' (ECDSA) to the list of known hosts.
Last login: Thu Jun 20 11:33:03 2024 from client-server.demo-kerberos-auth_default
[krb5user@service-server ~]$

これで Kerberos 認証を利用したサーバーへの接続が確認できました。

参考資料

Discussion