DockerでKea DHCPを構築。CiscoとArubaに同時にOption43が渡せるようになった。

## はじめに
自前で運用しているISC-DHCPをDockerに乗せ換えました。
Kea-1.7系もありますが、stableのKea-1.6を導入しました。

いままで出来ていなかった、CiscoとArubaのAP混在環境で、それぞれの機器に適切にOption43が割り当てられるようにできました。
これで、マルチベンダー環境でしかも同一セグメントであっても、DHCPサーバひとつで、適切にコントローラ割り当てができるようになりました。

対象はIPv4のみです。そのうちIPv6もやろうと思います。

## 更新
DHCPはIPマスカレード環境でうまく動作しなかったので、network_mode を host に修正しました。
パケット内にIPアドレスが埋め込まれており、単純なNAPTだとコンテナ内のアドレスがDHCPサーバとなってしまうため。


## 対象機器および環境


### 検証環境
* CentOS8(8.1.1911)
* Docker(19.03.5)
* ISC-Kea(1.6) <-- DockerコンテナはCentOS7ベース
* Cisco AP1700(AIR-CAP1702I-Q-K9)(15.3(3)JC15)
* Cisco Virtual Wireless LAN Contoroller(8.2.170.0)
* Aruba AP-105(6.4.4.12)
* Aruba Mobility Controller 3200(6.4.4.12)

コンテナ間でsyslogの転送を行うため、別のエントリで作成した `infraserv-network` に所属させています。


### 初期設定

設定ファイルが意外と長くて、Dockerfileに記載するのが面倒かつ、あまり意味がなさそうなので、イメージ作成時点では、パッケージのデフォルト設定のままです。
このエントリのとおりに設定をしていくと、以下のパラメータでリースされます。
必要に応じて [設定ファイルの修正](#設定ファイルの修正) の部分で修正してください。

|項目|値|
|:--:|:--:|
|リース時間|10時間|
|DNSサーバ|10.254.10.241|
|suffix|prosper2.net|


リース対象セグメント

|セグメント|レンジ|GW|
|:--:|:--:|:--:|
|10.1.20.0/24|10.1.20.33 - 10.1.20.62|10.1.20.1|
|10.1.22.0/24|10.1.22.33 - 10.1.20.230|10.1.22.1|


Option43によりアクセスポイントに送付するコントローラアドレス

|対象|VCI文字列|コントローラアドレス|
|:--:|:--:|:--:|
|Cisco|Cisco AP|10.254.10.201,10.254.10.202|
|Aruba|ArubaAP|10.254.10.206|
CiscoはPrimary/Secondaryが渡せるので、２つ設定しました。
（Tertiaryも渡せるけど、あんま使わん）


## 作業内容

### firewallでmasqueradeを設定

```
firewall-cmd --add-service=dhcp --zone=public --permanent
firewall-cmd --reload
```

### Dockerイメージの準備

再利用できるようにイメージをつくっておきます。
Dockerfileと設定ファイルを置くための適当なディレクトリを作成しておきます

```
mkdir -p /opt/docker/dhcp
cd /opt/docker/dhcp
```

#### Dockerfileを作成

KeaはCentOS8のパッケージがないので、CentOS8ホスト上にCentOS7のコンテナをつくっています。

```:/opt/docker/dhcp/dhcp.df
FROM centos:centos7
ENV TZ='Asia/Tokyo'
RUN ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime ; \
    yum -y update ; yum -y install epel-release rsyslog ; \
    curl -1sLf \
      'https://dl.cloudsmith.io/public/isc/kea-1-6/cfg/setup/bash.rpm.sh' \
    | bash ; \
    yum -y update ; yum -y install isc-kea ; systemctl enable kea-dhcp4
COPY rsyslog.conf /etc/rsyslog.conf
COPY kea-dhcp4.conf /etc/kea/
CMD [ "/usr/sbin/init" ]
```

#### 設定ファイルの修正

自身の環境にあわせて修正します。

```/opt/docker/dhcp/kea-dhcp4.conf
{
"Dhcp4": {

  # リース時間などの調整
  "renew-timer": 9000,
  "rebind-timer": 18000,
  "valid-lifetime": 36000,

  # IFの設定。ホストのIF表記に合わせる必要があります。
  "interfaces-config": {
      "interfaces": [ "ens192" ]
  },

  # デフォルトのまま
  "control-socket": {
    "socket-type": "unix",
    "socket-name": "/tmp/kea-dhcp4-ctrl.sock"
  },

  # ファイル名や形式がいろいろあるみたいですが、デフォルトのままでもOK。
  "lease-database": {
      "type": "memfile",
      "persist": true,
      "name": "/var/lib/kea/dhcp4.leases"
  },

  # アクセスポイントのOption43のための定義セクションです。
  # CiscoとArubaでコントローラが２種類なら、このままでOK
  "option-def": [
    {
      "name":  "Cisco_vWLC",
      "code":  241,
      "space": "vendor-encapsulated-options-space",
      "type":  "ipv4-address",
      "array": true
    },
    {
      "name":  "Aruba_MC",
      "code":  43,
      "type":  "ipv4-address"
    }
  ],

  # DHCPでとりに行く際の VCI(vendor-class-identifier) を参照して、コントローラを振り分けています。
  # もし、「古いAPは古いWLCに接続」などあれば、適宜 "test": "substring～～" の箇所を工夫してください。
  # CiscoのVCIは以下が参考になります。
  # https://www.cisco.com/c/ja_jp/support/docs/wireless-mobility/wireless-lan-wlan/97066-dhcp-option-43-00.html#anc5 
  "client-classes": [

    # Cisco APで始まるものは、10.254.10.201/202 に接続させにいきます。
    {
      "name": "CiscoAP",
      "test": "substring(option[60].hex,0,8) == 'Cisco AP'",
      "option-data": [
        {
          "name":       "Cisco_vWLC",
          "code":       241,
          "space":      "vendor-encapsulated-options-space",
          "csv-format": true,
          "data":       "10.254.10.201,10.254.10.202"
        },
        {
          "name": "vendor-encapsulated-options"
        }

      ]
    },

    # ArubaAPで始まるものは、10.254.10.201/202 に接続させにいきます。
    # ArubaAPのVCIは ArubaAP で共通のようです。以下参照
    # https://www.arubanetworks.com/techdocs/ArubaOS_80_Web_Help/Content/ArubaFrameStyles/DHCP_Option_43/Windows_Based_DHCP_Serve.htm
    {
      "name": "ArubaAP",
      "test": "substring(option[60].hex,0,7) == 'ArubaAP'",
      "option-data": [
        {
          "name":  "Aruba_MC",
          "code":  43,
          "data":  "10.254.10.206"
        },
        {
          "name":  "vendor-class-identifier",
          "data":  "ArubaAP"
        }
      ]
    }

  ],

  # DNS関連の設定
  "option-data": [
    {
      "name": "domain-name-servers",
      "data": "10.254.10.241"
    },
    {
      "name": "domain-name",
      "data": "prosper2.net"
    },
    {
      "name": "domain-search",
      "data": "prosper2.net"
    }
  ],

  # ここからサブネットの情報を記載していきます。
  "subnet4": [
    {
      "subnet": "10.1.20.0/24",
      "pools": [ { "pool": "10.1.20.33 - 10.1.20.62" } ],
      "option-data": [
        {
          "name": "routers",
          "data": "10.1.20.1"
        }
      ]
    },
    {
      "subnet": "10.1.22.0/24",
      "pools": [ { "pool": "10.1.22.33 - 10.1.22.230" } ],
      "option-data": [
        {
          "name": "routers",
          "data": "10.1.22.1"
        }
      ]
    }
  ],

  # ログはまだよく見ていませんが、とりあえずデフォルトでOKです。
  "loggers": [
    {
    "name": "kea-dhcp4",
    "output_options": [
      {
        "output": "/var/log/kea-dhcp4.log"
      }
    ],
    "severity": "INFO",
    "debuglevel": 0
    }
  ]
}

}

```

#### syslog転送用の設定

ローカルのログファイルの変更を検知するモジュール `imfile` を利用して、リモートへsyslogを転送します。
別のエントリで作成した infraserv-network に所属させているため、`syslog`というホスト名で転送しています。

```:/opt/docker/dhcp/rsyslog.conf
module(load="imfile")
input(type="imfile"
      file="/var/log/kea-dhcp4.log"
      tag="pseudolog_kea_dhcp4_log"
      facility="local0"
      severity="notice")
:syslogtag, isequal, "pseudolog_kea_dhcp4_log" @syslog:514
```

### Dockerfileからイメージをビルドしてコンテナ作成

Dockerfileが作成できたら、ビルドします。
`--privileges` はなんか評判悪そう（？）なので、推奨されてるぽい方法でコンテナ生成します。


```
# docker build --force-rm -t infraserv:dhcp . -f ./dhcp.df ; \
  docker run --cap-add sys_admin --security-opt seccomp:unconfined  -v /sys/fs/cgroup:/sys/fs/cgroup:ro \
   --network host -it -d --name dhcp --hostname dhcp infraserv:dhcp
```


### Cisco機器の設定

enableになって、`conf t`してから以下の設定をいれていきます。

```
!interfaceへhelperアドレスを追加
Vlan2020
  ip helper-address 10.254.10.251
Vlan2022
  ip helper-address 10.254.10.251
end
```


## 動作確認

### CiscoAPのOption43

初期化ボタンを押しながら起動した際のログ
MACアドレス：`5897.bd0b.bedc`
IPアドレス：`10.1.20.34`
WLCアドレス：`10.254.10.201/202`
を取得して、コントローラ`VMwlc01`にjoinしようとしてます。

```
（ ～ 省略 ～ ）
*Feb  9 03:13:55.035: Using SHA-2 signed certificate for image signing validation.
*Feb  9 03:13:55.327: %DHCP-6-ADDRESS_ASSIGN: Interface BVI1 assigned DHCP address 10.1.20.34, mask 255.255.255.0, hostname AP5897.bd0b.bedc
（ ～ 省略 ～ ）
Translating "CISCO-CAPWAP-CONTROLLER.prosper2.net"...domain server (10.254.10.241)
*Feb  9 03:14:29.659: %CAPWAP-5-DHCP_OPTION_43: Controller address 10.254.10.201 obtained through DHCP
*Feb  9 03:14:29.659: %CAPWAP-5-DHCP_OPTION_43: Controller address 10.254.10.202 obtained through DHCP
*Feb  9 03:14:39.707: AP has SHA2 MIC certificate - Using SHA2 MIC certificate for DTLS.
*Feb  9 07:38:46.000: %CAPWAP-5-DTLSREQSEND: DTLS connection request sent peer_ip: 10.254.10.201 peer_port: 5246
*Feb  9 07:38:46.263: %CAPWAP-5-DTLSREQSUCC: DTLS connection created sucessfully peer_ip: 10.254.10.201 peer_port: 5246
*Feb  9 07:38:46.263: %CAPWAP-5-SENDJOIN: sending Join Request to 10.254.10.201
*Feb  9 07:38:51.263: %CAPWAP-5-SENDJOIN: sending Join Request to 10.254.10.201
*Feb  9 07:38:52.035: %CAPWAP-5-JOINEDCONTROLLER: AP has joined controller VMwlc01
（ ～ 省略 ～ ）
```

無事にコントローラにjoinされました

[![Screenshot from Gyazo](https://gyazo.com/fd3f6ecc795bb5c859522733e815a967/raw)](https://gyazo.com/fd3f6ecc795bb5c859522733e815a967)

Keaのログは同じMACアドレス、IPアドレスでリースされています。

```
10.1.20.34,58:97:bd:0b:be:dc,01:58:97:bd:0b:be:dc,36000,1581269861,1,1,1,ap5897.bd0b.bedc,0,
```

### ArubaAPのOption43

apbootからfactory_reset→bootした際のログ

```
（ ～ 省略 ～ ）
DHCP IP address: 10.1.20.36
DHCP subnet mask: 255.255.255.0
DHCP def gateway: 10.1.20.1
DHCP DNS server: 10.254.10.241
DHCP DNS domain: prosper2.net
Controller address: 10.254.10.206
Using eth0 device
TFTP from server 10.254.10.206; our IP address is 10.1.20.36; sending through gateway 10.1.20.1
Filename 'mips32.ari'.
Load address: 0x2000000
Loading: #####T #####
（ ～ 省略 ～ ）
## Starting application at 0x80e00000 ...
Uncompressing..............................................
Aruba Networks
ArubaOS Version 6.4.4.12 (build 58581 / label #58581)
（ ～ 省略 ～ ）
10.1.20.36 255.255.255.0 10.1.20.1
Running ADP...Done. Master is 10.254.10.206
（ ～ 省略 ～ ）
bond0 address=d8:c7:c8:cf:2c:92
br0 address=d8:c7:c8:cf:2c:92
wifi0: AP type AP-105, radio 0, max_bssids 8
（ ～ 省略 ～ ）
```

無事にコントローラにjoinされました

[![Screenshot from Gyazo](https://gyazo.com/a335c153e913a3fa15b563778e4eee35/raw)](https://gyazo.com/a335c153e913a3fa15b563778e4eee35)


Keaのログは同じMACアドレス、IPアドレスでリースされています。

```
10.1.20.36,d8:c7:c8:cf:2c:92,01:d8:c7:c8:cf:2c:92,36000,1581269931,1,0,0,,0,
```

## さいごに
ArubaAPはVCIをAPに戻してやらないと、AP側でちゃんと応答せず、ここの調査に時間がかかりました。
Kea自体もまだまだメジャーでないので、情報が少なくて苦労しました。


## 出典
https://kb.isc.org/docs/isc-kea-packages
https://lists.isc.org/pipermail/kea-users/2016-January/000217.html
https://kea.readthedocs.io/en/kea-1.6.0/
https://cloudsmith.io/~isc/repos/kea-1-6/setup/#formats-rpm