From nobody Mon Feb 2 07:25:57 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass(p=reject dis=none) header.from=lists.libvirt.org ARC-Seal: i=1; a=rsa-sha256; t=1767982369; cv=none; d=zohomail.com; s=zohoarc; b=LRiseyr1HbuO5g/DSllM4vzacrYd9yE4+zS0mdCsWouUic01xCKo5xi2yhZRkD9zeH81/l5AWCljWfU71nIM+WUxvobcjANV27a0IkQxuIeaGPpmVVCF+1wJkHGfkuu3FVVw59xYor7MWbMATFIxFxRG8mN2am3twcjdKwlJO/k= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1767982369; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Owner:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Subject:Subject:To:To:Message-Id; bh=M9+8i5xfhA7DnB0DcE7PEN4oPUUzX9+rJEKOGgu00Zo=; b=QPdUscZokfz66dULu/KCg0esu9iRk6kxRC240BqdAVo4FxkI7s21FaVIA0EhbVY7eHt6ZIuayAUeROdlE8sTjEsKUv+TfxRdPDphBesR1C1wDlwXAjnKFZF2y2ZkbYDMQHYwd0vqiawK2n/p2uiicBDk6tPHMUzmboiwhjZNP0k= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1767982369284850.840281091009; Fri, 9 Jan 2026 10:12:49 -0800 (PST) Received: by lists.libvirt.org (Postfix, from userid 993) id 12ABB41B95; Fri, 9 Jan 2026 13:12:48 -0500 (EST) Received: from [172.19.199.83] (lists.libvirt.org [8.43.85.245]) by lists.libvirt.org (Postfix) with ESMTP id 0091A43E81; Fri, 9 Jan 2026 13:10:08 -0500 (EST) Received: by lists.libvirt.org (Postfix, from userid 993) id 16E1143E00; Fri, 9 Jan 2026 13:09:48 -0500 (EST) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (3072 bits) server-digest SHA256) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id CB94543E07 for ; Fri, 9 Jan 2026 13:09:46 -0500 (EST) Received: from mail-pg1-f199.google.com (mail-pg1-f199.google.com [209.85.215.199]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-463-rjPDOIEqPJKtfriM9QFaAA-1; Fri, 09 Jan 2026 13:09:44 -0500 Received: by mail-pg1-f199.google.com with SMTP id 41be03b00d2f7-c1290abb178so3763146a12.2 for ; Fri, 09 Jan 2026 10:09:44 -0800 (PST) Received: from armenon-kvm.armenon-thinkpadp16vgen1.bengluru.csb ([49.36.108.228]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2a3e3cc8803sm111020495ad.71.2026.01.09.10.09.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 09 Jan 2026 10:09:42 -0800 (PST) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-3.4 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_LOW, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED,RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED,SPF_PASS autolearn=unavailable autolearn_force=no version=4.0.1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1767982186; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=M9+8i5xfhA7DnB0DcE7PEN4oPUUzX9+rJEKOGgu00Zo=; b=BwnzYX73eiHb3WRBAJLuJaullNtqY0x4mU3uY76TdZNRaBSNbI6k4zQkLiVbcKdHZOice0 dhSYh4w1He97xYrggbcNdXdIUWLA7PdUB2r1STu6WZbICZILMisy2g19z6FZVFKoeSEG67 Eu7DKKasCfftatJZcAmjl6+fyi+Z3k4= X-MC-Unique: rjPDOIEqPJKtfriM9QFaAA-1 X-Mimecast-MFC-AGG-ID: rjPDOIEqPJKtfriM9QFaAA_1767982184 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767982183; x=1768586983; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=M9+8i5xfhA7DnB0DcE7PEN4oPUUzX9+rJEKOGgu00Zo=; b=m/TxJ5yHfy0LUkhssMG49qlrBcBb6VJSUmzNc//ALKp8rR9uL/mwAiioExq81xRe7W 4afPh0DkAtxFmpCa9I+1hRoOMSRYKK/ATHD/OYaUCX8YXbADfzcpUzAPfSuoRccgIBWL wDoneHzpMpuB+SBS8hyYOzE8F/mKVI2DzSdUL5sr7zYInA9DrGKVJ7Eo4nonJhm2TwFK ONr4oqZXbDLARFlH+dT/pegVXWksL+vYmM5wQHNVO5Onr6LIbbp4hhSiawiFLAyd273m jJWtpCU9BtTWeguCr/UA1zqtnaRZ41o2d/dHKz64q8UX6fp+6mXz1Im6YYiSFtWErohN 0nWA== X-Gm-Message-State: AOJu0YyZr/YAFjpxukGEbEt9wuClRLu4c8e+LvJvgJH9KzqhDbSKrnxq z0RnNB9QKROnTf+Kax7UKkXx+Q/zESqJThJY/uBh+Y/zRMs9P2/ZSL4/Zq0X3gXm+z1Uog99a/q nITXStMwspu/jLY+VSoCC1kDNdZTtnL/oUrJ3Kbx4XWkaMmKQUsoPZTxhp2G+ryBOZA83o1ixzP 4H/CUQIZJ46IEbnwu4fzl/AFhJ2xf6HeuTlmEnJtzYsg== X-Gm-Gg: AY/fxX64ZpzHanX3dDcwPMMLrwmfvGSyfkfigvBrT9X8NAjF2jMRdWvUKV+y+/9B/ex 6SlUZbNrCJhKcralIHxh+UGXcYF7fcx1f0ZT7u3tJIMDJTmy8tIujJdBWdrWzryPPedusgfc69s tLAoTO8qcYx3FG1QyGZNMdcU5Zx886eXx+KfJEJWyjXwUGfULC0bx5k1Md6lS3Fy96UmKZt5nFC yXQS5xBSww31heqaE8b5XHXeyN1UI1o8WADPZ3YAZhUzY4hY0VSvqAbAcTde/kRVS5ID0XiIhpM Eg9T7zVZYoyaU6c7BMf7zy8zelFMmyHkIhQ4QkgH4spQTzgnTctUI2SpC/JLQ2eRacW8+vh+OcH TgL+Q+DLru1N/K5auhu3CxFtUT/cNvmmec6n0aN2sB0PlERx6CI8p0/iTUg== X-Received: by 2002:a05:6a20:3943:b0:35f:7e97:a08a with SMTP id adf61e73a8af0-3898f8f4bd6mr8614868637.9.1767982183256; Fri, 09 Jan 2026 10:09:43 -0800 (PST) X-Google-Smtp-Source: AGHT+IHTIAS9tGQcK9+O6aFOGbq9Mx8/4QDvnPVU53SfkvxlktrSRmYV/DHJrwU+GdGBs0ImHETIow== X-Received: by 2002:a05:6a20:3943:b0:35f:7e97:a08a with SMTP id adf61e73a8af0-3898f8f4bd6mr8614840637.9.1767982182637; Fri, 09 Jan 2026 10:09:42 -0800 (PST) To: devel@lists.libvirt.org Subject: [PATCH v4 1/6] util: Add support for GnuTLS decryption Date: Fri, 9 Jan 2026 23:39:31 +0530 Message-ID: <20260109180936.127454-2-armenon@redhat.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20260109180936.127454-1-armenon@redhat.com> References: <20260109180936.127454-1-armenon@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: gc9suzRqCPP-pJ5iX3RLhzvSgnFwuoYcV-3eqA5lkhA_1767982184 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Message-ID-Hash: T4DPQO5OIQ5JI2VYKAB66W6JPPPH5HY4 X-Message-ID-Hash: T4DPQO5OIQ5JI2VYKAB66W6JPPPH5HY4 X-MailFrom: armenon@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-devel.lists.libvirt.org-0; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Arun Menon X-Mailman-Version: 3.3.10 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Arun Menon via Devel Reply-To: Arun Menon X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1767982376525158500 Content-Type: text/plain; charset="utf-8"; x-default="true" Adds `virCryptoDecryptDataAESgnutls` and `virCryptoDecryptData` as wrapper functions for GnuTLS decryption. These functions are the inverse of the existing GnuTLS encryption wrappers. This commit also includes a corresponding test case to validate data decryp= tion. Signed-off-by: Arun Menon Reviewed-by: Peter Krempa --- src/libvirt_private.syms | 1 + src/util/vircrypto.c | 126 ++++++++++++++++++++++++++++++++++++++- src/util/vircrypto.h | 8 +++ tests/vircryptotest.c | 65 ++++++++++++++++++++ 4 files changed, 199 insertions(+), 1 deletion(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 4e57e4a8f6..63a1ae4c70 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2254,6 +2254,7 @@ virConfWriteMem; =20 =20 # util/vircrypto.h +virCryptoDecryptData; virCryptoEncryptData; virCryptoHashBuf; virCryptoHashString; diff --git a/src/util/vircrypto.c b/src/util/vircrypto.c index 3ce23264ca..00f723bb75 100644 --- a/src/util/vircrypto.c +++ b/src/util/vircrypto.c @@ -98,7 +98,7 @@ virCryptoHashString(virCryptoHash hash, } =20 =20 -/* virCryptoEncryptDataAESgntuls: +/* virCryptoEncryptDataAESgnutls: * * Performs the AES gnutls encryption * @@ -233,3 +233,127 @@ virCryptoEncryptData(virCryptoCipher algorithm, _("algorithm=3D%1$d is not supported"), algorithm); return -1; } + +/* virCryptoDecryptDataAESgnutls: + * + * Performs the AES gnutls decryption + * + * Same input as virCryptoDecryptData, except the algorithm is replaced + * by the specific gnutls algorithm. + * + * Decrypts the @data buffer using the @deckey and if available the @iv + * + * Returns 0 on success with the plaintext being filled. It is the + * caller's responsibility to clear and free it. Returns -1 on failure + * w/ error set. + */ +static int +virCryptoDecryptDataAESgnutls(gnutls_cipher_algorithm_t gnutls_dec_alg, + uint8_t *deckey, + size_t deckeylen, + uint8_t *iv, + size_t ivlen, + uint8_t *data, + size_t datalen, + uint8_t **plaintextret, + size_t *plaintextlenret) +{ + int rc; + uint8_t padding_length; + gnutls_cipher_hd_t handle =3D NULL; + gnutls_datum_t dec_key =3D { .data =3D deckey, .size =3D deckeylen }; + gnutls_datum_t iv_buf =3D { .data =3D iv, .size =3D ivlen }; + g_autofree uint8_t *plaintext =3D NULL; + size_t plaintextlen; + + if ((rc =3D gnutls_cipher_init(&handle, gnutls_dec_alg, + &dec_key, &iv_buf)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to initialize cipher: '%1$s'"), + gnutls_strerror(rc)); + return -1; + } + + plaintext =3D g_memdup2(data, datalen); + plaintextlen =3D datalen; + if (plaintextlen =3D=3D 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("decrypted data has zero length")); + goto error; + } + rc =3D gnutls_cipher_decrypt(handle, plaintext, plaintextlen); + gnutls_cipher_deinit(handle); + if (rc < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to decrypt the data: '%1$s'"), + gnutls_strerror(rc)); + goto error; + } + /* Before encryption, padding is added to the data. + * The last byte indicates the padding length, because in PKCS#7, all + * padding bytes are set to the padding length value. + */ + padding_length =3D plaintext[plaintextlen - 1]; + if (padding_length > plaintextlen) { + virReportError(VIR_ERR_INVALID_SECRET, "%s", + _("decrypted data has invalid padding")); + goto error; + } + *plaintextlenret =3D plaintextlen - padding_length; + *plaintextret =3D g_steal_pointer(&plaintext); + return 0; + error: + virSecureErase(plaintext, plaintextlen); + return -1; +} + +/* virCryptoDecryptData: + * @algorithm: algorithm desired for decryption + * @deckey: decryption key + * @deckeylen: decryption key length + * @iv: initialization vector + * @ivlen: length of initialization vector + * @data: data to decrypt + * @datalen: length of data + * @plaintext: stream of bytes allocated to store plaintext + * @plaintextlen: size of the stream of bytes + * Returns 0 on success, -1 on failure with error set + */ +int +virCryptoDecryptData(virCryptoCipher algorithm, + uint8_t *deckey, + size_t deckeylen, + uint8_t *iv, + size_t ivlen, + uint8_t *data, + size_t datalen, + uint8_t **plaintext, + size_t *plaintextlen) +{ + switch (algorithm) { + case VIR_CRYPTO_CIPHER_AES256CBC: + if (deckeylen !=3D 32) { + virReportError(VIR_ERR_INVALID_ARG, + _("AES256CBC decryption invalid keylen=3D%1$zu= "), + deckeylen); + return -1; + } + if (ivlen !=3D 16) { + virReportError(VIR_ERR_INVALID_ARG, + _("AES256CBC initialization vector invalid len= =3D%1$zu"), + ivlen); + return -1; + } + return virCryptoDecryptDataAESgnutls(GNUTLS_CIPHER_AES_256_CBC, + deckey, deckeylen, iv, ivlen, + data, datalen, + plaintext, plaintextlen); + case VIR_CRYPTO_CIPHER_NONE: + case VIR_CRYPTO_CIPHER_LAST: + break; + } + + virReportError(VIR_ERR_INVALID_ARG, + _("algorithm=3D%1$d is not supported"), algorithm); + return -1; +} diff --git a/src/util/vircrypto.h b/src/util/vircrypto.h index 5f079ac335..2e8557839d 100644 --- a/src/util/vircrypto.h +++ b/src/util/vircrypto.h @@ -61,3 +61,11 @@ int virCryptoEncryptData(virCryptoCipher algorithm, uint8_t **ciphertext, size_t *ciphertextlen) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(6) ATTRIBUTE_NONNULL(8) ATTRIBUTE_NONNULL(9) G_GNUC_WARN_UNUSED_RESULT; + +int virCryptoDecryptData(virCryptoCipher algorithm, + uint8_t *deckey, size_t deckeylen, + uint8_t *iv, size_t ivlen, + uint8_t *data, size_t datalen, + uint8_t **plaintext, size_t *plaintextlen) + ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(6) + ATTRIBUTE_NONNULL(8) ATTRIBUTE_NONNULL(9) G_GNUC_WARN_UNUSED_RESULT; diff --git a/tests/vircryptotest.c b/tests/vircryptotest.c index 9ffe70756e..864fa8838d 100644 --- a/tests/vircryptotest.c +++ b/tests/vircryptotest.c @@ -62,6 +62,14 @@ struct testCryptoEncryptData { size_t ciphertextlen; }; =20 +struct testCryptoDecryptData { + virCryptoCipher algorithm; + uint8_t *input; + size_t inputlen; + uint8_t *plaintext; + size_t plaintextlen; +}; + static int testCryptoEncrypt(const void *opaque) { @@ -101,6 +109,44 @@ testCryptoEncrypt(const void *opaque) return 0; } =20 +static int +testCryptoDecrypt(const void *opaque) +{ + const struct testCryptoDecryptData *data =3D opaque; + g_autofree uint8_t *deckey =3D NULL; + size_t deckeylen =3D 32; + g_autofree uint8_t *iv =3D NULL; + size_t ivlen =3D 16; + g_autofree uint8_t *plaintext =3D NULL; + size_t plaintextlen =3D 0; + + deckey =3D g_new0(uint8_t, deckeylen); + iv =3D g_new0(uint8_t, ivlen); + + if (virRandomBytes(deckey, deckeylen) < 0 || + virRandomBytes(iv, ivlen) < 0) { + fprintf(stderr, "Failed to generate random bytes\n"); + return -1; + } + + if (virCryptoDecryptData(data->algorithm, deckey, deckeylen, iv, ivlen, + data->input, data->inputlen, + &plaintext, &plaintextlen) < 0) + return -1; + + if (data->plaintextlen !=3D plaintextlen) { + fprintf(stderr, "Expected plaintexlen(%zu) doesn't match (%zu)\n", + data->plaintextlen, plaintextlen); + return -1; + } + + if (memcmp(data->plaintext, plaintext, plaintextlen)) { + fprintf(stderr, "Expected plaintext doesn't match\n"); + return -1; + } + + return 0; +} =20 static int mymain(void) @@ -155,7 +201,26 @@ mymain(void) =20 #undef VIR_CRYPTO_ENCRYPT =20 +#define VIR_CRYPTO_DECRYPT(a, n, i, il, c, cl) \ + do { \ + struct testCryptoDecryptData data =3D { \ + .algorithm =3D a, \ + .input =3D i, \ + .inputlen =3D il, \ + .plaintext =3D c, \ + .plaintextlen =3D cl, \ + }; \ + if (virTestRun("Decrypt " n, testCryptoDecrypt, &data) < 0) \ + ret =3D -1; \ + } while (0) + + VIR_CRYPTO_DECRYPT(VIR_CRYPTO_CIPHER_AES256CBC, "aes256cbc", + expected_ciphertext, 16, secretdata, 7); + +#undef VIR_CRYPTO_DECRYPT + return ret =3D=3D 0 ? EXIT_SUCCESS : EXIT_FAILURE; + } =20 /* Forces usage of not so random virRandomBytes */ --=20 2.51.1 From nobody Mon Feb 2 07:25:57 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass(p=reject dis=none) header.from=lists.libvirt.org ARC-Seal: i=1; a=rsa-sha256; t=1767982456; cv=none; d=zohomail.com; s=zohoarc; b=FvFHEp17zzfda8m8D4AE7Rg7ykIf7FI8z9JnAHSRk/UOW41Ce5EYSDTrlYTqez0VoZldDMgDs/f0CM9+qtpuZHvT1fkp5XvVetaCoaYuL2baUoPEfjA7/ky9eDWgZFA7gmqo6XYGKlaYzmSXQnBj7lO3khNrySAQ/6VAps03vnM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1767982456; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Owner:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Subject:Subject:To:To:Message-Id; bh=a8l6ZUHUmYX97jfGG1Xms5qz8+jqpEGDJsvCji3ZL5c=; b=cVbmuNnrJr3YARLHCXQ8xBOk/vukHlPJ+Z7ecDBXv9MAo6gWW5e+e9J1BH5SiCwqh90AvqAjF3kj4174y8dGnmACGWG1m8q/mUc1Wy33v6471OewE0r0+/ABGjbu89urSPbEdFrG1iM2sqsfqPeIcoXvpGFx/vjXUUv1cuWhEus= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1767982456705727.0115658276866; Fri, 9 Jan 2026 10:14:16 -0800 (PST) Received: by lists.libvirt.org (Postfix, from userid 993) id AF61743E53; Fri, 9 Jan 2026 13:14:15 -0500 (EST) Received: from [172.19.199.83] (lists.libvirt.org [8.43.85.245]) by lists.libvirt.org (Postfix) with ESMTP id 6F3CE43EDA; Fri, 9 Jan 2026 13:10:17 -0500 (EST) Received: by lists.libvirt.org (Postfix, from userid 993) id A1DCE43E0C; Fri, 9 Jan 2026 13:09:51 -0500 (EST) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (3072 bits) server-digest SHA256) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id 9A19443E00 for ; Fri, 9 Jan 2026 13:09:49 -0500 (EST) Received: from mail-pl1-f198.google.com (mail-pl1-f198.google.com [209.85.214.198]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-423-eKP4heIhNRCdyMAxh-pHVw-1; Fri, 09 Jan 2026 13:09:46 -0500 Received: by mail-pl1-f198.google.com with SMTP id d9443c01a7336-2a351686c17so53929985ad.0 for ; Fri, 09 Jan 2026 10:09:46 -0800 (PST) Received: from armenon-kvm.armenon-thinkpadp16vgen1.bengluru.csb ([49.36.108.228]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2a3e3cc8803sm111020495ad.71.2026.01.09.10.09.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 09 Jan 2026 10:09:44 -0800 (PST) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-3.4 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_LOW, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED,RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED,SPF_PASS autolearn=unavailable autolearn_force=no version=4.0.1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1767982189; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=a8l6ZUHUmYX97jfGG1Xms5qz8+jqpEGDJsvCji3ZL5c=; b=CqZ9/DH65M7D0yEKBlo9yDUZhMUKmy/vpkc7Vr/lbseoI9j0MlHV3wpVx/798X9OeH/gJr UR0N4yRJZNUZo+AciuC5o+SitVUFQbARldXx11kVPYxP32zEA3AO8zoUy+vhQIr+gXArk8 mpNL5XgoBCBgQF+aWDgbRjOdghw2H3o= X-MC-Unique: eKP4heIhNRCdyMAxh-pHVw-1 X-Mimecast-MFC-AGG-ID: eKP4heIhNRCdyMAxh-pHVw_1767982186 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767982185; x=1768586985; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=a8l6ZUHUmYX97jfGG1Xms5qz8+jqpEGDJsvCji3ZL5c=; b=EXmXGcmen09b43JtVkB7OTa04QxQw4w9xecM8FvkBu4ZEH4/KOkiQRljNOe4XcRt2w kZs97j1EmbDiNAMJFkcNGlvRynVmbB9GUVZtpbUJlnTVFCaAE8QFq/StG5dvmyVGDwQY 9EFPseG+2YUyE8Clyl0yzlRzNok2rWM+97PubB3zI+WdhXleYYqiG3VxxDS8zDrISEYl k1mzxEciuap3n3c2YaINf1/CB9TjaKpWL2Q16yv+8NxNreS5G5kJe6UzULrB22H4nwEW nxf75D3FrCEdSCCGY3cO1IcWBqmgcviYlgkufTdfOlom4MNezQwoCCmHPxugRH4xZJVe +moQ== X-Gm-Message-State: AOJu0YxoV30XIBZAWkGmxozEj9ioVn/Ho3TYZfiipA8RKTmtYbfSIo4N 1YqRBVWpL7jVnq20UbB2ORAo4L+0kgEq5WP1yin4OwMT6ooSmy02SKqALQO2pE/xzUnwOH6zT/m txqWkortTe2Dwltew30K2GHOfnbn8qXbMzw+bmkQbtVmm4buS68f9xCo0dD8WxwAsDVlU9DpV74 8++bLYxxOq+R4Rk2BERyq2rycuC8d7cWlulnbvbQcvSQ== X-Gm-Gg: AY/fxX4w8QUgIzT8Iy8FTOmYckOeyIcEDS2Qwsrzg5fvrQxrCxcIIlB2Dm28ViofOAB lqhAbduqtB+5aSWzUOpPczySjfMyWQA8+/x501lu1wGWDsJx9nDofV1Ly3hQiytFA7ZczOLBGEF CAFgPj+FAalxXd0GS2Txc8AT8pTkETsF0gRaTUYUO638J9VS6fTD8+svwIS/E3rC/+jAKVQZ08j WV5qTsbPU91hNQ10nr6tMOAtMPFO7g9bRyrJw6jQBKBXS05PFmhOfEfPs4ZxNXeiokaBepmeqSc qZ1qKHLb6xPQO2g80TgDIJ1aDXTHHdYHIiP88G+dUcJ1Fyh3qDK4g/cax06sB616jf/N6SF/PjO Pvbgr73ZgaN0tpy6tfqF0ZskLFfv+Gi9sTndhqwy9nV9zDix5gti9eN/rvQ== X-Received: by 2002:a17:903:1247:b0:2a0:b7d3:eec5 with SMTP id d9443c01a7336-2a3ee4e85bdmr101559465ad.33.1767982185250; Fri, 09 Jan 2026 10:09:45 -0800 (PST) X-Google-Smtp-Source: AGHT+IHmUoVRiBBTNNvq6OIir0aO48HxdaFo4SDWTDcWfqEArydSj+92oP5V3iBlLpsoGzWKk4vgAQ== X-Received: by 2002:a17:903:1247:b0:2a0:b7d3:eec5 with SMTP id d9443c01a7336-2a3ee4e85bdmr101559285ad.33.1767982184639; Fri, 09 Jan 2026 10:09:44 -0800 (PST) To: devel@lists.libvirt.org Subject: [PATCH v4 2/6] secret: Set up default encryption secret key for the virtsecretd service Date: Fri, 9 Jan 2026 23:39:32 +0530 Message-ID: <20260109180936.127454-3-armenon@redhat.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20260109180936.127454-1-armenon@redhat.com> References: <20260109180936.127454-1-armenon@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: hJuipw0542M2N0ulYBOKSeX-VdCCG_67SufnQnbzDKM_1767982186 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Message-ID-Hash: HAVBP6H7HKO7NICYDPB6R6GHLS4ER5BC X-Message-ID-Hash: HAVBP6H7HKO7NICYDPB6R6GHLS4ER5BC X-MailFrom: armenon@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-devel.lists.libvirt.org-0; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Arun Menon X-Mailman-Version: 3.3.10 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Arun Menon via Devel Reply-To: Arun Menon X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1767982463147158500 Content-Type: text/plain; charset="utf-8"; x-default="true" This commit sets the foundation for encrypting the libvirt secrets by provi= ding a secure way to pass a secret encryption key to the virtsecretd service. A random secret key is generated using the new virt-secret-init-encryption service. This key can be consumed by the virtsecretd service. By using the "Before=3D" directive in the new virt-secret-init-encryption service and using "Requires=3D" directive in the virtsecretd service, we make sure that the daemon is run only after we have an encrypted secret key file generated and placed in /var/lib/libvirt/secrets. The virtsecretd service can then read the key from CREDENTIALS_DIRECTORY. [= 1] This setup therefore provides a default key out-of-the-box for initial use. A subsequent commit will introduce the logic for virtsecretd to access and use this key via the $CREDENTIALS_DIRECTORY environment varia= ble. [2] [1] https://www.freedesktop.org/software/systemd/man/latest/systemd-creds.h= tml [2] https://systemd.io/CREDENTIALS/ Signed-off-by: Arun Menon --- libvirt.spec.in | 5 +++++ src/meson.build | 1 + src/remote/libvirtd.service.in | 4 ++++ src/secret/meson.build | 13 +++++++++++++ src/secret/virt-secret-init-encryption.service.in | 8 ++++++++ src/secret/virtsecretd.service.extra.in | 8 ++++++++ 6 files changed, 39 insertions(+) create mode 100644 src/secret/virt-secret-init-encryption.service.in diff --git a/libvirt.spec.in b/libvirt.spec.in index ccfe75135b..6a497bfecd 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -1890,13 +1890,16 @@ exit 0 %pre daemon-driver-secret %libvirt_sysconfig_pre virtsecretd %libvirt_systemd_unix_pre virtsecretd +%libvirt_systemd_oneshot_pre virt-secret-init-encryption =20 %posttrans daemon-driver-secret %libvirt_sysconfig_posttrans virtsecretd %libvirt_systemd_unix_posttrans virtsecretd +%libvirt_systemd_unix_posttrans virt-secret-init-encryption =20 %preun daemon-driver-secret %libvirt_systemd_unix_preun virtsecretd +%libvirt_systemd_unix_preun virt-secret-init-encryption =20 %pre daemon-driver-storage-core %libvirt_sysconfig_pre virtstoraged @@ -2248,11 +2251,13 @@ exit 0 %{_datadir}/augeas/lenses/virtsecretd.aug %{_datadir}/augeas/lenses/tests/test_virtsecretd.aug %{_unitdir}/virtsecretd.service +%{_unitdir}/virt-secret-init-encryption.service %{_unitdir}/virtsecretd.socket %{_unitdir}/virtsecretd-ro.socket %{_unitdir}/virtsecretd-admin.socket %attr(0755, root, root) %{_sbindir}/virtsecretd %dir %attr(0700, root, root) %{_sysconfdir}/libvirt/secrets/ +%dir %attr(0700, root, root) %{_localstatedir}/lib/libvirt/secrets/ %ghost %dir %attr(0700, root, root) %{_rundir}/libvirt/secrets/ %{_libdir}/libvirt/connection-driver/libvirt_driver_secret.so %{_mandir}/man8/virtsecretd.8* diff --git a/src/meson.build b/src/meson.build index 47c978cc1f..f18f562fd9 100644 --- a/src/meson.build +++ b/src/meson.build @@ -837,6 +837,7 @@ if conf.has('WITH_LIBVIRTD') 'sbindir': sbindir, 'sysconfdir': sysconfdir, 'initconfdir': initconfdir, + 'localstatedir': localstatedir, 'name': unit['name'], 'service': unit['service'], 'SERVICE': unit['service'].to_upper(), diff --git a/src/remote/libvirtd.service.in b/src/remote/libvirtd.service.in index b0a062e885..7965010a0a 100644 --- a/src/remote/libvirtd.service.in +++ b/src/remote/libvirtd.service.in @@ -12,6 +12,8 @@ After=3Dlibvirtd.socket After=3Dlibvirtd-ro.socket After=3Dlibvirtd-admin.socket Requires=3Dvirtlogd.socket +Requires=3Dvirt-secret-init-encryption.service +After=3Dvirt-secret-init-encryption.service Wants=3Dvirtlockd.socket After=3Dvirtlogd.socket After=3Dvirtlockd.socket @@ -29,6 +31,8 @@ Conflicts=3Dxendomains.service Type=3Dnotify-reload Environment=3DLIBVIRTD_ARGS=3D"--timeout 120" EnvironmentFile=3D-@initconfdir@/libvirtd +Environment=3DSECRETS_ENCRYPTION_KEY=3D%d/secrets-encryption-key +LoadCredentialEncrypted=3Dsecrets-encryption-key:@localstatedir@/lib/libvi= rt/secrets/secrets-encryption-key ExecStart=3D@sbindir@/libvirtd $LIBVIRTD_ARGS ExecReload=3D/bin/kill -HUP $MAINPID KillMode=3Dprocess diff --git a/src/secret/meson.build b/src/secret/meson.build index 3b859ea7b4..b69abe32ab 100644 --- a/src/secret/meson.build +++ b/src/secret/meson.build @@ -31,6 +31,18 @@ if conf.has('WITH_SECRETS') 'name': 'virtsecretd', } =20 + virt_secret_init_encryption_conf =3D configuration_data() + + virt_secret_init_encryption_conf.set('localstatedir', localstatedir) + + configure_file( + input: 'virt-secret-init-encryption.service.in', + output: '@0@.service'.format('virt-secret-init-encryption'), + configuration: virt_secret_init_encryption_conf, + install: true, + install_dir: unitdir, + ) + virt_daemon_units +=3D { 'service': 'virtsecretd', 'name': 'secret', @@ -50,5 +62,6 @@ if conf.has('WITH_SECRETS') virt_install_dirs +=3D [ confdir / 'secrets', runstatedir / 'libvirt' / 'secrets', + localstatedir / 'lib' / 'libvirt' / 'secrets', ] endif diff --git a/src/secret/virt-secret-init-encryption.service.in b/src/secret= /virt-secret-init-encryption.service.in new file mode 100644 index 0000000000..44940bd72b --- /dev/null +++ b/src/secret/virt-secret-init-encryption.service.in @@ -0,0 +1,8 @@ +[Unit] +Before=3Dvirtsecretd.service +Before=3Dlibvirtd.service +ConditionPathExists=3D!@localstatedir@/lib/libvirt/secrets/secrets-encrypt= ion-key + +[Service] +Type=3Doneshot +ExecStart=3D/usr/bin/sh -c 'umask 0066 && (dd if=3D/dev/urandom status=3Dn= one bs=3D32 count=3D1 | systemd-creds encrypt --name=3Dsecrets-encryption-k= ey - @localstatedir@/lib/libvirt/secrets/secrets-encryption-key)' diff --git a/src/secret/virtsecretd.service.extra.in b/src/secret/virtsecre= td.service.extra.in index 1fc8c672f7..116458b22a 100644 --- a/src/secret/virtsecretd.service.extra.in +++ b/src/secret/virtsecretd.service.extra.in @@ -1,2 +1,10 @@ # The contents of this unit will be merged into a base template. # Additional units might be merged as well. See meson.build for details. +# +[Unit] +Requires=3Dvirt-secret-init-encryption.service +After=3Dvirt-secret-init-encryption.service + +[Service] +LoadCredentialEncrypted=3Dsecrets-encryption-key:@localstatedir@/lib/libvi= rt/secrets/secrets-encryption-key +Environment=3DSECRETS_ENCRYPTION_KEY=3D%d/secrets-encryption-key --=20 2.51.1 From nobody Mon Feb 2 07:25:57 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass(p=reject dis=none) header.from=lists.libvirt.org ARC-Seal: i=1; a=rsa-sha256; t=1767982545; cv=none; d=zohomail.com; s=zohoarc; b=Cfkc7CMpvlqV4w48qSXmK6QoJaSabb5mlpuZeclEZFbNec7WHnibKuh/iPOW6dfIks/5C+pXWAgU1g2d7A5siVkIoTKiocrQqX8xcMM+UyZeRA4QDWha5azj9IVWNPGbWi8E2MWtK9UgMs2tmFlJjn7dbnEoApSm6sOCPUsTydI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1767982545; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Owner:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Subject:Subject:To:To:Message-Id; bh=wONg7O0UgEhCFTWcJOGcBUsrqRsMBLQrAn2MvoO89eU=; b=SY7Frw1JO6wZcU6a+rlhCcSJT9zn5a8/vcbwRQXVXvzHi4tqDV+PxkWhBlgr+4ySZRa1mOfGa0biZfkTl+98Bsjg6T8Vy2SkKQ4OqlZklzugmEhw5G66DcXGUGqXAg99PkTJoXd+Lm+C7asknEQJzOb0yNcIIzAxkTJjDIzgZFA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1767982545298541.7429080240945; Fri, 9 Jan 2026 10:15:45 -0800 (PST) Received: by lists.libvirt.org (Postfix, from userid 993) id D561F43E3D; Fri, 9 Jan 2026 13:15:44 -0500 (EST) Received: from [172.19.199.83] (lists.libvirt.org [8.43.85.245]) by lists.libvirt.org (Postfix) with ESMTP id 9936344150; Fri, 9 Jan 2026 13:10:21 -0500 (EST) Received: by lists.libvirt.org (Postfix, from userid 993) id 7EBA943E0B; Fri, 9 Jan 2026 13:09:52 -0500 (EST) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (3072 bits) server-digest SHA256) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id C9B7443E0A for ; Fri, 9 Jan 2026 13:09:50 -0500 (EST) Received: from mail-pl1-f197.google.com (mail-pl1-f197.google.com [209.85.214.197]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-457-jRGV86pkOhmOPBvVPZvNMQ-1; Fri, 09 Jan 2026 13:09:48 -0500 Received: by mail-pl1-f197.google.com with SMTP id d9443c01a7336-2a13be531b2so53111335ad.2 for ; Fri, 09 Jan 2026 10:09:48 -0800 (PST) Received: from armenon-kvm.armenon-thinkpadp16vgen1.bengluru.csb ([49.36.108.228]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2a3e3cc8803sm111020495ad.71.2026.01.09.10.09.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 09 Jan 2026 10:09:46 -0800 (PST) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-3.4 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_LOW, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED,RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED,SPF_PASS autolearn=unavailable autolearn_force=no version=4.0.1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1767982190; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=wONg7O0UgEhCFTWcJOGcBUsrqRsMBLQrAn2MvoO89eU=; b=UgC7bMqmzIVZ6TCv/A1x6vxQiOb+5lk9UmU1dJM0h48p12TkTY6SGtgswM0/iR69Bf61uW AEpuVp+DOFcNSBbyjcnGdMqGycE6OwdpjsqomfkovawC+vHmF0kBh3piNygcNIu4zYa6NN kyzfusq1rMG8JP5JZQdED/+LxWIPlqI= X-MC-Unique: jRGV86pkOhmOPBvVPZvNMQ-1 X-Mimecast-MFC-AGG-ID: jRGV86pkOhmOPBvVPZvNMQ_1767982187 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767982187; x=1768586987; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=wONg7O0UgEhCFTWcJOGcBUsrqRsMBLQrAn2MvoO89eU=; b=ugXs/sm9OKidMxfi4XwjbbDobt3woQfWtkiIvU5yfhJYQikKUsJTgzHnloPcU3K3Wi UlHExDzdShfL8dpCO6Nj4BV+UPhK0agd+4f+1CslUC+s/RWky5G0//vdYRkBEvuDnjO2 c3uY55hGbSZWHEBvVYnUsCL0LO5t4e8xCi9ihQhUoa7az/IWEnt4VJI567zUIseS7lUB 6dMr59VaQAzZts/vp4dAIYvecQOE8zh8J2l52XCXoe3I+ofs2/yvB7Y+YHa4wxVIuyVE wnYNUo1YB5svl87XuES+zgxmPQfGOmV0LUvLFK2bNfVzddCU45fd7p83yWIsXUrumoqU ThEg== X-Gm-Message-State: AOJu0YyfXRk8NJ+JMtDSVjj5SsVbDbIJF1UnPSAWMvrske4gWnT/0z08 IpiXOUNmAOGJHpuzS3NqcriT3ezCEETA/ui/+n1PeT6ql/tAnRVizrMGLgB/8YgUvqeV5mXFaeV aGbsGi4YG6EEl+9KpyvH5J2Tz4qf2WlTSc/8802+CfvxKgRZP/WZJ6QTTLvWsBANRwh5Mx/ASKz bQBZMf2vrtOMp5RbOYRuCzPRpNKl4ypKdFSPgMLhwePw== X-Gm-Gg: AY/fxX4sGdwYPRgg3KgLS2rHI7R3Sda5Ia3DP9b1QzW3T+Uhv491yQImOzSgCauBMsK TDdGN5zRiGeGjnf3u73cTTkr9XlizUuNLPtXbAEQqDSrlRYMmM3n2KfwvzKHF/y0iXEb/LPZC3Q q0Wx9eGqCLPVo1xP0AeP/rzzLdxFWuwbUKhVI5IaSk/YJROTP5du9XUwKmUv2zsW8cv44IxPvNb hHrykJh5Xol9gdF6SVymSN2c44IjqpdNtWvILuviyij83ygPkwkIEN8/5WWygYPk/AAtGSX3rSh c3JeqUEmVZlsRKTypOeXVOjIG4fm2M8F4/PYqLiQ4f9h2R38bppDhwZsl3Dz0oSEYukbQpdb07+ zuu27f7W3NBqxL1LX+fKk8NmbTQWWZ7jvgou47I+Yj0GZGJCEgauc1eeL4Q== X-Received: by 2002:a17:902:dac3:b0:2a3:e6f9:be2a with SMTP id d9443c01a7336-2a3ee468432mr97725845ad.7.1767982187019; Fri, 09 Jan 2026 10:09:47 -0800 (PST) X-Google-Smtp-Source: AGHT+IFgcMgGG+SQWKPDS+jVloqeVbF2VGx2H8uV5rlDeoDEv08xt6Yp1G6edaRLAk1Q2Li1XAhleA== X-Received: by 2002:a17:902:dac3:b0:2a3:e6f9:be2a with SMTP id d9443c01a7336-2a3ee468432mr97725655ad.7.1767982186347; Fri, 09 Jan 2026 10:09:46 -0800 (PST) To: devel@lists.libvirt.org Subject: [PATCH v4 3/6] secret: Add secret.conf configuration file and parse it Date: Fri, 9 Jan 2026 23:39:33 +0530 Message-ID: <20260109180936.127454-4-armenon@redhat.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20260109180936.127454-1-armenon@redhat.com> References: <20260109180936.127454-1-armenon@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: cAhljtaVJFfdJw2FKmGF1o8woTtDLA98d8ZrpZva8mw_1767982187 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Message-ID-Hash: ED2ZWCE7ZDPBBQBSSB2RZIQL6MML4G22 X-Message-ID-Hash: ED2ZWCE7ZDPBBQBSSB2RZIQL6MML4G22 X-MailFrom: armenon@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-devel.lists.libvirt.org-0; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Arun Menon X-Mailman-Version: 3.3.10 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Arun Menon via Devel Reply-To: Arun Menon X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1767982555840158500 Content-Type: text/plain; charset="utf-8"; x-default="true" A new configuration file called secret.conf is introduced to let the user configure the path to the secrets encryption key. This key will be used to encrypt/decrypt the secrets in libvirt. By default the path is set to the runtime directory /run/libvirt/secrets, and it is commented in the config file. After parsing the file, the virtsecretd driver checks if an encryption key is present in the path and is valid. If no encryption key is present in the path, then the service will by default use the encryption key stored in the CREDENTIALS_DIRECTORY. Add logic to parse the encryption key file and store the key. It also checks for the encrypt_data attribute in the config file. The encryption and decryption logic will be added in the subsequent patches. Signed-off-by: Arun Menon --- include/libvirt/virterror.h | 1 + libvirt.spec.in | 3 + po/POTFILES | 1 + src/secret/libvirt_secrets.aug | 40 ++++++ src/secret/meson.build | 19 +++ src/secret/secret.conf.in | 14 ++ src/secret/secret_config.c | 179 +++++++++++++++++++++++++ src/secret/secret_config.h | 40 ++++++ src/secret/secret_driver.c | 11 ++ src/secret/test_libvirt_secrets.aug.in | 6 + src/util/virerror.c | 3 + 11 files changed, 317 insertions(+) create mode 100644 src/secret/libvirt_secrets.aug create mode 100644 src/secret/secret.conf.in create mode 100644 src/secret/secret_config.c create mode 100644 src/secret/secret_config.h create mode 100644 src/secret/test_libvirt_secrets.aug.in diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index f02da046a3..fa07c36ceb 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -353,6 +353,7 @@ typedef enum { command within timeout (Since: = 11.2.0) */ VIR_ERR_AGENT_COMMAND_FAILED =3D 113, /* guest agent responded with fa= ilure to a command (Since: 11.2.0) */ + VIR_ERR_INVALID_ENCR_KEY_SECRET =3D 114, /* encryption key is invalid = (Since: 12.0.0) */ =20 # ifdef VIR_ENUM_SENTINELS VIR_ERR_NUMBER_LAST /* (Since: 5.0.0) */ diff --git a/libvirt.spec.in b/libvirt.spec.in index 6a497bfecd..50159e7461 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -2250,6 +2250,9 @@ exit 0 %config(noreplace) %{_sysconfdir}/libvirt/virtsecretd.conf %{_datadir}/augeas/lenses/virtsecretd.aug %{_datadir}/augeas/lenses/tests/test_virtsecretd.aug +%{_datadir}/augeas/lenses/libvirt_secrets.aug +%{_datadir}/augeas/lenses/tests/test_libvirt_secrets.aug +%config(noreplace) %{_sysconfdir}/libvirt/secret.conf %{_unitdir}/virtsecretd.service %{_unitdir}/virt-secret-init-encryption.service %{_unitdir}/virtsecretd.socket diff --git a/po/POTFILES b/po/POTFILES index f0aad35c8c..ede667cfaf 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -232,6 +232,7 @@ src/rpc/virnetsshsession.c src/rpc/virnettlscert.c src/rpc/virnettlsconfig.c src/rpc/virnettlscontext.c +src/secret/secret_config.c src/secret/secret_driver.c src/security/security_apparmor.c src/security/security_dac.c diff --git a/src/secret/libvirt_secrets.aug b/src/secret/libvirt_secrets.aug new file mode 100644 index 0000000000..8dda373e62 --- /dev/null +++ b/src/secret/libvirt_secrets.aug @@ -0,0 +1,40 @@ +(* /etc/libvirt/secret.conf *) + +module Libvirt_secrets =3D + autoload xfm + + let eol =3D del /[ \t]*\n/ "\n" + let value_sep =3D del /[ \t]*=3D[ \t]*/ " =3D " + let indent =3D del /[ \t]*/ "" + + let array_sep =3D del /,[ \t\n]*/ ", " + let array_start =3D del /\[[ \t\n]*/ "[ " + let array_end =3D del /\]/ "]" + + let str_val =3D del /\"/ "\"" . store /[^\"]*/ . del /\"/ "\"" + let bool_val =3D store /0|1/ + let int_val =3D store /[0-9]+/ + let str_array_element =3D [ seq "el" . str_val ] . del /[ \t\n]*/ "" + let str_array_val =3D counter "el" . array_start . ( str_array_element = . ( array_sep . str_array_element ) * ) ? . array_end + + let str_entry (kw:string) =3D [ key kw . value_sep . str_val ] + let bool_entry (kw:string) =3D [ key kw . value_sep . bool_val ] + let int_entry (kw:string) =3D [ key kw . value_sep . int_val ] + let str_array_entry (kw:string) =3D [ key kw . value_sep . str_array_va= l ] + + let secrets_entry =3D str_entry "secrets_encryption_key" + | bool_entry "encrypt_data" + + (* Each entry in the config is one of the following three ... *) + let entry =3D secrets_entry + let comment =3D [ label "#comment" . del /#[ \t]*/ "# " . store /([^ \= t\n][^\n]*)?/ . del /\n/ "\n" ] + let empty =3D [ label "#empty" . eol ] + + let record =3D indent . entry . eol + + let lns =3D ( record | comment | empty ) * + + let filter =3D incl "/etc/libvirt/secret.conf" + . Util.stdexcl + + let xfm =3D transform lns filter diff --git a/src/secret/meson.build b/src/secret/meson.build index b69abe32ab..cfcc861f4f 100644 --- a/src/secret/meson.build +++ b/src/secret/meson.build @@ -1,5 +1,6 @@ secret_driver_sources =3D [ 'secret_driver.c', + 'secret_config.c', ] =20 driver_source_files +=3D files(secret_driver_sources) @@ -27,6 +28,24 @@ if conf.has('WITH_SECRETS') ], } =20 + secret_conf =3D configure_file( + input: 'secret.conf.in', + output: 'secret.conf', + copy: true + ) + virt_conf_files +=3D secret_conf + + virt_aug_files +=3D files('libvirt_secrets.aug') + + virt_test_aug_files +=3D { + 'name': 'test_libvirt_secrets.aug', + 'aug': files('test_libvirt_secrets.aug.in'), + 'conf': files('secret.conf.in'), + 'test_name': 'libvirt_secrets', + 'test_srcdir': meson.current_source_dir(), + 'test_builddir': meson.current_build_dir(), + } + virt_daemon_confs +=3D { 'name': 'virtsecretd', } diff --git a/src/secret/secret.conf.in b/src/secret/secret.conf.in new file mode 100644 index 0000000000..a231c48f8d --- /dev/null +++ b/src/secret/secret.conf.in @@ -0,0 +1,14 @@ +# +# Configuration file for the secrets driver. +# +# The secret encryption key is used to override default encryption +# key path. The user can create an encryption key and set the secret_encry= ption_key +# to the path on which it resides. +# The key must be 32-bytes long. +#secrets_encryption_key =3D "/run/libvirt/secrets/secret-encryption-key" + +# The encrypt_data setting is used to indicate if the encryption is on or = off. +# 0 indicates off and 1 indicates on. By default it is on +# if secrets_encryption_key is set to a non-NULL +# path, or if a systemd credential named "secrets-encryption-key" exists. +#encrypt_data =3D 1 diff --git a/src/secret/secret_config.c b/src/secret/secret_config.c new file mode 100644 index 0000000000..4e11bca1b6 --- /dev/null +++ b/src/secret/secret_config.c @@ -0,0 +1,179 @@ +/* + * secret_config.c: secret.conf config file handling + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#include +#include +#include "configmake.h" +#include "datatypes.h" +#include "virlog.h" +#include "virerror.h" +#include "virfile.h" +#include "virutil.h" +#include "virsecureerase.h" +#include "secret_config.h" + + +#define VIR_FROM_THIS VIR_FROM_SECRET + +VIR_LOG_INIT("secret.secret_config"); + +static virClass *virSecretDaemonConfigClass; +static void virSecretDaemonConfigDispose(void *obj); + +static int +virSecretConfigOnceInit(void) +{ + if (!VIR_CLASS_NEW(virSecretDaemonConfig, virClassForObject())) + return -1; + + return 0; +} + + +VIR_ONCE_GLOBAL_INIT(virSecretConfig); + + +int +virSecretDaemonConfigFilePath(bool privileged, char **configfile) +{ + if (privileged) { + *configfile =3D g_strdup(SYSCONFDIR "/libvirt/secret.conf"); + } else { + g_autofree char *configdir =3D NULL; + + configdir =3D virGetUserConfigDirectory(); + + *configfile =3D g_strdup_printf("%s/secret.conf", configdir); + } + + return 0; +} + + +static int +virSecretLoadDaemonConfig(virSecretDaemonConfig *cfg, + const char *filename) +{ + g_autoptr(virConf) conf =3D NULL; + int res; + + if (virFileExists(filename)) { + conf =3D virConfReadFile(filename, 0); + if (!conf) + return -1; + res =3D virConfGetValueBool(conf, "encrypt_data", &cfg->encryptDat= a); + if (res < 0) { + return -1; + } else if (res =3D=3D 1) { + cfg->encryptDataWasSet =3D true; + } else { + cfg->encryptDataWasSet =3D false; + } + + if (virConfGetValueString(conf, "secrets_encryption_key", + &cfg->secretsEncryptionKeyPath) < 0) { + return -1; + } + } + return 0; +} + + +static int +virGetSecretsEncryptionKey(virSecretDaemonConfig *cfg, + uint8_t **secretsEncryptionKey, + size_t *secretsKeyLen) +{ + VIR_AUTOCLOSE fd =3D -1; + int encryptionKeyLength; + + if ((encryptionKeyLength =3D virFileReadAll(cfg->secretsEncryptionKeyP= ath, + VIR_SECRETS_ENCRYPTION_KEY_L= EN, + (char**)secretsEncryptionKey= )) < 0) { + return -1; + } + if (encryptionKeyLength !=3D VIR_SECRETS_ENCRYPTION_KEY_LEN) { + virReportError(VIR_ERR_INVALID_ENCR_KEY_SECRET, + _("Encryption key length must be '%1$d' '%2$s'"), + VIR_SECRETS_ENCRYPTION_KEY_LEN, + cfg->secretsEncryptionKeyPath); + return -1; + } + + *secretsKeyLen =3D (size_t)encryptionKeyLength; + return 0; +} + + +virSecretDaemonConfig * +virSecretDaemonConfigNew(bool privileged) +{ + g_autoptr(virSecretDaemonConfig) cfg =3D NULL; + g_autofree char *configdir =3D NULL; + g_autofree char *configfile =3D NULL; + g_autofree char *rundir =3D NULL; + const char *credentialsDirectory; + + if (virSecretConfigInitialize() < 0) + return NULL; + + if (!(cfg =3D virObjectNew(virSecretDaemonConfigClass))) + return NULL; + + if (virSecretDaemonConfigFilePath(privileged, &configfile) < 0) + return NULL; + + if (virSecretLoadDaemonConfig(cfg, configfile) < 0) + return NULL; + + credentialsDirectory =3D getenv("CREDENTIALS_DIRECTORY"); + + if (!cfg->secretsEncryptionKeyPath && credentialsDirectory) { + cfg->secretsEncryptionKeyPath =3D g_strdup_printf("%s/secrets-encr= yption-key", + credentialsDirecto= ry); + if (!virFileExists(cfg->secretsEncryptionKeyPath)) { + g_clear_pointer(&cfg->secretsEncryptionKeyPath, g_free); + } + } + + if (!cfg->encryptDataWasSet) { + if (!cfg->secretsEncryptionKeyPath) { + /* No path specified by user or environment, disable encryptio= n */ + cfg->encryptData =3D false; + } else { + cfg->encryptData =3D true; + } + } else { + if (cfg->encryptData) { + if (!cfg->secretsEncryptionKeyPath) { + /* Built-in default path must be used */ + rundir =3D virGetUserRuntimeDirectory(); + cfg->secretsEncryptionKeyPath =3D g_strdup_printf("%s/secr= ets/encryption-key", + rundir); + } + } + } + VIR_DEBUG("Secrets encryption key path: %s", NULLSTR(cfg->secretsEncry= ptionKeyPath)); + + if (cfg->encryptData) { + if (virGetSecretsEncryptionKey(cfg, + &cfg->secretsEncryptionKey, + &cfg->secretsKeyLen) < 0) { + return NULL; + } + } + return g_steal_pointer(&cfg); +} + + +static void +virSecretDaemonConfigDispose(void *obj) +{ + virSecretDaemonConfig *cfg =3D obj; + + virSecureErase(cfg->secretsEncryptionKey, cfg->secretsKeyLen); + g_free(cfg->secretsEncryptionKeyPath); +} diff --git a/src/secret/secret_config.h b/src/secret/secret_config.h new file mode 100644 index 0000000000..888acf272b --- /dev/null +++ b/src/secret/secret_config.h @@ -0,0 +1,40 @@ +/* + * secret_config.h: secret.conf config file handling + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#pragma once + +#include "internal.h" +#include "virinhibitor.h" +#include "secret_event.h" +#define VIR_SECRETS_ENCRYPTION_KEY_LEN 32 + +typedef struct _virSecretDaemonConfig virSecretDaemonConfig; +struct _virSecretDaemonConfig { + virObject parent; + /* secrets encryption key path from secret.conf file */ + char *secretsEncryptionKeyPath; + + /* Store the key to encrypt secrets on the disk */ + unsigned char *secretsEncryptionKey; + + size_t secretsKeyLen; + + /* Indicates if the newly written secrets are encrypted or not. + */ + bool encryptData; + + /* Indicates if the config file has encrypt_data set or not. + */ + bool encryptDataWasSet; +}; + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(virSecretDaemonConfig, virObjectUnref); + +int virSecretDaemonConfigFilePath(bool privileged, char **configfile); +virSecretDaemonConfig *virSecretDaemonConfigNew(bool privileged); +int virSecretDaemonConfigLoadFile(virSecretDaemonConfig *data, + const char *filename, + bool allow_missing); diff --git a/src/secret/secret_driver.c b/src/secret/secret_driver.c index 04c3ca49f1..9b13772ad3 100644 --- a/src/secret/secret_driver.c +++ b/src/secret/secret_driver.c @@ -42,6 +42,7 @@ #include "secret_event.h" #include "virutil.h" #include "virinhibitor.h" +#include "secret_config.h" =20 #define VIR_FROM_THIS VIR_FROM_SECRET =20 @@ -70,6 +71,10 @@ struct _virSecretDriverState { =20 /* Immutable pointer, self-locking APIs */ virInhibitor *inhibitor; + + /* Require lock to get reference on 'config', + * then lockless thereafter */ + virSecretDaemonConfig *config; }; =20 static virSecretDriverState *driver; @@ -454,6 +459,7 @@ secretStateCleanupLocked(void) VIR_FREE(driver->configDir); =20 virObjectUnref(driver->secretEventState); + virObjectUnref(driver->config); virInhibitorFree(driver->inhibitor); =20 if (driver->lockFD !=3D -1) @@ -518,6 +524,8 @@ secretStateInitialize(bool privileged, driver->stateDir); goto error; } + if (!(driver->config =3D virSecretDaemonConfigNew(driver->privileged))) + goto error; =20 driver->inhibitor =3D virInhibitorNew( VIR_INHIBITOR_WHAT_NONE, @@ -553,6 +561,9 @@ secretStateReload(void) if (!driver) return -1; =20 + if (!(driver->config =3D virSecretDaemonConfigNew(driver->privileged))) + return -1; + ignore_value(virSecretLoadAllConfigs(driver->secrets, driver->configDi= r)); =20 return 0; diff --git a/src/secret/test_libvirt_secrets.aug.in b/src/secret/test_libvi= rt_secrets.aug.in new file mode 100644 index 0000000000..1bb205e0f2 --- /dev/null +++ b/src/secret/test_libvirt_secrets.aug.in @@ -0,0 +1,6 @@ +module Test_libvirt_secrets =3D + @CONFIG@ + + test Libvirt_secrets.lns get conf =3D +{ "secrets_encryption_key" =3D "/run/libvirt/secrets/secret-encryption-key= " } +{ "encrypt_data" =3D "1" } diff --git a/src/util/virerror.c b/src/util/virerror.c index abb014b522..b7d23f81c7 100644 --- a/src/util/virerror.c +++ b/src/util/virerror.c @@ -1296,6 +1296,9 @@ static const virErrorMsgTuple virErrorMsgStrings[] = =3D { [VIR_ERR_AGENT_COMMAND_FAILED] =3D { N_("guest agent command failed"), N_("guest agent command failed: %1$s") }, + [VIR_ERR_INVALID_ENCR_KEY_SECRET] =3D { + N_("Invalid encryption key for the secret"), + N_("Invalid encryption key for the secret: %1$s") }, }; =20 G_STATIC_ASSERT(G_N_ELEMENTS(virErrorMsgStrings) =3D=3D VIR_ERR_NUMBER_LAS= T); --=20 2.51.1 From nobody Mon Feb 2 07:25:57 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass(p=reject dis=none) header.from=lists.libvirt.org ARC-Seal: i=1; a=rsa-sha256; t=1767982610; cv=none; d=zohomail.com; s=zohoarc; b=h0Z6jmkS+HmHO96zeZ3KvExGESTPq1kgNIvC91AbuxUwteGXVi1ri7BKOG4uxk+iO0RY+GuowoPjTjFJ94frxXdJO7golD30n5iqqVaIhtEpGdCvZFkfDsvHXV1Q7oWaGS7wbXeF6br0UJX5AhOgS+BUVPlUpOIUVoGQiQrRyLI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1767982610; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Owner:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Subject:Subject:To:To:Message-Id; bh=si6iM5Q08+odV2itqkAkXBPQ8Cjneuo1vXCrpiaPveg=; b=aP9isDnG/LPBw1OouHO3BnvyP7yFh/aGcggLn4MFADdfGdylq1btyyhnlBqeTye+rxDYR2TnWDr0gPbeLPdeRc+FiY1PqJKZ3HxGL8hssqAukIVPQrEWN2un3GKxq6nq9ir9cArehODhsAeroEvElcHETpZKvCNDzU9PfmLQ4CU= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1767982610637461.06300893670027; Fri, 9 Jan 2026 10:16:50 -0800 (PST) Received: by lists.libvirt.org (Postfix, from userid 993) id B97FE44084; Fri, 9 Jan 2026 13:16:49 -0500 (EST) Received: from [172.19.199.83] (lists.libvirt.org [8.43.85.245]) by lists.libvirt.org (Postfix) with ESMTP id 165D0441C9; Fri, 9 Jan 2026 13:10:26 -0500 (EST) Received: by lists.libvirt.org (Postfix, from userid 993) id 3BCD243E0C; Fri, 9 Jan 2026 13:09:53 -0500 (EST) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (3072 bits) server-digest SHA256) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id C4D8C43E0C for ; Fri, 9 Jan 2026 13:09:51 -0500 (EST) Received: from mail-pl1-f198.google.com (mail-pl1-f198.google.com [209.85.214.198]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-333--4Zv4h8-OI-bKzMqSv_uAg-1; Fri, 09 Jan 2026 13:09:50 -0500 Received: by mail-pl1-f198.google.com with SMTP id d9443c01a7336-2a09845b7faso38557895ad.3 for ; Fri, 09 Jan 2026 10:09:49 -0800 (PST) Received: from armenon-kvm.armenon-thinkpadp16vgen1.bengluru.csb ([49.36.108.228]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2a3e3cc8803sm111020495ad.71.2026.01.09.10.09.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 09 Jan 2026 10:09:47 -0800 (PST) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-3.4 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_LOW, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED,RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED,SPF_PASS autolearn=unavailable autolearn_force=no version=4.0.1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1767982191; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=si6iM5Q08+odV2itqkAkXBPQ8Cjneuo1vXCrpiaPveg=; b=fGJpHSETTQ5b7z6CZjZCdh6XlJhoa3tXN8bdJpul7uAHtzR6M2cYFaa93c+gigLuLXgLwY imlzef2xBhgxMatySNY7cKZWRwYK9U87ODZCbFSXS44ZuEmtTJmTifHsm3LTEFjXrnFuR0 YLpq65f8dU3m/tiIbKzPGx7nWsJou1c= X-MC-Unique: -4Zv4h8-OI-bKzMqSv_uAg-1 X-Mimecast-MFC-AGG-ID: -4Zv4h8-OI-bKzMqSv_uAg_1767982189 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767982188; x=1768586988; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=si6iM5Q08+odV2itqkAkXBPQ8Cjneuo1vXCrpiaPveg=; b=gynPuc+PLOgJON39aZKo2ipIID0Qw/M9byLPovd5gW03v9iJmrLr7vR50qU6e2adYf +iAicY9uUxy2roakEsfhaeVJj/jAuu2GaSXPddMJ260Z0DaWuxLWiohznJQkp6xfHYz0 K+0r2mB6SYgH2Ijcx/svJTP1Jk4CZZy0N9/HRJzz7TMoCzhVIsM2TNyniyalI4yaeLBX l92plyUtZH0lR779NLyBgt4KyZgMqTfV4+eLVTWyFLUj4xKwXSnHmFM5SK+uFnnsz5hL vmU3OEYxRe//wzv+pEbxEsQWf6mlTs3j+e2hY/2tkmBi8iyI0GJ5y9dhGx27BPLnQ72Z blBQ== X-Gm-Message-State: AOJu0YxTPKDh+6ENZ7PqcRu/TqsrtbY8rXP3cNhiTFigUxaOf3i3MIkY XuC17ohKeH+ztv5q2q8zKaFRhDXM6bOX6cb1hxCq6Ttx23OdIY0Tg5WjGBPN6JYWAMR0RVpLTFE TA0b8dN6phGhxrHjpvVtQ/k+DUCcVaD1gCV2gKAxOFtvokCIr0BaGhxoHW+mh+caf2NVRniSt9g EuvIf0d2aTe2B34ZdpH42qkPSYY0yHU7g3ap+8YQA7wA== X-Gm-Gg: AY/fxX5gtSpReDjdLkD+CApCwVUtP3K6iMkoO+l/YLbxVNlOp5e2e25Z0ULkS6AHi6Y 19wxGEdNjksZMJb9dyD38WbiJX8DEyqFNzrPM7hTY/5+cudHWn/aFQYjN1mvkHsJzptWkuYQgMx HKClhDUA1r2Bq0dOqeot2VxXZ/DrhyFu2S3SBXD2zDOBKWCcKIpSP3X76RNoypmsrdOREvEFhvy eV0Kac7oTz8EAusdywhjFamk1PpqSZdinx60e5hAVZ1gSxYSnBPWmrugfcLrdVsJ5gfTvA5sW/J gYJGiOCT/0NaUanXRvjr3bzlYQOuWnutCQM9sWcznasVn9pNuXzusQdMhfvQjIj5kOa0BsqdGdG e8JInq4IkHalvCGN0SqSE/6lLKkIEkF2+UyGfrE91p0F6O7Vnfvs0NWB8Pw== X-Received: by 2002:a17:903:2ec5:b0:29e:9e97:ca70 with SMTP id d9443c01a7336-2a3ee45b3a9mr109913925ad.25.1767982188484; Fri, 09 Jan 2026 10:09:48 -0800 (PST) X-Google-Smtp-Source: AGHT+IHWiFgpgbRR7j2LkrWah0C5BrMjwhYQqiq0N6/o1V23bwLz1Nx/4uxDovs2dDFIJ2wlJjm8og== X-Received: by 2002:a17:903:2ec5:b0:29e:9e97:ca70 with SMTP id d9443c01a7336-2a3ee45b3a9mr109913775ad.25.1767982188074; Fri, 09 Jan 2026 10:09:48 -0800 (PST) To: devel@lists.libvirt.org Subject: [PATCH v4 4/6] secret: Rename virSecretObj structure attribute from base64File to secretValueFile Date: Fri, 9 Jan 2026 23:39:34 +0530 Message-ID: <20260109180936.127454-5-armenon@redhat.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20260109180936.127454-1-armenon@redhat.com> References: <20260109180936.127454-1-armenon@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: ym40yRH0z6VVr_8MT1LbZPBx2qzcFOcQga1L3iyTpW8_1767982189 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Message-ID-Hash: FHQOAZCGMERCEAJE74HP3NYPBZQBUWXW X-Message-ID-Hash: FHQOAZCGMERCEAJE74HP3NYPBZQBUWXW X-MailFrom: armenon@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-devel.lists.libvirt.org-0; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Arun Menon X-Mailman-Version: 3.3.10 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Arun Menon via Devel Reply-To: Arun Menon X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1767982616197158500 Content-Type: text/plain; charset="utf-8"; x-default="true" Change the attribute name of _virSecretObj because we want it to have a gen= eric name to indicate that secret values can be stored in it in both base64 and encrypted formats. Signed-off-by: Arun Menon --- src/conf/virsecretobj.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/conf/virsecretobj.c b/src/conf/virsecretobj.c index 66270e2751..a3dd7983bb 100644 --- a/src/conf/virsecretobj.c +++ b/src/conf/virsecretobj.c @@ -39,7 +39,7 @@ VIR_LOG_INIT("conf.virsecretobj"); struct _virSecretObj { virObjectLockable parent; char *configFile; - char *base64File; + char *secretValueFile; virSecretDef *def; unsigned char *value; /* May be NULL */ size_t value_size; @@ -139,7 +139,7 @@ virSecretObjDispose(void *opaque) g_free(obj->value); } g_free(obj->configFile); - g_free(obj->base64File); + g_free(obj->secretValueFile); } =20 =20 @@ -378,11 +378,11 @@ virSecretObjListAdd(virSecretObjList *secrets, if (!(obj =3D virSecretObjNew())) goto cleanup; =20 - /* Generate the possible configFile and base64File strings + /* Generate the possible configFile and secretValueFile strings * using the configDir, uuidstr, and appropriate suffix */ if (!(obj->configFile =3D virFileBuildPath(configDir, uuidstr, ".x= ml")) || - !(obj->base64File =3D virFileBuildPath(configDir, uuidstr, ".b= ase64"))) + !(obj->secretValueFile =3D virFileBuildPath(configDir, uuidstr= , ".base64"))) goto cleanup; =20 if (virHashAddEntry(secrets->objs, uuidstr, obj) < 0) @@ -656,7 +656,7 @@ virSecretObjDeleteData(virSecretObj *obj) { /* The configFile will already be removed, so secret won't be * loaded again if this fails */ - unlink(obj->base64File); + unlink(obj->secretValueFile); } =20 =20 @@ -691,7 +691,7 @@ virSecretObjSaveData(virSecretObj *obj) =20 base64 =3D g_base64_encode(obj->value, obj->value_size); =20 - if (virFileRewriteStr(obj->base64File, S_IRUSR | S_IWUSR, base64) < 0) + if (virFileRewriteStr(obj->secretValueFile, S_IRUSR | S_IWUSR, base64)= < 0) return -1; =20 return 0; @@ -813,26 +813,26 @@ virSecretLoadValue(virSecretObj *obj) struct stat st; g_autofree char *contents =3D NULL; =20 - if ((fd =3D open(obj->base64File, O_RDONLY)) =3D=3D -1) { + if ((fd =3D open(obj->secretValueFile, O_RDONLY)) =3D=3D -1) { if (errno =3D=3D ENOENT) { ret =3D 0; goto cleanup; } virReportSystemError(errno, _("cannot open '%1$s'"), - obj->base64File); + obj->secretValueFile); goto cleanup; } =20 if (fstat(fd, &st) < 0) { virReportSystemError(errno, _("cannot stat '%1$s'"), - obj->base64File); + obj->secretValueFile); goto cleanup; } =20 if ((size_t)st.st_size !=3D st.st_size) { virReportError(VIR_ERR_INTERNAL_ERROR, _("'%1$s' file does not fit in memory"), - obj->base64File); + obj->secretValueFile); goto cleanup; } =20 @@ -845,7 +845,7 @@ virSecretLoadValue(virSecretObj *obj) =20 if (saferead(fd, contents, st.st_size) !=3D st.st_size) { virReportSystemError(errno, _("cannot read '%1$s'"), - obj->base64File); + obj->secretValueFile); goto cleanup; } contents[st.st_size] =3D '\0'; --=20 2.51.1 From nobody Mon Feb 2 07:25:57 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass(p=reject dis=none) header.from=lists.libvirt.org ARC-Seal: i=1; a=rsa-sha256; t=1767982681; cv=none; d=zohomail.com; s=zohoarc; b=dCKkPGAnvKz+7a8pm9D1KLHgY/eQcjWLCBbhhVoDUXcoOrZt+a+oQwXCH13IYAHFDHq0Xm4RAmO4XOOvcMqpfFanYupco6AIqxbCYxVKLzY1jb8nD7LJYFS3hupzHPCJSqNBY8UjcLlhq6kIqY0Bm/UdNcov53wamKbmGJ75IA8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1767982681; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Owner:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Subject:Subject:To:To:Message-Id; bh=WNB6OLtVPivx6R4QtSq9av4SuhjrOvAoVFJ77w5MYT4=; b=MDff9IpXVZgvr8cN08OJk+oEcqpjRD99qGppPbxekrIu8XZHjqO2B2UVmAgvy9jqHvjeg9+/c/7WOGkeua5FnVPPMXAMTkYwdFYVPYzCKyfffyw/1XK+rrC2kFVmz0eTOojfpRK6U9R6ukuAgx71zVTPp3VskEBytM5DRGIhx2s= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 17679826810091015.8712643267716; Fri, 9 Jan 2026 10:18:01 -0800 (PST) Received: by lists.libvirt.org (Postfix, from userid 993) id 882CA43F0F; Fri, 9 Jan 2026 13:18:00 -0500 (EST) Received: from [172.19.199.83] (lists.libvirt.org [8.43.85.245]) by lists.libvirt.org (Postfix) with ESMTP id 7417344204; Fri, 9 Jan 2026 13:10:30 -0500 (EST) Received: by lists.libvirt.org (Postfix, from userid 993) id 9110B43FC2; Fri, 9 Jan 2026 13:10:05 -0500 (EST) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (3072 bits) server-digest SHA256) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id B09DA43E35 for ; Fri, 9 Jan 2026 13:09:53 -0500 (EST) Received: from mail-pl1-f197.google.com (mail-pl1-f197.google.com [209.85.214.197]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-119-mzmUJe8uNmen9bCK7GNVMA-1; Fri, 09 Jan 2026 13:09:51 -0500 Received: by mail-pl1-f197.google.com with SMTP id d9443c01a7336-2a0a0bad5dfso80688365ad.0 for ; Fri, 09 Jan 2026 10:09:51 -0800 (PST) Received: from armenon-kvm.armenon-thinkpadp16vgen1.bengluru.csb ([49.36.108.228]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2a3e3cc8803sm111020495ad.71.2026.01.09.10.09.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 09 Jan 2026 10:09:49 -0800 (PST) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-3.4 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_LOW, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED,RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED,SPF_PASS autolearn=unavailable autolearn_force=no version=4.0.1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1767982193; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=WNB6OLtVPivx6R4QtSq9av4SuhjrOvAoVFJ77w5MYT4=; b=IBLejPE2LerRqL5DPA0zTXO96EJm5cBXNXMOj79ynh2qdk3ey7JG1Ofa8AoWmYUPY9qbcY 2zDS2jeDAmd0uPng0QQ35rtOBozhrX8Yh1OuWvX+XxKPsB0opfq51tL/s3WPIvjNFuVITo CMJuAFHtvf+II0o1TIDtOtBnC8pg904= X-MC-Unique: mzmUJe8uNmen9bCK7GNVMA-1 X-Mimecast-MFC-AGG-ID: mzmUJe8uNmen9bCK7GNVMA_1767982191 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767982190; x=1768586990; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=WNB6OLtVPivx6R4QtSq9av4SuhjrOvAoVFJ77w5MYT4=; b=hPPudut5RUfiowtDrPr/VI6QdXxpKTe9P6rAv+cuQ6a9jNy0Fjy6lZ2R3C/CYQ764W dwFwSbBI2YeubIW0aH818fhgl0QVfb/4B5a5A17vYpUUBlRPjz5hTtDonV2aTqJqhdZb S0DP7cAIwedZtHX+F251nmu/LEkklg7VmDTMW/hiafK9r0df4P6014JOJIWDz8cwKONT 8jQX7YhvjoXgVrPHGIfkwYmopcIWL4268IuzaGCKrVbpbLRyq4GMxUBF4Z6hQRgpoE1I 0/A1oQZa3NOnhmc+kJGUSdO5xlOr4GXZj0ZAfTmGmmZe07LajslcdU0hOp6Gk3pmEv5a an1A== X-Gm-Message-State: AOJu0Yx2X79pYDJ6hCIzNP7c/68eisGXKzFgUZCv0kDufvcfHwGZxXAA 17J0eshCYLE7uwCKutyZEOBB44O5z/qCZmeYNHyqKlH1lU4Qu2JG6W+pgNs/rcLT4X/NZ3wlYmw 2Haqs1Nx53SsIMv3YSlzmd4KLJBhjWN/maprV6Z9zOYfvCt8iSRidYqUAPKi/dQIHfLnKCGriR6 zN72No0g+DtROSay2E8YYOE7Tq84hPfeqNdz0749f9zQ== X-Gm-Gg: AY/fxX5lEFKqpVvOJLiZ0j5V7fsnimlVX6KuoismDhZcc6SowJJpEZhk8FYx8Oe2YnC aZ6h5nOSknJHBxxhYuZnOFsYUrvQ0Mb9MWkppcbH+WwDEXLPRxliNJJICGcG+dNPVHhvNJUbpJO OEXw5Brwa1h0cpJFox3yDq+789BEVr+Q4NjBtHRjqs+VyajfHQtHiYLZxZ0juWCL+Ddv8etvipR 5/VxQgIjo4FiAyBGAcnJvPWiRbqs0kn4e+5xwe0IOOWDoPLwGsWtsQ3D8XOy/ija/J57PLiArWg JppldK9JQGZ+TUsuz3trsFHYzOA1mTSSvZmQdEg8skPD5uT3nFb9u3IxIJ+gV6r6az3fl+0o3qy OFW1v4/dXVsfGnQ9cNRBCawqC4Vf0I9dMJM2GR0fLoMUbOP8j+VYldbWvnQ== X-Received: by 2002:a17:903:234a:b0:2a0:b066:3f55 with SMTP id d9443c01a7336-2a3ee4151fbmr97422745ad.10.1767982190380; Fri, 09 Jan 2026 10:09:50 -0800 (PST) X-Google-Smtp-Source: AGHT+IHEIq7Y13NlaJN/K4TgZAXvAqMXF2p/yqsNps62EySeBN8BFx2AsevIoSGh8VqphINmRJyokw== X-Received: by 2002:a17:903:234a:b0:2a0:b066:3f55 with SMTP id d9443c01a7336-2a3ee4151fbmr97422505ad.10.1767982189770; Fri, 09 Jan 2026 10:09:49 -0800 (PST) To: devel@lists.libvirt.org Subject: [PATCH v4 5/6] secret: Add functionality to load and save secrets in encrypted format Date: Fri, 9 Jan 2026 23:39:35 +0530 Message-ID: <20260109180936.127454-6-armenon@redhat.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20260109180936.127454-1-armenon@redhat.com> References: <20260109180936.127454-1-armenon@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: REIXmKTRc2dGDbB8ocgBGVoxhqHFWSvAam3gYJyYxM8_1767982191 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Message-ID-Hash: KZZMO6P226T3N7YKDH76SA6QYJQGWW3L X-Message-ID-Hash: KZZMO6P226T3N7YKDH76SA6QYJQGWW3L X-MailFrom: armenon@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-devel.lists.libvirt.org-0; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Arun Menon X-Mailman-Version: 3.3.10 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Arun Menon via Devel Reply-To: Arun Menon X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1767982707690158500 Content-Type: text/plain; charset="utf-8"; x-default="true" Now that we have the functionality to provide the secrets driver with an encryption key through a configuration file or using system credentials, and the newly introduced array to iterate over the encryption schemes, we can use the key to save and load secrets. Encrypt all secrets that are going to be saved on the disk if the 'secrets_encryption_key' path is set in the secret.conf file OR if a valid systemd generated credential exists. While loading secrets, identify the decryption method by matching the file extension of the stored secret against the known array values. If no matching scheme is found, the secret is skipped. If the encryption key is changed across restarts, then also the secret driver will fail to lo= ad the secrets from the disk that were encrypted with the former key. Signed-off-by: Arun Menon --- src/conf/virsecretobj.c | 175 ++++++++++++++++++++++++++++++------- src/conf/virsecretobj.h | 18 +++- src/secret/secret_driver.c | 23 +++-- 3 files changed, 176 insertions(+), 40 deletions(-) diff --git a/src/conf/virsecretobj.c b/src/conf/virsecretobj.c index a3dd7983bb..4dcb32f69a 100644 --- a/src/conf/virsecretobj.c +++ b/src/conf/virsecretobj.c @@ -31,6 +31,10 @@ #include "virhash.h" #include "virlog.h" #include "virstring.h" +#include "virsecret.h" +#include "virrandom.h" +#include "vircrypto.h" +#include "virsecureerase.h" =20 #define VIR_FROM_THIS VIR_FROM_SECRET =20 @@ -45,6 +49,16 @@ struct _virSecretObj { size_t value_size; }; =20 +typedef struct _virSecretSchemeInfo { + const char *suffix; + virCryptoCipher cipher; +} virSecretSchemeInfo; + +virSecretSchemeInfo schemeInfo[] =3D { + { ".aes256cbc", VIR_CRYPTO_CIPHER_AES256CBC }, + { ".base64", -1 }, +}; + static virClass *virSecretObjClass; static virClass *virSecretObjListClass; static void virSecretObjDispose(void *obj); @@ -323,7 +337,8 @@ virSecretObj * virSecretObjListAdd(virSecretObjList *secrets, virSecretDef **newdef, const char *configDir, - virSecretDef **oldDef) + virSecretDef **oldDef, + bool encryptData) { virSecretObj *obj; virSecretDef *objdef; @@ -363,6 +378,11 @@ virSecretObjListAdd(virSecretObjList *secrets, } else { /* No existing secret with same UUID, * try look for matching usage instead */ + const char *secretSuffix =3D ".base64"; + g_autofree char *encryptionSchemeSuffix =3D NULL; + g_autofree char *oldSecretValueFile =3D virFileBuildPath(configDir, + uuidstr, + secretSuffi= x); if ((obj =3D virSecretObjListFindByUsageLocked(secrets, (*newdef)->usage_type, (*newdef)->usage_id))= ) { @@ -379,10 +399,24 @@ virSecretObjListAdd(virSecretObjList *secrets, goto cleanup; =20 /* Generate the possible configFile and secretValueFile strings - * using the configDir, uuidstr, and appropriate suffix + * using the configDir, uuidstr, and appropriate suffix. + * By default, the latest encryption cipher will be used to encryp= t secrets. */ + if (encryptData) { + /* The virSecretObjListAdd() function is called during both + * loading a secret and creating a new one. Check if there is = an unencrypted + * .base64 secret present on the disk. + */ + if (virFileExists(oldSecretValueFile)) { + encryptionSchemeSuffix =3D g_strdup(secretSuffix); + } else { + encryptionSchemeSuffix =3D g_strdup(schemeInfo[0].suffix); + } + } else { + encryptionSchemeSuffix =3D g_strdup(secretSuffix); + } if (!(obj->configFile =3D virFileBuildPath(configDir, uuidstr, ".x= ml")) || - !(obj->secretValueFile =3D virFileBuildPath(configDir, uuidstr= , ".base64"))) + !(obj->secretValueFile =3D virFileBuildPath(configDir, uuidstr= , encryptionSchemeSuffix))) goto cleanup; =20 if (virHashAddEntry(secrets->objs, uuidstr, obj) < 0) @@ -682,15 +716,40 @@ virSecretObjSaveConfig(virSecretObj *obj) =20 =20 int -virSecretObjSaveData(virSecretObj *obj) +virSecretObjSaveData(virSecretObj *obj, + bool encryptData, + uint8_t *secretsEncryptionKey, + size_t secretsKeyLen) { g_autofree char *base64 =3D NULL; + g_autofree uint8_t *secret =3D NULL; + g_autofree uint8_t *encryptedValue =3D NULL; + size_t encryptedValueLen =3D 0; + size_t secretLen =3D 0; + uint8_t iv[16] =3D { 0 }; =20 if (!obj->value) return 0; =20 - base64 =3D g_base64_encode(obj->value, obj->value_size); - + if (encryptData && secretsEncryptionKey) { + if (virRandomBytes(iv, sizeof(iv)) < 0) { + return -1; + } + if (virCryptoEncryptData(schemeInfo[0].cipher, + secretsEncryptionKey, secretsKeyLen, + iv, sizeof(iv), + (uint8_t *)obj->value, obj->value_size, + &encryptedValue, &encryptedValueLen) < 0)= { + return -1; + } + secretLen =3D sizeof(iv) + encryptedValueLen; + secret =3D g_new0(uint8_t, secretLen); + memcpy(secret, iv, sizeof(iv)); + memcpy(secret + sizeof(iv), encryptedValue, encryptedValueLen); + base64 =3D g_base64_encode(secret, secretLen); + } else { + base64 =3D g_base64_encode(obj->value, obj->value_size); + } if (virFileRewriteStr(obj->secretValueFile, S_IRUSR | S_IWUSR, base64)= < 0) return -1; =20 @@ -737,7 +796,10 @@ virSecretObjGetValue(virSecretObj *obj) int virSecretObjSetValue(virSecretObj *obj, const unsigned char *value, - size_t value_size) + size_t value_size, + bool encryptData, + uint8_t *secretsEncryptionKey, + size_t secretsKeyLen) { virSecretDef *def =3D obj->def; g_autofree unsigned char *old_value =3D NULL; @@ -753,7 +815,10 @@ virSecretObjSetValue(virSecretObj *obj, obj->value =3D g_steal_pointer(&new_value); obj->value_size =3D value_size; =20 - if (!def->isephemeral && virSecretObjSaveData(obj) < 0) + if (!def->isephemeral && virSecretObjSaveData(obj, + encryptData, + secretsEncryptionKey, + secretsKeyLen) < 0) goto error; =20 /* Saved successfully - drop old value */ @@ -807,11 +872,23 @@ virSecretLoadValidateUUID(virSecretDef *def, =20 =20 static int -virSecretLoadValue(virSecretObj *obj) +virSecretLoadValue(virSecretObj *obj, + uint8_t *secretsEncryptionKey, + size_t secretsKeyLen) { - int ret =3D -1, fd =3D -1; + int ret =3D -1; + VIR_AUTOCLOSE fd =3D -1; struct stat st; + size_t i; + g_autofree char *contents =3D NULL; + g_autofree uint8_t *contentsEncrypted =3D NULL; + g_autofree uint8_t *decryptedValue =3D NULL; + + size_t decryptedValueLen =3D 0; + uint8_t iv[16] =3D { 0 }; + uint8_t *ciphertext =3D NULL; + size_t ciphertextLen =3D 0; =20 if ((fd =3D open(obj->secretValueFile, O_RDONLY)) =3D=3D -1) { if (errno =3D=3D ENOENT) { @@ -841,25 +918,52 @@ virSecretLoadValue(virSecretObj *obj) goto cleanup; } =20 - contents =3D g_new0(char, st.st_size + 1); - - if (saferead(fd, contents, st.st_size) !=3D st.st_size) { - virReportSystemError(errno, _("cannot read '%1$s'"), - obj->secretValueFile); - goto cleanup; + /* Iterate over the encryption schemes and decrypt the contents + * of the file on the disk, by matching the file extension with the en= cryption + * scheme. + * If there is no scheme matching the file extension, then that secret= is not loaded. */ + + for (i =3D 0; i < G_N_ELEMENTS(schemeInfo); i++) { + if (virStringHasSuffix(obj->secretValueFile, schemeInfo[i].suffix)= ) { + contents =3D g_new0(char, st.st_size + 1); + if (saferead(fd, contents, st.st_size) !=3D st.st_size) { + virReportSystemError(errno, _("cannot read '%1$s'"), + obj->secretValueFile); + goto cleanup; + } + contents[st.st_size] =3D '\0'; + if (schemeInfo[i].cipher !=3D -1) { + contentsEncrypted =3D g_base64_decode(contents, &obj->valu= e_size); + if (sizeof(iv) > obj->value_size) { + virReportError(VIR_ERR_INVALID_SECRET, + _("Encrypted secret size '%1$zu' is inv= alid"), + obj->value_size); + goto cleanup; + } + memcpy(iv, contentsEncrypted, sizeof(iv)); + ciphertext =3D contentsEncrypted + sizeof(iv); + ciphertextLen =3D obj->value_size - sizeof(iv); + if (virCryptoDecryptData(schemeInfo[i].cipher, + secretsEncryptionKey, secretsKeyL= en, + iv, sizeof(iv), + ciphertext, ciphertextLen, + &decryptedValue, &decryptedValueL= en) < 0) { + goto cleanup; + } + g_free(obj->value); + obj->value =3D g_steal_pointer(&decryptedValue); + obj->value_size =3D decryptedValueLen; + } else { + obj->value =3D g_base64_decode(contents, &obj->value_size); + } + break; + } } - contents[st.st_size] =3D '\0'; - - VIR_FORCE_CLOSE(fd); - - obj->value =3D g_base64_decode(contents, &obj->value_size); - ret =3D 0; - cleanup: - if (contents !=3D NULL) - memset(contents, 0, st.st_size); - VIR_FORCE_CLOSE(fd); + virSecureErase(contentsEncrypted, obj->value_size); + virSecureErase(contents, st.st_size); + virSecureErase(iv, sizeof(iv)); return ret; } =20 @@ -868,7 +972,10 @@ static virSecretObj * virSecretLoad(virSecretObjList *secrets, const char *file, const char *path, - const char *configDir) + const char *configDir, + bool encryptData, + uint8_t *secretsEncryptionKey, + size_t secretsKeyLen) { g_autoptr(virSecretDef) def =3D NULL; virSecretObj *obj =3D NULL; @@ -879,10 +986,10 @@ virSecretLoad(virSecretObjList *secrets, if (virSecretLoadValidateUUID(def, file) < 0) return NULL; =20 - if (!(obj =3D virSecretObjListAdd(secrets, &def, configDir, NULL))) + if (!(obj =3D virSecretObjListAdd(secrets, &def, configDir, NULL, encr= yptData))) return NULL; =20 - if (virSecretLoadValue(obj) < 0) { + if (virSecretLoadValue(obj, secretsEncryptionKey, secretsKeyLen) < 0) { virSecretObjListRemove(secrets, obj); g_clear_pointer(&obj, virObjectUnref); return NULL; @@ -894,7 +1001,10 @@ virSecretLoad(virSecretObjList *secrets, =20 int virSecretLoadAllConfigs(virSecretObjList *secrets, - const char *configDir) + const char *configDir, + bool encryptData, + uint8_t *secretsEncryptionKey, + size_t secretsKeyLen) { g_autoptr(DIR) dir =3D NULL; struct dirent *de; @@ -915,7 +1025,10 @@ virSecretLoadAllConfigs(virSecretObjList *secrets, if (!(path =3D virFileBuildPath(configDir, de->d_name, NULL))) continue; =20 - if (!(obj =3D virSecretLoad(secrets, de->d_name, path, configDir))= ) { + if (!(obj =3D virSecretLoad(secrets, de->d_name, path, configDir, + encryptData, + secretsEncryptionKey, + secretsKeyLen))) { VIR_ERROR(_("Error reading secret: %1$s"), virGetLastErrorMessage()); continue; diff --git a/src/conf/virsecretobj.h b/src/conf/virsecretobj.h index 17897c5513..2e4d980988 100644 --- a/src/conf/virsecretobj.h +++ b/src/conf/virsecretobj.h @@ -51,7 +51,8 @@ virSecretObj * virSecretObjListAdd(virSecretObjList *secrets, virSecretDef **newdef, const char *configDir, - virSecretDef **oldDef); + virSecretDef **oldDef, + bool encryptData); =20 typedef bool (*virSecretObjListACLFilter)(virConnectPtr conn, @@ -86,7 +87,10 @@ int virSecretObjSaveConfig(virSecretObj *obj); =20 int -virSecretObjSaveData(virSecretObj *obj); +virSecretObjSaveData(virSecretObj *obj, + bool encryptData, + uint8_t *secretsEncryptionKey, + size_t secretsKeyLen); =20 virSecretDef * virSecretObjGetDef(virSecretObj *obj); @@ -101,7 +105,10 @@ virSecretObjGetValue(virSecretObj *obj); int virSecretObjSetValue(virSecretObj *obj, const unsigned char *value, - size_t value_size); + size_t value_size, + bool encryptData, + uint8_t *secretsEncryptionKey, + size_t secretsKeyLen); =20 size_t virSecretObjGetValueSize(virSecretObj *obj); @@ -112,4 +119,7 @@ virSecretObjSetValueSize(virSecretObj *obj, =20 int virSecretLoadAllConfigs(virSecretObjList *secrets, - const char *configDir); + const char *configDir, + bool encryptData, + uint8_t *secretsEncryptionKey, + size_t secretsKeyLen); diff --git a/src/secret/secret_driver.c b/src/secret/secret_driver.c index 9b13772ad3..f25b9ba73f 100644 --- a/src/secret/secret_driver.c +++ b/src/secret/secret_driver.c @@ -223,13 +223,17 @@ secretDefineXML(virConnectPtr conn, goto cleanup; =20 if (!(obj =3D virSecretObjListAdd(driver->secrets, &def, - driver->configDir, &backup))) + driver->configDir, &backup, + driver->config->encryptData))) goto cleanup; objDef =3D virSecretObjGetDef(obj); =20 if (!objDef->isephemeral) { if (backup && backup->isephemeral) { - if (virSecretObjSaveData(obj) < 0) + if (virSecretObjSaveData(obj, + driver->config->encryptData, + driver->config->secretsEncryptionKey, + driver->config->secretsKeyLen) < 0) goto restore_backup; } =20 @@ -333,7 +337,10 @@ secretSetValue(virSecretPtr secret, if (virSecretSetValueEnsureACL(secret->conn, def) < 0) goto cleanup; =20 - if (virSecretObjSetValue(obj, value, value_size) < 0) + if (virSecretObjSetValue(obj, value, value_size, + driver->config->encryptData, + driver->config->secretsEncryptionKey, + driver->config->secretsKeyLen) < 0) goto cleanup; =20 event =3D virSecretEventValueChangedNew(def->uuid, @@ -542,7 +549,10 @@ secretStateInitialize(bool privileged, if (!(driver->secrets =3D virSecretObjListNew())) goto error; =20 - if (virSecretLoadAllConfigs(driver->secrets, driver->configDir) < 0) + if (virSecretLoadAllConfigs(driver->secrets, driver->configDir, + driver->config->encryptData, + driver->config->secretsEncryptionKey, + driver->config->secretsKeyLen) < 0) goto error; =20 return VIR_DRV_STATE_INIT_COMPLETE; @@ -564,7 +574,10 @@ secretStateReload(void) if (!(driver->config =3D virSecretDaemonConfigNew(driver->privileged))) return -1; =20 - ignore_value(virSecretLoadAllConfigs(driver->secrets, driver->configDi= r)); + ignore_value(virSecretLoadAllConfigs(driver->secrets, driver->configDi= r, + driver->config->encryptData, + driver->config->secretsEncryption= Key, + driver->config->secretsKeyLen)); =20 return 0; } --=20 2.51.1 From nobody Mon Feb 2 07:25:57 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass(p=reject dis=none) header.from=lists.libvirt.org ARC-Seal: i=1; a=rsa-sha256; t=1767982743; cv=none; d=zohomail.com; s=zohoarc; b=EIh8sPDqtKnGEWhgLRyxImTxz+oCldYKr1NBfVN++D3hyJCpWGFyA2KKSJPRA0ojMCF/FBidwN5qE+aEMSbB0ZezTcmOjVWqisRsMpov2JC2dUGWRFb1N3SjxoXywUbQqm0VdP5Ws42teOIFUu94ZwkkTwQks0ozkdjuJr3a91o= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1767982743; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Owner:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Subject:Subject:To:To:Message-Id; bh=NMLKTVgOID2ZVVWcJiLaxsBvyoc6Cpy2r0z4jFERyG8=; b=UJDDGaDr7bBqXYeo4y+n8w907TTu0EnUEq67toqALMrxLrmWCcx5aqvLiKcRZbKA/eZVbAPmc8gTensz6ZKdtkU1FHyaFk9AyiwQ3gu5Nu3KIs24DYTqVfJkS+qRMPNLo/EwpXNLMEVGhV8mXmPHiasyecNgxgyh0BLGQ9BB0Q8= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1767982743906684.4055367632726; Fri, 9 Jan 2026 10:19:03 -0800 (PST) Received: by lists.libvirt.org (Postfix, from userid 993) id 0CA5943E53; Fri, 9 Jan 2026 13:19:03 -0500 (EST) Received: from [172.19.199.83] (lists.libvirt.org [8.43.85.245]) by lists.libvirt.org (Postfix) with ESMTP id ABF6B44213; Fri, 9 Jan 2026 13:10:34 -0500 (EST) Received: by lists.libvirt.org (Postfix, from userid 993) id A002343FDA; Fri, 9 Jan 2026 13:10:13 -0500 (EST) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (3072 bits) server-digest SHA256) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id 5685C43E7B for ; Fri, 9 Jan 2026 13:09:55 -0500 (EST) Received: from mail-pg1-f199.google.com (mail-pg1-f199.google.com [209.85.215.199]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-211-tbvOgy8yNSmboGTOwT0BYw-1; Fri, 09 Jan 2026 13:09:53 -0500 Received: by mail-pg1-f199.google.com with SMTP id 41be03b00d2f7-c56848e6f45so527678a12.2 for ; Fri, 09 Jan 2026 10:09:53 -0800 (PST) Received: from armenon-kvm.armenon-thinkpadp16vgen1.bengluru.csb ([49.36.108.228]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2a3e3cc8803sm111020495ad.71.2026.01.09.10.09.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 09 Jan 2026 10:09:51 -0800 (PST) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-3.4 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_LOW, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED,RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED,SPF_PASS autolearn=unavailable autolearn_force=no version=4.0.1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1767982195; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=NMLKTVgOID2ZVVWcJiLaxsBvyoc6Cpy2r0z4jFERyG8=; b=JVXDjnPU9uegtxM+l98H4HRxeU02a01HOjNkfw8ghAHtocKgo7QjsMO959EEXaeptiClfn HFcqLdQoQRS+GtxWEqwy2N443OpvAaVy63lWdasbWgBggCF8hxRa0KNDGGGwH9tH7fB8lt +9f/X6pciqjKyy9/F2Jc0fhWjWmWsBc= X-MC-Unique: tbvOgy8yNSmboGTOwT0BYw-1 X-Mimecast-MFC-AGG-ID: tbvOgy8yNSmboGTOwT0BYw_1767982192 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767982192; x=1768586992; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=NMLKTVgOID2ZVVWcJiLaxsBvyoc6Cpy2r0z4jFERyG8=; b=u4/X4eFYSYyF9UV0/IICdEAIJNVhjR+j08uilNCFMIda/B3IIZUw7hVPyCXk5ArA7w rJ0ejP60HSKmeUC3L4L8/2lk9x2T66TDrjOeNwW1zFwirwjWY+QdTPB8ofJg8JDnXDZ4 pMgHQxnL40lh41jb6OuEcWGRWZqkQnimXMm2CvsOdWtgBrxaA0e0tk/s7uPck8mxBjkZ 23q01h3ZLzEjqulxphyywfBv+t3aqnt7MpfCSz8Qi8JQx6Vg+ipDM+JezmoOrcs2R70a TOIiS58GTSoFFAd7C1yxX0mYmxbj2NXJO1/bulFlFL94hBCdDTd5iE6HluBKGREi5bLr N/dw== X-Gm-Message-State: AOJu0Yz005d5So2Ea0UzsdZZoPSESr2dXGkCk1daVGJ9SXRH5/lCbC4e +lUYNqa1jSqJ/VZxIss6jraWl+N0FrqFKrtU7DI9pLfcHX828ofkWacHIdR77ba9r6E4JhkXrkD QEA/YLmZQCHralbShsu43CAwurozv65vIQu8LNUO84EOlH05QIPeSEzLaFJTokScAGspVk8NUmI ohid0Z0MS0tIHGWecojm/HIW+Cg22a5Rq9NcfcT4TY0w== X-Gm-Gg: AY/fxX6tupUcGPa3lfTSV9KNxztQ+abaBDq0Kk8N55dssqjzrr6ITM6+iFeC/wCAOxk FHkJGQqekl8HDHIZ0NpmrabwIm7MYYLI9TpNEVNGZY4+uVSLv8f5WApOW3sSKhe9cSItMZAjDuQ +W4B6z2WNc4Tr5+lLNS4H1Io6x7leay/UZQergU3q9wTmrC/V8PukIVKWbblMHdPJfya+YE6SM4 VMfvXRzk3/ckbzxHHlVvnMcxGJo1p2deKEByIXbchsWv2erzZ0V/pktGzYiRmQ83dppr9k2aKR7 mLIN0YO98HWa42SLWjPaHjM646xhbetwpvxan6DZ62bTnPXJ7nLhnyyMf1mTQtDGJxO8rixDGD+ Yq3AGhR4iUYzYCU+LMqAEPoPFMJOD5ZJT9EIc9VANeDakBmUDg9st/lpYnQ== X-Received: by 2002:a17:903:2cb:b0:2a0:ccee:b354 with SMTP id d9443c01a7336-2a3ee47f36fmr107164815ad.35.1767982191899; Fri, 09 Jan 2026 10:09:51 -0800 (PST) X-Google-Smtp-Source: AGHT+IEByZb5wWOraeWdNdhyl1B8TzyqBkAbUGqMA7czsADXMzg4z/06ABFY3swkgoGh5Hn+EQlUnA== X-Received: by 2002:a17:903:2cb:b0:2a0:ccee:b354 with SMTP id d9443c01a7336-2a3ee47f36fmr107164625ad.35.1767982191400; Fri, 09 Jan 2026 10:09:51 -0800 (PST) To: devel@lists.libvirt.org Subject: [PATCH v4 6/6] docs: secret: Add documentation of secret encryption feature Date: Fri, 9 Jan 2026 23:39:36 +0530 Message-ID: <20260109180936.127454-7-armenon@redhat.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20260109180936.127454-1-armenon@redhat.com> References: <20260109180936.127454-1-armenon@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: 6bkuk--ns_tBWwZknh035eeDgxc5j1iY4cMY6nRE9Go_1767982192 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Message-ID-Hash: GEODMIV6U2UZ5B64BNKQRK6XARKRYDAX X-Message-ID-Hash: GEODMIV6U2UZ5B64BNKQRK6XARKRYDAX X-MailFrom: armenon@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-devel.lists.libvirt.org-0; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Arun Menon X-Mailman-Version: 3.3.10 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Arun Menon via Devel Reply-To: Arun Menon X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1767982749093158500 Content-Type: text/plain; charset="utf-8"; x-default="true" Document the new encryption of secrets feature in secretencryption.rst. Signed-off-by: Arun Menon --- docs/drvsecret.rst | 4 ++ docs/meson.build | 1 + docs/secretencryption.rst | 86 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 docs/secretencryption.rst diff --git a/docs/drvsecret.rst b/docs/drvsecret.rst index 76a9097d2b..234551d5ae 100644 --- a/docs/drvsecret.rst +++ b/docs/drvsecret.rst @@ -63,3 +63,7 @@ the traditional system or session libvirt connections to = QEMU. Normal practice would be to open the secret driver in embedded mode any time one of the ot= her drivers is opened in embedded mode so that the two drivers can interact in-process. + +Further reading +---------------------------- +- `Secret Encryption `__ diff --git a/docs/meson.build b/docs/meson.build index 21e0b19c25..0e74f9c4bf 100644 --- a/docs/meson.build +++ b/docs/meson.build @@ -97,6 +97,7 @@ docs_rst_files =3D [ 'programming-languages', 'python', 'remote', + 'secretencryption', 'securityprocess', 'ssh-proxy', 'storage', diff --git a/docs/secretencryption.rst b/docs/secretencryption.rst new file mode 100644 index 0000000000..0762fec685 --- /dev/null +++ b/docs/secretencryption.rst @@ -0,0 +1,86 @@ +.. role:: since + +Secret storage and encryption +----------------------------- + +The secret objects can either be ephemeral or persistent. +Ephemeral secrets are only kept in memory, never stored persistently on th= e disk. +See `Secrets `__ + +:since:`Since 12.0.0` if a secret is defined as persistent, then it is sto= red **encrypted** on the disk. + + +Systemd Credentials Sealing +--------------------------- + +Out of the box, secrets are sealed using systemd credentials. This ties the +encrypted secret files to the specific host. + +The `virt-secret-init-encryption` service automatically generates a random +32-byte key and encrypts it using `systemd-creds`, storing the result in +`/var/lib/libvirt/secrets/secrets-encryption-key`. The `virtsecretd` servi= ce +then automatically loads this key securely via the systemd `LoadCredential= Encrypted` +mechanism. + +Disabling Systemd Credentials +----------------------------- + +You can control encryption behavior by editing the `secret.conf` configura= tion +file located in ``@SYSCONFDIR@/libvirt/secret.conf`` or ``$XDG_CONFIG_HOME= /libvirt/secret.conf`` +depending on how the daemon was started (system mode or session mode respe= ctively). + +To **disable encryption entirely** (which effectively disables the use of = any +systemd credentials for this purpose): + +:: + + encrypt_data =3D 0 + +Setting ``encrypt_data =3D 0`` takes precedence over any available systemd +credentials. If you have existing encrypted secrets, this setting will pre= vent +the secret driver from loading the encryption key, making those secrets +inaccessible. New or updated secrets will be stored in plain base64 format. + +To **use a custom encryption key** instead of the systemd credential. +Defining a custom key path takes precedence over the systemd credential + +:: + + secrets_encryption_key =3D "/path/to/custom/key" + +Configuring Encryption on Non-Systemd Hosts +------------------------------------------- + +On hosts without systemd, or if you prefer to manage the key manually, you= can +create a raw encryption key and configure libvirt to use it. + +Generate a random 32-byte key: + +:: + + dd if=3D/dev/urandom of=3D/path/to/key/file bs=3D32 count=3D1 + +Update `secret.conf` to point to this key: + +:: + + secrets_encryption_key =3D "/path/to/key/file" + +Manual Systemd Credential Creation +---------------------------------- + +If you want to use systemd credentials but need to customize the encryptio= n parameters +(for example, to specify which TPM PCRs to bind to), you can generate the +credential file manually. + +To create the default `/var/lib/libvirt/secrets/secrets-encryption-key` ma= nually +using `systemd-creds` (adjusting arguments to `systemd-creds encrypt` as n= eeded): + +:: + + dd if=3D/dev/urandom bs=3D32 count=3D1 | \ + systemd-creds encrypt --name=3Dsecrets-encryption-key - \ + /var/lib/libvirt/secrets/secrets-encryption-key + +You can pass extra arguments to `systemd-creds encrypt `__, +such as ``--tpm2-device=3D...`` or ``--tpm2-pcrs=3D...``, to customize the= sealing policy. --=20 2.51.1