2011-07-19

[OpenVPN TIPS] 証明書認証ではなく、ID/パスワード認証を使用する

By Taro Yamazaki  |  23:30

OpenVPNを使用している方ならよくご存知だと思いますが、通常OpenVPNでは証明書認証を使用します。証明書認証はID/パスワード認証に比較すると安全性が高いとされます(もちろん、秘密鍵の管理方法に大きく依存します)が、証明書認証の概念を理解しにくいユーザーが秘密鍵や証明書を紛失しやすい(しかも、たいていバックアップは取っていない...)というリスクや、管理者の手間(証明書の更新、失効手続などが必要になる)などのハードルもあります。それで、OpenVPNをID/パスワード認証で使用したいというニーズも少なからずあります(プラムシステムズ株式会社vpnux miniでは、認証方式としてID/パスワード認証を採用しています)。



OpenVPNでID/パスワード認証を使用する場合は、以下のようにします。

[1] ID/パスワード認証を行うプラグインを作成する

OpenVPNでID/パスワード認証を行うには、ユーザーから送信されてくるID/パスワードを認証する機能を独自に実装する必要があります。この実装方法には2つの方法があり、(1) スクリプトプラグイン(auth-user-pass-verifyディレクティブと組み合わせる)を使用する、(2) コンパイルされたShared ObjectやDLLとしてのプラグイン(pluginディレクティブと組み合わせる)を使用する、のいずれかになります。動作速度やセキュリティの面では (2) が優位ですが、(1) のほうが手軽に利用できます。基本的な動作は共通で、スクリプト内で認証処理を行い、認証に成功したら 0 を、失敗したら 1 を戻り値として返します。

[2] サーバー側のOpenVPN設定ファイルを変更する

サーバー側のOpenVPN設定ファイルを変更し、作成したプラグインを使って認証を行うよう設定します。

では、iniファイル形式で記述されたID/パスワードファイルを使って認証を行う、簡単なpythonスクリプトを作成してみましょう。

ID/パスワードファイル

説明を簡単にするため、ハッシュ化していないiniファイル形式にしています。実際にはハッシュ化するなどの対策が必要になるでしょう。以下の内容を /etc/openvpn/passwdfile に保存しておきます。
[password]
user1=pass9876#
user2=test%5%pass
user3=sECret4U

認証スクリプトプラグイン

上記のiniファイル形式のファイルを読み込んで認証するpythonスクリプトは次のようになります(エラー処理等は省略しています)。/etc/openvpn/auth.py として保存しておきます。
#! /usr/bin/env python
import sys,ConfigParser

# Read username and password
filename = sys.argv[1] .................... (1)
fp = open(filename)
data = fp.readlines()
fp.close()
userId = data[0].rstrip() .................... (2)
password = data[1].rstrip() .................... (3)

# Read users database
config = ConfigParser.ConfigParser()
config.readfp(open('passwdfile'))
users = config.items('password')

# Check for users database
flag = (userId, password) in users  .................... (4)

if flag == True:
        print "[Auth] Success!"
        sys.exit(0) .................... (5)
else:
        print "[Auth] Failed."
        sys.exit(1) .................... (6)
(1) 後述するauth-user-pass-verifyディレクティブでvia-fileオプションをセットすると、クライアント側でユーザーが入力したIDとパスワードはサーバー上に一時ファイルとして書き出され、そのファイルのパスが引数としてスクリプトに渡されてきます。そのファイルには1行目には入力されたユーザー名が、2行目には入力されたパスワードが書かれています。
(2) 一時ファイルの1行目に書かれているユーザー名を読み込んでいます。
(3) 一時ファイルの2行目に書かれているパスワードを読み込んでいます。
(4) パスワードファイル(/etc/openvpn/passwdfile)に該当するID/パスワードがあるかをチェックし、フラグをセットします。
(5) 認証にパスした場合は戻り値 0 をセットします。
(6) 認証に失敗した場合は戻り値 1 を返します。

OpenVPN設定ファイル

サーバー側設定ファイルに以下のようなディレクティブを設定します。
script-security 2 .................... (1)
client-cert-not-required .................... (2)
username-as-common-name .................... (3)
auth-user-pass-verify /etc/openvpn/auth.py via-file .................... (4)
(1) ユーザー定義プラグインを使用する場合は、script-securityディレクティブを2か3に設定する必要があります(設定しない場合はデフォルトの1とみなされます)。認証情報を環境変数経由で受け渡すとき以外は2で問題ありません。
(2) クライアント証明書を使用せずにID/パスワードのみで認証するよう指定します。
(3) 入力されたユーザー名をユーザーの共通名として使用する場合、このディレクティブを設定しておきます。
(4) 認証に使用するプラグインを指定します。最初の引数がプラグインのファイル名で、2番目の引数は認証情報を受け渡す方法を指定します。「via-file」だと一時ファイルを使って受け渡し、「via-env」だと環境変数を使って受け渡すことになります。セキュリティ上、「via-file」が推奨されています。

ざっと説明してきましたが、いかがでしょうか? 意外に簡単、と思われたのではないでしょうか。
もちろん、VPNは不正アクセスが発生すると被害が大きくなりやすいので、特に厳密なID/パスワード管理が必要なことは言うまでもありません。ID/パスワードによる認証を使用する場合には、パスワードの複雑さや有効期限などを適切に設定するなどの対策を取ることをお勧めします。

Author: Taro Yamazaki

© 2015 yamata::memo | Distributed By My Blogger Themes | Created By BloggerTheme9
TOP