OpenVPN مع المصادقة المتقدمة والترخيص

يناقش المقال تكوين OpenVPN مع ميزات إضافية:

  • شهادات الرمز للمصادقة الأساسية (Rutoken كمثال)
  • الواجهة الخلفية لـ LDAP للمصادقة الثانوية (باستخدام ActiveDirectory كمثال)
  • تصفية الموارد الداخلية المتاحة للمستخدمين (عبر iptables)

يصف أيضًا كيفية تكوين عملاء لنظامي التشغيل Linux و Windows و MacOS.

إعداد الخادم


تثبيت OpenVPN


خذ البرنامج النصي Nyr / openvpn-install ، قم بتشغيله من الجذر.

git clone https://github.com/Nyr/openvpn-install.git cd openvpn-install 

ستقوم عملية بدء التشغيل بطرح بعض الأسئلة.

  • بروتوكول UDP
  • المنفذ 1194
  • خوادم DNS - المحلية
  • عنوان IP الخارجي للبوابة على الإنترنت والذي من خلاله سيكون خادم vpn متاحًا

هناك أيضًا نسخة محسنة من الأمان للنص الأصلي - github.com/Angristan/OpenVPN- install . لديها المزيد من إعدادات التشفير مع شرح لماذا.

إدارة المستخدم


مضيفا
إذا لم يتم استخدام الرموز المميزة ، تتم إضافة المستخدم من خلال البرنامج النصي نفسه. يقوم البرنامج النصي بشكل أساسي بإنشاء تكوين ovpn مخصص وإدراج شهادة موقعة من شهادة الجذر هناك.

إذا تم استخدام الرموز المميزة (انظر القسم الموجود على الرموز أدناه) ، فسيتم كتابة الشهادة يدويًا بناءً على طلب الشهادة التي تم إنشاؤها على الرمز المميز. يجب أن يتم تكوين المستخدم يدويًا من القالب الموجود (من نفس القالب الذي تم إنشاء البرنامج النصي للتكوين منه). القالب هنا /etc/openvpn/client-common.txt . لا يتم تضمينه في حزمة openvpn ويتم إنشاؤه بواسطة البرنامج النصي أثناء عملية التكوين.

حذف
تتم إزالة المستخدمين من خلال نفس البرنامج النصي للتثبيت. تتم إضافة الشهادة إلى CRL ، ويتم دفع CRL الجديد إلى خادم vpn. يعتبر الخادم جميع الشهادات الموجودة في CRL غير صالحة ويرفض قبولها.

كيفية إبطال الشهادة يدويًا:

 cd /etc/openvpn/easyrsa #   ./easyrsa revoke $CLIENT #   crl ./easyrsa gen-crl #   crl rm -rf /etc/openvpn/crl.pem #    cp /etc/openvpn/easy-rsa/pki/crl.pem /etc/openvpn/crl.pem # openvpn    crl,       nobody chown nobody:nobody /etc/openvpn/crl.pem 

تصفية المضيفين المتاحة للعملاء


يجب أن يقتصر العملاء على المضيفين حتى يتمكنوا من الوصول إلى الشبكة عند اتصالهم بـ openvpn.

يدويا

تتمثل الفكرة في التقاط الحزم حتى على واجهة tun0 ، والتي يأتون إليها من العملاء وتصفيتها قبل الدخول إلى NAT. بعد NAT ، لن يكون هناك سبب لتصفيتها - سيكون لديهم جميعًا عنوان IP لخادم openvpn على الشبكة الداخلية. قبل الدخول إلى NAT ، يكون للحزم لكل مستخدم عنوان IP فريد خاص به (لمراسلات عناوين IP والمستخدمين ، راجع الملف /etc/openvpn/ipp.txt ).

تتم معالجة الحزم التي تمر عبر النظام (لا تأتي منه مباشرة وليست واردة ، أي في الواقع ، يتم توجيهها بواسطة النظام) بواسطة جدول FORWARD. تتم معالجة الجداول في iptables من أعلى إلى أسفل ، إذا لم تؤدي أي من القواعد في الجدول إلى قرار بشأن مصير الحزمة ، فسيتم تشغيل القاعدة الافتراضية.

تحضير جدول FORWARD:

 #   iptables -F FORWARD #     FORWARD -    iptables -P FORWARD DROP #     iptables -I FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT 

قواعد المثال لعميل معين. نظرًا لأن القاعدة الافتراضية للجدول هي DROP ، يبقى فقط السماح لأزواج منافذ المضيف + حيث يمكنك ذلك. السماح بالوصول إلى المنفذ على المضيف + تنفيذ الأمر ping للمضيف نفسه:

 iptables -I FORWARD -s 10.8.0.3 -i tun0 -d 10.0.2.3 -p tcp --dport 443 -j ACCEPT iptables -I FORWARD -s 10.8.0.3 -i tun0 -d 10.0.2.3 -p icmp --icmp-type echo-request -j ACCEPT 

في المثال أعلاه ، يُسمح للمضيف 10.8.0.3 بالوصول إلى المنفذ 443 الخاص بالمضيف 10.0.2.3.

كيفية إغلاق الوصول:

 #         iptables -L FORWARD --line-numbers #     iptables -D FORWARD { } 

ثم تحتاج إلى العثور على جميع القواعد لعميل معين وحذفها.

أثناء تصحيح الأخطاء ، من المريح النظر إلى القواعد الناجحة. كل قاعدة لديها عداد من الحزم معالجتها.

 #  ,      watch iptables -nvL FORWARD #     iptables -Z FORWARD 

تلقائيا

خادم openvpn لديه القدرة على تنفيذ البرامج النصية لإجراءات معينة. على وجه الخصوص ، عند الاتصال وفصل العملاء. يمكن كتابة البرامج النصية على أي شيء إذا كانت قابلة للتنفيذ فقط. داخل البرنامج النصي ، تقوم متغيرات البيئة بتمرير جميع أنواع المعلمات إلى الاتصال الحالي. نحن مهتمون بالمتغيرات:

  • common_name (اسم مالك الشهادة ؛ ما الذي يدفع إلى حقل الاسم الشائع عند إنشاء الشهادة)
  • ifconfig_pool_remote_ip (عنوان IP للعميل على tun0)
  • script_type (حدث ما حدث - الاتصال أو قطع الاتصال).

تحتاج امتيازات الجذر لإدارة iptables. المسنجر بعد ربط حقوق إعادة تعيين لأحد ولا يعمل البرامج النصية منه. من الخطأ عدم السماح لأي شخص بعمل شيء من تحت sudo ، ومن الأفضل عدم استخدام علامة النجمة في القواعد ، ولكن بطريقة ما تحتاج إلى السماح للمستخدم بالتحكم في iptables.

 # /etc/sudoers.d/50_openvpn # #    nobody ALL = NOPASSWD: /sbin/iptables -A FORWARD* #     nobody ALL = NOPASSWD: /sbin/iptables -L FORWARD* #    nobody ALL = NOPASSWD: /sbin/iptables -D FORWARD* 

في تهيئة الخادم ، تحتاج إلى إضافة إذن لتنفيذ ملفات الجهات الخارجية وتمكين ربطتين مسؤولتين عن توصيل المستخدم وقطع الاتصال به.

 script-security 2 client-connect /etc/openvpn/bin/hosts.rb client-disconnect /etc/openvpn/bin/hosts.rb 

البرنامج النصي نفسه ، الذي يقرأ التكوينات ويطبق قواعد iptables. البرنامج النصي يعمل على نفس المبادئ كما هو موضح في القسم السابق.

/openvpn/bin/hosts.rb
 #!/usr/bin/ruby # -*- coding: utf-8 -*- require 'pp' def log(string) puts 'hosts.rb: ' + string end def parse_config_file(name) config_path = "hosts/#{name}" unless File.exist?(config_path) puts "There is no specific configuration for #{name}." p name exit 0 end config_source = IO.read(config_path).split("\n") config = config_source.inject([]) do |result,line| ip, port, protocol = line.split(/\s+/) result << { ip: ip, port: port, protocol: protocol || 'tcp' } end end def get_config(name) user_config = parse_config_file(name) if user_config everybody_config = parse_config_file('everybody') end everybody_config + user_config end def apply_rule(rule) command = "sudo iptables #{rule}" log(command) system(command) end def remove_rule(number) command = "sudo iptables -D FORWARD #{number}" log(command) system(command) end def allow_target(source_ip, options) #         . apply_rule("-A FORWARD -s #{source_ip} -i tun0 -d #{options[:ip]} -p #{options[:protocol]} --dport #{options[:port]} -j ACCEPT") #       apply_rule("-A FORWARD -s #{source_ip} -i tun0 -d #{options[:ip]} -p icmp --icmp-type echo-request -j ACCEPT") end def clear_targets(source_ip) #      FORWARD,  source_ip. rules_exist = true while rules_exist table = `sudo iptables -L FORWARD --line-number`.split("\n") the_line = table.find do |line| fields = line.split(/\s+/) ip = fields[4] ip == source_ip end if the_line number = the_line.split(/\s+/)[0] remove_rule(number) else rules_exist = false end end end ################################################################################ script_type = ENV['script_type'] log(script_type) name = ENV['common_name'] source_ip = ENV['ifconfig_pool_remote_ip'] case script_type when 'client-connect' config = get_config(name) config.each{|target| allow_target(source_ip, target)} when 'client-disconnect' clear_targets(source_ip) else puts "Unknown script type #{script_type}." end 

يتم تخزين القواعد في ملفات متوافقة مع الاسم الشائع للشهادات في المجلد /etc/openvpn/hosts . وهي تحدد بالضبط عناوين IP المتاحة لعميل معين. فاصل - عدد تعسفي من المساحات. تتم كتابة عنوان IP والمنفذ والبروتوكول (tcp أو udp) من خلال الفاصل.

 10.0.0.24 53 udp 10.0.0.25 53 udp 10.0.2.3 443 tcp 

نتيجة لذلك ، يجب أن /etc/openvpn الهيكل التالي في المجلد /etc/openvpn

├── بن
s. └── hosts.rb
├── المضيفين
1 ├── user1
2 ├── user2
└── └── الجميع
├── server.conf
└── ...

User1 و user2 هي ملفات بالتنسيق أعلاه. يصفون أي المضيفين الذي يحمل الاسم الشائع المقابل له حق الوصول إلى.

يوجد ملف إضافي آخر everybody ، يحتوي على قواعد تنطبق على جميع العملاء ، بشرط أن يكون هناك ملف تكوين منفصل لهؤلاء العملاء. أي إذا كان لدى المستخدم قائمة بالمضيفات حيث يمكنه الانتقال ، فسيتم تطبيق هذه القائمة والمضيفين المدرجين في everybody . إذا لم يكن كذلك ، everybody قابل للتطبيق. على سبيل المثال ، من الملائم وضع خادم DNS في هذا الملف.

تسجيل

يتضمن البرنامج النصي للتثبيت فقط تسجيل الاتصالات الحالية (معلمة status) . حتى يظهر سجل منتظم ، تحتاج إلى إضافة سطر إلى تهيئة الخادم ( /etc/openvpn/server.conf ):
 log-append /var/log/openvpn.log 


LDAP

هناك مكون إضافي openvpn-auth-ldap يسمح لك بمصادقة مستخدم مرة أخرى عبر LDAP.

تسليم الحزمة:

 sudo yum install openvpn-auth-ldap 

إضافة إلى server.conf:

 plugin /usr/lib64/openvpn/plugin/lib/openvpn-auth-ldap.so "/etc/openvpn/ldap.conf" 

قم بإنشاء تهيئة لـ ldap في /etc/openvpn/ldap.conf :
 <LDAP> URL ldaps://{LDAP_DOMAIN_HERE} Timeout 15 TLSEnable no FollowReferrals yes BindDN "BIND_DN_HERE" Password "BIND_PASSWORD_HERE" </LDAP> <Authorization> BaseDN "{BASE_DN_HERE}" SearchFilter "(&(sAMAccountName=%u)(objectClass=organizationalPerson)(objectCategory=person)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))" RequireGroup false </Authorization> 

أضف السطر إلى تهيئة ovpn المخصصة:

 auth-user-pass 

وبالتالي ، سيُطلب من المستخدم أولاً اسم المستخدم وكلمة المرور من المجال ، ثم رقم التعريف الشخصي من الرمز المميز. إذا فشلت إحدى هذه الخطوات ، فلن يتم تأسيس الاتصال.

وصف خيارات ldap.conf في مستودع البرنامج المساعد . يدعم المصادقة حسب عضوية المجموعة ، لكنني لم أختبرها.

السرعة


أكبر زيادة في السرعة يعطي إدراج وضع udp. ينصح هذا في جميع الأدلة. النقطة المهمة هي أنه لا معنى لبدء اتصال عميل tcp في قناة tcp. واحد tcp في العميل يكفي لجعل التسليم الصحيح للحزم. إذا فقدت الحزم في قناة UDP ، فإن اتصال tcp للعميل سوف يتحكم في ضبط التسليم.

ستزداد السرعة على الأقل لأنه لا توجد حاجة لانتظار تأكيد تسليم كل حزمة في القناة. هناك مشكلة ثانية مع tcp - حزمة tcp للعميل على الأرجح لا تنسجم مع حزمة واحدة من قناة vpn. MTU هي نفسها ، لكن يجب إضافة الرؤوس إلى حزمة العميل. نتيجة لذلك ، يجب عليك إرسال رزمتين داخل قناة vpn لكل رزمة مستخدم.

من المنطقي استخدام TCP عندما يكون ذلك مستحيلًا بطريقة أخرى. على سبيل المثال ، عندما يعمل VPN عبر قناة ssh.

مثال على تكوين الخادم الكامل


سبيل المثال server.conf
 port 1194 proto tcp dev tun sndbuf 0 rcvbuf 0 ca ca.crt cert server.crt key server.key dh dh.pem tls-auth ta.key 0 topology subnet server 10.8.0.0 255.255.255.0 ifconfig-pool-persist ipp.txt push "redirect-gateway def1 bypass-dhcp" push "dhcp-option DNS 10.0.0.25" push "dhcp-option DNS 10.0.0.24" keepalive 10 120 cipher AES-256-CBC comp-lzo user nobody group nobody persist-key persist-tun status openvpn-status.log verb 3 crl-verify crl.pem log-append /var/log/openvpn.log script-security 2 client-connect /etc/openvpn/bin/hosts.rb client-disconnect /etc/openvpn/bin/hosts.rb 


رمز الإعداد


PKCS # 11 مكتبة


للعمل مع الرموز ، تحتاج إلى مكتبة خاصة. هناك حاجة إلى المكتبة لإنشاء أزواج المفاتيح والاتصال الفعلي. تحميل لجميع المنصات من خلال الرابط .

أينما تم العثور على librtpkcs11ecp.so لاحقًا - فهذه هي المكتبة التي تحتاج إلى التنزيل ووضعها في مكان مناسب.

إنشاء شهادة على رمز مميز


إنشاء زوج المفاتيح على الرمز المميز. المعلمة id هنا هي الرقم التسلسلي للفتحة الموجودة على الرمز المميز حيث يناسب زوج المفاتيح.

 pkcs11-tool --module /usr/lib64/librtpkcs11ecp.so --keypairgen --key-type rsa:2048 -l --id 01 

تقديم طلب شهادة للمفتاح العمومي. في عملية إنشاء طلب شهادة ، يتم تعيين عمر الشهادة والاسم الشائع ، والذي يستخدم لتصفية عناوين IP المتوفرة داخل الشبكة. يجب أن يطابق الاسم الشائع تسجيل الدخول في ActiveDirectory بحيث لا يكون هناك أي تشويش.

 openssl openssl> engine -t dynamic -pre SO_PATH:/usr/lib64/openssl/engines/pkcs11.so -pre ID:pkcs11 -pre LIST_ADD:1 -pre LOAD -pre MODULE_PATH:/usr/lib64/librtpkcs11ecp.so openssl> req -engine pkcs11 -new -key slot_0-id_01 -keyform engine -out /home/john/good.req 

يجب نقل الطلب المستلم إلى المجلد /etc/openvpn/easy-rsa/pki/reqs/ . يجب أن يكون امتداد الملف req .
تحويل الطلب إلى شهادة:

 cd /etc/openvpn/easy-rsa/ ./easyrsa sign-req client good 

بعد ذلك ، ستظهر شهادة تحمل الاسم نفسه ولكن بالامتداد crt في المجلد /etc/openvpn/easy-rsa/pki/issued/ .

قبل التسجيل ، يجب تحويل الشهادة إلى DER:

 openssl x509 -in /home/user/user-cert.pem -out /home/user/user-cert.crt -outform DER 

كتابة شهادة الرمز المميز:

 pkcs11-tool --module /usr/lib/librtpkcs11ecp.so -l -y cert -w /home/user/user-cert.crt --id 45 --label TEST 

إنه مكتوب على أساس المقال "استخدام Rutoken EDS مع OpenSSL (RSA)" .

استخدام الرمز للمصادقة


ابحث عن معرف الشهادة ليتم تقديمه إلى الخادم:

 $ openvpn --show-pkcs11-ids /usr/lib64/librtpkcs11ecp.so The following objects are available for use. Each object shown below may be used as parameter to --pkcs11-id option please remember to use single quote mark. Certificate DN: /CN=User1 Serial: 490B82C4000000000075 Serialized id: aaaa/bbb/41545F5349474E415455524581D2A1A1B23C4AA4CB17FAF7A4600 

نحن مهتمون في الرقم التسلسلي هنا.

الخيارات التي يجب إدخالها في تكوين ovpn بحيث تلتقط الرموز المميزة:

 pkcs11-providers /usr/lib64/librtpkcs11ecp.so pkcs11-id 'aaaa/bbb/41545F5349474E415455524581D2A1A1B23C4AA4CB17FAF7A4600' 

يجب pkcs11-id خيار pkcs11-id في علامات اقتباس مفردة.

هذا الدليل منطقي على جميع المنصات. تحتاج إلى تحديد المسار إلى المكتبة ومعرف الشهادة على الرمز المميز. قد يتم استدعاء المكتبة بشكل مختلف قليلاً ، تكون .dll ، وليس .so ، لكن المعنى هو نفسه.

في هذه الحالة ، تحتاج إلى إزالة مقاطع الشهادات والمفاتيح من ملف ovpn ، لأنه سيتم أخذ الشهادة والمفتاح الخاص من الرمز المميز.

يبدو التكوين الكامل للعميل (للنوافذ) كما يلي:

client.ovpn
client
dev tun
proto tcp
sndbuf 0
rcvbuf 0
remote 78.47.37.247 22222
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
cipher AES-256-CBC
comp-lzo
setenv opt block-outside-dns
key-direction 1
verb 3

pkcs11-providers "c://Windows//System32//rtPKCS11ECP.dll"
pkcs11-id 'Aktiv\x20Co\x2E/Rutoken\x20ECP/342b871d/Rutoken/01'

-----BEGIN CERTIFICATE-----
{CERT_HERE}
-----END CERTIFICATE-----


<tls-auth>
#
# 2048 bit OpenVPN static key
#
-----BEGIN OpenVPN Static key V1-----
{KEY_HERE}
-----END OpenVPN Static key V1-----
</tls-auth>


مكتوب على أساس "كيفية إضافة مصادقة ثنائية العوامل إلى تكوين OpenVPN باستخدام البطاقات الذكية من جانب العميل . "

إعداد العملاء


لينكس


يحتوي Openvpn على خطأ يمنع المستخدم من إدخال رمز PIN من الرمز المميز إذا تم إنشاء الحزمة مع دعم systemd. نظرًا لأن systemd كان موجودًا في كل مكان مؤخرًا ، يتم تجميع جميع الحزم المتوفرة بالفعل في المستودعات بدعمها. يحتاج العملاء على نظام Linux إلى تجميع الحزمة بمفردهم. فيما يلي مثال للتكوين الذي عمل لي في Arch Linux:

 ./configure \ --prefix=/usr \ --sbindir=/usr/bin \ --enable-iproute2 \ --enable-pkcs11 \ --enable-plugins \ --enable-x509-alt-username 

يمكنك التحقق من أن openvpn مبني على أو بدون systemd باستخدام الأمر التالي:

 openvpn --version | grep --color enable_systemd 

ماس السراج


تحت Mac OS ، يوجد عميل واحد مجاني - Tunnelblink .

لا يعرف كيفية إدخال رمز التعريف الشخصي من رمز مميز من واجهة المستخدم الرسومية. تم وصف الخطأ على سبيل المثال هنا - https://groups.google.com/forum/#!topic/tunnelblick-discuss/f_Rp_2nV-x8 تجاوز من خلال إطلاق openvpn من وحدة التحكم. هذا ليس مفاجئًا ، نظرًا لأن العميل الرسمي لنظام التشغيل windows لا يعرف هذا أيضًا.

أيضًا ضمن نظام التشغيل Mac OS (على عكس النوافذ) هناك حاجة إلى برامج نصية إضافية لتكوين الشبكة. إذا قمت ببساطة بتشغيل openvpn من وحدة التحكم ، فلن يعمل DNS (ربما شيء آخر ، سوف يظهر DNS فقط).

يحتوي برنامج TunnelBlick على برامج نصية لتكوين الشبكة ، ولا يحتاج إلا إلى الاتصال به عند إنشاء الاتصال وفصله. ما تحتاج إلى إضافته إلى التكوين ovpn:

 script-security 2 up "/Applications/Tunnelblick.app/Contents/Resources/client.up.tunnelblick.sh -9 -d -f -m -w -ptADGNWradsgnw" down "/Applications/Tunnelblick.app/Contents/Resources/client.down.tunnelblick.sh -9 -d -f -m -w -ptADGNWradsgnw" 

مثال نصي لبدء تشغيل اتصال openvpn ، والذي يمكن وضعه على سطح المكتب وإدخاله بالماوس:

 #!/bin/bash tunnelblick=/Applications/Tunnelblick.app/Contents/Resources/openvpn/openvpn-2.4.2-openssl-1.0.2k sudo $tunnelblick/openvpn --config $tunnelblick/user.ovpn 

نوافذ


تحت النوافذ ، يبدو أن كل شيء يعمل. لا يعرف العميل الرسمي كيفية إدخال رمز التعريف الشخصي من الرمز المميز ، فإنه يدير openvpn باليد من وحدة التحكم.

الشيء الأكثر أهمية هو أن تفعل كل شيء من تحت المسؤول. قم بتشغيل برنامج تثبيت العميل كمسؤول. قم بتشغيل محطة يبدأ فيها openvpn أيضًا بحقوق المسؤول ، وإلا فلن يكون قادرًا على التحكم في واجهة الشبكة.

تحت Windows ، يجب تسجيل المسار إلى المكتبة للعمل مع الرموز عبر خطوط مائلة مزدوجة. ينطبق هذا على كل من ovpn config --show-pkcs11-ids في سطر الأوامر.

 pkcs11-providers "c://Windows//System32//rtPKCS11ECP.dll" pkcs11-id 'Aktiv\x20Co\x2E/Rutoken\x20ECP/342b871d/Rutoken/01' 

Source: https://habr.com/ru/post/ar433250/


All Articles