From nobody Wed Feb 11 03:02:07 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; 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=1770711282; cv=none; d=zohomail.com; s=zohoarc; b=fB2DfFE8JrqpBn1CXu7bZz3LqQxUAhOZqdbQKFlNst2SOVB8KBK+jsfYC8JR1ZFIpxGmHTyiFMepX+DxqdLBDG1/GIUCOlbKHKi1Bf2B22oAEBN/dl9CPWJRFbf0KvSQsVWoymDBX42pg2FBnMO0Tu3tDscs3apD4tzTwHaqw0w= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1770711282; 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=bgNp1ECUBLvQo36J/DBZcMqZSPBkwyBvfAi64UTxOEU=; b=GMaOxzsquxTfpxY5ciRT7DYQma09vY71OcnP9pqELU2DHGk/XvqODI+e7BOYXudNS8f2LhDUYnrObRGELcijhsq2Lv/3jcWnLV79ZKv5ya68fwgeR1q4N/oHUNgQUpTQ8BsWrVUlEYc1KNgpUitwNP6AHAq9ofuVmiHQ8UMv8CU= 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 1770711282598275.4329203920779; Tue, 10 Feb 2026 00:14:42 -0800 (PST) Received: by lists.libvirt.org (Postfix, from userid 993) id 67FFE43ED9; Tue, 10 Feb 2026 03:14:41 -0500 (EST) Received: from [172.19.199.6] (lists.libvirt.org [8.43.85.245]) by lists.libvirt.org (Postfix) with ESMTP id B72CD44110; Tue, 10 Feb 2026 03:11:27 -0500 (EST) Received: by lists.libvirt.org (Postfix, from userid 993) id E331E3F357; Tue, 10 Feb 2026 03:00:26 -0500 (EST) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.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 833803F2B4 for ; Tue, 10 Feb 2026 03:00:22 -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-258-wjV8SCGNPISosLbZKM4MUw-1; Tue, 10 Feb 2026 03:00:20 -0500 Received: by mail-pl1-f197.google.com with SMTP id d9443c01a7336-2ab0b2e804cso7519395ad.3 for ; Tue, 10 Feb 2026 00:00:20 -0800 (PST) Received: from armenon-kvm.armenon-thinkpadp16vgen1.bengluru.csb ([49.36.106.198]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2aadc397d8dsm98273835ad.1.2026.02.10.00.00.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Feb 2026 00:00:17 -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=-5.0 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED, 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=1770710422; 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=bgNp1ECUBLvQo36J/DBZcMqZSPBkwyBvfAi64UTxOEU=; b=QbuGHZc67FvCsSYPsPq8IpLZ48Ku6pn+fgDtsH+OiCtOcU5/l9grYBdQ9FzBDyO3elrL0E 7125KR3ktqoQmmxzv6CwHy7rTbVfHPeheeUwJZrPd/vjzNQQJwOamRTPxv2wQz95gSi0e2 Ecfi2G6NBCNFGoM9vf4YB1X6svfbMnA= X-MC-Unique: wjV8SCGNPISosLbZKM4MUw-1 X-Mimecast-MFC-AGG-ID: wjV8SCGNPISosLbZKM4MUw_1770710419 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770710419; x=1771315219; 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=bgNp1ECUBLvQo36J/DBZcMqZSPBkwyBvfAi64UTxOEU=; b=YGDHLWEu73BDTD7dVU3Q/lTY6byCZNmMwkK3kqgUSy/wYWOjNZv3os9iPJrHlkC7eb 205Kmjuuhx8y6o0bfumlVRyJQC20KJbvBpBcv3BLYX8TG2+2jD+KGU67IrwelySqMd/+ I84WOljRzdA+EodLbSSaHSMXJzmVlUugC6QcDtPF1Zm1aoaqA9nHgrNX5QxZ+PhsCsPv az5fyPjGC49wGNWl8Ft6Q6vn/7B+JkJlSzl6/6J3h2VYVR1lyobcQKe16Tq8SA2DelrO NHrwAOiCeb7DYSpYeZ6Msv2C9Fs/X4qY6OUtLN2eYwCPWCpmOfqag0PuyIRWHp9wwyU1 kH7A== X-Gm-Message-State: AOJu0Ywh31LB1eFTFHqdSD9khgXPaviz++KSivVk5mtcEI8FUaJISm2H DC884AoLSbnnn/z5kb04FGBOdlAmiOIWG+NQUoMe+njdLu9MR+7zW8oXntfMO8ARGhp/OIdsoyk j6U5gxfRLYvL1hrvtyPOEQVSWbbMDeYDRmNYBdA4m0bUsW6N7HMFKhrpOuctltVh2cw3SDWpfDg kdYKY5PMcTBJIR6N1eWNMvhEXUV0RwGvNJM9YxrjNDFw== X-Gm-Gg: AZuq6aKaPP3mEZiPQMIppS+s7BybIEmkP7jaqDDDiArwCFXTrgofOI0IdStqocQ0FZQ Jfd1+8RjMuYxHxwz3eZWdHLSZ/Z3NeP/ob7lnv4ZYlW5S74hUeu6EuulBoJNLf9NSo3bq2LGx3c Qti1pt2GjrQbJgL6cG3F0bWt6lY9XYE2k1+eEDW1z6vzPOA7GLRTuPCRd4HUh7kdWA4ptqYvvXE KIQ4T1g0ld4VZLQzGylusgmzQLXd4zRjBZ6GeAwVX+yxWoTKLpupm+Y3tFp5eHOdMWl0qWr53yA X22+ET5dYsijuwfi7PBSaFdEtlbWK/1zZHf+LFq5i22sqdNfOZ9mAQs2qBJCA/GvHUMNH0nppKb l4auTm3C1mRS5kxSyBwU3dEY+bnMg0bmATgLGYGnbDVkReKO+n85NQFxJzdromp+o8oDElg== X-Received: by 2002:a17:903:234b:b0:2aa:d7a7:8084 with SMTP id d9443c01a7336-2aad7a7836amr77374265ad.6.1770710418800; Tue, 10 Feb 2026 00:00:18 -0800 (PST) X-Received: by 2002:a17:903:234b:b0:2aa:d7a7:8084 with SMTP id d9443c01a7336-2aad7a7836amr77373625ad.6.1770710418136; Tue, 10 Feb 2026 00:00:18 -0800 (PST) To: devel@lists.libvirt.org Subject: [PATCH v5 1/6] util: Add support for GnuTLS decryption Date: Tue, 10 Feb 2026 13:30:07 +0530 Message-ID: <20260210080012.17753-2-armenon@redhat.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20260210080012.17753-1-armenon@redhat.com> References: <20260210080012.17753-1-armenon@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: 3WkFS-9s_QUQtz58ZiPNOrht46wywKZDpVHMErcumnw_1770710419 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Message-ID-Hash: YQ2J6V4FAJIVXC6AE55LWLIPRCZ6A2KE X-Message-ID-Hash: YQ2J6V4FAJIVXC6AE55LWLIPRCZ6A2KE 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: 1770711292486158500 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 d81b30f0b6..40af831070 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2248,6 +2248,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 Wed Feb 11 03:02:07 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; 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=1770711499; cv=none; d=zohomail.com; s=zohoarc; b=HBH2DZfqAjyZuwVCFXuIVasVMkWPFiTOKBmYFhMRseQ9St4lCgpPzMuM5eAFv8dgHNnSndXqihlomTdtCzmzlKNoBoXVZWGwzQHFacLaUKDCA2UlabkNVnjPoUnB5Owj+dlE0XnXB2CkXnJyV5UG4Y4h4zQIFhp3QtHZKszXaDw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1770711499; 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=7wyuNw9mDtcomhtr5XeLuiKU4nTl8PPFENM2pQCqjMw=; b=SqvTaPmhi1asSm0SLo+ssdyycYNGyTXdmHbkCRILZdDdElbpR2i0pBHEdZETdCSBkRv/9pSgspWY8uThCbF6tQu6YhvtjF6G9JxGBF0Y8PQ07xe9bRVTYma0LpafgUTxhQ42w1nsMCaxUhjKvnvbuU6ncD8ctuynD/Y4KvBtaN8= 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 1770711499457863.9764066283983; Tue, 10 Feb 2026 00:18:19 -0800 (PST) Received: by lists.libvirt.org (Postfix, from userid 993) id 8805E44054; Tue, 10 Feb 2026 03:18:19 -0500 (EST) Received: from [172.19.199.6] (lists.libvirt.org [8.43.85.245]) by lists.libvirt.org (Postfix) with ESMTP id 5367B4410B; Tue, 10 Feb 2026 03:16:40 -0500 (EST) Received: by lists.libvirt.org (Postfix, from userid 993) id A58B43F36D; Tue, 10 Feb 2026 03:00:28 -0500 (EST) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.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 80EE93F322 for ; Tue, 10 Feb 2026 03:00:24 -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-204-oRwAx90ePsuSx_h6gEri7A-1; Tue, 10 Feb 2026 03:00:22 -0500 Received: by mail-pl1-f197.google.com with SMTP id d9443c01a7336-2aad5fc5b2fso6973845ad.1 for ; Tue, 10 Feb 2026 00:00:22 -0800 (PST) Received: from armenon-kvm.armenon-thinkpadp16vgen1.bengluru.csb ([49.36.106.198]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2aadc397d8dsm98273835ad.1.2026.02.10.00.00.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Feb 2026 00:00:19 -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=-5.0 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED, 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=1770710424; 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=7wyuNw9mDtcomhtr5XeLuiKU4nTl8PPFENM2pQCqjMw=; b=TAfNlRgXdyPw3tkjLXRqqM0pg/IrQa4dzaqSwsHqNhZfOQ/vBj6Q5jlOBNF5HNAWpVCtDI jhywNgDuHHn3yF2+aWIJThK5k6glxhHIw3fUdTCgYLPtdpN8r+hL6q5PKd8gGGynCoolr5 P3DACQW94Ym5IF0KjEi7LwwTaY4LIAM= X-MC-Unique: oRwAx90ePsuSx_h6gEri7A-1 X-Mimecast-MFC-AGG-ID: oRwAx90ePsuSx_h6gEri7A_1770710421 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770710421; x=1771315221; 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=7wyuNw9mDtcomhtr5XeLuiKU4nTl8PPFENM2pQCqjMw=; b=Y/mYLqGz0yBocXNOKCkXL44Y6K5RJLZWE40q87kLcRvgBaAIGXfwLLeNeQzmvKSpqR vGx2UNWrPgliwi5g9Q1Q+ZTzH8fuaWsSU9endWTFMKhHGJKOQt/d/mY9bMqcGg2ae/sT Ruidh8mvhlIqr+qaSiAM3Ji6BM+Um3j3LYeryN9RvMwf1fp8Uww4/BwLmOqLYZ/2v56q grAaKXCiu4VqZmPszOTPHIa0QXGIL9vXpYAo16XNtUB7BYGhuf0QUQJG3zqjQ7zBNHN8 3LilVqXPLO8Mcq221QtlOfg6jOiZyjyyyQ4YhBpSoZWjpSDDDWHCeISjzdvumhA+TvAY SFSg== X-Gm-Message-State: AOJu0Yz8vOfBUlyckBwhd+poHYT3zB128ZFG0RHqYVGPd0hzbsg7gDjq KJYB3yE3/eQ1O+JDq2ZZpBowLAc2tNL7PKxOCk8HHV4IMeRSK6ZpED3FB/2S/qHdAiymfUT8eBk C4zAd4duynKBWR0ulySuU7Bh4DYBgcG0iTHRLr0VFpVr/9Nfg+WpIQaBGP5fuwVfkRTqa5ToqxK Lqacs7raQwt4MXvfW3nMXiI4oRRu79dy+UNptVGfuOuQ== X-Gm-Gg: AZuq6aKHGSwceRNh/RIuYrVc9C8iYow3OJ9voZ0YAZv+3cZHuwwnE5zmQJ1hC01VD17 hcBkuH9pXZ/RjhoWh3bnMz0NSryYaxOXkjgsfzGOHaoQhtnZwWuq61hR+l6ThQJ1QWuFE4ke5sW MQLjr6VhuJ4QIoUe291lz3G87MWkDrqM2iWoCtzfDYieP2EstWSf7N2Yw9aBlZ+AbHmW7aqT/rG pwQlECloAw0jl13ItjhUG4C3ivSrtLw+aCN6ay1/1fmEP+kg6E2AjaYHMqlq3BqQ89PH7871LPp ux5+tTlSufLpb9miCTRBaFf6Ud+X65JYSfsj4uAa74ooHFpDE46Rd8uIBiP80omECWwXJMrfVIr 5zkxkZwNyH/ndQOot3kHr8Wc+oG1mEXEqpVyOsAoGki3A2KJhdJFP/wPZ0Y87sTzkhhikmw== X-Received: by 2002:a17:902:ce08:b0:2a9:622e:fd3f with SMTP id d9443c01a7336-2a9622f3041mr122671685ad.36.1770710420638; Tue, 10 Feb 2026 00:00:20 -0800 (PST) X-Received: by 2002:a17:902:ce08:b0:2a9:622e:fd3f with SMTP id d9443c01a7336-2a9622f3041mr122670955ad.36.1770710419779; Tue, 10 Feb 2026 00:00:19 -0800 (PST) To: devel@lists.libvirt.org Subject: [PATCH v5 2/6] secret: Set up default encryption secret key for the virtsecretd service Date: Tue, 10 Feb 2026 13:30:08 +0530 Message-ID: <20260210080012.17753-3-armenon@redhat.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20260210080012.17753-1-armenon@redhat.com> References: <20260210080012.17753-1-armenon@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: NDzUuLDttJSd6DZQOkBYv2K2uaeqHAYdwAEDl3fSLjE_1770710421 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Message-ID-Hash: 3ESEFPSYFMYNUVAMEIHRIZKXYQPEOGA6 X-Message-ID-Hash: 3ESEFPSYFMYNUVAMEIHRIZKXYQPEOGA6 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: 1770711533881158500 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 Reviewed-by: Peter Krempa --- 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 22c9975d9f..34a47d689c 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -1891,13 +1891,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 @@ -2249,11 +2252,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 16875622f4..cab52ce7a3 100644 --- a/src/meson.build +++ b/src/meson.build @@ -833,6 +833,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..8fd54002a0 --- /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 0077 && (dd if=3D/dev/random status=3Dno= ne bs=3D32 count=3D1 | systemd-creds encrypt --name=3Dsecrets-encryption-ke= y - @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 Wed Feb 11 03:02:07 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; 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=1770711797; cv=none; d=zohomail.com; s=zohoarc; b=Te4TQDNxZvMhk5b0b0FwGyY4ZtxjLXjL2JNBBtKqjYvHh/5x1X5Cq3YoqbGBFyjaO552sh03FLhBUNh5EsX+91PNrdR209cZdOqVMwGNGA2uLbBipudktNBL2bp/ZBZ+d6yMp44KVneajexm+FjRjk/pvitp0A54l+d6pNIMmHQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1770711797; 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=o16mGRUufZzHcNsIRcpVYkpz5LDuwQVAaW1Xt83wbtw=; b=d18Uez3C2ZD6J2cxSqCjoU04vBwHXqAZHfU2vtfZU0fsb9y9qSFpatyu5k/+lxJBgRYKz/dgf3ifl4l1BgC0ozF39QVS7nIRKOWvjXIyHxfAEXMiZdRf2wO5LQmOqhkXhvGrByhJFxRgQ8yJUI4bZCeDc0H70NsOo+cQ9ZDrbJo= 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 1770711797834983.8807849977469; Tue, 10 Feb 2026 00:23:17 -0800 (PST) Received: by lists.libvirt.org (Postfix, from userid 993) id D6BFB44046; Tue, 10 Feb 2026 03:23:16 -0500 (EST) Received: from [172.19.199.6] (lists.libvirt.org [8.43.85.245]) by lists.libvirt.org (Postfix) with ESMTP id D3F81441B2; Tue, 10 Feb 2026 03:19:01 -0500 (EST) Received: by lists.libvirt.org (Postfix, from userid 993) id 7EDBC3F287; Tue, 10 Feb 2026 03:00:30 -0500 (EST) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.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 6D5533F344 for ; Tue, 10 Feb 2026 03:00:28 -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-492-0N40CqaqOP-V3a7RTKDFeA-1; Tue, 10 Feb 2026 03:00:24 -0500 Received: by mail-pl1-f197.google.com with SMTP id d9443c01a7336-2aaf0dbd073so21355955ad.3 for ; Tue, 10 Feb 2026 00:00:24 -0800 (PST) Received: from armenon-kvm.armenon-thinkpadp16vgen1.bengluru.csb ([49.36.106.198]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2aadc397d8dsm98273835ad.1.2026.02.10.00.00.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Feb 2026 00:00:21 -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=-5.0 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED, 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=1770710428; 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=o16mGRUufZzHcNsIRcpVYkpz5LDuwQVAaW1Xt83wbtw=; b=Zra/vrOGODBg3pqMICqtC31L7CmzI7liakZ/wP0BYYbJFuHeF8yUzKUfei8JXgoaa1qaJW hl7gPz6ZBh2jCgb0qP+aXEUkllv0tGl68erm0iL3EXM2Ls4+MKsk7fopZDfM1hidW/khsJ zI2XUV+eXLRlCLu5FqijFsPeUfBGMIU= X-MC-Unique: 0N40CqaqOP-V3a7RTKDFeA-1 X-Mimecast-MFC-AGG-ID: 0N40CqaqOP-V3a7RTKDFeA_1770710423 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770710423; x=1771315223; 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=o16mGRUufZzHcNsIRcpVYkpz5LDuwQVAaW1Xt83wbtw=; b=X/qc80WnWlyuIZ8aooI5ivT2uXxI4Xqqt1lDs82EejSrVRnweJsSCRuwCE/f6v9pZj gY4DBwxq6pCSRSlkecwbZMsGDpbAynaRMp2sRnuWsVJ20wEmaKGYJkZeiemAByjk1KQK t9o1tINNbrOlfBsaPfHGFYBQg0tp6vpknck8BxvKmiaZ0BgG+hQOHW5e7Furb+5WxBev V83Vk4+cuoPKZ3SzIumk8dhUbObcqh7SQhWdGkpc1/1lCIZWALOacnpaOCE3uie0IRq+ QbxYp2YtLwAN+CBIIfTuysvkzs7VvFccdM6kx6O8sRGTirvNBO3IPAr4uutzn3t08Kdx LzZg== X-Gm-Message-State: AOJu0YyVnBzhTJegX+5UTjq3XSFa29qB/g9C1hMfv44CqYs0yUfg1RSu 0ang081vgKV7To2WZrdCkN8wBSpSeleiy5bqTZ+Zi5173WeHwTKP4WpmaN4K+k9zM4Lg1iW2luz zqaXAFosBgfYpoBwF0YtPCdNn/FmhKVDoB0D+9QMHgfxM/Ca0JZRfcF0gjXaQSdAVCCGd8+xM35 jnrt8Eq2oHL5m1hYmp+IxeGm4BpmAvoQaeAFDLcViOEQ== X-Gm-Gg: AZuq6aIpSJEjMHC8tjAETUJsi+ii6FvKCtQdiR1upLM2zagqw1wE9xKgTOyqnRnpVdu yRL00su8wA1+qozL/O8Yg4zz4jaqmLcGvMxpdb0ZzP7RM17A+7eSfNGrjasa3q5lwLoZh7FKHNR /zqgRNAHnqTAVzbI2yqon+jP6yjO9oAV0Oeqv9pFRUeTYJHFSWUYzwpHkyTkkXFUxNhp0DNBzRA IE8fKXctRc9ZGjxjkyy6Nmx7LpL9PlwPa+yAGKVAu35gPa8JIfgBH0/JwxCIu08tejLhouljHLC nuaOqCiMnO6JN44fuA3qY9IxXpnoNbqvf8D8sTV18EfaqcVZG4UzM1TmEbCKezkZVqCTgHFICED UOu/oNb8xYno3V5ASCMNOkoZ0D8wO3SNoEuLDwhR9R2gs2K0uXbFnJ36HrypmaAZ+3hVynA== X-Received: by 2002:a17:903:174e:b0:2a9:2858:19a2 with SMTP id d9443c01a7336-2ab10a0dee7mr13786015ad.43.1770710422877; Tue, 10 Feb 2026 00:00:22 -0800 (PST) X-Received: by 2002:a17:903:174e:b0:2a9:2858:19a2 with SMTP id d9443c01a7336-2ab10a0dee7mr13785215ad.43.1770710421956; Tue, 10 Feb 2026 00:00:21 -0800 (PST) To: devel@lists.libvirt.org Subject: [PATCH v5 3/6] secret: Add secret.conf configuration file and parse it Date: Tue, 10 Feb 2026 13:30:09 +0530 Message-ID: <20260210080012.17753-4-armenon@redhat.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20260210080012.17753-1-armenon@redhat.com> References: <20260210080012.17753-1-armenon@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: GZ_Iumsv1pAGXPnD5UoONV6Czk38rmJlw0x4F812nZk_1770710423 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Message-ID-Hash: 47P5S5NM4GEBC7VC43YHWEZWH6TUUXQN X-Message-ID-Hash: 47P5S5NM4GEBC7VC43YHWEZWH6TUUXQN 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: 1770711809169158500 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 Reviewed-by: Peter Krempa --- 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..c1cac7a3dd 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.1.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 34a47d689c..0ba7bf4197 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -2251,6 +2251,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 c78d2b8000..0042ddad08 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 Wed Feb 11 03:02:07 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; 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=1770711591; cv=none; d=zohomail.com; s=zohoarc; b=Xhv+G6qU0Mw4/6wrf0B4J2zAILqbTFq05B9CZj7gCtwpkh+PiVUrCO1OBxkDfwkLpNDlOrITmC83zrkjJiTghDycNUftyo+czbwxMXalkqFsmhhK+h1G/WOaMs9ipQ2D6iG19bU77BBYW247td4TePzp7yWl3DWwJLjvUZOvtxU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1770711591; 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=miFwiCEtlhixFjsvUp2hfKJpehcqvoGC+A4QLZpl4mE=; b=Oez6y2XyHtglUVZYpwVKI8umyUkN9TU6c8x9EMY3xmb4V3SkUYgX5uuXFYhEa3yMk0KYrv17T9erXfVCZSOeyX7TlvjyUBzqi2S04C8MZ1WXNzBFOdfSHY/WF13gCgGgc5n4jrw8ZhPaNT1DTWQXDmJh9MnhiOmxdw6PW8+9hU0= 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 1770711590985854.4174617543518; Tue, 10 Feb 2026 00:19:50 -0800 (PST) Received: by lists.libvirt.org (Postfix, from userid 993) id 8554D44154; Tue, 10 Feb 2026 03:19:49 -0500 (EST) Received: from [172.19.199.6] (lists.libvirt.org [8.43.85.245]) by lists.libvirt.org (Postfix) with ESMTP id 9FB9844167; Tue, 10 Feb 2026 03:18:34 -0500 (EST) Received: by lists.libvirt.org (Postfix, from userid 993) id 6F1983F287; Tue, 10 Feb 2026 03:00:29 -0500 (EST) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.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 174393F2B4 for ; Tue, 10 Feb 2026 03:00:27 -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-520-oIQKqSwqOYGIVRcTSuRLVg-1; Tue, 10 Feb 2026 03:00:25 -0500 Received: by mail-pl1-f197.google.com with SMTP id d9443c01a7336-2a7b7f04a11so15823325ad.3 for ; Tue, 10 Feb 2026 00:00:25 -0800 (PST) Received: from armenon-kvm.armenon-thinkpadp16vgen1.bengluru.csb ([49.36.106.198]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2aadc397d8dsm98273835ad.1.2026.02.10.00.00.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Feb 2026 00:00:23 -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=-5.0 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED, 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=1770710426; 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=miFwiCEtlhixFjsvUp2hfKJpehcqvoGC+A4QLZpl4mE=; b=E3YXKAMK7qVUOcDzEI8yotBIt9G4EfeQJxrAQxoHFMBy6EEJFce8FzG8FbieADP3V/hdds o9vPaFKEYsAm/V+jGqasbEF40QUTutGAE2zvJmaOx4QzQAfpJNdNjqxIj69RiVHtz+piRR WNEzCJZBslg8cOTHc5aZJhvEkjlWmAg= X-MC-Unique: oIQKqSwqOYGIVRcTSuRLVg-1 X-Mimecast-MFC-AGG-ID: oIQKqSwqOYGIVRcTSuRLVg_1770710424 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770710424; x=1771315224; 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=miFwiCEtlhixFjsvUp2hfKJpehcqvoGC+A4QLZpl4mE=; b=kcpIOU07jT39ANzT2SMhrrLW14y+JQv0ioIB6xzm24jRu0qW635o4p5/34k1k6udyU g8DVRIfvbP7sGfbIJXcQ7TFHcVbLOHY5zRwUtEJi23uB21oI3/ocXcA7Oaos4PZaeVuv /O01QRxHzIdKX8TcvcnZwj6UVipBxm9/O3hUp9kHdnt9hIbjHFtmKun/Npl0LAs9Mg+G 2nLyHQO69n6/DqowFTfWvEo8VTu1lte3CYwSF09EfUl7fUhWpdo9HqDPushDzHLaYHYR SOYM6y+6stL7oVw8ZZOqF5vorSWYPCOE1jHLypQIC4ItumN6YoE/D3GZbAlRwl3I6h6g rl0w== X-Gm-Message-State: AOJu0YydJ2/xHtpCTc78b4KB1DHZJRpAsca0/BoDB3bVHGsuZb7SRsVV fTa1XWgxno9HJX/cKxsR4+nw2kbOjIrLHFxedY6jVb3ioE8x5Vekoif5f4ac8/msTKPh32ex5V7 HlNyTYTlEbrFijsFwMIPUusoauAbL5wl30aBB9ULLE0kBF1fQJwJQLgJoNWv3rB9wK4UI0vSdSy K+c2mw7Y0a+dTCcNwTxm79HrBvi2fW5AjommvO9FcF+A== X-Gm-Gg: AZuq6aJMKZCYejvnGy1Q0XSBLGsbptzF0IjiYWfm0IsGecOfva9oV+c4i5wE33x+joj eOJr+lc0TcW0YNK0YDZDFvHOZV1JlsHVRY6n7sFRwtvgM3Y2TW6CMhjWRwnuLZ4Qj02wj4Xy1PV OF51N/xQ9qb2m1vmle96u6wUb/RA6xmXeNCnWEky2fvzFpuJD0StyAceK2fRn4PkwMGPYhXIqY3 m5RWcx3x61Kclp5KrO+2D2Jp0Dfqf2j5a20cgaUMr9sPdKr2iy0aVE50/7a67TqJwwudV/to/AP kLT6Tk3b3I3qTLIuBrG5elWxpqmDITHRlVjGmuLowzsbzektbPM417Ev0WMhvrl4/1xuSvbsYTq oERy735DSuD+Z1Sz3y/GC3aXvYG/71Sk6oLdleBAS1TzFH52N4tXD2arxXEdMlPYCYBGDNw== X-Received: by 2002:a17:903:2984:b0:2a0:c84f:4124 with SMTP id d9443c01a7336-2a9519bcc43mr134877385ad.52.1770710424114; Tue, 10 Feb 2026 00:00:24 -0800 (PST) X-Received: by 2002:a17:903:2984:b0:2a0:c84f:4124 with SMTP id d9443c01a7336-2a9519bcc43mr134876855ad.52.1770710423520; Tue, 10 Feb 2026 00:00:23 -0800 (PST) To: devel@lists.libvirt.org Subject: [PATCH v5 4/6] secret: Rename virSecretObj structure attribute from base64File to secretValueFile Date: Tue, 10 Feb 2026 13:30:10 +0530 Message-ID: <20260210080012.17753-5-armenon@redhat.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20260210080012.17753-1-armenon@redhat.com> References: <20260210080012.17753-1-armenon@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: yjvmcj3kh7r0il4IPD1rN2I7uVbBCyIYre-CmzgvgZ8_1770710424 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Message-ID-Hash: 4QHKSNNJO6BU6FMP43XBXNSICIEV5FDQ X-Message-ID-Hash: 4QHKSNNJO6BU6FMP43XBXNSICIEV5FDQ 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: 1770711602364154100 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 Reviewed-by: Peter Krempa --- 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 Wed Feb 11 03:02:07 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; 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=1770712187; cv=none; d=zohomail.com; s=zohoarc; b=VzSFA3/NQpqcyuZMQAzmAcQymNLHvmpc+zJ2aPeWMYYkRn8hpw5jHLldRo8ovhvrU+qZTYNkvCZ/Raz7qkC/oFzQmK4mms3OClU2zWI9exlzC0sTMXERETwDIm1FQ7x+8m+4q7F7NtwWDX0rh0NKd+oPLd1aq10A6Lt/cyEcFpQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1770712187; 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=zmED5tmZ80C0xHeREcGGn9qHYT1BWzJRQwRnf65NtNQ=; b=himGL4l5SOW39spiQ5xR4TxXTykIW0xVA8JxZWOLeVpGdSS9GClifi/nZdN/TMxYi8DCTalEK8erkr6ZcFfdktIIJxsPH3GXEmtckK4nHBqasYUSLe0lXCVYMqMHDDUI10HYj14Ujjgzq67fYswvgB7MgQ46a2vcdcey1Vcrl8Y= 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 1770712187586580.0677854071433; Tue, 10 Feb 2026 00:29:47 -0800 (PST) Received: by lists.libvirt.org (Postfix, from userid 993) id A738644181; Tue, 10 Feb 2026 03:29:46 -0500 (EST) Received: from [172.19.199.6] (lists.libvirt.org [8.43.85.245]) by lists.libvirt.org (Postfix) with ESMTP id 79E8D44120; Tue, 10 Feb 2026 03:27:33 -0500 (EST) Received: by lists.libvirt.org (Postfix, from userid 993) id 73E593F2B4; Tue, 10 Feb 2026 03:00:32 -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 8E84A3F344 for ; Tue, 10 Feb 2026 03:00:31 -0500 (EST) Received: from mail-pl1-f200.google.com (mail-pl1-f200.google.com [209.85.214.200]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-661-8zlMaBLSNWGfcATBfOQWBg-1; Tue, 10 Feb 2026 03:00:29 -0500 Received: by mail-pl1-f200.google.com with SMTP id d9443c01a7336-2aad5fec176so28785555ad.2 for ; Tue, 10 Feb 2026 00:00:29 -0800 (PST) Received: from armenon-kvm.armenon-thinkpadp16vgen1.bengluru.csb ([49.36.106.198]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2aadc397d8dsm98273835ad.1.2026.02.10.00.00.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Feb 2026 00:00:24 -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=-5.0 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED, 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=1770710431; 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=zmED5tmZ80C0xHeREcGGn9qHYT1BWzJRQwRnf65NtNQ=; b=GkS40yxfNVJ0uq1eJGRZwwGhsVX/zGMSY5bBUlyUbcjikNpZT0mA35lRZPD3STRdCOaXgH AUJsG8GHa5NGRYezBbIk5pyCmdSTfVFHLZTnfPtisMmNS4LBjLkDZ8HZ4Q6EiqZy10TLm1 vH0qkRF49qqrdtg6qwuW3ZM5CoFAd4w= X-MC-Unique: 8zlMaBLSNWGfcATBfOQWBg-1 X-Mimecast-MFC-AGG-ID: 8zlMaBLSNWGfcATBfOQWBg_1770710428 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770710428; x=1771315228; 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=zmED5tmZ80C0xHeREcGGn9qHYT1BWzJRQwRnf65NtNQ=; b=Nn0ggFNlGz8Ngg3ZT+jKGXQsl7/azDXjuF2lO9fxvmLDaR7Hx6PwzEcv2NHASmBHOq H1Ql8b8RFB/IEobghYH2PJcfcqzuszOWW3SG5WHFgvgo+UzW9KcuwSu/U0zzaao/KmTA BhQOo/ROUTXpoAtPTqz4gHm0SpG1Iq2V3hgISNgz5aTqQE+R9ldq4FcnarlgLKc+tKFX xtkh6zWYjdHsWbFadq2OQwYOWZgSGrxfUOjyX6Uf+P3AG81cEAq9rDYrSVOcBJ2lP4oW 7AMEfQD8aHMfWqMiaNqgB4qUdGboCKmJyJdC8o4FnWamQ+pctKZ88YBJGq5QkTg2q450 zQ/g== X-Gm-Message-State: AOJu0YyZ3LTIvPvC6NfWS8J1n9jpUvuFQaH+cQhAPPABfN9va1QjJT2W iHBKoVyjyuXxwdXTTCdjdupfo5n1x24QfY6eO8eBP9MC7xeyX+5ka3gNb8ukgV+APdpvFhEGtDF aMrTAwSrnLGywoeMjgBhGUsNYMh2eSDKkgYSd6yS26gX87xEuG9IXnOAxw5DE2AA99Wxglrj0Dl sub25p09KQFnSC6U0SujWn8Jg9YFrXb9I0Pn/HSn28Ow== X-Gm-Gg: AZuq6aIDl54QP7mOYTYmuD68d6cKpkELnGqWdrUQSk0hG3N5YaTT8obooEoHS4lKNGJ b1306GqHlPG7tKM/VOjqAkfMwS1GlKkap1lsEeC9TVhCnNMkhrrrWK32s3rFJGDkyHjy5lUBG8i zmMG1HQ4urOJ1xgxnETJuI/Jw4uI6NLYU8jEMzGR2lFT/X0xbFe69YBkjcmbUXmRIsv+5+bzDwe b2sna3dHB10ZTs7RlNhm03b2Kw5W7x0oXk1jjBiKSpoKfJF2sTwAxg3oiko4/lYOW4qs1Fh/QoE YEE3h42xM+j42OE6XovBFgp5OSE0gL08uJVk+eNYPhIlUvhJ33Vnj75g5U9XEX+H9DmL6lQAncj /TYeCOogZlc2moU0rZ71qDF1HYnkiwJCD3CHw6kTZnh0bXLtqCKGUpu74tyV78WV6mOZRNw== X-Received: by 2002:a17:903:906:b0:29e:76b8:41e5 with SMTP id d9443c01a7336-2a9521f3eebmr148760315ad.30.1770710427676; Tue, 10 Feb 2026 00:00:27 -0800 (PST) X-Received: by 2002:a17:903:906:b0:29e:76b8:41e5 with SMTP id d9443c01a7336-2a9521f3eebmr148758455ad.30.1770710425158; Tue, 10 Feb 2026 00:00:25 -0800 (PST) To: devel@lists.libvirt.org Subject: [PATCH v5 5/6] secret: Add functionality to load and save secrets in encrypted format Date: Tue, 10 Feb 2026 13:30:11 +0530 Message-ID: <20260210080012.17753-6-armenon@redhat.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20260210080012.17753-1-armenon@redhat.com> References: <20260210080012.17753-1-armenon@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: 2wtnIAmMqtVCTlT2F4BAdl_60UUxxlfQx7Yqw7qSKjw_1770710428 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Message-ID-Hash: PXDTPZHDT2DOXNYBDK44SXFM545VJQ3H X-Message-ID-Hash: PXDTPZHDT2DOXNYBDK44SXFM545VJQ3H 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: 1770712200614154101 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 | 249 ++++++++++++++++++++++++++++--------- src/conf/virsecretobj.h | 16 ++- src/secret/secret_driver.c | 20 ++- 3 files changed, 222 insertions(+), 63 deletions(-) diff --git a/src/conf/virsecretobj.c b/src/conf/virsecretobj.c index a3dd7983bb..49b69b4867 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); @@ -377,12 +391,14 @@ virSecretObjListAdd(virSecretObjList *secrets, =20 if (!(obj =3D virSecretObjNew())) goto cleanup; - /* Generate the possible configFile and secretValueFile strings - * using the configDir, uuidstr, and appropriate suffix + * using the configDir, uuidstr, and appropriate suffix. + * Note that secretValueFile extension is not set here. It is dete= rmined + * based on a) existing availability of secret file (virSecretLoad= Value) or + * b) target storage format (virSecretObjSaveData) */ if (!(obj->configFile =3D virFileBuildPath(configDir, uuidstr, ".x= ml")) || - !(obj->secretValueFile =3D virFileBuildPath(configDir, uuidstr= , ".base64"))) + !(obj->secretValueFile =3D virFileBuildPath(configDir, uuidstr= , NULL))) goto cleanup; =20 if (virHashAddEntry(secrets->objs, uuidstr, obj) < 0) @@ -682,18 +698,75 @@ virSecretObjSaveConfig(virSecretObj *obj) =20 =20 int -virSecretObjSaveData(virSecretObj *obj) +virSecretObjSaveData(virSecretObj *obj, + const char *configDir, + bool encryptData, + uint8_t *secretsEncryptionKey, + size_t secretsKeyLen) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + g_autofree char *base64 =3D NULL; + g_autofree char *newSecretFile =3D NULL; + g_autofree uint8_t *secret =3D NULL; + g_autofree uint8_t *encryptedValue =3D NULL; + + const char *selectedSuffix =3D NULL; + size_t encryptedValueLen =3D 0; + + size_t i; + 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); + virUUIDFormat(obj->def->uuid, uuidstr); + + /* Based on whether encryption is on/off, save the secret in either + * the latest encryption scheme or in base64 formats. + * Subsequently, delete the other formats of the same uuid on the disk. + */ + if (encryptData && secretsEncryptionKey) { + selectedSuffix =3D schemeInfo[0].suffix; + 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 { + int baseElement =3D G_N_ELEMENTS(schemeInfo) - 1; + selectedSuffix =3D schemeInfo[baseElement].suffix; + base64 =3D g_base64_encode(obj->value, obj->value_size); + } + + if (!(newSecretFile =3D virFileBuildPath(configDir, uuidstr, selectedS= uffix))) { + return -1; + } + g_free(obj->secretValueFile); + obj->secretValueFile =3D g_steal_pointer(&newSecretFile); =20 if (virFileRewriteStr(obj->secretValueFile, S_IRUSR | S_IWUSR, base64)= < 0) return -1; =20 + for (i =3D 0; i < G_N_ELEMENTS(schemeInfo); i++) { + g_autofree char* deleteFile =3D virFileBuildPath(configDir, + uuidstr, + schemeInfo[i].suffi= x); + if (STRNEQ_NULLABLE(schemeInfo[i].suffix, selectedSuffix)) { + unlink(deleteFile); + } + } return 0; } =20 @@ -737,7 +810,11 @@ virSecretObjGetValue(virSecretObj *obj) int virSecretObjSetValue(virSecretObj *obj, const unsigned char *value, - size_t value_size) + size_t value_size, + const char *configDir, + bool encryptData, + uint8_t *secretsEncryptionKey, + size_t secretsKeyLen) { virSecretDef *def =3D obj->def; g_autofree unsigned char *old_value =3D NULL; @@ -753,7 +830,11 @@ 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, + configDir, + encryptData, + secretsEncryptionKey, + secretsKeyLen) < 0) goto error; =20 /* Saved successfully - drop old value */ @@ -807,59 +888,109 @@ virSecretLoadValidateUUID(virSecretDef *def, =20 =20 static int -virSecretLoadValue(virSecretObj *obj) +virSecretLoadValue(virSecretObj *obj, + const char *configDir, + uint8_t *secretsEncryptionKey, + size_t secretsKeyLen) { - int ret =3D -1, fd =3D -1; + int ret =3D -1; + char uuidstr[VIR_UUID_STRING_BUFLEN]; + VIR_AUTOCLOSE fd =3D -1; struct stat st; - g_autofree char *contents =3D NULL; + size_t i; =20 - if ((fd =3D open(obj->secretValueFile, O_RDONLY)) =3D=3D -1) { - if (errno =3D=3D ENOENT) { - ret =3D 0; + 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; + + virUUIDFormat(obj->def->uuid, uuidstr); + + /* Iterate over the list of suffixes, find the one that when appended = to the + * uuid will result in a file that exists on the disk. This essentiall= y is the + * secret file. Subsequently, load/decrypt the secret by using the app= ropriate + * encryption scheme. + */ + for (i =3D 0; i < G_N_ELEMENTS(schemeInfo); i++) { + g_autofree char *candidatePath =3D NULL; + if (!(candidatePath =3D virFileBuildPath(configDir, + uuidstr, + schemeInfo[i].suffix))) { goto cleanup; } - virReportSystemError(errno, _("cannot open '%1$s'"), - obj->secretValueFile); - goto cleanup; - } - - if (fstat(fd, &st) < 0) { - virReportSystemError(errno, _("cannot stat '%1$s'"), - obj->secretValueFile); - goto cleanup; - } - - if ((size_t)st.st_size !=3D st.st_size) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("'%1$s' file does not fit in memory"), - obj->secretValueFile); - goto cleanup; - } - - if (st.st_size < 1) { - ret =3D 0; - goto cleanup; - } - - 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; + if (virFileExists(candidatePath)) { + if ((fd =3D open(candidatePath, O_RDONLY)) =3D=3D -1) { + if (errno =3D=3D ENOENT) { + ret =3D 0; + } else { + virReportSystemError(errno, _("cannot open '%1$s'"), + candidatePath); + } + goto cleanup; + } + if (fstat(fd, &st) < 0) { + virReportSystemError(errno, _("cannot stat '%1$s'"), + candidatePath); + goto cleanup; + } + if ((size_t)st.st_size !=3D st.st_size) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("'%1$s' file does not fit in memory"), + candidatePath); + goto cleanup; + } + if (st.st_size < 1) { + ret =3D 0; + goto cleanup; + } + 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'"), + candidatePath); + 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); + } + + g_free(obj->secretValueFile); + obj->secretValueFile =3D g_steal_pointer(&candidatePath); + + 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 +999,9 @@ static virSecretObj * virSecretLoad(virSecretObjList *secrets, const char *file, const char *path, - const char *configDir) + const char *configDir, + uint8_t *secretsEncryptionKey, + size_t secretsKeyLen) { g_autoptr(virSecretDef) def =3D NULL; virSecretObj *obj =3D NULL; @@ -882,7 +1015,7 @@ virSecretLoad(virSecretObjList *secrets, if (!(obj =3D virSecretObjListAdd(secrets, &def, configDir, NULL))) return NULL; =20 - if (virSecretLoadValue(obj) < 0) { + if (virSecretLoadValue(obj, configDir, secretsEncryptionKey, secretsKe= yLen) < 0) { virSecretObjListRemove(secrets, obj); g_clear_pointer(&obj, virObjectUnref); return NULL; @@ -894,7 +1027,9 @@ virSecretLoad(virSecretObjList *secrets, =20 int virSecretLoadAllConfigs(virSecretObjList *secrets, - const char *configDir) + const char *configDir, + uint8_t *secretsEncryptionKey, + size_t secretsKeyLen) { g_autoptr(DIR) dir =3D NULL; struct dirent *de; @@ -915,7 +1050,9 @@ 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, + 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..74a36baf6d 100644 --- a/src/conf/virsecretobj.h +++ b/src/conf/virsecretobj.h @@ -86,7 +86,11 @@ int virSecretObjSaveConfig(virSecretObj *obj); =20 int -virSecretObjSaveData(virSecretObj *obj); +virSecretObjSaveData(virSecretObj *obj, + const char *configDir, + bool encryptData, + uint8_t *secretsEncryptionKey, + size_t secretsKeyLen); =20 virSecretDef * virSecretObjGetDef(virSecretObj *obj); @@ -101,7 +105,11 @@ virSecretObjGetValue(virSecretObj *obj); int virSecretObjSetValue(virSecretObj *obj, const unsigned char *value, - size_t value_size); + size_t value_size, + const char *configDir, + bool encryptData, + uint8_t *secretsEncryptionKey, + size_t secretsKeyLen); =20 size_t virSecretObjGetValueSize(virSecretObj *obj); @@ -112,4 +120,6 @@ virSecretObjSetValueSize(virSecretObj *obj, =20 int virSecretLoadAllConfigs(virSecretObjList *secrets, - const char *configDir); + const char *configDir, + uint8_t *secretsEncryptionKey, + size_t secretsKeyLen); diff --git a/src/secret/secret_driver.c b/src/secret/secret_driver.c index 9b13772ad3..e1668730dd 100644 --- a/src/secret/secret_driver.c +++ b/src/secret/secret_driver.c @@ -229,7 +229,11 @@ secretDefineXML(virConnectPtr conn, =20 if (!objDef->isephemeral) { if (backup && backup->isephemeral) { - if (virSecretObjSaveData(obj) < 0) + if (virSecretObjSaveData(obj, + driver->configDir, + driver->config->encryptData, + driver->config->secretsEncryptionKey, + driver->config->secretsKeyLen) < 0) goto restore_backup; } =20 @@ -333,7 +337,11 @@ 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->configDir, + driver->config->encryptData, + driver->config->secretsEncryptionKey, + driver->config->secretsKeyLen) < 0) goto cleanup; =20 event =3D virSecretEventValueChangedNew(def->uuid, @@ -542,7 +550,9 @@ 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->secretsEncryptionKey, + driver->config->secretsKeyLen) < 0) goto error; =20 return VIR_DRV_STATE_INIT_COMPLETE; @@ -564,7 +574,9 @@ 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->secretsEncryption= Key, + driver->config->secretsKeyLen)); =20 return 0; } --=20 2.51.1 From nobody Wed Feb 11 03:02:07 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; 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=1770711944; cv=none; d=zohomail.com; s=zohoarc; b=loiAULxj4NKNkdC9ssYdq3eNgcL8JqoRnpzpboNkZFswXCAGcQHoR7EZM2eRn5GXGGnB4xa43WRCjX90uIJcpJBIXahRR8Sbb60oMfvN2K0BaSxSBNR/SSlg9KsrPj5hRQ09hQFss9iBkbc/yxvSlDvOuQKhLWdzueB5t01IXl4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1770711944; 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=EHnE4K6DbnPsop/MmOxy3C/dHhWvHC7Sk0o+Z1R3ji8=; b=T4b9E9MhPCTGGLFn4UB8KJLJXrEheQkLkYVBGQUJ/84sk2INZdqCNy2uevEA911kZXQFp/fPV1ddSDlOEOZx2VAtgkw9xoYzo6MLRl10b87PZhMYrqy8QzeNLwSqSQ8GaZPW8cnMZUitU8IfU8Tw+x1fjYvll6m3rXMAFkOi2nU= 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 177071194414398.59977185366836; Tue, 10 Feb 2026 00:25:44 -0800 (PST) Received: by lists.libvirt.org (Postfix, from userid 993) id 4248843F71; Tue, 10 Feb 2026 03:25:43 -0500 (EST) Received: from [172.19.199.6] (lists.libvirt.org [8.43.85.245]) by lists.libvirt.org (Postfix) with ESMTP id 0C1F044194; Tue, 10 Feb 2026 03:21:33 -0500 (EST) Received: by lists.libvirt.org (Postfix, from userid 993) id 1A4323F357; Tue, 10 Feb 2026 03:00:32 -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 57A0E3F287 for ; Tue, 10 Feb 2026 03:00:31 -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-645-tlcNtgC7OXGA5IEM7NN8rw-1; Tue, 10 Feb 2026 03:00:29 -0500 Received: by mail-pl1-f198.google.com with SMTP id d9443c01a7336-2a94369653aso55884735ad.1 for ; Tue, 10 Feb 2026 00:00:29 -0800 (PST) Received: from armenon-kvm.armenon-thinkpadp16vgen1.bengluru.csb ([49.36.106.198]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2aadc397d8dsm98273835ad.1.2026.02.10.00.00.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Feb 2026 00:00:27 -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=-5.0 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED, 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=1770710431; 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=EHnE4K6DbnPsop/MmOxy3C/dHhWvHC7Sk0o+Z1R3ji8=; b=KwLIEj6grzhNKzSD0Z19OJL+6mCLsbfjDso4cs8P0kIqU5035dCoWG0lHfebs0xUkk3m/F JQDQrvWd2XwD/kn8pg4NF39BKEbubhGmiAYK7kfOhgvHPrSi24Qy7gbXW/2DCRHExClhZD B8/D7Eg26PxklxGuzSD8zpfJqyHzqUI= X-MC-Unique: tlcNtgC7OXGA5IEM7NN8rw-1 X-Mimecast-MFC-AGG-ID: tlcNtgC7OXGA5IEM7NN8rw_1770710428 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770710428; x=1771315228; 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=EHnE4K6DbnPsop/MmOxy3C/dHhWvHC7Sk0o+Z1R3ji8=; b=J/n+HCHzFHAPBobOjxp17oEUArK/+yEoAjE2wu7I5BceJdr8JpboROlJxNRwGXdF20 jP9poglQn+cDrMh+oxYMxDo8lyEwL01XizVsd5FDU/YfhSWdfFayNuzUD7mURiv1i0Eq Rq8MTVq2I5qSuWh7CMxUyc9iqAUkDGemU0e4VpkL/qrKvBWh+xGtH+xbyY0pU7vf3iiE IZeH7NtGMAn6OWDvarZ2kkjtKcG6EK8xSM0cLn0L6PbcKIpEkCLBE9KUxIWVl+Yiov+e hHiSmpzY2lyc3lMmHAnQs35U/+oDPuduyFZRWvX2A0mLoApBufqDNIo0FmJ3MfLwe2hZ VOhA== X-Gm-Message-State: AOJu0YzFp2YJAadeIkFV2G3ELVhbuwENvm+JXjQBjePx5ptF3rNobqf5 Jlf4e8VXdYgd9ogjmXMydkU3xVfpZ3Ct3bNqayCUsn5WEGLEGB93UoYFt3krniUezuflQBgo+r4 53EtmHZ0Zc99QCfPL59T/jq90MBTowRMSTTmoYSvNgYGcWPawG6S9RgQ0p6/vi3U2Y/dta0zCUB ssrw/zF00JmABM6RBkCChOhlZxA7FrHh9ekvm3jC42bg== X-Gm-Gg: AZuq6aJzATtq2NMU3/KCQ7s1PHIDVLWFdVed2HicQT4Yk7qJTNitG1Etwt2OXIJ8/Fq l1ACktDAl981U0Phg8iOL57KGpXllNHixLEwiDyw7B8WXrhAzQ6yfdhvXt8pOPPBZZY3mjBN+W0 55NcUN8rrgy4gvPut929r0otHdIWdFXqq4Z17CMqUfTrNWLqdv6uwNVQ9nzU7esEBZXHdglIjW6 pq83kmtZxZjaA6FMbLMwIsmg7+rcVMTIGdl5v6PP+TDlfTCIYJ1a7K4pJfyRc4Sir8jo95osQIF aFDrzJhmH0iIxbYCn6XoQdHr4Ng4AB1CCWc0K1fyoA9BVYroN+gDxGObB2I5NyTWwnQQXZuoKMJ 4JeN/b9Gc0wbns42Hnf8Bo4LOcEg5FQW8iasrqI6WK9MPMXXezAyN7tYo0uQB481gLh4g4g== X-Received: by 2002:a17:903:11d0:b0:2a7:a3b3:3225 with SMTP id d9443c01a7336-2a95225ad92mr142313525ad.53.1770710427976; Tue, 10 Feb 2026 00:00:27 -0800 (PST) X-Received: by 2002:a17:903:11d0:b0:2a7:a3b3:3225 with SMTP id d9443c01a7336-2a95225ad92mr142313105ad.53.1770710427447; Tue, 10 Feb 2026 00:00:27 -0800 (PST) To: devel@lists.libvirt.org Subject: [PATCH v5 6/6] docs: secret: Add documentation of secret encryption feature Date: Tue, 10 Feb 2026 13:30:12 +0530 Message-ID: <20260210080012.17753-7-armenon@redhat.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20260210080012.17753-1-armenon@redhat.com> References: <20260210080012.17753-1-armenon@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: cgH12WSx5rG-a7wUHmy99MAaFI_3y6WwhM8OMfBjl3E_1770710428 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Message-ID-Hash: KWZ7C4EJ4Z2MQ2YVLTQVO33TVECHIW6T X-Message-ID-Hash: KWZ7C4EJ4Z2MQ2YVLTQVO33TVECHIW6T 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: 1770711951169158500 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 Reviewed-by: Peter Krempa --- docs/drvsecret.rst | 4 ++ docs/meson.build | 1 + docs/secretencryption.rst | 105 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 110 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..4908339f2d --- /dev/null +++ b/docs/secretencryption.rst @@ -0,0 +1,105 @@ +.. role:: since + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D +Secret storage and encryption +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D + +.. contents:: + +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.1.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/random 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/random 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. + +Upgrading Libvirt for secret encryption +--------------------------------------- +Starting 12.1.0, secrets can be stored on the disk in an encrypted format,= rather than +the default base64 encoding. + +Any secret created before upgrading libvirt, remain stored in their origin= al base64 +format on the disk. +A pre-existing secret will only be encrypted if you explicitly update its = value using +**virsh secret-set-value** after the upgrade, provided that encryption is = enabled in +secret.conf configuration file. + +It is important to note that encrypted secrets are not backwards compatibl= e. In case of +a downgrade to an older version of libvirt, the encrypted secrets will not= be loaded from +the disk. Therefore, before reverting to an older version libvirt, make su= re that all the +secrets have been reverted to the standard base64 format, to avoid service= disruptions. --=20 2.51.1