Konfigurasi Libvirt Selamat dengan TLS dan Pengesahan Kerberos melalui SASL

Percubaan saya dengan libvirt pada mulanya tidaklah serius. Hanya ingin mengenali asas pengurusan mesin maya menerusi virt-install dan virsh, sambil-sambil membaca dokumentasi yang ditemui di Internet. Namun begitu, semakin lama saya mencuba, semakin tertarik saya kepada aspek keselamatan dan pengesahan sambungan klien dalam libvirt, sesuatu yang sebelum ini saya abaikan kerana berasakan tidak perlu.
Rujukan seperti ArchWiki hanya memperkenalkan topik autentikasi ini secara sepintas lalu, dengan pautan kepada dokumentasi rasmi: libvirt: Connection authentication. Dari sinilah saya mula menyelami secara lebih serius kaedah-kaedah autentikasi yang disokong oleh libvirt.
Memandangkan sistem saya sudahpun dikonfigurasikan dengan Kerberos sebagai kaedah pengesahan untuk sambungan SSH dalam rangkaian tempatan, saya tertarik untuk mengintegrasikan libvirt dengan Kerberos melalui GSSAPI. Dalam teori, ia kelihatan mudah, dan saya dengan penuh yakin menganggap ia boleh disiapkan dalam masa singkat.
Namun realitinya tidak begitu. Apa yang kelihatan mudah di permukaan, rupanya penuh dengan kekangan konfigurasi, modul yang tidak didokumentasikan sepenuhnya, dan cabaran pemahaman konsep SASL, TLS, serta hak akses pengguna. Beberapa kali saya hampir berputus asa, benar-benar terasa ingin berhenti.
Alhamdulillah, selepas beberapa pusingan cubaan, penyahpepijatan, dan bacaan lintang-pukang, saya akhirnya berjaya menyiapkan satu konfigurasi libvirt yang selamat, lengkap dengan sokongan TLS serta autentikasi Kerberos menggunakan SASL.
Catatan ini saya tulis bukan sahaja untuk rujukan pengguna lain yang ingin mencapai perkara sama, tetapi juga sebagai ingatan kepada diri sendiri bahawa jalan yang sukar selalunya menyimpan pelajaran yang tidak ternilai.
Skop dan Objektif Artikel
Artikel ini menggunakan pendekatan modular daemons, bukan lagi libvirtd.service. Jika anda masih menggunakan monolithic daemon, sesetengah bahagian perlu disesuaikan.
Penulisan ini memfokuskan kepada konfigurasi libvirt untuk menyokong sambungan selamat melalui protokol TLS serta pengesahan berasaskan Kerberos menggunakan modul SASL. Ia mengandaikan persekitaran rangkaian tempatan (LAN) yang telah sedia mempunyai perkhidmatan Kerberos dan akses kepada pengguna sah melalui GSSAPI.
Tujuan utama adalah untuk:
- Menyediakan konfigurasi
TLSyang betul antara hos dan klienlibvirt; - Mengaktifkan dan menyelaras modul
SASLdengan kaedahGSSAPIuntuk autentikasi pengguna berasaskanKerberos; - Menghurai isu-isu umum yang mungkin timbul semasa integrasi, termasuk konfigurasi hak akses, ralat modul, serta tingkah laku sambungan;
- Memberikan penyelesaian berasaskan senario sebenar, bukan sekadar bergantung pada dokumentasi rasmi.
Sasaran Pembaca
Artikel ini ditujukan kepada pengguna yang telah terbiasa dengan asas libvirt, serta memahami konsep asas Kerberos, SASL, dan konfigurasi perkhidmatan dalam sistem berasaskan Linux, khususnya Arch Linux dan yang setaraf dengannya.
Keperluan Sistem
Sesetengah sistem operasi tidak memasang plugin SASL Kerberos secara lalai. Anda boleh menyemak keberadaannya dengan arahan berikut:
bashpluginviewer | grep gssapiSekiranya tiada output terpapar, anda perlu memasang pakej cyrus-sasl-gssapi. Setelah dipasang, semakan semula menggunakan pluginviewer akan memaparkan mekanisme seperti berikut:
...
Plugin "gssapiv2" [loaded], API version: 4
SASL mechanism: GSSAPI, best SSF: 256, supports setpass: no
security flags: NO_ANONYMOUS|NO_PLAINTEXT|NO_ACTIVE|PASS_CREDENTIALS|MUTUAL_AUTH
features: WANT_CLIENT_FIRST|PROXY_AUTHENTICATION|DONTUSE_USERPASSWD
...
- Senarai pemasangan pakej (distribusi
Arch Linux) :
*virt-install/virt-manager
*virt-viewer(untuk akses GUI VM melalui protokol SPICE menggunakanremote-viewer)
*qemu-base
*qemu-hw-display-qxl
*qemu-ui-spice-app
*dnsmasq(diperlukan untukvirtual NAT bridge)
*dmidecode
*openssl(untuk penjanaan sijil TLS)edk2-ovmfswtpm
Senarai Pemilikan dan Mod Fail Sijil / Kunci TLS serta Keytab Kerberos
Saya kongsikan dahulu struktur pemilikan (pengguna & kumpulan) serta mod kebenaran direktori dan fail untuk sijil + kunci TLS serta keytab Kerberos.
- Mod direktori :
0750 - Mod fail sijil TLS :
0644 - Mod fail kunci TLS :
0600 - Mod fail keytab :
0600

- Tambah pengguna ke dalam kumpulan
libvirt-qemu:bashsudo usermod -aG libvirt-qemu $USER
Penghasilan Sijil TLS x509
Saya gunakan OpenSSL untuk menghasilkan kesemua sijil dan kunci di direktori $HOME saya sendiri, yang kemudian disalin dan ditampal ke direktori sebenar.
Sijil serta kunci CA akar dicipta hanya sekali dan disalin ke direktori-direktori projek yang memerlukan.
Sila rujuk libvirt | Public Key Infrastructure set up untuk mengetahui struktur direktori dan lokasi fail sijil yang betul.
Certificate Authority (CA)
cd ke dalam direktori ~/pki/CA.
Rujuk nota tepi saya tentang penjanaan sijil dan kunci TLS untuk CA akar dengan
OpenSSLdi sini: Jana Sijil HTTPS untuk Domain yang Berasaskan ’localhost’.Salin
cacert.pemke senarai direktori dan namakan semula sijilnya mengikut keperluan.bashcp cacert.pem ~/.pki sudo cp cacert.pem /etc/pki/CA sudo cp cacert.pem /etc/pki/libvirt-spice/ca-cert.pem
Libvirt (TLS x509)
Menjana Sijil Pelayan
cd ke dalam direktori ~/pki/libvirt/server.
Hasilkan permintaan sijil (CSR).
Nota penting:CNdi sini mesti dinyatakan dalam bentuk FQDN (nama hos penuh).bashopenssl req -out server.csr -new -newkey rsa:2048 -sha256 \ -noenc -keyout serverkey.pem \ -subj "/C=MY/ST=Negeri/L=Bandar/O=Libvirt-Project/CN=<pc.example.com>"Cipta fail konfigurasi dengan maklumat berikut. Edit DNS dan alamat IP yang merujuk ke PC sendiri.
~/pki/libvirt/server/configbasicConstraints=CA:FALSE keyUsage = digitalSignature, keyEncipherment extendedKeyUsage = serverAuth subjectAltName = @alt_names [alt_names] DNS.1 = pc.example.com IP.1 = 192.168.x.xTanda tangani sijil menggunakan CA akar yang dijana sebelum ini.
bashopenssl x509 -in server.csr \ -req -sha256 -out servercert.pem \ -days 365 -extfile config \ -CA ~/pki/CA/cacert.pem \ -CAkey ~/pki/CA/cakey.pem \ -CAcreateserialGunakan opsyen
-CAcreateserialjika ini adalah kali pertama anda menandatangani sijil. JikaCApernah menandatangani sijil lain, gantikan sahaja opsyen tersebut dengan-CAserial ~/pki/CA/cacert.srl.Salin sijil dan kunci pelayan yang dihasilkan ke direktori berikut.
bashsudo cp servercert.pem /etc/pki/libvirt sudo cp serverkey.pem /etc/pki/libvirt/private
Menjana Sijil Klien
cd ke dalam direktori ~/pki/libvirt/client.
Hasilkan permintaan sijil (CSR).
bashopenssl req -out client.csr -new -newkey rsa:2048 -sha256 \ -noenc -keyout clientkey.pem \ -subj "/C=MY/ST=Negeri/L=Bandar/O=Libvirt-Project/CN=<nama-klien>"Cipta fail konfigurasi dengan maklumat berikut.
~/pki/libvirt/client/configbasicConstraints=CA:FALSE keyUsage = digitalSignature, keyEncipherment extendedKeyUsage = clientAuthTanda tangani sijil menggunakan sijil CA akar yang dijana sebelum ini.
bashopenssl x509 -in client.csr \ -req -sha256 -out clientcert.pem \ ... (salin baris opsyen selebihnya)Salin sijil dan kunci pelayan yang dihasilkan ke direktori berikut.
bashcp clientcert.pem ~/.pki/libvirt cp clientkey.pem ~/.pki/libvirt sudo cp clientcert.pem /etc/pki/libvirt sudo cp clientkey.pem /etc/pki/libvirt/private
SPICE (TLS x509)
cd ke dalam direktori ~/pki/libvirt-spice.
Hasilkan permintaan sijil (CSR).
bashopenssl req -out server.csr -new -newkey rsa:2048 -sha256 \ -noenc -keyout server-key.pem \ -subj "/C=MY/ST=Negeri/L=Bandar/O=Libvirt-Spice/CN=<pc.example.com>"Cipta fail konfigurasi dengan maklumat berikut.
~/pki/libvirt-spice/configbasicConstraints=CA:FALSE keyUsage = digitalSignature subjectAltName = @alt_names ... (salin senarai nama alternatif yang terdapat pada fail konfig pelayan libvirt)Tanda tangani sijil menggunakan CA akar yang dijana sebelum ini.
Salin sijil dan kunci pelayan yang dihasilkan ke direktori berikut.
bashsudo cp server-cert.pem /etc/pki/libvirt-spice sudo cp server-key.pem /etc/pki/libvirt-spice
Konfigurasi GSSAPI/Kerberos
Libvirt (GSSAPI)
Menurut dokumentasi rasmi libvirt di pautan GSSAPI/Kerberos auth, hos perlu memiliki satu prinsipal iaitu libvirt/full.hostname@KERBEROS.REALM. Prinsipal ini perlu dieksport ke dalam keytab dan diletakkan di lokasi khusus, iaitu /etc/libvirt/krb5.tab.
Namun begitu, berdasarkan pengalaman saya, hanya meletakkan satu prinsipal ini mengakibatkan kegagalan proses autentikasi. Berikut ialah mesej ralat yang saya hadapi:
virtproxyd: authentication failed: Failed to start SASL negotiation: -13 (SASL(-13): authentication failure: GSSAPI Failure: gss_accept_sec> virtproxyd: authentication failed: authentication failed virtproxyd: Cannot recv data: Input/output error
Saya mendapati bahawa autentikasi hanya berjaya setelah saya menambah dua prinsipal berikut ke dalam fail krb5.tab.
host/pc.example.com@EXAMPLE.COMlibvirt/pc.example.com@EXAMPLE.COM
Tambah kunci untuk servis
libvirt.bashsudo kadmin.localkadmin.local: addprinc -randkey libvirt/pc.example.com No policy specified for libvirt/pc.example.com@EXAMPLE.COM; defaulting to no policy Principal "libvirt/pc.example.com@EXAMPLE.COM" created. kadmin.local: ktadd -k /etc/libvirt/krb5.tab libvirt/pc.example.com Entry for principal libvirt/pc.example.com with kvno 2, encryption type aes256-cts-hmac-sha384-192 added to keytab WRFILE:/etc/libvirt/krb5.tab. Entry for principal libvirt/pc.example.com with kvno 2, encryption type aes128-cts-hmac-sha256-128 added to keytab WRFILE:/etc/libvirt/krb5.tab.
Semak kandungan
keytab:bashsudo klist -kt /etc/libvirt/krb5.tabKeytab name: FILE:/etc/libvirt/krb5.tab KVNO Timestamp Principal ---- ------------------- ------------------------------------------------------ 3 08/01/2025 11:46:03 host/pc.example.com@EXAMPLE.COM 3 08/01/2025 11:46:03 host/pc.example.com@EXAMPLE.COM 2 08/01/2025 11:57:17 libvirt/pc.example.com@EXAMPLE.COM 2 08/01/2025 11:57:17 libvirt/pc.example.com@EXAMPLE.COM
SPICE (GSSAPI)
Autentikasi SASL melalui GSSAPI juga disokong oleh SPICE, akan tetapi proses konfigurasi ini lebih rumit berbanding libvirt. Dokumentasi yang tersedia banyak merujuk kepada penggunaan prinsipal qemu/full.hostname@KERBEROS.REALM, yang ternyata tidak berfungsi dalam kes saya.
Hanya selepas beberapa kali percubaan, barulah muncul ralat yang mendedahkan prinsipal sebenar yang diperlukan:
(remote-viewer): GSpice-CRITICAL : Failed to start SASL negotiation: -1 (SASL(-1): generic failure: GSSAPI Error: Unspecified GSS failure. Minor code may provide more information (Server spice/pc.example.com@EXAMPLE.COM not found in Kerberos database))
Rupa-rupanya, SPICE menjangkakan prinsipal spice/FQDN@REALM, bukannya qemu.
Berikut ialah langkah-langkah yang saya ambil untuk menyelesaikan isu ini:
Tambah prinsipal
spice/pc.example.comdengan opsyen-randkeymenggunakankadmin.local.Eksport kunci prinsipal ini ke dalam fail
/etc/qemu/krb5.tab.
Fail Konfigurasi TLS + SASL (GSSAPI) Libvirt
/etc/libvirt/virtproxyd.conflisten_tls = 1
auth_tls = "sasl"/etc/sasl2/libvirt.confmech_list: gssapi
keytab: /etc/libvirt/krb5.tabFail Konfigurasi TLS + SASL (GSSAPI) SPICE
/etc/libvirt/qemu.confspice_listen = "0.0.0.0"
spice_tls = 1
spice_sasl = 1/etc/sasl2/qemu.confmech_list: gssapi
keytab: /etc/qemu/krb5.tabUji Sambungan
Sebelum saya mengaktifkan sambungan supaya servis dan soket yang berkaitan bermula secara automatik semasa boot, saya hanya mulakan sahaja dahulu segalanya sebagai langkah menguji. Rujuk dokumentasi
libvirtdi Modular driver daemons: Switching to modular daemons untuk bacaan lanjut.Mulakan servis dan soket untuk set daemon berikut:
bashfor drv in qemu network nodedev storage do sudo systemctl start virt${drv}d{,-ro,-admin}.socket done sudo systemctl start virtproxyd{,-ro,-admin}.socket sudo systemctl start virtproxyd-tls.socketDalam perintah baris mula-mula di atas, situasi saya cuma memerlukan pemacu hypervisor
virtqemud, serta pemacu-pemacu kedua iaituvirtnetworkd,virtnodedevddanvirtstoraged. Oleh itu, saya hanya mengaktifkan daemon dan soket yang berkaitan dengan perkhidmatan berkenaan.kinitdan semak tiket:bashkinit <username> klistTicket cache: KEYRING:persistent:1000:1000 Default principal: <username>@EXAMPLE.COM
Valid starting Expires Service principal 08/02/2025 22:36:06 08/03/2025 08:36:06 krbtgt/EXAMPLE.COM@EXAMPLE.COM renew until 08/09/2025 22:36:06Kemas kini fail konfig
shell(i.e..bashrcatau.zshrc) dengan menambah environment URI lalai untuk sambungan.~/.zshrcexport LIBVIRT_DEFAULT_URI="qemu://pc.example.com/system"sourcefail konfigshell.~/.zshrcsource ~/.zshrcUji sambungan dengan arahan
virshdan semak URI sambungan dengan menaipuri. Arahan tersebut akan mengembalikan alamat yang ditetapkan dalam fail~/.zshrctadi:bashvirshWelcome to virsh, the virtualization interactive terminal.
Type: 'help' for help with commands'quit' to quitvirsh # uri qemu://pc.example.com/systemJika berjaya, semakan tiket seterusnya akan turut memaparkan prinsipal servis untuk
libvirt:... Valid starting Expires Service principal 08/02/2025 22:45:12 08/03/2025 08:36:06 libvirt/pc.example.com@EXAMPLE.COM renew until 08/09/2025 22:36:06 ...Semak status perkhidmatan jika timbul sebarang isu untuk melihat mesej ralat:
bashsudo systemctl status <service-name>
Cipta VM
Demi ujian pantas, gunakan aplikasi GUI
virt-manageruntuk mencipta VM.Opsyen untuk paparan
spicedenganTLSsekiranya menggunakanvirt-install:--graphics spice,listen=0.0.0.0,defaultMode=secure
- Jika mengubah terus
XMLdomain:<graphics type='spice' autoport='yes' defaultMode='secure'> <listen type='address' address='0.0.0.0'/> </graphics>
Paparan grafik
SPICEuntuk mengakses GUI VM boleh didapatkan dengan arahan berikut:bashremote-viewer --spice-ca-file=/etc/pki/libvirt-spice/ca-cert.pem "spice://pc.example.com?tls-port=5900"Setelah memastikan semuanya berjalan lancar, barulah saya aktifkan
systemduntuk memulakan modular daemon bagi pemacu terlibat semasa sistem boot.bashfor drv in qemu network nodedev storage do sudo systemctl unmask virt${drv}d.service sudo systemctl unmask virt${drv}d{,-ro,-admin}.socket sudo systemctl enable virt${drv}d.service sudo systemctl enable virt${drv}d{,-ro,-admin}.socket done sudo systemctl unmask virtproxyd.service sudo systemctl unmask virtproxyd{,-ro,-admin}.socket sudo systemctl enable virtproxyd.service sudo systemctl enable virtproxyd{,-ro,-admin}.socket sudo systemctl unmask virtproxyd-tls.socket sudo systemctl enable virtproxyd-tls.socket
Penyelesaian Masalah
Jika
libvirt NATgagal mendapatkan alamatDHCP, pastikanfirewalltidak menyekat rangkaianvirbr0: Gunakan peraturan umum berikut untuk membenarkan trafik NAT dan DHCP:bashsudo ufw allow in on virbr0 sudo ufw allow out on virbr0 sudo ufw reloadvirbr0ialah antara muka rangkaian maya (virtual bridge) yang digunakan olehlibvirtsecara lalai untuk NAT.Isu kebenaran ditolak melibatkan hak akses ke direktori sistem:
Pastikan direktori/var/lib/libvirt/imagesdimiliki oleh pengguna dan kumpulanlibvirt-qemu.Jika berlaku ralat dalaman (’internal error’) semasa memulakan pemasangan VM yang menolak paparan grafik
SPICE, cuba tukarkan paparan grafik kepadaVNCterlebih dahulu. Yang penting, pemasangan berjalan dan VM-nya wujud. Kemudian, bolehlah sunting perincian VM tersebut untuk mendapatkan paparan grafikSPICEdengan autentikasi TLS + GSSAPI (SASL), baik melaluivirt-manager, mahupunvirsh.
Kesimpulan
Pendekatan modular daemons dalam konfigurasi libvirt yang digabungkan dengan sokongan TLS dan GSSAPI (Kerberos) menawarkan kelebihan dari aspek keselamatan dan pengasingan perkhidmatan.
Walau bagaimanapun, pelaksanaannya bukanlah sesuatu yang mudah memandangkan dokumentasi rasmi agak terpecah dan memerlukan pemahaman mendalam terhadap Kerberos, SASL, dan pengurusan TLS.
Semoga catatan ini dapat membantu pengguna lain yang sedang mencuba kaedah autentikasi selamat untuk libvirt.
