Linux Kernel TLS dan Nginx

Dalam artikel ini saya akan berbicara tentang sejarah perkembangan dan kondisi teknologi saat ini untuk mempercepat distribusi konten dalam koneksi TLS dengan mentransfer enkripsi ke inti sistem operasi, serta tentang kontribusi saya untuk pengembangan arah ini.

Latar Belakang


Kembali pada tahun 2015, Randall Stewart dan Scott Long dari Netflix membuat presentasi di konferensi AsiaBSDCon2015 tentang mengoptimalkan distribusi konten terenkripsi. Pesan utama dari laporan ini adalah untuk mentransfer enkripsi data ke kernel sistem operasi untuk mengurangi jumlah salinan data antara ruang-kernel dan ruang-pengguna dan menggunakan panggilan sistem sendfile () non-blocking yang dioptimalkan. Topiknya ternyata sangat menjanjikan dan sudah pada konferensi Netdev 1.2 2016, Dave Watson dari Facebook membuat presentasi tentang perlunya membuat soket TLS di kernel Linux, dan Boris Pismenny, Ilya Lesokhin dan Liran Liss dari Mellanox membuat presentasitentang kemampuan untuk menggunakan akselerasi perangkat keras TLS dalam kartu jaringan. Topik ini juga dibahas di HighLoad ++ 2017 oleh pembicara dari Tempesta Technologies.

Dukungan kernel Linux


Hasil dari semua percakapan ini adalah munculnya Kernel TLS di Linux 4.13 kernel (2017) dengan dukungan untuk TLSv1.2 dan cipher AES128-GCM. Awalnya, enkripsi hanya lalu lintas keluar didukung, dukungan dekripsi muncul kemudian di kernel Linux 4.17 (2018). Dalam versi 5.1, mereka menambahkan dukungan untuk TLSv1.3 dan AES256-GCM, dan dalam versi 5.2 mereka juga menambahkan cipher AES128-CCM (2019).

Dukungan di ruang pengguna


Dalam semua laporan yang disebutkan di atas, dikatakan bahwa hanya enkripsi data berguna yang dapat ditempatkan di kernel, dan semua persetujuan TLS dan pesan kontrol harus ditangani sama di ruang pengguna. Dan untuk ini, versi OpenSSL yang dimodifikasi digunakan. Namun, pada saat publikasi laporan dalam domain publik tidak ada informasi tentang modifikasi yang perlu dilakukan pada perpustakaan terkenal ini untuk mendukung fungsi tersebut. Mungkin satu-satunya contoh menggunakan Linux Kernel TLS yang tersedia adalah artikel blog Filippo Valsorda Playing dengan kernel TLS di Linux 4.13 dan Go, yang muncul segera setelah rilis kernel Linux 4.13. Dan, meskipun menunjukkan contoh yang valid dari penggunaan teknologi, itu tidak membawa pemahaman tentang bagaimana menggunakan teknologi dalam proyek nyata. Memang, sangat sedikit orang yang menulis server WEB untuk proyek mereka sendiri, biasanya semua orang menggunakan alat yang terkenal dan telah teruji waktu.

Dukungan dalam OpenSSL


Diskusi pertama teknologi di OpenSSL muncul pada musim panas 2017 tak lama sebelum rilis Linux 4.13 kernel ( PR 3631 ), tetapi proses diskusi sangat, sangat lambat, komentar nyata pertama muncul pada bulan Oktober (setelah rilis kernel 4.13), dan versi kerja yang sebenarnyamulai berdiskusi pada Februari 2018. Pada saat semua koreksi disetujui, jendela untuk menambahkan fungsionalitas baru di OpenSSL 1.1.1 ditutup, dan dukungan untuk Kernel TLS dipindahkan ke rilis berikutnya. Sejak saat itu, dukungan Kernel TLS RX telah ditambahkan, dan SSL_sendfile () adalah panggilan ke syscall terkait dengan sedikit pemrosesan kemungkinan situasi dalam protokol TLS. Tetapi sekarang di tahun 2020, OpenSSL 3.0 belum keluar, TLSv1.3 didukung oleh sebagian besar browser, dan cipher AES128-GCM secara aktif diganti oleh AES256-GCM yang lebih tahan. Jadi saya mengambil kebebasan dan mengirim Permintaan Tarik untuk mendukung sandi dan TLSv1.3 baru dengan harapan mereka akan menerimanya sebelum rilis baru perpustakaan.

Dukungan di WEB-server


Tetapi mendukung Kernel TLS di perpustakaan TLS tidak cukup. Laporan tentang teknologi mengatakan bahwa efisiensi maksimum dapat diperoleh dengan mengirim tanpa menyalin data ke ruang pengguna - menggunakan panggilan sistem sendfile (). Dan aplikasi server harus dapat membedakan antara situasi di mana Anda dapat menggunakan sendfile () pada soket dengan TLS, dan ketika Anda perlu melakukan "baca cara lama" baca () / SSL_write (). Beberapa kemajuan dalam menambahkan fungsionalitas ke Nginx muncul pada April 2019, tetapi tidak ada perubahan yang diterima pada kode utama. Posisi pengembang adalah bahwa API untuk fungsi-fungsi ini belum disetujui di OpenSSL, dan kode aktual yang diusulkan dalam tambalan tampaknya tidak cukup portabel untuk platform yang berbeda. Sejujurnya, kode ini tidak hanya tidak terlihat sangat bagus, tetapi juga mengandung kesalahan yang mencegah Nginx dibangun tanpa koreksi tambahan.Saya tidak dapat menemukan dukungan Kernel TLS di server web lain sama sekali (mungkin seseorang melihatnya - beri tahu saya di komentar).

Dan apa yang harus dilakukan?


Sementara komunitas sedang menunggu rilis OpenSSL 3.0, untuk mulai mengembangkan dukungan untuk Kernel TLS di Nginx dengan API yang stabil, saya memilih sebaliknya. Di sudut nyaman saya di GitHub, saya melakukan 2 hal:

  1. Saya membuat garpu OpenSSL dan meng-backport semua yang terkait dengan Kernel TLS ke versi stabil OpenSSL 1.1.1 (cabang OpenSSL_1_1_1-ktls). Terutama agar dapat memeriksa fungsionalitas dalam kondisi operasi yang stabil dari seluruh perpustakaan. Ketika versi stabil tersedia, saya mencoba untuk rebase sehingga fork up to date.
  2. Saya membuat garpu Nginx, di mana saya menambahkan (berdasarkan tambalan dari Mellanox) dukungan untuk memanggil SSL_sendfile () dalam kondisi ketika itu benar-benar mungkin dan dengan pemeriksaan soket SSL yang diperlukan, dan kemampuan untuk mengaktifkan / menonaktifkan fungsi melalui variabel konfigurasi. Selain fitur ini, di garpu saya ada juga beberapa tambalan yang mengoptimalkan kerja Nginx sedikit dan memperbaiki beberapa bug (master-feature branch). Sejauh mungkin, saya mencoba untuk rebase berdasarkan cabang utama dari repo utama Nginx, agar garpu tetap up to date.

Saya mengundang semua orang untuk ikut serta dalam pengujian. Komentar dan koreksi kode dapat dilemparkan ke Issue on GitHub. Untuk membangun Nginx ini dengan OpenSSL ini dan dukungan TLS Kernel yang disertakan, tambahkan parameter ke skrip configure:

./configure --with-openssl=<OpenSSL-fork-dir> --with-openssl-opt="enable-ktls"

Saat ini, saya tidak memiliki kesempatan untuk menguji bundel Nginx + OpenSSL ini di bawah beban berat untuk mengonfirmasi kinerja dari komentar di patch Nginx, jadi jika tiba-tiba seseorang dapat mengukur perbedaan dalam beban CPU dengan kecepatan unggah file yang tinggi, akan sangat bagus untuk mendapatkan grafik dan menambahkan mereka menjadi sebuah artikel untuk pemahaman visual tentang efeknya.

All Articles