LDAP認証できるSoftEtherを構築する

LDAP のアカウントで認証して使える SoftEther を構築してみたのでメモ

構成

SoftEther に radius 認証と連携できる仕組みがあるので LDAP をバックエンドにした FreeRadius を使ってユーザー管理を委任した構成にします。
動くところまでしか見ていないので参考程度に…。

環境

AWS の ec2 に Ubuntu をおいて検証しました。

 1lsb_release -a
 2No LSB modules are available.
 3Distributor ID: Ubuntu
 4Description:    Ubuntu 22.04.1 LTS
 5Release:        22.04
 6Codename:       jammy
 7
 8docker -v
 9Docker version 20.10.12, build 20.10.12-0ubuntu4
10docker-compose -v
11docker-compose version 1.26.0, build d4451659

設定

SoftEther の設定

まずは SoftEther 単体で構築します。

サーバ管理用のパスワードがあるとリモートから全ての設定が行えるので扱いに注意が必要です。
後ほど freeradius の設定を投入するのに使います。

 1version: "3"
 2services:
 3  vpn:
 4    image: siomiz/softethervpn
 5    cap_add:
 6      - NET_ADMIN
 7    ports:
 8      - 443:443
 9    environment:
10      SPW: sample_spw_password

あとは README に従って諸々のファイルを用意します。

証明書を生成します。

1sudo docker run --rm siomiz/softethervpn gencert > .env

コンテナを起動して接続用の情報をチェックします。
環境変数でユーザ名を指定していない場合ログにそのまま出ています。

1sudo docker-compose up -d
2sudo docker-compose logs | head -n 5
3Attaching to vpn_vpn_1
4vpn_1  | # ========================
5vpn_1  | # user1234
6vpn_1  | # 1234.1234.1234.1234.1234
7vpn_1  | # ========================

AWS のセキュリティグループからインバウンドルールを追加して 443/tcp を開放しておきます。
クライアント側からポート開放チェックをして疎通しているか確認します。

1# VM 上
2nc -v -w 1 localhost 443
3Connection to localhost (127.0.0.1) 443 port [tcp/https] succeeded!
4
5# クライアント上
6nc -v -w 1 203.0.113.1 443
7Connection to 203.0.113.1 (203.0.113.1) 443 port [tcp/https] succeeded!

下記ページからクライアントを落としておきます。

下記設定で接続設定を追加します。

  • 接続設定名
    • 任意
  • ホスト名
    • VM のグローバル IP
  • ポート番号
    • 443
  • 仮想 HUB 名
    • DEFAULT
  • プロキシの種類
    • 直接 TCP/IP 接続
  • ユーザー認証
    • 種類
      • 標準パスワード認証
    • ユーザー名
      • user1234
    • パスワード
      • 1234.1234.1234.1234.1234

この後の作業が楽なので VPN を繋いだまま作業します。

LDAP の設定

今回は以下の設定で LDAP を構築します。

  • dc
    • dc=sample, dc=com
  • ou
    • People
  • cn
    • Group

イメージは以下を利用します

1  ldap:
2    image: osixia/openldap:latest
3    environment:
4      LDAP_ORGANISATION: "sampleorg"
5      LDAP_DOMAIN: "sample.com"
6      LDAP_ADMIN_PASSWORD: "sample_ldap_password"
7    ports:
8      - 389:389

起動して中身を確認しておきます。

 1sudo docker-compose up -d
 2sudo docker-compose exec ldap slapcat
 3dn: dc=sample,dc=com
 4objectClass: top
 5objectClass: dcObject
 6objectClass: organization
 7o: sampleorg
 8dc: sample
 9structuralObjectClass: organization
10entryUUID: e00880d0-19ec-103d-821e-673cb810be11
11creatorsName: cn=admin,dc=sample,dc=com
12createTimestamp: 20221227044421Z
13entryCSN: 20221227044421.597972Z#000000#000#000000
14modifiersName: cn=admin,dc=sample,dc=com
15modifyTimestamp: 20221227044421Z

ldif 書いても良いのですが、LDAP 触っていたのがだいぶ前で思い出せないので GUI から設定します。
お好きな LDAP クライアントから以下の設定で接続します。

  • Host
    • VM の IP
  • Base
    • dc=sample,dc=com
  • Account
    • username
      • cn=admin,dc=sample,dc=com
    • password
      • sample_ldap_password

接続したら OrganizationalUnit と Group を最初に記載した通り作成しておきます。
OrganizationalUnit 配下に User を追加しておきます。
また、当該ユーザの attribute に userPAssword が付与されていることを確認しておきます。

freeradius の設定

freeradius の設定(追記前)

折りたたんでいる部分は 2023/02/11 時点でこちらの手順を再検証したところうまく動きませんでした。
イメージを独自でビルドする方法を改めて追記したのでそちらを御覧ください。

以下のイメージを利用します。

接続先設定で楽したいので先程の docker-compose に追記して利用します。

 1version: "3"
 2services:
 3  ldap:
 4  ...
 5  radius:
 6    image: irasnyd/freeradius-ldap:latest
 7    ports:
 8      - "1812:1812/udp"
 9      - "1813:1813/udp"
10    environment:
11      - "LDAP_HOST=ldap"
12      - "LDAP_USER=cn=admin,dc=sample,dc=com"
13      - "LDAP_PASS=sample_ldap_password"
14      - "LDAP_BASEDN=dc=sample,dc=com"
15      - "LDAP_USER_BASEDN=ou=People,dc=sample,dc=com"
16      - "LDAP_GROUP_BASEDN=ou=Groups,dc=sample,dc=com"
17      - "RADIUS_CLIENT_CREDENTIALS=127.0.0.1:password1234"

実行イメージを手元でビルドするようにします。

1version: "3"
2services:
3  ldap:
4  ...
5  radius:
6    build: ./freeradius
7    ports:
8      - "1812:1812/udp"
9      - "1813:1813/udp"

./freeradius/Dockerfile

公式の3.2系の最新版を利用してイメージをビルドします。
最小構成から LDAP 関連の設定のみ追加します。

1FROM freeradius/freeradius-server:latest-3.2
2
3COPY raddb/ /etc/raddb/
4
5RUN ln -s /etc/raddb/mods-available/ldap /etc/raddb/mods-enabled/ldap
6
7CMD ["radiusd", "-f", "-l", "stdout"]

./freeradius/raddb/mods-available/ldap

https://github.com/FreeRADIUS/freeradius-server/blob/v3.2.x/raddb/mods-available/ldap を参考に設定します。

  1# -*- text -*-
  2
  3# base file
  4# https://github.com/FreeRADIUS/freeradius-server/blob/v3.2.x/raddb/mods-available/ldap
  5
  6ldap {
  7    server = 'ldap'
  8    base_dn = 'dc=sample,dc=com'
  9    identity = 'cn=admin,dc=sample,dc=com'
 10    password = 'sample_ldap_password'
 11
 12	sasl {}
 13	update {
 14		control:Password-With-Header	+= 'userPassword'
 15
 16		control:			+= 'radiusControlAttribute'
 17		request:			+= 'radiusRequestAttribute'
 18		reply:				+= 'radiusReplyAttribute'
 19	}
 20
 21	user {
 22		base_dn = "${..base_dn}"
 23		filter = "(uid=%{%{Stripped-User-Name}:-%{User-Name}})"
 24		sasl {}
 25	}
 26
 27	group {
 28		base_dn = "${..base_dn}"
 29		filter = '(objectClass=posixGroup)'
 30		membership_attribute = 'memberOf'
 31	}
 32
 33	profile {}
 34
 35	client {
 36		base_dn = "${..base_dn}"
 37		filter = '(objectClass=radiusClient)'
 38		template {}
 39		attribute {
 40			ipaddr				= 'radiusClientIdentifier'
 41			secret				= 'radiusClientSecret'
 42		}
 43	}
 44
 45	accounting {
 46		reference = "%{tolower:type.%{Acct-Status-Type}}"
 47
 48		type {
 49			start {
 50				update {
 51					description := "Online at %S"
 52				}
 53			}
 54
 55			interim-update {
 56				update {
 57					description := "Last seen at %S"
 58				}
 59			}
 60
 61			stop {
 62				update {
 63					description := "Offline at %S"
 64				}
 65			}
 66		}
 67	}
 68
 69	post-auth {
 70		update {
 71			description := "Authenticated at %S"
 72		}
 73	}
 74
 75	options {
 76		chase_referrals = yes
 77		rebind = yes
 78		res_timeout = 10
 79		srv_timelimit = 3
 80		net_timeout = 1
 81		idle = 60
 82		probes = 3
 83		interval = 3
 84		ldap_debug = 0x0028
 85	}
 86
 87	tls {
 88		cipher_list = "DEFAULT"
 89	}
 90
 91	pool {
 92		start = ${thread[pool].start_servers}
 93		min = ${thread[pool].min_spare_servers}
 94		max = ${thread[pool].max_servers}
 95		spare = ${thread[pool].max_spare_servers}
 96		uses = 0
 97		retry_delay = 30
 98		lifetime = 0
 99		idle_timeout = 60
100	}
101}

./freeradius/raddb/clients.conf

1client ldap {
2	ipaddr = 127.0.0.1
3	secret = password1234
4}

上記のファイルを利用してビルドした上でコンテナを起動しておきます。

1sudo docker-compose up -d --build

radtest コマンドを利用して freeradius <-> ldap 間の接続テストを行います。
今回はホスト側に用意して検証します。

1sudo apt-get -y install freeradius
2sudo systemctl stop freeradius
3sudo systemctl disable freeradius

今回は LDAP 構築時に username と password を hoge にしたアカウントを用意しておいたのでそのアカウントを利用して動作確認します。

1# 別コンソールで開いておく
2sudo docker-compose logs ldap -f
3
4# 作成した LDAP アカウントで接続
5radtest hoge hoge 127.0.0.1 1812 password1234

うまくいくと以下のようなログが出ます。

1radtest hoge hoge 127.0.0.1 1812 password1234
2Sent Access-Request Id 88 from 0.0.0.0:41979 to 127.0.0.1:1812 length 74
3        User-Name = "hoge"
4        User-Password = "hoge"
5        NAS-IP-Address = 127.0.0.1
6        NAS-Port = 1812
7        Message-Authenticator = 0x00
8        Cleartext-Password = "hoge"
9Received Access-Accept Id 88 from 127.0.0.1:1812 to 127.0.0.1:41979 length 20

失敗すると最後の行が以下のようになり Reject されます。

1(0) -: Expected Access-Accept got Access-Reject

自分の場合はタイポしていたので LDAP 側のログを見ていて気付きました。

1ldap_1    | 63aa936c conn=1010 op=3 SRCH base="ou=Poeple,dc=sample,dc=com" scope=2 deref=0 filter="(uid=hoge)"

また RADIUS_CLIENT_CREDENTIALS で事前に鍵共有して認証していますが、ここの設定がずれていると以下のようなログが出るので設定を見直す必要があります。
以下の場合は RADIUS_CLIENT_CREDENTIALS=192.0.2.29:password1234 にする必要があります。

1radius_1  | Tue Dec 27 06:32:41 2022 : Error: Ignoring request to auth address * port 1812 as server default from unknown client 192.0.2.29 port 60803 proto udp

よりセキュアにする場合は LDAP_RADIUS_ACCESS_GROUP 等を利用して特定ユーザーのみグループに入れて利用可能等にすると良さそうです。

最後にこの後の手順で追加する SoftEther からの接続を受け入れるために以下に clients.conf を差し替えておきます。

client ldap {
ipaddr = vpn
secret = password1234
}

SoftEther の設定変更


追記 2023/02/11

この設定が使えるのはリージョンロックの影響で日本か中国でない環境に限ります。
検証時は AWS のインスタンスを適当に建てていたので記憶がないですが、手元環境で構築したところ Radius 認証を有効に出来ませんでした。

その場合は下記を参考に回避できます。

下記 Dockerfile でソースコードをダウンロードしたあとに設定を書き換えます。

以下のような置換でブログと同様の内容でリビルドした Docker image を使うことで日本環境された場合でも当該機能を有効化できました。

1RUN sed -i -e "10920 s/ret;/false;/g" /usr/local/src/SoftEtherVPN_Stable-4.39-9772-beta/src/Cedar/Server.c

追記終わり


radius サーバが用意できたのでつなぎこみます。
先程 VPN を張れるようにした際にリモートから設定投入できるようになっているので GUI で設定してしまいます。

SE-VPN サーバ管理ツールを起動して新しい接続設定の作成から設定を追加します。

  • 接続設定名
    • 任意
  • ホスト名
    • VM のグローバル IP
  • ポート番号
    • 443
  • プロキシの種類
    • 直接  TCP/IP 接続
  • 管理モード
    • サーバー管理モード
  • 管理パスワード
    • sample_spw_password(最初に設定した SPW 変数の中身)

接続したら仮想 HUB の管理を開きます。

認証サーバの設定へ進み、以下の設定を追加します。

  • Radius サーバの設定
    • 認証を使用する
      • チェック
    • ホスト名
      • VM のローカル IP
    • ポート番号
      • 1812
    • 共有シークレット
      • password1234(RADIUS_CLIENT_CREDENTIALSと対応したもの)
    • 共有シークレットの確認入力
      • 同上
    • 再試行間隔
      • 500 msec

ユーザーの管理へ進み、新規作成から以下のユーザーを追加します。

  • ユーザー名
    • *
  • 認証方式
    •  RADIUS 認証

追加したら一度 VPN 接続を切って LDAP で追加したユーザーIDとパスワードでログインして接続出来たら OK です。