web-dev-qa-db-ja.com

(オープン)VPNクライアント接続を単一システムユーザーに制限する方法

マルチユーザーセットアップ(Ubuntu)を使用しています(異なるTTYで同時にログインしているユーザー)。

nordvpn connectを使用して1つのアカウントからNordVPNに接続すると、すべてのユーザーがそのVPN経由でインターネットに接続されます。

ユーザーのネットワークをどうにかして分離する方法。つまり、VPNに接続すると、現在のユーザーのみが影響を受け、そのユーザーのすべての接続でVPNを使用する必要があります。


  • nordvpnopenvpnの単なるラッパーであり、openvpnを使用して直接接続することが可能であるため、純粋なopenvpnソリューションも役立ちます。
  • ユーザーはSudoを介してrootアクセスできます。
  • 私はスクリプトソリューションで大丈夫です。
7
pLumo

ユーザーごとに個別にvpnを使用する方法:

ユーザーが異なるユーザースペースを使用している状況:

デフォルトでは、ユーザースペースはネットワークを分離する( netns )ので、nordvpn connectは他のユーザースペースには影響しませんが、これはLinuxでのユーザーシステムのデフォルトの機能ではないため、別のセットアップが必要です。各ユーザーのネットワークを分離するためのユーザー空間。また、ネットワークインターフェイスは、単一の名前空間ブリッジまたはvethインターフェイスにのみ存在し、ユーザー空間間のトラフィックをトンネルするために使用できます。

ユーザーが同じユーザースペースを使用している状況:

Linuxユーザーシステムは同じネットワークシステムの下に残ります。一方のユーザーがwifiに接続している場合、ネットワークカードはルートレベルでセットアップされ、デフォルトのセットアップでネットワークを使用しているすべてのユーザーが共有されるため、もう一方のユーザーはその接続から恩恵を受けます。 。

VPN接続は新しい仮想インターフェイス(tunまたはtap)で行われ、メインネットワークインターフェイス(wifiまたはeth0)にリンクされます... vpn接続が初期化されると、tun/tapインターフェイスが作成され、VPNサーバーに接続されますトンネルを作成しますが、これはすべての接続がVPNインターフェースを介してトンネルされることを意味しません。クラシックなVPN接続を確立するために、最初に接続が仮想インターフェースで初期化され、次にルートが使用されます。 が追加され、すべての接続が強制的にVPNインターフェースを経由するようになり、これはroutingと呼ばれます。

これらの情報を知っておくと、解決策はルーティングなしでVPN接続を開始し、ユーザーごとに個別にルーティングをセットアップすることです。 VPNを必要としないユーザーには変更は必要ありません。 VPNを使用する必要があるユーザーのために、iptables/ip-routeを使用して特別なルーティングを追加する必要があります。つまり、VPNインターフェースはセットアップされますが、デフォルトのインターフェースにはなりません(デフォルトのVPNルーティングルールがプッシュされないため)。

VPNのデフォルトの状況:[Connect Command]> [Create-Tun/Tap]> [Connect Tun/Tap]> [Route to Make Tun/Tap as Default Interface]

ルートなしのVPN:[Connect Command]> [Create-Tun/Tap]> [Connect Tun/Tap]

VPNとカスタムルート:[Connect Command]> [Create-Tun/Tap]> [Connect Tun/Tap]then[カスタムルート]を手動または自動で追加します

「ルート」ステップを使用せずにvpnに接続してから、カスタムルートをプッシュ/セットアップします。これは、iptables/ip-routeまたはVPN confセットアップファイルを使用して行うことができます。

デフォルトゲートウェイ/ルートをプッシュせずにopenvpnを構成する方法:

Vpn confファイルを編集して、route-nopullディレクティブを追加します。 (nordvpnコマンドを使用してアクセス可能なopenvpn confファイルを使用する場合は、必要に応じて編集できます。それ以外の場合は、openvpnまたはネットワークマネージャーを使用してvpnに接続する必要があります)

特定のLinuxユーザーに特定のインターフェースを使用します:

このガイド は、あなたが達成したいのとまったく同じことを達成しています。それ以外の場合 これらの回答 詳細な代替案を示します。

3
intika

部分的な回答(問題の詳細が必要):

「通常の」インターネット接続とNordVPNインターネット接続を区別する1つの方法は、ネットワーク名前空間を作成し、この名前空間でnordvpnを開始してから、この名前空間でこのVPNを使用するすべてのプロセスを開始することです。

詳細は、使用方法によって異なります。

  • NordVPNを常に起動する単一のユーザーがいる場合、ログイン時にそのネットワーク名前空間を作成し、そのネットワーク名前空間でそのユーザーのすべてのプロセスを開始することもできます。その結果、そのユーザーは「通常の」インターネット接続を利用できなくなります。

  • 「通常の」インターネット接続とNordVPN接続の両方を使用したいユーザーが複数いる場合は、その名前空間を作成し、その中でNordVPNを起動し、追加のアプリケーションを起動できるターミナルをユーザーに提供するスクリプトを作成できます。たぶん、この名前空間でWebブラウザのようなアプリケーションをすでに起動しているかもしれません。このスクリプトはconnectコマンドを置き換えます。

要件が何であるかに応じて、それを行う方法はおそらく他にもたくさんあります。質問を編集して、要件/状況を説明してください。

ネームスペースを作成するには、root権限が必要です。つまり、スクリプトをsetuid-rootにする必要があります(スクリプトにバグがある場合はセキュリティ上の問題になる可能性があります)。ユーザーにSudoアクセス権を付与する必要がある場合もあります。

1
dirkt

この問題は、既存の設定全体、プロバイダー独自の設定を変更する可能性、サポートする実際のvpnタイプ、および多少複雑な設定を受け入れるかどうかに応じて、さまざまな方法で対処できると思います。

NordVPNサービスに固有のソリューションの場合、nordvpnコマンドは必ずしもOpenVPNを使用する必要はなく、IPSecまたはPPTP/L2TPを使用する可能性があるため、サポートを依頼することもできます。

ただし、NordVPNサービスと完全に互換性があるという一般的なOpenVPNソリューションの場合、最善のアプローチは、ポリシールーティングを使用することです。

しかし、最初に、名前空間への関心を見て、これらを使用した可能なアプローチに関する私の意見を述べたいと思います。

確かに名前空間を使用することで、ユーザー間のネットワーキングの真の分離が得られます。OpenVPNだけでなく、あらゆるタイプのVPNの一般的なソリューションであるという主な顕著な利点があります。

ただし、問題の問題はunshareまたはip netns execコマンドを使用して簡単に対処できるものではないため、設定に必要なツールは多くのLinuxディストリビューションでは一般的にインストールされません。これらは、ユーザーの既存のセッション全体ではなく、そのコマンドセッション以降で実行されるプロセスに対してのみ新しい名前空間の可視性を許可します。

また、必要なツールをインストールして必要な方法でセットアップしたとしても、同じ物理ネットデバイスを使用し、UNIXを共有しながら、各ユーザーを独自のネットワーク名前空間に分離するために、システムを慎重にセットアップする必要があります。ローカルホストで実行されているドメインソケットとサービス。ブリッジ(またはmacvlans)、サブネットの設定、アドレスの割り当て、場合によってはNAT化、その他の複雑さ。それはおそらく可能ですが、それをまっすぐにすることは単純ではない可能性があり、私は元の問題よりはるかに複雑だと思います。


したがって、ルーティングポリシーアプローチに戻ると、ベースソリューションは、おそらく最も単純で実用的なものであり、ほとんどの一般的なユースケースに十分であり、またはより洗練されたバリアントに挑戦する前の出発点として、個別のユーザーのUIDに基づくルーティングポリシーを介して検索される、各ユーザーのトンネルごとのルーティングテーブル。

次の主要な特性があります。

  • openVPNの(かなり)標準バージョンが必要(つまり、プロバイダーによって大幅にカスタマイズされていない)
  • ユーザーのUID番号に基づいて関連するトラフィックをマークするには、iptablesコンパニオンルールが必要です
  • 既存のファイアウォールまたはルーティングルールに沿って使用する場合は、慎重な統合が必要になる場合があります
  • ただし、ユーザーがSudoを介して実行したプロセス(これらはUID 0で実行されるため)や、setuidコマンドやアプリケーションをルートとして実行することは識別できません。これらは、通常のデスクトップシナリオにはほとんど当てはまりませんが、発生する可能性があり、意図したとおりに処理されません(つまり、トラフィックの一部がVPNに送信されません)。

すべては2つのヘルパースクリプトで処理できます。 1つはbyOpenVPNで使用され、もう1つはrunで使用されますopenvpn自体。

標準のOpenVPNはipコマンドを使用して、tun/tapデバイスに設定し、VPNプロバイダーによってプッシュされたルートをインストールします。問題は、デフォルトでipコマンドがシステム全体で使用されるメインルーティングテーブルで動作するため、そのすべてのユーザーが含まれることです。

ただし、OpenVPNでは、適用する必要がある設定に使用する別のコマンドを指定できるため、ipのラッパーを提供するだけで、さまざまなルーティングテーブルで動作します。

このような(仮にmyip.shという名前の)ラッパースクリプトは次のようになります。

#!/bin/bash -

my_session="$(ps -p $$ -o sid --no-header)" || exit 1
real_uid="$(ps -p $$ -o ouid --no-header || ps -p $my_session -o ruid --no-header || echo 0)"

real_ip_cmd=/sbin/ip

if [ $real_uid -ne 0 ] && [[ "$1" = ro* ]] ; then
    ! [ $2 ] && exec $real_ip_cmd "$1" list table $real_uid
    [[ "$2" =~ ^([adcfls]|rep).*$ ]] && exec $real_ip_cmd "$1" "$2" table $real_uid "${@:3}"
fi
exec $real_ip_cmd "$@"

最初の2行は、OpenVPNを実行している実際のUIDを取得しようとするものです。そのUIDをテーブルIDとして使用します。このようにして、各ユーザーはvpnを開始するときに独自のルーティングテーブルを持ちます。

if-then-fiブロックはroute設定の呼び出しをキャッチし(ipコマンドの短縮された明確なキーワードを受け入れる機能を模倣する)、openvpnから渡されたすべてのコマンドの前にtableオプションは、ユーザーの実際のUIDと等しいIDを保持します。他のすべてのipコマンド(つまり、route以外)はそのまま通過します。

もう1つのスクリプトはopenvpnコマンドをラップし、ユーザーが生成したトラフィックを個別のテーブルに従ってルーティングするように設定します。このラッパースクリプトの要点は、プロバイダー独自の構成ファイルに含めることができ、シームレスな統合を可能にします。これは、vpnを非対話的に(たとえば、ブート時に)確立したい場合に役立ちます。ただし、代わりにこのラッパースクリプトを使用することで、構成ファイルをいじる必要がなくなります。そのため、このバージョンを提示することにしました。

したがって、そのような単一のラッパースクリプトは次のようになります。

#!/bin/bash

my_session="$(ps -p $$ -o sid --no-header)" || exit 1
real_uid="$(ps -p $$ -o ouid --no-header || ps -p $my_session -o ruid --no-header || echo 0)"
[ $real_uid -eq 0 ] && { echo "will not run for UID 0" >&2 ; exit 1; }

remove_tagging() {
        iptables -t mangle -D OUTPUT -m owner --uid $real_uid -j MARK --set-mark $real_uid
        ip rule del fwmark $real_uid
        ip route flush table $real_uid
} 2>/dev/null

trap 'remove_tagging' EXIT

source <(ip route | sed "s/^/ip route add table ${real_uid} /")

(
ip -o monitor | grep -qm 1 '^[0-9]\+: tun[0-9]\+[[:blank:]]\+inet '
ip rule add fwmark $real_uid lookup $real_uid
iptables -t mangle -A OUTPUT -m owner --uid $real_uid -j MARK --set-mark $real_uid
) &

openvpn --iproute myip.sh --config tunnel-config.ovpn

最初の3行は、ユーザーの実際のUIDを試行して取得するために再び機能し、取得できない場合は続行されません。

次に、スクリプトからEXITで実行する関数があります。この関数は、次のサブシェルによって設定された設定を削除します。

ただし、最初に、現在のメインルーティングテーブル全体をユーザー用の個別のテーブルにコピーします。

次に、OpenVPNによってtunXデバイスがセットアップされるのを待機するサブシェルを実行し、その後、ユーザーが生成したトラフィックをマークするルーティングルールとiptablesコンパニオンルールを追加しますオン。ユーザー名とパスワードを要求する必要がある場合に備えてOpenVPNをフォアグラウンドで実行する必要があるため、これをバックグラウンドで実行します。

sourceコマンド、サブシェル(ip -o monitorパイプラインなし)、およびremove_tagging関数は、vpn構成ファイルで(それぞれ)uproute-uproute-pre-downオプション。そうすることで、このラッパースクリプトを完全に取り除くことができます。

最後に、実際のopenvpnコマンドを実行し、独自のmyip.shスクリプトをコマンドとして使用してネットワークをセットアップするように指示します。


可能性のあるわずかなバリエーションは、ルーティングでipの代わりにuidrangeオプションを使用するiproute2パッケージの最新バージョン(fwmarkコマンドを提供)を使用することによる可能性があります。ルール。

したがって、このようなバリアントはiptablesコマンドを削除し、ip rule fwmark ..コマンドをip rule uidrange ${real_uid}-${real_uid} lookup $real_uidコマンドに置き換えます(それぞれのip rule del ..コマンドについても同様です)。


Sudoを介して実行されるコマンドの一部のサポートの別のバリアントは、UIDではなくユーザーのグループ(GID)に基づいてポリシールーティングを作成することです。これには追加の基本要件があります。

  • 多くのLinuxディストリビューション(Ubuntuを含む)で一般的であるように、ユーザーに存在する一意のGID
  • Sudo追加のオプション(-g <user> -u rootまたはsudoersの同等の構成)を使用して実行し、元のGID番号を保持します

ただし、そのようなSudoの外部でユーザーが実行するUID 0プロセスを特定することはできません。


「UID 0プロセス」の問題に実際に対処するには、cgroupを使用できますが、当然、これにはさらに追加の要件があります。

  • iptablesコンパニオンルール。関連するトラフィックをiptables独自の「cgroup」モジュールでマークします。 Ubuntu 14.04
  • 既存の既存のcgroupセットアップと競合する可能性があります

Cgroupsを使用すると、net-class-idの設定は、pam_exec.soによって実行される単純なスクリプトを介してかなりうまく処理される可能性があります

#!/bin/bash -e

uid=$(id -ru "${PAM_USER}")
mkdir -p /sys/fs/cgroup/net_cls/user/${uid} && echo $uid > /sys/fs/cgroup/net_cls/user/${uid}/net_cls.classid
echo $$ > /sys/fs/cgroup/net_cls/user/${uid}/cgroup.procs

次に、次の行を/etc/pam.dの下の目的の構成ファイルに追加します。

session optional    pam_exec.so /root/set-net-cls-id.sh

上記の行は、ssh、コンソールログイン、デスクトップ環境などのインタラクティブサービスを介して開始されたすべてのセッションをカバーするために、従来の/etc/pam.d/common-sessionファイルに配置される可能性があります。

この設定では、ラッパースクリプトで使用されるiptablesコマンドは次のようになります。

iptables -t mangle -A OUTPUT -m cgroup --cgroup $real_uid -j MARK --set-mark $real_uid

-Dの代わりに-Aを使用したそれぞれの削除コマンド。

Cgroupソリューションの考えられるバリエーションは、systemdへの統合であり、systemdの機能を使用して、pam_execを使用せずにcgroupを直接処理できます。

ただし、このcgroupセットアップはUbuntu 14.04ではうまく機能しません。そのバージョンは、各ユーザーのセッションのcgroupを設定するために使用され、このソリューションによって設定されたセットアップを上書きするためです。むしろ、セッションごとにオンザフライで作成されたcgroupのclassid値を設定する必要があります。その名前は、cat /proc/self/cgroup出力を解析することで簡単に取得できます。

1
LL3