KCD(Kerberos Constrained Delegation) を理解する (2)
前回からの続きです。
KCD(Kerberos Constrained Delegation) を理解する (1)
https://blogs.technet.com/b/junichia/archive/2015/10/20/3656083.aspx
今回は SPN(サービス プリンシパル ネーム)について。SPN は KCD はもとより、Kerberos そのものを理解するうえでとても重要なので、ぜひ理解しておきましょう。これも長くなりそうだな。。。
Kerberos では「プリンシパル名」を使用してユーザーやコンピューターを識別します。プリンシパル名には2種類あります。
- ユーザープリンシパル名(UPN)
- サービスプリンシパル名(SPN)
UPN はユーザーアカウントに対して設定できるものですが、SPN はユーザーアカウントおよびコンピューターアカウントのいずれにも設定できます。SPN も UPN も、フォレスト内で一意でなければなりません。一意に識別して認証するわけですから、当然ですね。SPN が一意でなかったり設定されていなければ、サービスを呼び出すこともできなくなります。
ご存知の通り、「サービス」は必ず何らかのアカウントの配下で動作します。言い換えると、サービスは、SPN が設定されたアカウントの配下で動作するということです。サービスアカウントという特別なユーザーアカウントがありますが、これは SPN が設定された”ユーザー”アカウントのことです。Network Service や Local System、Local Service といったサービスアカウントが、サービスアカウントの既定値としてよく使わることはご存知の通りです。
以下は、とあるコンピューターに登録されているサービスの一覧です。CIFS や DHCP といった文字列が見えるかと思いますが、これは「サービスの種類」です。SPN には、必ず サービスの種類 が含まれます。
ところで、SPN って見たことありますか?
以下のような文字列で表現されます。URL のように見えますが、HTTP の後にはコロンが入っていませんので注意してください。
- HTTP/www.contoso.com
- CIFS/fs.contoso.com
- MSSQLSvc/sqlsrvr.contoso.com:1433
SPN を登録できるのは、基本的にはドメインのシステム管理権限をもったユーザーですが、例外として System アカウントはコンピューターアカウントに対して SPN を登録することができます。SPN はフォレストで一意でなければなりません。一意でないと認証に失敗します。なぜならば、一方の SPN は悪意のある第三者がサービス偽装するために登録した可能性があるからです。
SPN のフォーマットは以下のような形式で、4つの要素から成り立っています。
<service class>/<host>:<port>/<service name>
上の例で言えば、HTTP や CIFS が <service class> に相当し、www.contoso.com などが <host> です。この2つの要素によって、どんなサービスがどのサーバーで動作しているのかが把握できるわけですね。これら 2 つは必須ですが、その他の要素 <port> と <service name> は省略が可能です。
Windows Server 2003 Active Directory で使用されている <service class> は以下の通りです(2012以降はもっと増えているはず)。サービスの種類として適切な SPN が無い場合は、基本的に HOST を使用します。HOST を使用すると、SPN はコンピューターアカウントとして認識されます。
alerter |
http |
policyagent |
scm |
appmgmt |
ias |
protectedstorage |
seclogon |
browser |
iisad |
rasman |
snmp |
cifs |
min |
remoteaccess |
spooler |
cisvc |
messenger |
replicator |
tapisrv |
clipsrv |
msiserver |
rpc |
time |
dcom |
mcsvc |
rpclocator |
trksvr |
dhcp |
netdde |
rpcss |
trkwks |
dmserver |
netddedsm |
rsvp |
ups |
dns |
netlogon |
samss |
w3svc |
dnscache |
netman |
scardsvr |
wins |
eventlog |
nmagent |
scesrv |
www |
eventsystem |
oakley |
schedule |
|
fax |
plugplay |
コンピューターアカウントのプロパティを属性エディタで見てみると、以下のような SPN が登録されていることがわかります。
SPN はサービスを一意に識別するために使用することは既に書いた通りですが、それでは、SPN を使用してサービスがどのように認証されるのかについてみてみます。
以下の図を見てください。面倒くささが倍増しますよね。。。でも苦労してまとめてみたんです。。。以降、図とにらめっこしながら読んでくださいね。
既にユーザーはログオンして、TGT(Ticket Granting Ticket)が発行されていると思ってください。ユーザーがログオンすると、Kerberos の KDC(キー配布サービス)から TGT と ”Session Key” が発行されます。TGT はドメイン内のサービスにアクセスするための ”Service Ticket” を発行してもらうための予約券みたいなものです。Session Key は KDC との通信に使用する暗号キーで、両者を共有することで暗号化したデータをお互いに復号できるようになります。
ユーザーは、KDC から TGT を受け取る際に、生データでもらうわけではありません。TGT は Ticket Grating Service Key(TGS Key)で暗号化されており、暗号化された状態で受け取り、ローカルにキャッシュしています。
①に示すように、ユーザーがサービスにアクセスしたい場合には、TGS Key で暗号化された状態の TGTと、自分の UPN、そしてアクセスしたいサービスの SPN、その他を Session Key で暗号化して KDC に送ります。
KDC は自分でキャッシュしている Session Key でデータを復号し、暗号化された TGT、UPN、SPN 等を取り出します。取り出した暗号化済 TGT は、やはりローカルにキャッシュしている TGS Key を使用すれば復号でき、本物かどうかをチェックできます。
次に ② です。正しい TGT だと判断しユーザーの正当性を確認できたら、今度は SPN を使用して、そんなサービスが本当にあるかどうかを LDAP Query を使ってチェックします。このとき SPN の示された文字列が見つからなければ「そんなサービス 無ぇ」ってことになるわけです。
サービスが見つかれば ③ です。サービスは「サービスアカウント」か「コンピューターアカウント」と紐づいていると書きました。アカウントと紐づいているということは、そいつらのパスワードが存在するということです。これが Service Key となります。
KDC は、SPN 用に ”Service Session Key” を生成します。Service Session Key は、クライアントがサービスと通信する際に使用する暗号化キーです。KDC は、さらに、はサービスにアクセスするための ”Service Ticket” も生成します。Service Ticket の中には Service Session Key が格納されます。ここには書いてませんが、Windows の場合には、Service Ticket の中に PAC(Privileged Attribute Certificate)も含まれます。PAC とは、ユーザーの SID や参加しているグループの一覧などが格納されたデータで、サービスはこれを見てユーザーのアクセス権を判定することができるようになっています。
KDC は Service Key(パスワード)によって Service Ticket を暗号化します。さらに、もう一つ Service Session Key の複製を用意して、Service Ticket と Service Session Key を Session Key で暗号化します。
繰り返しますが、Session Key は KDC とクライアントの通信を暗号化するためのものなので、クライアントも保持しています。Service Session Key をもう1つ用意したのは、クライアントが Service Session Key を取り出してサービスとの通信に使用するためです。Service Ticket にも Service Session Key は格納されていますが、Service Key(コンピューターアカウントのパスワード)で暗号化されているので、クライアントからは取り出せないからです。
次に④.
Service Ticket を受け取ったクライアントは Session Key を使ってデータ復号し、Service Session Key を取り出します。
Service Key で暗号化された Service Ticket、そして、Service Session Key で暗号化した UPN、TimeStamp 等をサービス側に送ります。
いよいよ⑤.はふぅ。
Service Key で暗号化された Service Ticket を受けとったサービスは、当然自分でもキャッシュしている Service Key(自分のパスワードですからね) を使用して Service Ticket を取り出します。取り出した Service Ticket には Service Session Key が含まれているので、これも取り出します。
Service Ticket が正しいと判断されたら、取り出した Service Session Key を使用して UPN や TimeStamp を復号できます。
サービスはこれに対して応答メッセージを作成します。この中には、サービスの SPN や送られてきた TimeStamp が含まれています。この TimeStamp が実は重要で、返信された TimeStamp が、最初の TimeStamp と一致していることを確認できると「このサービスは、クライアントがアクセスしたいサービスだ」と判断されるのです。
ここまでの流れで1つ気づくことがあると思います。
サービスは KDC と通信していない。
そうなんです。サービスを認証する過程では、サービス自身が KDC と通信を行うことは無いのです。ユーザーもサービスも KDC を信頼しています。信頼しているから、KDC というオーソリティが発行したチケットであることが保証できれば、あえて KDC に問い合わせる必要が無いのです。なぜ KDC が信頼できるかといえば、KDC がサービスアカウントまたはコンピューターアカウントのパスワード(実際には パスワードハッシュ)を知っているからですね。コンピューターアカウントのパスワードは自動的に更新され続けています。マネージドサービスアカウントの場合も同様です。パスワードが定期的に更新されているという安心感があるので、直接会話しなくてもお互いに信頼関係が保てるのです。そう考えると、普通のユーザーアカウントをサービスアカウントとして使用する危険性というのは途方もないですね。
で、この話をベースに、次回は KCD(制約付き委任)について解説します。