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 TLS yang betul antara hos dan klien libvirt ;
  • Mengaktifkan dan menyelaras modul SASL dengan kaedah GSSAPI untuk autentikasi pengguna berasaskan Kerberos ;
  • 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:

bash
pluginviewer | grep gssapi

Sekiranya 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
...

Perisian Tambahan diperlukan:

  • dnsmasq : diperlukan untuk virtual NAT bridge.
  • certtool atau OpenSSL : untuk penjanaan sijil TLS.
  • remote-viewer : untuk akses GUI VM melalui protokol SPICE.

Konfigurasi Autentikasi GSSAPI/Kerberos

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.

  1. host/full.hostname@EXAMPLE.COM
  2. libvirt/full.hostname@EXAMPLE.COM

Tambah kunci untuk servis libvirt

  • bash
    sudo kadmin.local
    kadmin.local:  addprinc -randkey libvirt/full.hostname
    No policy specified for libvirt/full.hostname@EXAMPLE.COM; defaulting to no policy
    Principal "libvirt/full.hostname@EXAMPLE.COM" created.
    kadmin.local:  ktadd -k /etc/libvirt/krb5.tab libvirt/full.hostname
    Entry for principal libvirt/full.hostname with kvno 2, encryption type aes256-cts-hmac-sha384-192 added to keytab WRFILE:/etc/libvirt/krb5.tab.
    Entry for principal libvirt/full.hostname with kvno 2, encryption type aes128-cts-hmac-sha256-128 added to keytab WRFILE:/etc/libvirt/krb5.tab.
    
  • Semak kandungan keytab :

    bash
    sudo klist -kt /etc/libvirt/krb5.tab
    Keytab name: FILE:/etc/libvirt/krb5.tab
    KVNO Timestamp           Principal
    ---- ------------------- ------------------------------------------------------
       3 08/01/2025 11:46:03 host/full.hostname@EXAMPLE.COM
       3 08/01/2025 11:46:03 host/full.hostname@EXAMPLE.COM
       2 08/01/2025 11:57:17 libvirt/full.hostname@EXAMPLE.COM
       2 08/01/2025 11:57:17 libvirt/full.hostname@EXAMPLE.COM
    

Uji Sambungan Menggunakan TCP

Sebagai langkah awal, saya memulakan ujian sambungan menggunakan protokol TCP sebelum mengaktifkan TLS. Hal ini memudahkan saya mengasingkan isu berkaitan autentikasi tanpa diganggu masalah sijil keselamatan.

  1. Konfigurasi Fail Berkaitan:

    Apabila beralih kepada sambungan TLS, tukar nilai “listen_tls” kepada 1 dan “listen_tcp” kepada 0. Nyahkomen juga auth_tls="sasl".

    /etc/libvirt/virtproxyd.conf
    listen_tls = 0
    listen_tcp = 1
    auth_tcp = "sasl"
    #auth_tls = "sasl"
    /etc/sasl2/libvirt.conf
    mech_list: gssapi
    keytab: /etc/libvirt/krb5.tab
  2. Saya rujuk dokumentasi libvirt di Modular driver daemons: Switching to modular daemons untuk mengaktifkan perkhidmatan berkaitan:

    bash
    for drv in qemu network
      do
        sudo systemctl enable virt${drv}d.service virt${drv}d{,-ro,-admin}.socket
      done
  3. Mulakan soket untuk set daemon yang sama:

    bash
    for drv in qemu network
      do
        sudo systemctl start virt${drv}d{,-ro,-admin}.socket
      done
  4. Aktifkan juga perkhidmatan virtproxyd :

    bash
    sudo systemctl enable virtproxyd.service virtproxyd{,-ro,-admin}.socket
    sudo systemctl start virtproxyd{,-ro,-admin}.socket

    Dalam konfigurasi ini, hanya virtqemud, virtnetworkd, dan virtproxyd digunakan. Oleh itu, saya hanya mengaktifkan daemon dan soket yang berkaitan dengan ketiga-tiga perkhidmatan tersebut.

  5. kinit dan semak tiket:

    bash
    kinit <username>
    klist
    Ticket 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:06
  6. Mulakan soket virtproxyd-tcp :

    bash
    sudo systemctl start virtproxyd-tcp.socket
  7. Gunakan arahan di bawah untuk uji sambungan:

    bash
    virsh -c qemu+tcp://<hostname>/system

    Gantikan <hostname> dengan nama hostname / FQDN yang ditetapkan untuk alamat IP peranti anda di dalam fail /etc/hosts.

    Jika 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/full.hostname@EXAMPLE.COM
            renew until 08/09/2025 22:36:06
    ...
    

Konfigurasi Sijil TLS x509

Setelah autentikasi GSSAPI berfungsi menggunakan protokol TCP, saya beralih kepada konfigurasi sambungan TLS yang lebih selamat dan disokong sepenuhnya oleh libvirt.

certtool

  1. Rujuk libvirt | Public Key Infrastructure set up untuk mengetahui struktur direktori dan lokasi fail sijil yang betul.

  2. Ikuti langkah-langkah penjanaan sijil CA, pelayan dan klien dari pautan tersebut.

  3. Tambah entri encryption_key dalam fail server.info dan client.info untuk mengelakkan ralat decryption failed:

    server.info
    ...
    tls_www_server
    encryption_key
    signing_key
    client.info
    ...
    tls_www_client
    encryption_key
    signing_key
  4. Kemudian, sunting /etc/libvirt/virtproxyd.conf semula untuk mengaktifkan TLS.

  5. Aktifkan dan mulakan soket virtproxyd-tls :

    bash
    sudo systemctl enable --now virtproxyd-tls.socket

Uji Sambungan Menggunakan TLS

  • Gunakan arahan di bawah untuk uji sambungan menggunakan TLS :

    bash
    virsh -c qemu://full.hostname/system

    Saya menetapkan dua nama hos bagi peranti ini:

    1. kdc.archey.loc
    2. wrarchey

    Walau bagaimanapun, hanya nama hos penuh pertama yang berjaya disambung. Hostname pendek seperti wrarchey gagal kerana sijil tidak memadankan nama hos.

    warning : virNetTLSContextCheckCertificate:532 : Certificate check failed Certificate [session] owner does not match the hostname wrarchey
    error: failed to connect to the hypervisor
    error: authentication failed: Failed to verify peer's certificate
    
  • Semak status perkhidmatan virtqemud, virtnetworkd dan virtproxyd dengan arahan:

    bash
    sudo systemctl status <service-name>

Konfigurasi SPICE (GUI VM)

  • Nyahkomen baris berikut pada fail:

    /etc/libvirt/qemu.conf
    spice_listen = "0.0.0.0"
    spice_tls = 1
  • Sijil untuk SPICE perlu diletakkan di /etc/pki/libvirt-spice. Direktori ini mesti mengandungi:

    1. ca-cert.pem - sijil CA
    2. server-cert.pem - sijil pelayan
    3. server-key.pem - kunci peribadi pelayan
  • Opsyen untuk paparan spice dengan TLS sekiranya menggunakan virt-install :

    --graphics spice,listen=0.0.0.0,defaultMode=secure 
    

  • Jika mengubah terus XML domain:
    <graphics type='spice' autoport='yes' defaultMode='secure'>
      <listen type='address' address='0.0.0.0'/>
    </graphics>
    

  • Akses GUI VM melalui SPICE :
    bash
    remote-viewer --spice-ca-file=/etc/pki/libvirt-spice/ca-cert.pem "spice://full.hostname?tls-port=5900"

Penjanaan Sijil untuk SPICE

Menggunakan OpenSSL

  • Rujuk artikel Jana Sijil HTTPS untuk Domain yang Berasaskan ’localhost’ sebagai panduan asas.

  • Ubah suai fail domains.ext agar sesuai untuk digunakan dengan spice, dengan melakukan penyesuaian berikut:

    1. Sunting nilai keyUsage dan kekalkan hanya digitalSignature. Nilai ini sahaja sudah mencukupi kerana SPICE menggunakan sijil ini untuk tujuan pengesahan identiti, bukan penyulitan berlapis seperti HTTPS.

    2. Gantikan entri nama domain localhost dengan nama domain yang merujuk kepada alamat IP peranti anda.

Menggunakan certtool

  • Prosedurnya sama seperti untuk libvirt, tetapi untuk spice, anda tidak perlu menyertakan entri encryption_key dalam fail server.info, kerana SPICE tidak memerlukan fungsi penyulitan tahap tinggi yang sama.

Autentikasi SASL (GSSAPI/Kerberos) untuk SPICE

Autentikasi SASL melalui GSSAPI juga disokong oleh SPICE, namun 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 sebenar 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/full.hostname@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:

  1. Tambah prinsipal spice/full.hostname dengan opsyen -randkey menggunakan kadmin.local.

  2. Eksport kunci prinsipal ini ke dalam fail /etc/qemu/krb5.tab.

  3. Tetapkan pemilikan fail tersebut kepada pengguna dan kumpulan libvirt-qemu.

  4. Nyahkomen entri di bawah pada fail berikut:

    /etc/libvirt/qemu.conf
    spice_sasl = 1
  5. Pastikan fail yang seterusnya ini mengandungi baris-baris berikut:

    /etc/sasl2/qemu.conf
    mech_list: gssapi
    keytab: /etc/qemu/krb5.tab
  6. Mulakan semula semua perkhidmatan yang berkaitan:

    bash
    for drv in qemu network
      do
        sudo systemctl restart virt${drv}d{,-ro,-admin}.socket
      done
    sudo systemctl restart virtproxyd{,-ro,-admin}.socket
    sudo systemctl restart virtproxyd-tls.socket

Penyelesaian Masalah

  • Sambungan ke rangkaian maya NAT bridge gagal disebabkan sekatan firewall Saya menggunakan UFW, dan perlu membuka port serta antara muka yang berkaitan:

    bash
    sudo ufw allow in on virbr0
    sudo ufw allow out on virbr0
    sudo ufw allow in proto udp from 192.168.122.0/24 to any port 67

    virbr0 ialah antara muka rangkaian maya (virtual bridge) yang digunakan oleh libvirt secara lalai untuk NAT.

  • Isu kebenaran ditolak melibatkan hak akses ke direktori sistem Pastikan pengguna dan kumpulan libvirt-qemu mempunyai akses penuh ke direktori berikut:

    1. /var/lib/libvirt/images
    2. /etc/pki/libvirt-spice

    Tambahkan juga pengguna anda ke dalam kumpulan libvirt dan libvirt-qemu:

    bash
    sudo usermod -aG libvirt,libvirt-qemu $USER

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.


Kali terakhir dikemaskini:

Tentang Blog & Penulis

Topik perbincangan dalam blog ini merangkumi Linux dan perisian sumber terbuka, Virtual Machine, serta Typesetting system.
Fokus semasa: Full Stack Development
Minat sampingan: Analisis Data
Bakat tersembunyi hamba: Menyanyi dan melukis.

Sumber dari Wallpaper Cave.