AWS Directory Serviceを使ってEnterprise Wi-Fiを使う

# AWS Directory Serviceを使ってEnterprise Wi-Fiを使う

ユーザ管理をADでやりたいけどWindowsサーバを管理したくないということでAWS Direcotry Serviceを使った上でEnterprise Wi-Fi(802.1X)に対応してみます。

利点

1. サーバがAWS管理でレプリカあり
2. スナップショットも取ってくれる

欠点

1. Windows Serverと信頼関係が結べないのでいろいろ機能が使えない。特にNPSが使えない（Enterpriseなら結べるけど高いので却下）

NPSが使えないというかSimple ADにJoinしただけで作ったユーザはDial-in情報が使えずにエラーになってしまうという状態で回避する手段が見つからないという状態です。
よって、NPSの代わりをAmazon LinuxでFreeradius立ててやって安く済ませます。

ユーザ管理用するWindows Serverは別目的で建てたサーバを使います。ADにJoinできて管理ツールが立ち上がればいいだけで、必要なデータを保持することはないのでなんでもいいです。

# AWS Directory Service

DNSをADに変更する関係上、無関係なドメイン名(wacul.localとか)を割り当てるか、サブドメインを割り当てるかする必要があります。ここでは`ds.wacul.co.jp`とします。

|Param|Value|
|---|---|
|**Directory type**|Simple AD|
|**Directory DNS**|ds.wacul.co.jp|
|**NetBIOS name**|WACUL|

その他とVPCは構成済みとして適当に選びます。

# Amazon Linux

せっかくなのでAmazon Linuxを使います。パスとかはAmazon Linux準拠です。RedHat系ならほとんど同じはず。
インスタンスを立てるVPCは当然Directory Serviceで選んだものと同じで、自動でグローバルを与えず、セットアップ中だけElasticIPを与えてネットにつなぐだけにしてセキュリティを担保します。


## Prerequirements

```
yum install -y krb5-workstation samba samba-winbind samba-winbind-clients freeradius freeradius-utils gcc openssl-devel libnl-devel
chkconfig winbind on
chkconfig radiusd on
```
## Samba & krb5

sambaの設定。samba本体は今回必要ないので起動しないのですが、winbindやnetコマンドがこのファイルを参照するので。

```/etc/samba/smb.conf
[global]
        workgroup = WACUL
        server string = Samba Server Version %v
        log file = /var/log/samba/log.%m
        max log size = 50
        security = ads
        realm = DS.WACUL.CO.JP
        password server = ds.wacul.co.jp
        winbind refresh tickets = yes
```

kerberos認証をするのでkrb5.confを設定します。

```/etc/krb5.conf
[logging]
 default = FILE:/var/log/krb5libs.log
 kdc = FILE:/var/log/krb5kdc.log
 admin_server = FILE:/var/log/kadmind.log

[libdefaults]
 ticket_lifetime = 24000
 default_realm = DS.WACUL.CO.JP
 dns_lookup_realm = false
 dns_lookup_kdc = false

[realms]
 DS.WACUL.CO.JP = {
  kdc = ds.wacul.co.jp
 }

[domain_realm]
 .ds.wacul.co.jp = DS.WACUL.CO.JP
 ds.wacul.co.jp  = DS.WACUL.CO.JP
```

AD上でしっかりDNS名を登録するためにはhostnameの設定が必須です。登録しなくてもいいんですが。ホスト名は`radius.ds.wacul.co.jp`とします。

* 即反映される様にhostnameで実行

```
hostname radius.ds.wacul.co.jp
```

* 再起動時にhostnameが反映される様に

```diff:/etc/sysconfig/network
- HOSTNAME=localhost.localdomain
+ HOSTNAME=radius.ds.wacul.co.jp
```

* hostsに書いておかないとnet ads joinでDNSエラー

```conf:/etc/hosts
127.0.0.1   radius radius.ds.wacul.co.jp localhost localhost.localdomain
```

* nameserverをAWS Directory Serviceで表示される`DNS Address`に変えます。

```conf:/etc/resolve.conf
search ds.wacul.co.jp
nameserver xx.xx.xx.xx
nameserver xx.xx.xx.xx
```

### Directory ServiceにJoinする

```net ads join -U administrator```
実行後パスワードが聞かれるのでAWS Directory Serviceで作成した時に入れたAdministratorのパスワードを入れます。
成功していれば`Joined 'RADIUS' to dns domain 'ds.wacul.co.jp'`のように表示されるはずです。

ここでwinbindを起動してユーザとグループが取れてるか確認します。

```
service winbind start
wbinfo -u
wbinfo -g
```

一覧が取れてればsambaの設定は完了です。

## ADのユーザ作成

適当なWindowsからADにJoinしてActive Directoryのユーザ管理でユーザ作ります。
まずはADに入る必要があるので

1. DNSの参照先はDirectory Serviceのものにする
1. システムプロパティからWORK GROUPではなくdomainにしてds.wacul.co.jpを入れて、認証はAdministratorユーザで行う


ただし、VPCをVPNでつないでDNSを参照するならDirectory Serviceのものにするのは通信料がかかるのでds.wacul.co.jpだけForwardしたほうがいいでしょう。

## Freeradius

Freeradiusでの認証をしていきます。
認証には下記の`ntlm_auth`コマンドが使われるので、作成したユーザが認証できるか確認できます。

```ntlm_auth --request-nt-key --username=user --password=mypassword```


ここからFreeradiusの設定をしていきます。

```diff:/etc/raddb/modules/mschap
-#	use_mppe = no
+ 	use_mppe = yes

-#	require_encryption = yes
+ 	require_encryption = yes

-#	require_strong = yes
+ 	require_strong = yes

-#	with_ntdomain_hack = no
+ 	with_ntdomain_hack = yes

-#	ntlm_auth = "/usr/bin/ntlm_auth --request-nt-key --username=%{%{Stripped-User-Name}:-%{%{User-Name}:-None}} --challenge=%{%{mschap:Challenge}:-00} --nt-response=%{%{mschap:NT-Response}:-00}"
+ 	ntlm_auth = "ntlm_auth --request-nt-key --username=%{mschap:User-Name} --challenge=%{%{mschap:Challenge}:-00} --nt-response=%{%{mschap:NT-Response}:-00}"
```
```diff:/etc/raddb/modules/ntlm_auth
-        program = "/path/to/ntlm_auth --request-nt-key --domain=MYDOMAIN --username=%{mschap:User-Name} --password=%{User-Password}"
+        program = "/usr/bin/ntlm_auth --request-nt-key --username=%{mschap:User-Name} --password=%{User-Password}"
```

これだけ長いのでcontext形式で

```diff:/etc/raddb/sites-enabled/default
--- /etc/raddb/sites-enabled/default.org	2015-12-17 03:19:01.271652279 +0000
+++ /etc/raddb/sites-enabled/default	2015-12-17 03:21:41.541314813 +0000
@@ -96,7 +96,7 @@
 	#
 	#  The chap module will set 'Auth-Type := CHAP' if we are
 	#  handling a CHAP request and Auth-Type has not already been set
-	chap
+#	chap

 	#
 	#  If the users are logging in with an MS-CHAP-Challenge
@@ -110,7 +110,7 @@
 	#  If you have a Cisco SIP server authenticating against
 	#  FreeRADIUS, uncomment the following line, and the 'digest'
 	#  line in the 'authenticate' section.
-	digest
+#	digest

 	#
 	#  The WiMAX specification says that the Calling-Station-Id
@@ -167,7 +167,7 @@

 	#
 	#  Read the 'users' file
-	files
+#	files

 	#
 	#  Look in an SQL database.  The schema of the database
@@ -209,7 +209,7 @@
 	#  This module should be listed last, so that the other modules
 	#  get a chance to set Auth-Type for themselves.
 	#
-	pap
+#	pap

 	#
 	#  If "status_server = yes", then Status-Server messages are passed
@@ -254,18 +254,18 @@
 	#  PAP authentication, when a back-end database listed
 	#  in the 'authorize' section supplies a password.  The
 	#  password can be clear-text, or encrypted.
-	Auth-Type PAP {
-		pap
-	}
+#	Auth-Type PAP {
+#		pap
+#	}

 	#
 	#  Most people want CHAP authentication
 	#  A back-end database listed in the 'authorize' section
 	#  MUST supply a CLEAR TEXT password.  Encrypted passwords
 	#  won't work.
-	Auth-Type CHAP {
-		chap
-	}
+#	Auth-Type CHAP {
+#		chap
+#	}

 	#
 	#  MSCHAP authentication.
@@ -277,7 +277,7 @@
 	#  If you have a Cisco SIP server authenticating against
 	#  FreeRADIUS, uncomment the following line, and the 'digest'
 	#  line in the 'authorize' section.
-	digest
+#	digest

 	#
 	#  Pluggable Authentication Modules.
@@ -294,7 +294,7 @@
 	#  be used for authentication ONLY for compatibility with legacy
 	#  FreeRADIUS configurations.
 	#
-	unix
+#	unix

 	# Uncomment it if you want to use ldap for authentication
 	#
@@ -369,7 +369,7 @@

 	#
 	#  Read the 'acct_users' file
-	files
+#	files
 }
```

Freeradiusがwinbindを利用する際に`/var/lib/samba/winbindd_privileged/pipe`を使ってやりとりするようなので権限を与えます。

```
usermod -a -G wbpriv radiusd
```

まずはこのユーザ認証ができるかテストします。
`radiusd -X`
でデバッグ付きでサーバを立ち上げて別コンソールで
`radtest -t mschap user mypassword localhost 0 testing123`
を実行して
```
rad_recv: Access-Accept packet from host 127.0.0.1 port 1812
```
が帰って来れば認証できています。特にエラーなくAccess-Rejectなら単純にパスワードが間違っている可能性が高いです。

## 証明書

802.1X認証の際にはサーバの証明書が必要です。freeradiusにはデフォルトのテスト用の証明書が付いてますが、せっかくなのでこのサーバで作ってしまいます。期間は10年にしてしまってます。

```console:
$ cd /etc/pki/CA
$ echo 01 > serial
$ touch index.txt
$ openssl req -new -x509 -newkey rsa:2048 -out cacert.pem -keyout private/cakey.pem -days 3650
Generating a 2048 bit RSA private key
..........................................................................................................................+++
...........................+++
writing new private key to 'private/cakey.pem'
# cakey.pemのパスワードを作成
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:JP
State or Province Name (full name) []:Bunkyo-ku
Locality Name (eg, city) [Default City]:Tokyo
Organization Name (eg, company) [Default Company Ltd]:WACUL Inc.
Organizational Unit Name (eg, section) 
Common Name (eg, your name or your server's hostname) []:ds.wacul.co.jp
Email Address []:
$ openssl req -new -keyout radius_key.pem -out radius.req
penssl req -new -keyout private/radius_key.pem -out radius.req -nodes
Generating a 2048 bit RSA private key
...........+++
......................................+++
writing new private key to 'radius_key.pem'
# radius_key.pemのパスワードを作成
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:JP
State or Province Name (full name) []:Bunkyo-ku
Locality Name (eg, city) [Default City]:Tokyo
Organization Name (eg, company) [Default Company Ltd]:WACUL Inc.
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:radius.ds.wacul.co.jp
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
$ chmod 0600 radius.pem
$ chown radiusd radius.pem
$ openssl ca -days 3650 -out certs/radius.pem -infiles radius.req
Using configuration from /etc/pki/tls/openssl.cnf
# cakey.pemのパスワードを入力
Enter pass phrase for /etc/pki/CA/private/cakey.pem:
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 1 (0x1)
        Validity
            Not Before: Dec 17 07:00:06 2015 GMT
            Not After : Dec 14 07:00:06 2025 GMT
        Subject:
            countryName               = JP
            stateOrProvinceName       = Bunkyo-ku
            organizationName          = WACUL Inc.
            commonName                = radius.ds.wacul.co.jp
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            Netscape Comment:
                OpenSSL Generated Certificate
            X509v3 Subject Key Identifier:

Certificate is to be certified until Dec 14 07:00:06 2025 GMT (3650 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
```

詳しくは自己証明局とかでしらべてみてください。`ca-key.pem`の扱いには十分注意しましょう。

## eap

次にeap周りの設定を行います

```diff:/etc/raddb/eap.conf
-                default_eap_type = md5
+                default_eap_type = peap

-                       private_key_password = password
-                       private_key_file = ${certdir}/server.pem
+                       private_key_password = radius_key.pemのパスワード
+                       private_key_file = /etc/pki/CA/radius_key.pem

-                       certificate_file = ${certdir}/server.pem
+                       certificate_file = /etc/pki/CA/certs/radius.pem

-                       CA_file = ${cadir}/ca.pem
+                       CA_file = /etc/pki/CA/cacert.pem

-                       #random_file = ${certdir}/random
+                       random_file = /dev/urandom
```

radtestではeapの接続確認はできないので[wpa_supplicant](http://hostap.epitest.fi/wpa_supplicant/)を使ってテストします。

```console:
$ wget https://w1.fi/releases/wpa_supplicant-2.5.tar.gz
$ tar zxfv wpa_supplicant-2.5.tar.gz
$ cd wpa_supplicant-2.5/wpa_supplicant/
$ cp defconfig .config
$ vi .config
- #CONFIG_EAPOL_TEST=y
+ CONFIG_EAPOL_TEST=y
$ make eapol_test
$ vi peap-mschapv2.conf
network={
        ssid="example"
        key_mgmt=WPA-EAP
        eap=PEAP
        identity="user"
        password="mypassword"
        phase2="autheap=MSCHAPV2"
        ca_cert="/etc/pki/CA/cacert.pem"
}
$ ./eapol_test -c peap-mschapv2.conf -s testing123
```

うまくいけば`EAP: EAP entering state SUCCESS`がでてくるはずです。

## freeradiusの起動

最後にこのRadiusにつなぐWifiが接続できる様にクライアントを定義します。

```/etc/raddb/clients.conf
client 192.168.1.0/24 {
  secret	= notasecret
  shortname	= wifi
}
```

`radiusd -X`で起動したものは終了してから、freeradiusをサービスから起動します。

```
service freeradius start
```

無線側でradius認証先を立ち上げたサーバにすれば完成です。
起動しない場合などは`radiusd -X`による起動で確認するのがやりやすいです。


# トラブルシュート
## `net ads join -U administrator`でDNS bind errorがでる
joinはできているのでそのまま進めても大丈夫っぽいですが、設定したhostnameが引けない場合はDNSの登録エラーが出てしまう様です。

## `Exec-Program output: Reading winbind reply failed! (0xc0000001)`
radiusd -X 側で起動してデバッグメッセージ中にこれが出る場合、

`/var/lib/samba/winbindd_privileged`ディレクトリが存在して、freeradiusを起動しているユーザから読み込み可であるか確認してみてください。

# VLAN割り当て

802.1x認証しているのでVLAN割り当てできるように続き

 [AWS Directory Serviceを使ってEnterprise WI-FIを使う (2)](http://qiita.com/kanagi/items/46d80ebc85b4d9f02c89)