Skip to main content

如何结合Dotenvx保护DuckDB的Secrets

· 3 min read
Libing Chen
Java程序员,兼全栈、Rust和AI开发

DuckDB 1.4版本增加了数据库加密功能, 截止目前为止,DuckDB涉及到Secrets的主要包括如下:

  • 原生Secret:如S3和兼容存储服务的的AK/SK,http资源访问的token,huggingface和数据库访问的账号密码等
  • DuckLake:主要是MySQL/PostgreSQL元信息数据库的账号密码,S3服务的AK/SK等,这个是DuckLake的核心配置
  • 加密数据库:是对整个数据库的加密,使用AES 256进行加密,加密密码由用户提供

DuckDB虽然提供了Secret的管理能力,但是并没有达到安全的需求,而且用户使用体验也有一些问题,如:

  • Temporary Secrets:临时Secret,保存在内存中,进程退出后就会丢失,所以要每次都要创建,如S3的AK/SK,我都是每次创建,反复copy创建Secret的SQL。
  • Persistent Secrets: 持久化Secret,默认以未加密的方式保存在$HOME/.duckdb/stored_secrets目录下

鉴于DuckDB的Secret管理的加密特性缺失,所以也有不少人建议使用KMS来进行加密,而且好像也没有第三方的扩展来支持这一点。

此外如果你稍不留意的话,你创建的Secret的SQL语句就会被记录到$HOME/.duckdb_history文件中,这个文件也是明文保存的。

既然Dotenvx能够使用管理.env文件中的Secrets,那么能否结合Dotenvx来保护DuckDB的Secrets呢?

首先让我们看一个管理DuckDB Secrets的.env.duckdb的样例:

DUCKDB__HTTP_SECRET=secret
DUCKDB__HTTP_SECRET__TYPE=http
DUCKDB__HTTP_SECRET__BEARER_TOKEN=xxxx

再看一个加密数据库的样例:

DUCKDB__SECRET_DB=attach
DUCKDB__SECRET_DB__TYPE=duckdb
DUCKDB__SECRET_DB__URL=encrypted.db
DUCKDB__SECRET_DB__ENCRYPTION_KEY=123456

从上述的代码中,我们采用__作为层级分隔符,这样就可以将复杂的结构体转换为环境变量, 详细的方法大家可以参考: Structured data in environment variables

所以DuckDB的secret的配置就可以从SQL方式转换为标准的配置项,结构如下:

DUCKDB__OBJECT_NAME=attach/secret
DUCKDB__OBJECT_NAME_TYPE=secret_type/db_type
DUCKDB__OBJECT_NAME_ATTRIBUTE_NAME=value

考虑到该配置项主要是针对DuckDB的,所以Dotenvx对DuckDB添加了.env.duckdb的支持,当然你也可以使用.env文件。 如果是不同的项目,你只需要创建不同项目的.env.duckdb文件即可。

最后我们使用dotenvx link bin/duckdb创建DuckDB CLI的软链接,然后运行./bin/duckdb即可。 Dotenvx就会自动加载.env.duckdb文件中的加密配置项,然后转换为SQL,然后通过--cmd sql参数传递给DuckDB CLI, 这样就完成了DuckDB的Secret的创建。

提示: 通过该方式创建的Secret是临时的,进程退出后就会丢失,而且也不会保存到$HOME/.duckdb_history 文件中,这样就避免了Secret泄露的问题。