OpenVPN でセキュアな接続を確立

OpenVPN を利用して外出先の WiFi 等の安全ではないネットワークから安全な回線に接続できるようにします。

サーバー
LXD ゲスト
CPU
2コア
メモリー
4GB
OS
Ubuntu Server 24.04 LTS 64Bit
apt パッケージ バージョン
openvpn 2.6.12-0ubuntu0.24.04.1
easy-rsa 3.1.7-2

パッケージをインストール

以下のコマンドで必要なパッケージをイストールします。

sudo apt install openvpn easy-rsa

サーバーで使う証明書用の CA を作成

以下のコマンドで CA 用の鍵と証明書を作成します。

sudo make-cadir /etc/openvpn/easy-rsa

easy-rsa の設定ファイルを編集します。

sudo vim /etc/openvpn/easy-rsa/vars

EASYRSA_KEY_SIZE の値をデフォルトの 2048 から 4096 に変更して鍵長を長くしておきます。

EASYRSA_CERT_EXPIRE の値をデフォルトの 825 から 3650 にして証明書の有効期限を長くしておきます。

ルートユーザーに変更して以下のコマンドで PKI を作成します。

sudo su -
cd /etc/openvpn/easy-rsa/
./easyrsa init-pki
./easyrsa build-ca

CA 用のキーのパスワードを入力を求められるので入力します。ここでのパスワード入力は秘密鍵が平文で表示されるのを防ぎます。

CA の名前の入力を求められますが Enter キーの入力でデフォルト値を設定します。

サーバー用の鍵と証明書を作成

引き続きルートユーザーで以下のコマンドを実行してサーバー用の鍵を作成します。

作成後に名前の入力を求められますが Enter キーでデフォルト値を設定します。

./easyrsa gen-req <SERVER_NAME> nopass

以下のコマンドで Diffie Hellman パラメーターを作成します。OpenVPN サーバーに必要です。

./easyrsa gen-dh

以下のコマンドでサーバー用の証明書を CA から発行します。発行時に CA の鍵のパスワードを入力します。

./easyrsa sign-req server <SERVER_NAME>

作成した CA の証明書、サーバー用の鍵と証明書、DH パラメーターを /etc/openvpn/ にコピーします。

cp pki/dh.pem pki/ca.crt pki/issued/<SERVER_NAME>.crt pki/private/<SERVER_NAME>.key /etc/openvpn/

クライアント用の証明書を作成

引き続きルートユーザーで以下のコマンドを実行してクライアント用の証明書を作成します。<CLIENT_NAME> 部分を変更して必要なユーザーの数だけ発行します。

./easyrsa gen-req <CLIENT_NAME> nopass
./easyrsa sign-req client <CLIENT_NAME>

クライアント用の証明書の発行が終わったらルートユーザーから一般ユーザーに戻ります。

サーバーを設定

サーバーの設定ファイルをテンプレートからコピーします。

sudo cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf /etc/openvpn/server.conf

追加のセキュリティ設定 tls-auth で使用するキーを作成します。

cd /etc/openvpn
sudo openvpn --genkey tls-auth ta.key

/etc/openvpn/server.conf を編集してサーバーの設定を変更します。

sudo vim /etc/openvpn/server.conf

以下の鍵と証明書のファイル名が実際に存在しているファイルと一致することを確認します。

ca ca.crt
cert <SERVER_NAME>.crt
key <SERVER_NAME>.key
dh dh.pem

セキュリティ向上のためポートを変更しておきます。

port 11940

以下の行のコメントアウトを解除します。

;tls-auth ta.key 0

VPN 用のサブネットを変更したい場合は以下を変更します。

server 10.8.0.0 255.255.255.0

以下の行のコメントアウトを解除してクライアントが VPN 経由でインターネットへアクセスするようにします。

;push "redirect-gateway def1 bypass-dhcp"

VPN 接続で使用する DNS サーバーの IP を指定します。

push "dhcp-option DNS 8.8.8.8"
push "dhcp-option DNS 8.8.4.4"

以下の行を編集して弱い暗号方式が使用されないようにします。

data-ciphers AES-256-GCM:AES-128-GCM:CHACHA20-POLY1305

また以下の行を追加して弱い暗号方式が使用されないようにします。

auth SHA256
tls-ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256

ネットワークの設定

/etc/sysctl.conf を編集して以下の行のコメントアウトを解除します。

sudo vim /etc/sysctl.conf
#net.ipv4.ip_forward=1

sysctl を再読み込みします。

sudo sysctl -p /etc/sysctl.conf

sudo sysctl -p /etc/sysctl.conf以下のコマンドでファイアウォールの設定を変更して OpenVPN 用のポートを開放します。

sudo ufw allow 11940/udp

OpenVPN のサブネットから外部ネットワークへのルーティングをするために NAT を設定します。/etc/ufw/before.rules を編集して以下 “*filter” の直前、設定ファイルの上部に追加します。サブネットとネットワークインターフェースは環境に合わせて変更します。

# START OPENVPN RULES
*nat
:POSTROUTING ACCEPT [0:0]
# Allow traffic from OpenVPN client network to be NAT'd
-A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE
COMMIT
# END OPENVPN RULES

/etc/default/ufw 内の DEFAULT_FORWARD_POLICY を “ACCEPT” に設定してパケットの転送を許可します。

DEFAULT_FORWARD_POLICY="ACCEPT"

UFW を再起動します。

sudo ufw disable
sudo ufw enable

サーバーを起動

OpenVPN サーバーを起動します。設定を変更した後は restart をします。

sudo systemctl start openvpn@server

以下のコマンドでログを確認できます。”Initialization Sequence Completed” が表示されていれば正常に起動しています。

sudo journalctl -u openvpn@server -xe

/etc/default/openvpn を変更して OpenVPN サーバーを自動で起動するようにします。

sudo vim /etc/default/openvpn

以下の行のコメントアウトを解除してすべてのサーバー設定を自動起動するようにします。個別に設定ファイル名を指定することもできます。

AUTOSTART="all"

設定を反映させるために systemd を再読み込みします。

sudo systemctl daemon-reload

以下のコマンドで OpenVPN が作成した tun0 インターフェースを確認します。

ip addr show dev tun0

クライアント設定ファイルを作成

以下の内容のシェルスクリプトを generate-client-configs.sh として作成し実行権限を与えます。OUTPUT_DIR 等必要があれば変更します。

#!/bin/bash
# This script generates inline OpenVPN client configuration files
# for the given client names. It assumes that the client certificate
# and key are stored in separate directories.
#
# Usage:
#   ./generate-client-configs.sh client1 client2

# Common files (adjust paths as needed)
CA_FILE="/etc/openvpn/easy-rsa/pki/ca.crt"
TA_FILE="/etc/openvpn/ta.key"

# Directories where client certificates and keys are stored
CERT_DIR="/etc/openvpn/easy-rsa/pki/issued"
KEY_DIR="/etc/openvpn/easy-rsa/pki/private"

# Directory where the output configuration files will be stored
OUTPUT_DIR="./openvpn-client-configs"

# Prefix of client config file name
OUTPUT_FILE_PREFIX="my-openvpn-"

# Server information
SERVER_ADDRESS="example.com"
PORT=11940

# Base configuration template
BASE_CONFIG=$(cat <<EOF
client
dev tun
proto udp
remote ${SERVER_ADDRESS} ${PORT}
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
data-ciphers AES-256-GCM:AES-128-GCM:CHACHA20-POLY1305
auth SHA256
tls-ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
verb 3
EOF
)

# Function to embed file content in inline tags
embed_file() {
    local tag="$1"
    local file="$2"
    echo "<${tag}>"
    cat "${file}"
    echo "</${tag}>"
    echo ""
}

# Check if at least one client name is provided
if [ "$#" -eq 0 ]; then
    echo "Usage: $0 client_name1 [client_name2 ...]"
    exit 1
fi

# Create the output directory if it doesn't exist
mkdir -p "${OUTPUT_DIR}"

# Generate configuration file for each client provided as argument
for client in "$@"; do
    CLIENT_CERT="${CERT_DIR}/${client}.crt"
    CLIENT_KEY="${KEY_DIR}/${client}.key"

    # Check if all required files exist
    for file in "$CA_FILE" "$CLIENT_CERT" "$CLIENT_KEY" "$TA_FILE"; do
        if [ ! -f "$file" ]; then
            echo "Error: Required file '$file' not found for client '${client}'." >&2
            continue 2
        fi
    done

    OUTPUT_FILE="${OUTPUT_DIR}/${OUTPUT_FILE_PREFIX}${client}.ovpn"

    # Write the base configuration to the output file
    echo "${BASE_CONFIG}" > "${OUTPUT_FILE}"
    echo "" >> "${OUTPUT_FILE}"

    # Embed certificate and key files inline
    {
        embed_file "ca" "${CA_FILE}"
        embed_file "cert" "${CLIENT_CERT}"
        embed_file "key" "${CLIENT_KEY}"
        embed_file "tls-auth" "${TA_FILE}"
        echo "key-direction 1"
    } >> "${OUTPUT_FILE}"

    echo "Client config file '${OUTPUT_FILE}' created successfully."
done

このスクリプトにクライアント用の鍵と証明書を作成した時の <CLIENT_NAME> を引数にして実行します。

sudo ./generate-openvpn-client-configs.sh <CLIENT_NAME_1> <CLIENT_NAME_2> ...

OUTPUT_DIR にクライアント用の設定ファイルが出力されるのでクライアントデバイスへコピーし接続確認をします。この設定ファイルには鍵情報が埋め込まれているのに取り扱いには注意します。

参考

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です