VPS वर AES-NI तपासा आणि पुन्हा सुरू करा
तुमच्या VPS मध्ये AES-NI दिसते का तपासा, masked CPUID मुळे AES-GCM throughput किती घटतो ते मोजा आणि OPENSSL_ia32cap ने fast path पुन्हा सुरू करा.
VPS वर AES-NI मुळे प्रत्यक्षात काय मिळते
VPS वरील AES-NI हा x86 च्या सहा instructions चा संच आहे. या instructions हार्डवेअरमध्ये AES (advanced encryption standard) ची एक फेरी पूर्ण करतात. तुमच्या provider ने CPU model मधील ही feature लपवली असेल, तरी अंतर्गत silicon मध्ये ती उपलब्ध असते. मात्र OpenSSL ला ती दिसत नाही. त्यामुळे OpenSSL software implementation वापरते. यासाठी प्रत्येक byte मागे साधारण दहापट अधिक cycles लागतात. एका command ने ही feature उपलब्ध आहे का ते तपासता येते. दोन commands ने कामगिरीतील फरक मोजता येतो. अनेकदा एका environment variable ने fast path पुन्हा सुरू करता येतो.
ही instructions AESENC, AESENCLAST, AESDEC, AESDECLAST, AESIMC आणि AESKEYGENASSIST आहेत. Intel ने त्या 2010 मध्ये उपलब्ध करून दिल्या. त्यानंतर AMD नेही त्या उपलब्ध केल्या. त्यामुळे तुम्ही भाड्याने घेण्याची शक्यता असलेल्या कोणत्याही server CPU मध्ये हे silicon असते. PCLMULQDQ ही companion instruction carry-less multiplication करते. GCM (Galois/counter mode) ला authentication tag तयार करण्यासाठी याची गरज असते. AES-GCM तेव्हाच जलद असते जेव्हा दोन्ही उपलब्ध असतात. कारण cipher आणि tag ही स्वतंत्र कामे आहेत.
VPS वरील monitoring मध्ये हे पुढील चार ठिकाणी दिसते:
- TLS (transport layer security) termination. AES-128-GCM किंवा AES-256-GCM वापरून web server traffic देत असल्यास, bulk-crypto वेळेतील बहुतांश भाग AES मध्ये खर्च होतो.
- Encrypted volumes. LUKS (Linux unified key setup) आणि dm-crypt प्रत्येक read आणि प्रत्येक write वेळी kernel मध्ये, CPU वर
aes-xtsवापरतात. - AES-based VPN traffic.
AES-256-GCMसह OpenVPN आणि AES-GCM सह IPsec दोन्ही यावर अवलंबून असतात. - Encrypted backups. सर्व्हरमधून बाहेर जाण्यापूर्वी stream ला AES ने encrypt करणाऱ्या कोणत्याही प्रणालीला हाच खर्च येतो.
एका सामान्य workload वर याचा अजिबात परिणाम होत नाही. WireGuard आपल्या data साठी ChaCha20-Poly1305 वापरते आणि AES वापरत नाही. त्यामुळे flag masked असलेल्या host वरही self-hosted WireGuard VPN समान वेगाने चालते. स्वस्त VPS साठी tunnel निवडण्यापूर्वी WireGuard ची OpenVPN शी तुलना करण्याचे हे व्यावहारिक कारण आहे.
VPS मध्ये AES-NI आहे की नाही हे कसे तपासावे
Kernel CPUID feature bits /proc/cpuinfo मध्ये कॉपी करतो. त्यामुळे एक grep पुरेसे आहे.
grep -m1 -o '\baes\b' /proc/cpuinfo
lscpu | grep -i -o '\baes\b'aes दाखवणारी कोणतीही command CPU या guest ला AES-NI उपलब्ध असल्याचे दर्शवते. काहीही output न आल्यास AES-NI उपलब्ध नाही. lscpu त्याच flags वाचते, त्यामुळे दोन्ही command नेहमी समान परिणाम देतात. तुमच्या प्रणालीवर installed असलेली command वापरा.
आता host कोणता CPU वापरत असल्याचे दाखवतो ते तपासा.
grep -m1 'model name' /proc/cpuinfoIntel(R) Xeon(R) Gold 6338 CPU @ 2.00GHz किंवा AMD EPYC 7443P 24-Core Processor सारखा वास्तविक model string दिसल्यास host physical CPU model तुमच्यापर्यंत pass through करत आहे. QEMU Virtual CPU version 2.5+ किंवा Common KVM processor दिसल्यास वेगळे काही घडत आहे. हेच प्रकरण समजून घेणे महत्त्वाचे आहे.
सिलिकॉनमध्ये flag असूनही तो का दिसत नाही
CPUID ही अशी instruction आहे जिचा वापर करून एखादा program CPU ला त्याला कोणती features समर्थित आहेत हे विचारतो. Virtual machine मध्ये CPUID नेहमी hypervisor कडे trap होते. त्यामुळे guest ला काय सांगायचे हे hypervisor ठरवतो. बहुतेक panels हा निर्णय guest CPU model म्हणून दाखवतात. qemu64 आणि kvm64 हे generic baseline models आहेत. त्यांच्या feature set मध्ये AES-NI किंवा SSSE3 यांपैकी कोणतीही feature समाविष्ट नसते. त्यामुळे physical host सध्याचा EPYC असला तरी guest ला aes flag दिसत नाही. VPS म्हणजे दुसऱ्याच्या hardware वरील guest असतो. त्यामुळे तो कोणती feature report करतो हे प्रत्येक वेळी त्याच्या वरच्या स्तरावर घेतलेला निर्णय असतो. हे layering तुमच्यासाठी नवीन असल्यास VPS म्हणजे काय येथून सुरुवात करा.
वेगवेगळ्या processors असलेल्या machines मधील live migration कार्य करण्यासाठी hosts जाणीवपूर्वक generic model निवडतात. Destination machine मध्ये नसलेली feature guest ला कधीही सांगितली गेलेली नसावी, तेव्हाच migration कार्य करते. त्याची किंमत तुम्हाला मोजावी लागते. तुमचा kernel आणि तुमची OpenSSL ची copy startup वेळी masked CPUID वाचतात. त्यानंतर process चालू असेपर्यंत दोन्ही slow code path वापरतात.
याचा source वरील उपाय म्हणजे host-side setting: QEMU च्या भाषेत -cpu host, AES-NI समाविष्ट असलेले named model किंवा model मध्ये जोडलेले स्पष्ट +aes. हे कोणतेही setting तुम्ही guest मधून लागू करू शकत नाही. Support ticket उघडणे किंवा hypervisor ला CPU model pass through करू देणारा plan निवडणे हा टिकाऊ उपाय आहे.
openssl speed ने फरक मोजा
प्रकाशित benchmark वर आंधळा विश्वास ठेवू नका. तुमचा सर्व्हर प्रत्यक्षात ज्या cipher शी negotiation करतो तो cipher चालवून पाहा.
openssl version
openssl speed -evp aes-128-gcmनिकालातील row ला AES-128-GCM असे label केलेले असते. त्यात सहा block sizes साठी throughput दिलेला असतो. एकक 1000 bytes per second असते. Bulk transfer साठी 8192-byte column वाचा. 16-byte column वर प्रत्येक call चा overhead प्रभावी असतो. त्यामुळे file download बद्दल त्यातून कोणतीही उपयुक्त माहिती मिळत नाही.
आता software मध्ये AES-NI आणि PCLMULQDQ बंद करून हीच command पुन्हा चालवा:
OPENSSL_ia32cap="~0x200000200000000" openssl speed -evp aes-128-gcmही value OpenSSL च्या capability vector documentation मधून येते. सुरुवातीला ~ असल्यास त्याचा अर्थ “हे bits clear करा” असा होतो. Bit 57 म्हणजे AES-NI आणि bit 33 म्हणजे PCLMULQDQ. त्यामुळे 0x200000200000000 या दोन bitsनाच निर्दिष्ट करते; इतर कोणत्याही bit ला नाही. दुसरी value पहिल्यापेक्षा खूप कमी असल्यास तुमच्या मशीनवर AES-NI कार्यरत आहे आणि तुम्ही पुढे जाऊ शकता. दोन्ही values समान असल्यास OpenSSL आधीपासूनच software path वर चालत होते, कारण clear करण्यासाठी तो flag अस्तित्वातच नव्हता.
The data behind this chart
[
{
"label": "AES-NI and PCLMULQDQ",
"mb_per_sec": "4,850",
"cycles_per_byte": 0.7
},
{
"label": "Software fallback",
"mb_per_sec": 310,
"cycles_per_byte": 11.0
}
]ही आधुनिक x86 core साठी, सुमारे 3.4 GHz वेगावर, प्रकाशित केलेली प्रतिनिधिक आकडेवारी आहे. ती कोणत्याही एका host वरून घेतलेली measurement नाही. त्याकडे एकूण स्वरूप म्हणून पाहा. Hardware path सुमारे 0.7 cycles per byte वेगाने चालतो. Software fallback सुमारे 11.0 cycles per byte वेगाने चालतो. एका core वर हे अनुक्रमे सुमारे 4,850 MB/s आणि 310 MB/s इतके होते. तुमच्या सर्व्हरचे वर्णन करणारी एकमेव value वर दिलेल्या दोन commands मधून मिळते. हीच पद्धत मशीनच्या इतर भागांसाठीही लागू आहे. त्यामुळे plan बद्दल निष्कर्ष काढण्यापूर्वी हे VPS चा पुनरुत्पादक benchmark घेण्याची पद्धत यासोबत वापरा.
OPENSSL_ia32cap वापरून bits पुन्हा सक्षम करा
हा भाग अनेकांना आश्चर्यचकित करतो. AES-NI सूचना unprivileged असतात आणि hypervisor त्यांना trap करत नाही. फक्त CPUID trap केला जातो. त्यामुळे host तुमच्या guest ला AES-NI उपलब्ध नाही असे सांगू शकतो, तरी AESENC native पद्धतीने पूर्ण वेगाने चालू राहते. Software ने CPUID कडे विचारणा करून चुकीचे उत्तर मिळवल्यामुळे fast path वगळला जातो. सूचना स्वतः कधीही बंद झालेली नसते.
OpenSSL तुम्हाला CPU च्या वतीने उत्तर देण्याची सुविधा देते. OPENSSL_ia32cap मधील साधी hexadecimal value capability vector ला mask करण्याऐवजी पूर्णपणे overwrite करते.
OPENSSL_ia32cap="0x0200020207000000" openssl speed -evp aes-128-gcmहा run plain run पेक्षा अनेक पटींनी जलद असल्यास, त्या silicon मध्ये AES-NI उपलब्ध आहे आणि host ते लपवत आहे. हे प्रथम diagnosis आहे. OpenSSL साठी ते fix देखील ठरते.
हा hex value कसा तयार केला जातो
पहिला logical vector CPUID leaf 1 मधील EDX ला low 32 bits मध्ये आणि leaf 1 मधील ECX ला high 32 bits मध्ये pack करतो. Low half मध्ये bit 24 हा FXSR, bit 25 हा SSE आणि bit 26 हा SSE2 आहे; त्यामुळे 0x07000000 मिळते. Upper half मध्ये bit 33 हा PCLMULQDQ, bit 41 हा SSSE3 आणि bit 57 हा AES-NI आहे; त्यामुळे 0x02000202 मिळते. हे एकत्र केल्यावर 0x0200020207000000 मिळते. या यादीत SSSE3 समाविष्ट आहे, कारण OpenSSL चे PCLMULQDQ आधारित GHASH bytes बदलण्यासाठी pshufb वापरते आणि generic guest CPU model AES-NI सोबत SSSE3 देखील लपवतो.
येथे दोन इशारे लागू होतात आणि तुम्ही दोन्ही मुद्दाम निर्माण करू शकता.
फक्त पहिला vector सेट केल्यास नंतरचे vectors zero राहतात. त्यामुळे AVX2 आणि AVX-512 code paths बंद होतात. येथे ते जाणीवपूर्वक केले आहे. Mask केलेल्या guest वर AVX bits जबरदस्तीने सक्षम करण्याचा प्रयत्न करू नका, कारण AVX registers साठी operating system ने XCR0 मध्ये extended state सक्षम करणे आवश्यक असते. त्याच mask केलेल्या CPUID वरून तुमच्या kernel ने ते करण्यास नकार दिलेला असतो. त्यानंतर VEX-encoded instruction undefined-opcode fault निर्माण करते आणि process बंद होतो.
ज्या core मध्ये AES-NI प्रत्यक्षात उपलब्ध नाही, त्यावर AES-NI जबरदस्तीने सक्षम केल्यास process त्वरित बंद होतो:
Illegal instruction (core dumped)यामुळे AESENC undefined-opcode fault निर्माण करते, कारण त्या core वर अशी instruction execute करण्यासाठी उपलब्ध नसते. काही server firmware पुढील reset पर्यंत hardware मध्ये AES-NI बंद देखील करू शकते आणि त्याची लक्षणे तशीच असतात. दोन्ही परिस्थितींमध्ये उपाय वेगळा host आहे, वेगळे environment variable नाही.
दीर्घकाळ चालणाऱ्या service साठी हा override ठेवायचा असल्यास systemd drop-in वापरा.
sudo systemctl edit nginx[Service]
Environment="OPENSSL_ia32cap=0x0200020207000000"sudo systemctl daemon-reload
sudo systemctl restart nginx
sudo systemctl show nginx -p Environmentशेवटच्या command ने variable पुन्हा output मध्ये दाखवला पाहिजे. तुम्ही नेमके काय स्वीकारत आहात हे समजून घ्या: तो server कधी अशा host वर migrate झाला ज्याच्या CPU मध्ये प्रत्यक्ष AES-NI उपलब्ध नाही, तर nginx च्या पहिल्या TLS connection वेळी illegal instruction मुळे बंद होईल. हा मुद्दा तुमच्या runbook मध्ये नोंदवा किंवा override production मधून पूर्णपणे बाहेर ठेवा आणि ticket उघडताना मुद्दा सिद्ध करण्यापुरताच वापरा.
ओव्हरराइडने काय दुरुस्त होत नाही
OPENSSL_ia32cap OpenSSL पर्यंत पोहोचते; इतर कोणत्याही घटकापर्यंत पोहोचत नाही. इतर प्रत्येक सॉफ्टवेअर स्वतःचे feature detection चालवते आणि हे variable कधीही वाचत नाही.
Kernel हे यातील महत्त्वाचे प्रकरण आहे. dm-crypt आणि LUKS kernel crypto API वापरतात. CPU feature bit उपलब्ध नसल्यास aesni_intel module load होण्यास नकार देतो:
modprobe: ERROR: could not insert 'aesni_intel': No such deviceयासाठी user-space variable उपलब्ध नाही. Kernel boot वेळी CPUID एकदाच वाचतो. वेगळ्या host वर reboot करेपर्यंत हा निर्णय कायम राहतो. त्यामुळे OpenSSL काय करत असले तरी तुमचा encrypted volume software cipher वरच राहतो. प्रत्यक्षात कोणती कामगिरी मिळत आहे ते मोजा:
sudo cryptsetup benchmark -c aes-xts -s 256Hardware AES वापरताना aes-xts 256b row हजारो MiB/s पर्यंत पोहोचते. Hardware AES नसताना ती कमी शेकडो MiB/s मध्ये राहते. स्वतःचे detection वापरणारे language runtimes, त्यात Go आणि Java यांचा समावेश आहे, त्यांच्यावरही याचा परिणाम होत नाही. Go मधील crypto/aes CPUID थेट तपासते. Bit clear असल्यास ते शांतपणे त्याची constant-time software implementation वापरते. TLS terminate करणारी service Go binary असल्यास OpenSSL variable तिच्यासाठी काहीही बदलत नाही.
AES-NI उपलब्ध नसेल, तर ChaCha20 ला प्राधान्य द्या
ChaCha20-Poly1305 हे साध्या software मध्ये वेगाने चालण्यासाठी डिझाइन केले आहे. वापरता येण्याजोगे AES-NI नसलेल्या core वर ते सहसा AES-GCM पेक्षा मोठ्या फरकाने वेगवान असते. त्यामुळे अशा host वर AES ला प्राधान्य देणे थांबवणे हा योग्य निर्णय आहे.
nginx 1.19.4 किंवा त्यानंतरच्या आवृत्तीसाठी, आणि OpenSSL 1.1.1 किंवा त्यानंतरच्या आवृत्तीविरुद्ध build केले असल्यास:
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_conf_command Ciphersuites TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384;ssl_ciphers TLS 1.2 साठी लागू होते. ssl_conf_command Ciphersuites TLS 1.3 साठी लागू होते. TLS 1.3 साठी nginx मध्ये स्वतंत्र directive नाही. त्यामुळे nginx ही string तपासणी न करता थेट OpenSSL कडे पाठवतो. परिणामी, त्यातील typo शांतपणे स्वीकारला जातो. Configuration reload करा आणि client ला कोणता पर्याय दिला जातो ते तपासा:
sudo nginx -t && sudo systemctl reload nginx
openssl s_client -connect example.com:443 -tls1_3 </dev/null 2>/dev/null | grep -i cipherयशस्वी निकालात TLS_CHACHA20_POLY1305_SHA256 चे नाव दिसते. बदल कायम करण्यापूर्वी, त्याच box वर AES run च्या शेजारी openssl speed -evp chacha20-poly1305 चालवा आणि त्या दोन संख्यांवरून निर्णय घ्या.
ARM hosts वेगवेगळे extensions वापरतात
AES-NI केवळ x86 साठी आहे. ARM VPS मध्ये ARMv8 cryptographic extensions वापरले जातात. हेच काम करणारा हा स्वतंत्र instruction set आहे. aarch64 वर flags flags ऐवजी Features अंतर्गत असतात:
grep -m1 Features /proc/cpuinfoaes आणि pmull शोधा. pmull हा PCLMULQDQ चा ARM समकक्ष आहे आणि त्याच कारणासाठी GCM ला त्याची आवश्यकता असते. ARM वरील OpenSSL चे override variable OPENSSL_armcap आहे. त्याची स्वतंत्र bit layout OpenSSL source मधील crypto/arm_arch.h मध्ये परिभाषित केली आहे. त्यामुळे या मार्गदर्शकातील x86 hex value तेथे लागू होत नाही. प्रत्यक्षात VPS host म्हणून विकले जाणारे ARM server cores ही extensions उपलब्ध करून देतात. त्यामुळे masked-feature ची समस्या मुख्यतः x86 शी संबंधित आहे.
तुम्हाला दिसणाऱ्या स्ट्रिंग्ससह अपयशाच्या स्थिती
/proc/cpuinfo मध्ये aes नाही आणि सक्तीने चालवलेली चाचणी खूप वेगाने पूर्ण होते. Host CPUID लपवत आहे. Model name सामान्य आहे का ते तपासा. त्यानंतर तुमचा provider hypervisor कोणता guest CPU model दाखवतो ते विचारा.
/proc/cpuinfo मध्ये aes नाही आणि सक्तीने चालवलेल्या चाचणीत Illegal instruction दिसते. ही instructions प्रत्यक्षात उपलब्ध नाहीत किंवा firmware ने त्या अक्षम केल्या आहेत. Workload दुसऱ्या host वर हलवा.
aes उपलब्ध आहे, पण throughput अद्याप कमी आहे. तुम्ही 8192-byte column वाचत आहात का ते तपासा. तसेच core वर दुसरे कोणतेही काम सुरू नाही ना ते तपासा. Shared plan मध्ये noisy neighbour मुळे CPU feature नसल्यासारखेच दिसते. दिवसाच्या वेगवेगळ्या वेळी चाचणी दोनदा चालवल्यानंतरच फरक स्पष्ट होतो.
Masked run आणि normal run मध्ये समान number मिळते. OpenSSL आधीपासून software path वर होता. हाच निष्कर्ष आहे; चाचणीतील चूक नाही.
Nested virtualisation मुळे पुढील स्तरावर परिणाम बदलतो. Guest च्या आत चालणाऱ्या guest ला मधल्या स्तराने पुढे पाठवलेला CPUID मिळतो. तेथे AES-NI सहज गमावले जाऊ शकते आणि ते लक्षातही येत नाही. तुम्ही VPS वर nested virtual machines चालवत असल्यास, तुम्ही भाड्याने घेतलेल्या machine वर तसेच inner guest मध्येही flag तपासा.
FAQ
माझ्या VPS मध्ये /proc/cpuinfo मध्ये aes flag का नाही?
कारण hypervisor generic guest CPU model सादर करत आहे. qemu64 आणि kvm64 यांच्या feature sets मध्ये AES-NI समाविष्ट नाही. त्यामुळे physical processor कोणताही असला तरी CPUID त्याची अनुपस्थिती दाखवतो. वेगवेगळ्या CPU असलेल्या मशीनमध्ये चालू guest चे migration करता यावे म्हणून hosts असे करतात. grep -m1 'model name' /proc/cpuinfo चालवा: QEMU Virtual CPU version 2.5+ किंवा Common KVM processor सारखी string ही याची स्पष्ट खूण आहे. याउलट, Xeon किंवा EPYC model string दिसत असल्यास CPU model pass through केला जातो आणि flag खरोखर silicon मध्ये उपलब्ध नसतो.
OPENSSL_ia32cap खरोखर AES-NI सक्षम करते का, की फक्त तसा भास निर्माण करते?
ते प्रत्यक्ष instructions सक्षम करते. AES-NI instructions unprivileged आहेत आणि hypervisor त्यांना trap करत नाही. त्यामुळे CPUID काय सांगतो याची पर्वा न करता AESENC native पद्धतीने चालते. फक्त CPUID instruction intercept केली जाते. OPENSSL_ia32cap ला साधी hexadecimal value दिल्यास OpenSSL ला CPUID कडून मिळालेले उत्तर बदलते. त्यामुळे OpenSSL hardware code path निवडते आणि hardware तो full speed ने चालवतो. Silicon मध्ये ही instructions खरोखर नसल्यास, पहिल्या AES operation वेळी process Illegal instruction (core dumped) सह बंद होतो.
हा override माझ्या LUKS encrypted volume चा वेग वाढवेल का?
नाही. OPENSSL_ia32cap OpenSSL वाचते; इतर कोणतेही घटक ते वाचत नाहीत. LUKS आणि dm-crypt kernel crypto API वापरतात. Feature bit clear असल्यास aesni_intel module modprobe: ERROR: could not insert 'aesni_intel': No such device सह load होण्यात अपयशी ठरते. Kernel boot वेळी CPUID वाचतो. कोणतेही user-space variable हे बदलू शकत नाही. sudo cryptsetup benchmark -c aes-xts -s 256 वापरून प्रत्यक्ष figure मोजा आणि aes-xts 256b row flag दाखवणाऱ्या host वरील row शी तुलना करा.
AES-NI flag नसल्याने WireGuard चा वेग कमी होतो का?
नाही. WireGuard सर्व data साठी ChaCha20-Poly1305 वापरते आणि AES instructions कधीही वापरत नाही. त्यामुळे masked host आणि unmasked host वरील throughput समान असतो. AES-GCM सह configured OpenVPN आणि IPsec यांचा throughput AES-NI नसलेल्या host वर कमी होतो. त्यामुळे एकाच VPS वरील दोन tunnels वेगवेगळ्या प्रकारे कार्य करू शकतात. Network ला दोष देण्यापूर्वी ही बाब लक्षात घ्या.
ARM VPS वर AES-NI आहे का हे कसे तपासावे?
ARM cores मध्ये AES-NI नसते. त्यांच्यात ARMv8 cryptographic extensions असतात. वेगळ्या instructions वापरून त्या समान काम करतात. grep -m1 Features /proc/cpuinfo चालवा आणि aes व pmull शोधा. aarch64 मध्ये त्या Features अंतर्गत सूचीबद्ध असतात, flags अंतर्गत नाही. x86 OPENSSL_ia32cap value चा ARM वर अर्थ नाही. तेथील OpenSSL equivalent variable OPENSSL_armcap आहे. त्याची bit layout OpenSSL source मधील crypto/arm_arch.h मध्ये defined आहे.