Softether VPNのユーザ認証をOpenLDAPでやりたい

本記事ではSoftether VPNのユーザ認証にOpenLDAPを用いて認証させるまでを記載させています。

認証までの流れとしては、Softether VPNの外部認証はradiusしか設定できないので、
以下の方法でLDAP認証するようにします。

Softether VPN　→　radius PAP認証(freeradius)　→　LDAP認証(OpenLDAP)

# 環境情報
| ホスト名 | IPアドレス | OS | 用途 |
| ---- | ---- | ---- | --- |
| jitaku-vpn | 192.168.201.10 | Rocky Linux 9.5 | VPNサーバ |
| jitaku-radius | 192.168.201.11 | Rocky Linux 9.5 | radiusサーバ |
| jitaku-ldap | 192.168.201.12 | Rocky Linux 9.5 | LDAPサーバ |

# Softetherのインストール(jitaku-vpnで作業)

### パッケージの更新
```
# yum -y update
```
### ビルドに必要なパッケージのインストール

```
# yum -y install epel-release
# yum config-manager --set-enabled crb
# yum -y install groupinstall "Development Tools"
# yum -y install cmake libsodium-devel ncurses-devel openssl-devel readline-devel zlib-devel
```

### ソースコードのダウンロード
```
# git clone --depth 1 https://github.com/SoftEtherVPN/SoftEtherVPN.git
```

### サブモジュールの最終履歴のみshallow cloneする
```
# cd SoftEtherVPN
# git submodule update --init --recursive --recommend-shallow --depth 1
```

### リージョンロックの解除
10752行から10769をコメントアウトして、return falese;とする
```
# vim ./src/Cedar/Server.c
10750 bool SiIsEnterpriseFunctionsRestrictedOnOpenSource(CEDAR *c)
10751 {
10752 /*      char region[128];
10753         bool ret = false;
10754         // Validate arguments
10755         if (c == NULL)
10756         {
10757                 return false;
10758         }
10759
10760
10761         SiGetCurrentRegion(c, region, sizeof(region));
10762
10763         if (StrCmpi(region, "JP") == 0 || StrCmpi(region, "CN") == 0)
10764         {
10765                 ret = true;
10766         }
10767
10768         return ret;
10769 */
10770         return false;
10771 }
```

### ビルド
```
# ./configure
# make -C build
```

### インストール
```
# make -C build install
～省略～
-----------------------------------------------------------------------------------------------------------------
Build completed successfully.

Execute 'vpnserver start' to run the SoftEther VPN Server background service.
Execute 'vpnbridge start' to run the SoftEther VPN Bridge background service.
Execute 'vpnclient start' to run the SoftEther VPN Client background service.
Execute 'vpncmd' to run the SoftEther VPN Command-Line Utility to configure VPN Server, VPN Bridge or VPN Client.
-----------------------------------------------------------------------------------------------------------------
～省略～
```

### サービスの起動
```
# systemctl daemon-reload
# systemctl start softether-vpnserver.service
# systemctl enable softether-vpnserver.service
```

# freeradiusの構築(jitaku-radiusで作業)
### パッケージをインストール
```
# yum -y install freeradius freeradius-utils freeradius-ldap
```

### ログ出力設定
```
# vim /etc/raddb/radiusd.conf
auth = yes
auth_accept = yes
auth_reject = yes
auth_badpass = yes
auth_goodpass = yes
```
### LDAPへの認証設定
```
# vim /etc/raddb/mods-available/ldap
server = '192.168.201.12'
identity = 'cn=Manager,dc=jitaku,dc=local'
password = 'xxxxxxx'
base_dn = 'dc=jitaku,dc=local'

以下の項目をコメントアウト
#post-auth {
#       update {
#               description := "Authenticated at %S"
#       }
#}
```

### LDAP認証の有効化
```
# cd /etc/raddb/mods-enabled
# ln -s ../mods-available/ldap
```

### 認証時にLDAP使用する設定
```
# vim /etc/raddb/sites-available/default
以下項目のコメントアウトを外す
Auth-Type LDAP {
                ldap
}
```

### 認証受付の設定
```
# vim /etc/raddb/sites-available/inner-tunnel
すべてのアクセス元から許可
listen {
       ipaddr = *
       port = 0
       type = auth
}

-ldap　→　ldapに変更
ldap

以下項目のコメントアウトを外す
 Auth-Type LDAP {
                ldap
}
```

### 接続を許可するユーザーアカウント情報
```
# vim /etc/raddb/clients.conf

#client localhost {
#       ipaddr = 127.0.0.1
#       proto = *
#       secret = xxxxxxxxx
#       require_message_authenticator = no
#       nas_type = other
#               limit {
#               max_connections = 16
#               lifetime = 0
#               idle_timeout = 30
#       }
#}

# Server
client 192.168.201.0/24 {
        ipaddr = 192.168.201.0/24
        secret = xxxxxxxxx
}
```

### LDAPのユーザを参照するよう設定
```
# vim /etc/raddb/users
DEFAULT Auth-Type := LDAP
       Fall-Through = Yes
```

### サービス起動
```
# systemctl restart radiusd
# systemctl enable radiusd
```

# OpenLDAPの構築(jitaku-ldapで作業)
### openldap-serversを入手するためにリポジトリを有効化
```
# yum config-manager --set-enabled plus
```

### パッケージのインストール
```
# yum -y install openldap-servers openldap-clients
```

### サービスの起動と確認
```
# systemctl enable --now slapd
# systemctl status slapd
```

### LDAPで利用するポートを開放(389,636)
```
# firewall-cmd --add-service={ldap,ldaps} --permanent
# firewall-cmd --reload
# firewall-cmd --list-all
```

### LDAPの管理者パスワードを生成
```
# slappasswd
New password:
Re-enter new password:
{SSHA}xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

### 管理者パスワード設定用ファイル作成
```
# vim changerootpass.ldif
dn: olcDatabase={0}config,cn=config
changetype: modify
add: olcRootPW
olcRootPW: {SSHA}xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

### 管理者パスワードを反映
```
# ldapadd -Y EXTERNAL -H ldapi:/// -f changerootpass.ldif
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
modifying entry "olcDatabase={0}config,cn=config"
```

### 基本的なスキーマの読み込み
```
# ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/cosine.ldif
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
adding new entry "cn=cosine,cn=schema,cn=config"

# ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/nis.ldif
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
adding new entry "cn=nis,cn=schema,cn=config"

# ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/inetorgperson.ldif
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
adding new entry "cn=inetorgperson,cn=schema,cn=config"
```
### サービスを再起動
```
# systemctl restart slapd
```
### ドメイン設定ファイルを作成
今回は以下のドメインを例として作成する。
dc=jitaku,dc=local

```
# vim setdomain.ldif
dn: olcDatabase={1}monitor,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth"
  read by dn.base="cn=Manager,dc=jitaku,dc=local" read by * none

dn: olcDatabase={2}mdb,cn=config
changetype: modify
replace: olcSuffix
olcSuffix: dc=jitaku,dc=local

dn: olcDatabase={2}mdb,cn=config
changetype: modify
replace: olcRootDN
olcRootDN: cn=Manager,dc=jitaku,dc=local

dn: olcDatabase={2}mdb,cn=config
changetype: modify
add: olcRootPW
olcRootPW: {SSHA}xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

dn: olcDatabase={2}mdb,cn=config
changetype: modify
add: olcAccess
olcAccess: {0}to attrs=userPassword,shadowLastChange by
  dn="cn=Manager,dc=jitaku,dc=local" write by anonymous auth by self write by * none
olcAccess: {1}to dn.base="" by * read
olcAccess: {2}to * by dn="cn=Manager,dc=jitaku,dc=local" write by * read
```

### ドメイン設定を反映
```
# ldapmodify -Y EXTERNAL -H ldapi:/// -f setdomain.ldif
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
modifying entry "olcDatabase={1}monitor,cn=config"

modifying entry "olcDatabase={2}mdb,cn=config"

modifying entry "olcDatabase={2}mdb,cn=config"

modifying entry "olcDatabase={2}mdb,cn=config"

modifying entry "olcDatabase={2}mdb,cn=config"
```

### ドメインが設定されたか確認
```
# ldapsearch -H ldap:// -x -s base -b "" -LLL "namingContexts"
dn:
namingContexts: dc=jitaku,dc=local
ディレクトリ構成設定ファイル作成
# vim basedomain.ldif
dn: dc=jitaku,dc=local
objectClass: top
objectClass: dcObject
objectclass: organization
o: My hwdomain Organisation
dc: jitaku

dn: cn=Manager,dc=jitaku,dc=local
objectClass: organizationalRole
cn: Manager
description: OpenLDAP Manager

dn: ou=People,dc=jitaku,dc=local
objectClass: organizationalUnit
ou: People

dn: ou=Group,dc=jitaku,dc=local
objectClass: organizationalUnit
ou: Group
```

### ディレクトリ構成設定反映
```
# ldapadd -x -D cn=Manager,dc=jitaku,dc=local -W -f basedomain.ldif
Enter LDAP Password:
adding new entry "dc=jitaku,dc=local"

adding new entry "cn=Manager,dc=jitaku,dc=local"

adding new entry "ou=People,dc=jitaku,dc=local"

adding new entry "ou=Group,dc=jitaku,dc=local"
```

### ユーザが利用するパスワードを生成
```
# slappasswd
New password:
Re-enter new password:
{SSHA}xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
ユーザ定義ファイル作成
以下のユーザとグループを作成し、ユーザをグループに所属させます。
People=kenichi
Group=family

# vim adduser.ldif
dn: cn=family,ou=Group,dc=jitaku,dc=local
objectClass: posixGroup
cn: family
gidNumber: 1000
memberUid: family

dn: uid=kenichi,ou=People,dc=jitaku,dc=local
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
cn: kenichi
sn: kenichi
userPassword: {SSHA}xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
loginShell: /bin/bash
uidNumber: 1000
gidNumber: 1000
homeDirectory: /home/family/kenichi
shadowLastChange: 0
shadowMax: 0
shadowWarning: 0
```

### ユーザ定義反映
```
# ldapadd -x -D cn=Manager,dc=jitaku,dc=local -W -f adduser.ldif
Enter LDAP Password:
adding new entry "cn=family,ou=Group,dc=jitaku,dc=local"

adding new entry "uid=kenichi,ou=People,dc=jitaku,dc=local"
```

### 自己証明書作成
```
# cd /etc/pki/tls/certs
# openssl genrsa -aes128 2048 > server.key
Enter PEM pass phrase:

# openssl rsa -in server.key -out server.key
Enter pass phrase for server.key:
writing RSA key

# openssl req -utf8 -new -key server.key -out server.csr
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) []:
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:ldap
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

# openssl x509 -in server.csr -out server.crt -req -signkey server.key -days 3650
Signature ok
subject=C = JP, L = Default City, O = Default Company Ltd, CN = ldap
Getting Private key
```

### 作成した証明書のオーナを変更
```
# chown ldap:ldap /etc/pki/tls/certs/{server.crt,server.key}
```

### 証明書設定用ファイル作成
```
# vim mod_ssl.ldif
dn: cn=config
changetype: modify
add: olcTLSCACertificateFile
olcTLSCACertificateFile: /etc/pki/tls/certs/ca-bundle.crt
-
replace: olcTLSCertificateFile
olcTLSCertificateFile: /etc/pki/tls/certs/server.crt
-
replace: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/pki/tls/certs/server.key
```

### 証明書設定を反映
```
# ldapadd -Y EXTERNAL -H ldapi:/// -f mod_ssl.ldif
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
modifying entry "cn=config"
```

### ログ設定
```
# vim logging.ldif
dn: cn=config
changetype: modify
replace: olcLogLevel
olcLogLevel: stats
```

### 設定を反映
```
# ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f logging.ldif
```

### /etc/rsyslog.confに以下を追記
```
# vim /etc/rsyslog.conf
local4.*  /var/log/ldap/ldap.log
```

### rsyslogサービスを再起動
```
# systemctl restart rsyslog
# systemctl status rsyslog
```

### ログローテ設定
```
# vim /etc/logrotate.d/ldap
/var/log/ldap.log {
  rotate 30
  weekly
  missingok
  compress
  notifempty
}
```

## クライント側設定(全サーバに設定)
### パッケージのインストール
```
# yum -y install openldap-clients sssd sssd-ldap oddjob-mkhomedir
```

### 認証プロバイダをsssdに切り替え
```
# authselect select sssd with-mkhomedir --force
Backup stored at /var/lib/authselect/backups/2024-11-14-10-54-32.PA4CCD
Profile "sssd" was selected.
The following nsswitch maps are overwritten by the profile:
- passwd
- group
- netgroup
- automount
- services

Make sure that SSSD service is configured and enabled. See SSSD documentation for more information.

- with-mkhomedir is selected, make sure pam_oddjob_mkhomedir module
  is present and oddjobd service is enabled and active
  - systemctl enable --now oddjobd.service
```

### sssd設定
```
# vim /etc/sssd/sssd.conf
[domain/default]
id_provider = ldap
autofs_provider = ldap
auth_provider = ldap
chpass_provider = ldap
ldap_uri = ldaps://192.168.201.12/
ldap_search_base = dc=jitaku,dc=local
ldap_id_use_start_tls = True
ldap_tls_cacertdir = /etc/pki/tls/certs
cache_credentials = True
ldap_tls_reqcert = allow

[sssd]
services = nss, pam, autofs
domains = default

[nss]
homedir_substring = /home
```

### パーミッションを変更
```
# chmod 600 /etc/sssd/sssd.conf
```

### サービス起動
```
# systemctl restart sssd oddjobd
# systemctl enable sssd oddjobd
Created symlink /etc/systemd/system/multi-user.target.wants/oddjobd.service → /usr/lib/systemd/system/oddjobd.service.
```

### ログを確認
```
# less /var/log/ldap/ldap.log
Nov 16 09:20:19 ldap-clients slapd[1264]: conn=1144 fd=20 ACCEPT from IP=192.168.201.11:53806 (IP=0.0.0.0:636)
Nov 16 09:20:43 ldap-clients slapd[1264]: conn=1144 fd=20 TLS established tls_ssf=256 ssf=256
```

## ログイン確認
### クライント設定したサーバにLDAPユーザでログイン
```
login as:
kenichi@192.168.201.11's password:
Last login: Sat Nov 16 09:28:19 2024 from 192.168.11.43
[kenichi@ldap-clients ~]$ pwd
/home/family/kenichi
```