AWSにOpenVPN[AmazonLinux]を構築(冗長化 + SimpleADでユーザー認証編)

先日書かせていただきました
[AWSにOpenVPN[AmazonLinux]を構築(ユーザー & パスワード認証編)](https://qiita.com/ohechi/items/7ed8a61194eb1dcca283)は本内容のために書いた前段のものになります。
前回はOpenVPN ×1で、プライベートネットワークのEC2に接続するという個人趣味レベルの内容でしたが、今回は企業システムっぽく冗長化にしたいと思います。
(もっとさっさと書きたかったのだが、思いの外忙しく。。。間が空いてしまった。)

**環境はこんな感じ**
![OpenVPN_冗長.png](https://qiita-image-store.s3.amazonaws.com/0/191445/0356e88e-9721-24d4-30e9-29ce03d2b69c.png)

これ実は特に難しくもなく、
1. [AWSにOpenVPN[AmazonLinux]を構築(ユーザー & パスワード認証編)](https://qiita.com/ohechi/items/7ed8a61194eb1dcca283)で1台構築
2. 構築したOpenVPN(EC2)をAMIイメージ作成
3. AMIイメージ → EC2起動。別のAZ、パブリックネットワークに配置
4. パブリックIPアドレス(EIP)を割り当て

---
## NAT構成
NAT構成(VPNクライアントからプライベートネットワークにいるEC2への一方通行へ通信)の場合はこのまま利用できます。

## ルーティング構成
ルーティング構成の場合は、追加したOpenVPNから払い出すIPアドレスのレンジは変える必要があります。

↓下記を編集

```server.conf
# OpenVPNからクライアントへ払い出すIPアドレスのレンジ
# server 10.8.0.0 255.255.255.0
#↓修正
server 10.8.1.0 255.255.255.0
```

そして[【Private ルートテーブル】にも経路情報を追記](https://qiita.com/ohechi/items/7ed8a61194eb1dcca283#212-%E3%83%AB%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E6%A7%8B%E6%88%90%E3%81%AE%E5%A0%B4%E5%90%88)

---

後は、クライアントの構成ファイルに1行追記します。
追加したOpenVPNのパブリックIPです。

```client.ovpn
# 1台目
remote [VPNサーバのFQDN or IPアドレス] 443
# 2台目
remote [VPNサーバのFQDN or IPアドレス] 443
```

これだけです。
上に記載したものが優先度が高いので、まずは1台目に接続しにいきます。
`keep-alive`のデフォルト値まで応答がなかったら2台目に接続しにいきます。

冗長化としてはこれで完了です。(負荷分散ではないです:grinning:)

・・・・・・・・・・・・・・・・・・・・・・・・
・・・・・・・・・・・・・・・・・・・・・・・・
**これで終わりではないです！！**

実際に運用しようと考えた時、いろいろ問題があります。

- ユーザー管理どうしよう？
 - ローカルのOSユーザーを2台でそれぞれ追加？イケてない
- 接続先のEC2をプライベート向け(外部に公開しない)のWebサーバーとした時、InternalELBを前段にかましたい
 - InternalELBをRoute53で名前解決したい
 - でもRoute53のPrivateHostedZoneはVPC内でしか使えない:weary: (VPNクライアントはRoute53のレコードを参照してくれない)

てことで、タイトルにもある**AWS SimpleAD**を使って上の問題を両方解決してしまいます。

# 1. 環境構成
ということで、今回の構成はこんな感じです!
![OpenVPN_冗長2.png](https://qiita-image-store.s3.amazonaws.com/0/191445/80eba1e4-d70d-36bf-b64a-78dea61d187d.png)

ポイントは

- ユーザー管理
 - SimpleADで管理(OpenVPNユーザー)
- InternalELB
 - Route53 PrivateHostedZoneのAliasレコードに登録(例：`test-ielb.test.local`)
 - VPNクライアントにはSimpleADのDNSを参照させることで、SimpleADがRoute53 PrivateHostedZoneに勝手にDNSフォワードしてくれる！(正確にはAmazonProviderDNSかな)

といったところになります！！

# 2. InternalELB
てことで、EC2(httpでWebページが表示できる状態のもの)にInternalELBを作成して、紐付けます。
詳細は割愛します。

InternalELB作成時点ではOpenVPNで接続したクライアント端末は下記への接続が可能です。

InternalELB作成時のDNS名：`internal-xxxx-xxxxxxxx.ap-northeast-1.elb.amazonaws.com`

# 3. Route53
## 3.1. PrivateHostedZone
AWSコンソールより【Route 53】をクリック
【Hosted zones】より「Create Hosted Zone」をクリック
**例**
Domain Name：`test.local`
Type：Private Hosted Zone for Amazon VPC
VPC ID：Webサーバー、InternalELBが所属するVPC

## 3.2. Record作成
作成したHosted zoneを選択
「Create Hosted Zone」をクリック
**例**
Name：`test-ielb.test.local.`
Type：A - IPv4 address
Alias：Yes
Alias Target：2. で作成したInternalELBのDNS名

レコードが作成されると同じVPCに所属するEC2(OpenVPNサーバー)からは`test-ielb.test.local`が引けるようになる

ただし、OpenVPNクライアント端末はこの時点では名前で引けない

# 4. SimpleAD
## 4.1. SimpleAD作成
AWSコンソールより【Directory Service】をクリック
【Simple AD】を選択
**例**
ディレクトリDNS：simplead.local
NetBIOS：SIMPLEAD
ディレクトリのサイズ：管理するVPNユーザー数で決めればよい
サブネット：今回はプライベートサブネットに配置(OpenVPNが認証できればよい)

SimpleAD作成後はVPC DHCPオプションセットを作成し、VPC内のサーバがSimpleAD DNSを参照するように設定する。

| 項目 | 値 |
|:----|:----|
| ドメインネームサーバー | xxx.xxx.xxx.xxx, yyy.yyy.yyy.yyy|

## 4.2. OpenVPNサーバー側作業
SimpleADが作成されると、DNSサーバーのIPアドレスがコンソールより表示されるので、これをOpenVPNサーバーの`/etc/openvpn/server.conf`に下記のように修正する

```server.conf
# VPNクライアントの参照先DNS
push "dhcp-option DNS xxx.xxx.xxx.xxx"
push "dhcp-option DNS yyy.yyy.yyy.yyy"
```
OpenVPNサーバーのサービスを再起動
`/etc/init.d/openvpn reload`

## 4.3. OpenVPNクライアント側作業
一度切断し、再度OpenVPNを接続する

すると、クライアント側の接続ログに、追記した`dhcp-option DNS xxx.xxx.xxx.xxx,dhcp-option DNS yyy.yyy.yyy.yyy`が記載される。

```
nslookup
```
でSimpleADのDNSが参照されていればオッケー。

InternalELBのRoute53で登録したレコードの確認

```
ping test-ielb.test.local
```
IPが返ってくれば無事フォワード成功です。

## 注意事項
SimpleADは名前解決したいRoute53のHostedZoneとは異なるドメイン名で作成する必要があります。
HostedZoneと同じドメイン名の場合、SimpleADは自分が権威サーバーと判断し、
AmazonProvidedDNSにはフォワードされません。

例：
●フォワードされるパターン
Route53 PrivateHostedZone：`test.local`
SimpleAD ドメイン名：`simplead.local`

●フォワードされないパターン
Route53 PrivateHostedZone：`test.local`
SimpleAD ドメイン名：`test.local`

---
これについては逆引きも同じです。
逆引きのRoute53 PrivateHostedZoneは基本使えません。
SimpleAD側のDNSに逆引きゾーンが既に存在しているため、Route53に逆引きゾーンを作成してもフォワードされません。

逆引きを利用したい場合、SimpleAD DNSに逆引きレコードを登録するか、ゾーンを削除し、Route53にフォワードされるようにする必要があります。

---

# 5. OpenVPN LDAP認証設定
ここからOpenVPNユーザーをローカルユーザー&パスワード認証 → SimpleADユーザーへ変更し、
冗長化されたOpenVPNサーバーで同じユーザーが使えるようにします。

## 5.1. コンピュータをSimpleADに参加
ディレクトリを管理するのに必要なパッケージをインストールします。

```
yum -y install sssd realmd krb5-workstation
```

ディレクトリにインスタンスを参加させます。

```
realm join -U Administrator@simplead.local simplead.local --verbose
```

ドメイン参加状況を確認します。

```
# realm list
simplead.local
  type: kerberos
  realm-name: SIMPLEAD.LOCAL
  domain-name: simplead.local
  configured: kerberos-member
  server-software: active-directory
  client-software: sssd
  required-package: oddjob
  required-package: oddjob-mkhomedir
  required-package: sssd
  required-package: adcli
  required-package: samba-common
  login-formats: %U@simplead.local
  login-policy: allow-realm-logins
```

同じことをもう一つのOpenVPNサーバー(サブ)でも実施しドメイン参加します。

## 5.2. SimpleAD AdministratorでSSHできることを確認しておく
SSHサービスを設定して、パスワード認証を許可します。
sshd_configのPasswordAuthenticationをyesに設定します。

```
vim /etc/ssh/sshd_config
```

```sshd_config
PasswordAuthentication yes
```

インスタンスを再起動します。

```
shutdown -r now
```

再起動後完了後、再接続し、ドメイン管理者をsudoersリストに追加します。

```
visudo
```

以下を、sudoersファイルの最後に追記します。

```sudoers
## Add the "Domain Admins" group from the example.com domain.
%Domain\ Administrator@simplead.local ALL=(ALL:ALL) ALL
```

ここまでで、設定完了です。
試しに、Administratorユーザーで、インスタンスにログインしてみます。
Administratorのパスワードを入力し、無事ログインできれば成功です！

```
ssh -l Administrator@simplead.local [IPアドレス]
```

同じことをもう一つのOpenVPNサーバー(サブ)でも実施しドメイン参加します。

## 5.3. SimpleADに任意のユーザーを作成する
下記の手順はOpenVPNサーバー(AmazonLinux)からコマンドでSimpleADにユーザーを作成する手順になりますが、実際はWindowServerを用意し、SimpleADにコンピュータを参加させ、「AD管理ツール」をインストールしてやったほうがわかりやすくて楽だと思います。

必要なパッケージを追加します。

```
yum -y install samba-common openldap-clients krb5-workstation adcli
```

ユーザーを追加します。Administratorのパスワードを聞かれるので入力します。
`CN=ad-vpnuser01,CN=Users,DC=simplead,DC=local`で作成されます。

```
net ads user ADD ad-vpnuser01 P@ssw0rd -C "ad-vpnuser01" -U Administrator@simplead.local -S simplead.local
```

あたらしいユーザーはパスワードが設定されてEnabledにセットされるまでは無効です。
ファイルを作成してユーザーオブジェクトのuserAccountControl値を512にセットすることでユーザーアカウントをEnabledにします。

```
vim uac.ldif
```

```uac.ldif
dn:CN=ad-vpnuser01,CN=Users,DC=simplead,DC=local
changetype:modify
replace:userAccountControl
userAccountControl:512
```

前のステップで作成されたldifファイルをつかって変更を行うためにはopenldap-clientパッケージによって提供されるldapmodifyコマンドを使用します。

```
ldapmodify -h simplead.local -p 389 -D "cn=Administrator,cn=Users,dc=simplead,dc=local" -w [パスワード] -f uac.ldif
```

これでユーザーアカウントが有効になり利用できるようになり、Kerberosチケットを取得してテストできます。

```
# kinit ad-vpnuser01
Password for ad-vpnuser01@SIMPLEAD.LOCAL:
以下のコマンドを実行してKerborosチケットをみることができます。

# klist
Ticket cache: KEYRING:persistent:0:0
Default principal: ad-vpnuser01@SIMPLEAD.LOCAL

Valid starting       Expires              Service principal
07/27/2018 19:35:16  07/28/2018 19:35:11  krbtgt/SIMPLEAD.LOCAL@SIMPLEAD.LOCAL
	renew until 08/03/2018 19:35:11
```

ドメインのユーザー一覧を表示します。ちゃんと、kanpeiが追加されていますね。

```
# net ads user -S simplead.local -U Administrator@simplead.local
AWSAdminD-9567264E07
Administrator
ad-vpnuser01
krbtgt
Guest
```

## 5.4. OpenVPNでLdap認証させる

下記をインストール
```
yum -y install openvpn-auth-ldap
```

`/etc/openvpn/server.conf`を編集

```server.conf
#plugin /usr/lib64/openvpn/plugin/lib/openvpn-auth-pam.so login
plugin /usr/lib64/openvpn/plugin/lib/openvpn-auth-ldap.so "/etc/openvpn/auth/ldap.conf"
```

```
mkdir /etc/openvpn/auth
```

```
vim /etc/openvpn/auth/ldap.conf
```

下記ファイルでVPNユーザーで利用可能なOUやグループをフィルターします。
とりあえず、`cn=Users,dc=simplead,dc=local`配下のユーザーはVPN認証を許可します。

```ldap.conf
<LDAP>
  URL             ldap://simplead.local:389
  BindDN          cn=Administrator,cn=Users,dc=simplead,dc=local
  Password        xxxxxxxx
  Timeout         15
  TLSEnable       no
  FollowReferrals yes
</LDAP>

<Authorization>
  BaseDN          "cn=Users,dc=simplead,dc=local"
  SearchFilter    "(&(sAMAccountName=%u))"
  RequireGroup    false
</Authorization>
```

---
ちなみにグループとかOUでフィルターするときはこんな感じ

```ldap.conf
<LDAP>
  URL             ldap://simplead.local
  BindDN          cn=Administrator,cn=Users,dc=simplead,dc=local
  Password        xxxxxxxx
  Timeout         15
  TLSEnable       no
  FollowReferrals yes
</LDAP>

<Authorization>
  BaseDN          "dc=simplead,dc=local"
  SearchFilter    "(&(sAMAccountName=%u))"
  RequireGroup    true
  <Group>
    BaseDN          "ou=vpngroup,dc=simplead,dc=local"
    SearchFilter    "(|(cn=testgroup)(cn=stagegroup))"
    MemberAttribute "member"
  </Group>
</Authorization>
```

---

VPNサービスを再起動

```
/etc/init.d/openvpn restart
```

同じことをもう一つのOpenVPNサーバー(サブ)でも実施しドメイン参加します。

## 5.5. OpenVPNクライアントで接続
一度切断し、再度接続します。

SimpleADで作成したユーザーとパスワードを入力し、接続できたら完了
<img width="240" alt="スクリーンショット 2018-07-27 19.48.53.png" src="https://qiita-image-store.s3.amazonaws.com/0/191445/91b31dc7-5beb-443c-2e22-4f98cd9ad5fb.png">

以上です。

これで、

**1. OpenVPNの冗長化**
**2. Route53 PrivateHosted Zoneを使ったInternalで名前解決**
**3. SimpleADによるOpenVPNユーザーの管理**

ができました。
ちょっとそれっぽくなりましたね。

終わり