迁移至Azure后,Blob Storage中PGP加解密免费实现方案咨询
基于Azure Function和Blob Storage的PGP免费解密实现方案
核心思路
PGPCore本身支持流操作,无需依赖本地文件。我们可以直接读取Blob存储中的加密文件流,通过PGPCore解密后,将解密后的流直接写回Blob存储,全程避免本地文件操作,完美适配Azure无服务器环境。
实现步骤与代码示例
1. 依赖包安装
确保项目中安装以下NuGet包:
PGPCore(免费PGP处理库)Azure.Storage.Blobs(Blob存储操作)Azure.Security.KeyVault.Secrets(Key Vault密钥读取)Azure.Identity(Azure服务身份验证)
2. PGP流解密工具类
封装通用的流解密逻辑,避免重复代码:
using PgpCore; using System.IO; using System.Threading.Tasks; public static class PgpDecryptor { public static async Task<Stream> DecryptStreamAsync(Stream encryptedStream, string privateKey, string passphrase) { using var pgp = new PGP(); var decryptedStream = new MemoryStream(); // 将私钥字符串转换为流 using var privateKeyStream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(privateKey)); // 执行流对流传密 await pgp.DecryptStreamAsync(encryptedStream, decryptedStream, privateKeyStream, passphrase); decryptedStream.Position = 0; // 重置流指针,确保后续读取从头开始 return decryptedStream; } }
3. Azure Blob触发器函数实现
编写Blob触发的Function,完成从Blob读取、解密、写回的全流程:
using Azure.Storage.Blobs; using Azure.Security.KeyVault.Secrets; using Microsoft.Azure.Functions.Worker; using Microsoft.Extensions.Logging; using System.IO; using System.Threading.Tasks; public class BlobPgpDecryptFunction { private readonly BlobServiceClient _blobServiceClient; private readonly SecretClient _secretClient; // 通过依赖注入获取服务客户端 public BlobPgpDecryptFunction(BlobServiceClient blobServiceClient, SecretClient secretClient) { _blobServiceClient = blobServiceClient; _secretClient = secretClient; } [Function("BlobPgpDecrypt")] public async Task Run( [BlobTrigger("pgp-uploads/{name}", Connection = "BlobStorageConnection")] Stream inputBlob, string name, ILogger log) { log.LogInformation($"开始处理PGP加密文件: {name}"); // 从Key Vault获取私钥和密码 var privateKeySecret = await _secretClient.GetSecretAsync("pgp-private-key"); var passphraseSecret = await _secretClient.GetSecretAsync("pgp-passphrase"); string privateKey = privateKeySecret.Value.Value; string passphrase = passphraseSecret.Value.Value; try { // 解密加密流 using var decryptedStream = await PgpDecryptor.DecryptStreamAsync(inputBlob, privateKey, passphrase); // 生成解密后的文件名(替换后缀为.txt) string outputFileName = Path.ChangeExtension(name, ".txt"); var outputBlobClient = _blobServiceClient .GetBlobContainerClient("pgp-uploads") .GetBlobClient(outputFileName); // 将解密后的流上传回Blob存储 await outputBlobClient.UploadAsync(decryptedStream, overwrite: true); log.LogInformation($"解密完成,文件已保存: {outputFileName}"); } catch (Exception ex) { log.LogError(ex, $"解密文件 {name} 失败"); // 可扩展:将失败文件移至专门的错误容器,便于排查 throw; } } }
4. 服务配置(.NET 6+孤立模型)
在Program.cs中配置依赖注入,确保Function能获取Blob和Key Vault客户端:
using Microsoft.Azure.Functions.Worker; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Azure.Identity; var host = new HostBuilder() .ConfigureFunctionsWorkerDefaults() .ConfigureServices(services => { services.AddAzureClients(clientBuilder => { // 配置Blob存储客户端 clientBuilder.AddBlobServiceClient( Environment.GetEnvironmentVariable("BlobStorageConnection")); // 配置Key Vault客户端,使用托管身份验证 clientBuilder.AddSecretClient( new Uri(Environment.GetEnvironmentVariable("KeyVaultUri"))) .WithCredential(new DefaultAzureCredential()); }); }) .Build(); host.Run();
关键注意事项
- 流指针重置:解密后的流必须重置
Position到0,否则上传时会因流处于末尾而写入空内容。 - 权限配置:确保Function的托管身份拥有:
- Key Vault的
Secret Get权限 - Blob Storage的
Blob Contributor权限
- Key Vault的
- 大文件处理:如果处理超大文件,建议避免使用
MemoryStream,可改用Azure Function临时存储的FileStream,防止内存溢出。 - 异常排查:添加失败文件迁移逻辑,将解密失败的文件移至单独容器,便于后续分析问题。
内容的提问来源于stack exchange,提问作者Caverman
相关产品推荐
相关产品推荐

