いっそ SaaS とかに移行したいところだが、社内規定と先立つものが……。
要点
- Active Directory環境でパスワード不要のgitサーバを立てました。
- apache で spnego認証ならmod_auth_gssapi が推奨らしい。
- docker 使いました。ソースは github にアップしてあります 1
きっかけ
今まで社内gitサーバの認証には、BASIC認証 + LDAP(Active Directory)を使用していました。Windowsクライアントでgitサーバに接続するとID/パスワードは「資格情報マネージャ」に保存されます。
一度保存してしまえばID/パスワードを聞かれることはないのですが、社内のポリシーではパスワードの定期変更が必要です。
パスワード相違のときは新しいパスワード入力を促すという仕組みなら、それほどストレスは感じなかったでしょう。しかし現状ではgitは認証エラーが発生したら、新しいID/パスワードを聞くこともなく終了してしまいます。
パスワード変更の都度、資格情報マネージャから認証情報を削除しないといけない。
めんどくさい。 良い感じにシングルサインオンできないだろうかといろいろ調べました。2
環境
インフラ関連
役割 | バージョン |
---|---|
ドメインコントローラー | Windows Server 2019 Standard |
gitサーバ | docker desktop 2.4.1.0 |
クライアント | Windows 10 Pro 1909 |
gitクライアント | git for windows 2.29.2.windows.3 |
git for windows ではインストール時に認証を補助する「資格情報ヘルパー」を選択します。git 2.29 では Git Credential Manager Core がデフォルトになっているので今回はこれで確認しました。
Active Directory関連
項目 | |
---|---|
Active Directory ドメイン | hoge.local |
ドメインコントローラ | pdc.hoge.local |
レルム | HOGE.LOCAL |
チケット検証ユーザ | krbuser01 |
gitサーバ名 | gitsrv.hoge.local |
gitを使用するユーザ | user01 |
チケット検証ユーザは、ドメイン管理者に作ってもらいます。ただのドメインユーザです(gitサーバではなく、Active Directoryに作ります)。
Apache で spnego認証を実現するまで
そもそも spnego認証とは何か?
SPNEGO (読み方:スプネゴ) とは Simple and Protected gss-api NEGOtiation mechanism の略で、Microsoft が作成した SSO のためのプロトコルです。GSS-API の上で動作します。
GSS-API は (http, ldap, smtp, pop3, imap4 等の認証が必要な) 通信プロトコルの種類に依存せず、全ての通信プロトコル間で SSO を実現するためのフレームワークです。GSS-API では枠組みだけですので具体的な実装が必要です。その実装の 1 つが SPNEGO なのです。
【図解】初心者にも分かるKerberos認証とspnegoの仕組み ~SSOのシーケンス,統合windows認証について~ より。
今回の構築、このページにお世話になりました。GSS-APIの実装で、HTTPに特化したのが spnego (という認識で良いんですよね?)
spnego認証の設定は「 ApacheでActive Directory SSO 」を参考にしましたが、別のサイトでapacheのモジュールとしては、記事中で使用されている mod_auth_kerb ではなく mod_auth_gssapi を推奨していました。 Apache2-mod_auth_kerb Is Dead, Use Mod_auth_gssapi だそうです。
mod_auth_kerb 本家のメンテナンスはだいぶ前に止まっているらしい(各ディストリビューションではメンテされていると思いますが)のに比べ mod_auth_gssapi は
と良さそうだったのでこちらを使うことにしました。
Active Directory上の準備
- gitサーバにから Active Directory に問い合わせるためのユーザが必要です。ドメイン管理者にユーザを作成してもらってください。
- 作成されたユーザ名でkeytabファイルを作成します。このファイルは gitサーバで使用します。
ユーザの設定
Set-ADUser krbuser01 -KerberosEncryptionType AES256,AES128,RC4
# 内容確認
Get-AdUser krbuser01 -property MsDS-SupportedEncryptionTypes
keytab作成
ktpass -princ HTTP/gitsrv.hoge.local@HOGE.LOCAL -mapuser krbuser01@hoge.local -pass xxxxxx -crypto All -ptype KRB5_NT_PRINCIPAL -out kerberos.keytab 2> log
# 内容確認
Get-ADUser krbuser01 -property msDS-KeyVersionNumber
# 内容確認
dsquery * "CN=krbuser01,DC=hoge,DC=local" -attr msDS-KeyVersionNumber
# 内容確認
setspn -q 'HTTP/*' krbuser01
検証(gitサーバ構築後)
- gitサーバ構築後、以下のような形で keytabファイルの挙動を確認できます。(Windows上で確認する方法がわからない……)
$klist -ke -t /etc/kerberos.keytab
Keytab name: FILE:/etc/kerberos.keytab
KVNO Timestamp Principal
---- ----------------- --------------------------------------------------------
23 01/01/70 00:00:00 HTTP/gitsrv.hoge.local@HOGE.LOCAL (des-cbc-crc)
23 01/01/70 00:00:00 HTTP/gitsrv.hoge.local@HOGE.LOCAL (des-cbc-md5)
23 01/01/70 00:00:00 HTTP/gitsrv.hoge.local@HOGE.LOCAL (arcfour-hmac)
23 01/01/70 00:00:00 HTTP/gitsrv.hoge.local@HOGE.LOCAL (aes256-cts-hmac-sha1-96)
23 01/01/70 00:00:00 HTTP/gitsrv.hoge.local@HOGE.LOCAL (aes128-cts-hmac-sha1-96)
$ kinit -V -k -t /etc/kerberos.keytab HTTP/gitsrv.hoge.local
Using default cache: /tmp/krb5cc_0
Using principal: HTTP/gitsrv.hoge.local@HOGE.LOCAL
Using keytab: /etc/krb5.keytab
Authenticated to Kerberos v5
Git サーバの設定
kerberos の設定
- krb5.conf に Active Directory のドメイン構成を記載します。
[libdefaults]
default_realm = HOGE.LOCAL
# The following krb5.conf variables are only for MIT Kerberos.
kdc_timesync = 1
ccache_type = 4
forwardable = true
proxiable = true
fcc-mit-ticketflags = true
[realms]
HOGE.LOCAL = {
kdc = pdc.hoge.local
admin_server = pdc.hoge.local
default_domain = hoge.local
}
[domain_realm]
.hoge.local = HOGE.LOCAL
hoge.local = HOGE.LOCAL
apache の設定
git サーバとしてとりあえず、 git-http-backend を使用します。
ServerName gitsrv.hoge.local:80
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/
SetEnv GIT_PROJECT_ROOT /var/lib/git/
SetEnv GIT_HTTP_EXPORT_ALL
ScriptAlias /git /usr/lib/git-core/git-http-backend
RewriteEngine On
RewriteCond %{QUERY_STRING} service=git-receive-pack [OR]
RewriteCond %{REQUEST_URI} /git-receive-pack$
RewriteRule ^/git/ - [E=AUTHREQUIRED]
<Files "git-http-backend">
AuthType GSSAPI
AuthName "GSSAPI Auth"
GssapiAllowedMech krb5
GssapiCredStore keytab:/etc/kerberos.keytab
Require valid-user
</Files>
<Location /gssapi-test>
AuthType GSSAPI
AuthName "GSSAPI Auth"
GssapiAllowedMech krb5
GssapiNegotiateOnce On
GssapiCredStore keytab:/etc/kerberos.keytab
Require valid-user
AllowOverride None
AddHandler cgi-script .cgi
Options ExecCGI MultiViews SymLinksIfOwnerMatch
</Location>
ErrorLog /opt/log/error.log
CustomLog /opt/log/access.log combined
LogLevel Debug
</VirtualHost>
問題が発生したときの切り分けのため、ブラウザで認証の状況が確認できるように CGIスクリプトを用意しました。
#!/usr/bin/perl
print "Content-type: text/html\n\n";
print "<table>\n";
for $key (sort(keys(%ENV))) {
print "<tr><td>$key</td><td>$ENV{$key}</td></tr>\n";
}
print "</table>\n";
exit;
ブラウザで接続テスト
クライアントのチケットを全て削除して接続。
PS > klist purge
Current LogonId is 0:0x115ad2d
Deleting all tickets:
Ticket(s) purged!
ブラウザで http://gitsrv/gssapi-test/env.cgi にアクセスして画面にズラズラと環境変数が表示されれば成功です。
AUTH_TYPE Negotiate
CONTEXT_DOCUMENT_ROOT /var/www/
CONTEXT_PREFIX
DOCUMENT_ROOT /var/www/
GATEWAY_INTERFACE CGI/1.1
中略
REMOTE_USER user1@HOGE.LOCAL
REQUEST_METHOD GET
後略
認証の成功を確認した後、クライアントでチケットを確認してみましょう。
PS> klist
Current LogonId is 0:0x115ad2d
Cached Tickets: (2)
#0> Client: user1 @ HOGE.LOCAL
Server: krbtgt/HOGE.LOCAL @ HOGE.LOCAL
KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
Ticket Flags 0x40e10000 -> forwardable renewable initial pre_authent name_canonicalize
Start Time: 12/17/2020 15:37:43 (local)
End Time: 12/18/2020 1:37:43 (local)
Renew Time: 12/24/2020 15:37:43 (local)
Session Key Type: AES-256-CTS-HMAC-SHA1-96
Cache Flags: 0x1 -> PRIMARY
Kdc Called: pdc.hoge.local
#1> Client: user1 @ HOGE.LOCAL
Server: HTTP/gitsrv.hoge.local @ HOGE.LOCAL
KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
Ticket Flags 0x40a10000 -> forwardable renewable pre_authent name_canonicalize
Start Time: 12/17/2020 15:37:43 (local)
End Time: 12/18/2020 1:37:43 (local)
Renew Time: 12/24/2020 15:37:43 (local)
Session Key Type: AES-256-CTS-HMAC-SHA1-96
Cache Flags: 0
Kdc Called: pdc.hoge.local
きちんとチケットが取得できています。
そしてgitで接続テスト
gitサーバ側の準備
一つ、空のBareリポジトリを作成しておきます。
$ mkdir fuga.git
$ cd fuga.git
$ git init --bare
git クライアントの準備
git の設定として以下の設定をしておく必用があるようです
git config http.emptyAuth true
いよいよ clone
PS> git clone http://gitsrv.hoge.local/git/fuga.git
Cloning into 'fuga'...
warning: You appear to have cloned an empty repository.
できました!! (空のリポジトリをクローンしているので警告がでています)
ハマったこと
最初、ブラウザの接続は成功するけど、git clone は失敗する、という問題でハマりました。原因は git の URL指定時に、http://gitsrv/git/fuga.git とだけ書いて hoge.local を抜かしていたのが原因でした。
ブラウザでの確認のときは、 http://gitsrv/gssapi-test/env.cgi で接続が成功していたのですが、gitはそうした接続には対応していない模様。
当初は原因が分からず頭を抱えていましたが、接続後に klist
コマンドで出力されるチケットの Server
の項を確認して問題に気づきました。
その他
git kerberos 等で検索していると、git clone 時に URLに :@
を挟め (今回の例でいくと http://:@gitsrv/git/fuga.git) ということが書かれたりしていますが、今は不要なようです。
未確認事項
gitサーバが動いているホスト上でログインしようとすると kerberos認証ができず、basic認証のプロンプトが表示されてしまいます。他のクライアントから接続する場合は問題ありません。日常の使用に問題がないのであまり深追いしていませんが、kerberosの仕様かなにかでしょうか。もしご存じの方がいらっしゃれば教えて下さい。