#secrets-manager #secret #env-var #aws #google #aws-kms #api-bindings

secret-vault

库提供了一种安全的保险库,用于在内存中安全地存储来自Google/AWS/K8S和环境变量的应用程序机密

34个版本 (稳定)

1.14.0 2024年7月12日
1.12.0 2024年1月2日
1.10.1 2023年10月1日
1.8.0 2023年4月13日
0.10.0 2022年7月31日

#86密码学

Download history 70/week @ 2024-05-02 266/week @ 2024-05-09 240/week @ 2024-05-16 205/week @ 2024-05-23 179/week @ 2024-05-30 101/week @ 2024-06-06 245/week @ 2024-06-13 228/week @ 2024-06-20 132/week @ 2024-06-27 256/week @ 2024-07-04 465/week @ 2024-07-11 303/week @ 2024-07-18 317/week @ 2024-07-25 242/week @ 2024-08-01 285/week @ 2024-08-08 183/week @ 2024-08-15

每月1,085次下载

Apache-2.0

135KB
3K SLoC

Cargo Cargo tests and formatting security audit unsafe license

Rust Secret Vault

库提供以下crate

  • 通用秘密值类型 - 一种简单的秘密类型实现,支持安全的序列化(serde和proto)。
  • 秘密保险库 - 提供一个内存存储库,用于存储与应用程序秘密集成的外部秘密来源。

秘密保险库

库支持来自以下来源的秘密

  • Google Cloud Secret Manager
  • Amazon Secrets Manager
  • 环境变量
  • 文件来源(主要设计为读取作为文件挂载的K8S秘密)
  • 由密码学伪随机数生成器生成的临时可用秘密生成器

特性

  • 从定义的来源读取/缓存已注册的秘密及其元数据到内存中;
  • 使用AEAD密码学进行内存加密(可选);
  • 自动从来源刷新秘密的支持(可选);
  • 可扩展和强类型API,可以实现任何类型的来源;
  • 使用Google/AWS KMS 信封加密进行内存加密(可选);
  • 多来源支持;
  • 性能关键秘密的快照;

快速入门

Cargo.toml

[dependencies]
secret-vault = { version = "1.8", features=["..."] }
secret-vault-type = { version = "0.3" }

有关版本问题的安全考虑,请参阅以下内容。

Secret Vault提供的可选功能

  • gcp-secretmanager 用于Google Secret Manager支持
  • aws-secretmanager 用于Amazon Secret Manager支持
  • ring-aead-encryption 用于使用Ring AEAD加密支持
  • gcp-kms-encryption 用于Google KMS信封加密支持
  • aws-kms-encryption 用于Amazon KMS信封加密支持
  • serde 用于serde序列化支持
  • ahash 用于基于AHashMap的映射和快照

使用AEAD加密的GCP示例


// Describing secrets and marking them non-required
// since this is only example and they don't exist in your project
let secret1 = SecretVaultRef::new("test-secret1".into()).with_required(false);
let secret2 = SecretVaultRef::new("test-secret2".into())
    .with_secret_version("1".into())
    .with_required(false);

// Building the vault
let vault = SecretVaultBuilder::with_source(
    gcp::GcpSecretManagerSource::new(&config_env_var("PROJECT_ID")?).await?,
)
    .with_encryption(ring_encryption::SecretVaultRingAeadEncryption::new()?)
    .with_secret_refs(vec![&secret1, &secret2])
    .build()?;

// Load secrets from the source
vault.refresh().await?;

// Reading the secret values
let secret: Option<Secret> = vault.get_secret_by_ref(&secret1).await?;

// Or if you require it available
let secret: Secret = vault.require_secret_by_ref(&secret1).await?;
println!("Received secret: {:?}", secret);

// Using the Viewer API to share only methods able to read secrets
let vault_viewer = vault.viewer();
vault_viewer.get_secret_by_ref(&secret2).await?;

要运行此示例,请使用环境变量

# PROJECT_ID=<your-google-project-id> cargo run --example gcloud_secret_manager_vault

所有示例均可在secret-vault/examples目录中找到。

全局使用 SecretVaultRef

由于它们不包含任何敏感信息,在您的应用程序内部全局使用这些引用是很方便的。为了便于使用,请考虑使用如 lazy_staticonce_cell 这样的crate。

use once_cell::sync::Lazy;

pub static MY_SECRET_REF: Lazy<SecretVaultRef> = Lazy::new(|| {
   SecretVaultRef::new("my-secret".into())
});

多个来源

该库支持使用命名空间的概念同时从多个来源读取。


let secret_aws_namespace: SecretNamespace = "aws".into();
let secret_env_namespace: SecretNamespace = "env".into();

SecretVaultBuilder::with_source(
        MultipleSecretsSources::new()
            .add_source(&secret_env_namespace, InsecureEnvSource::new())
            .add_source(&secret_aws_namespace,
                aws::AwsSecretManagerSource::new(&config_env_var("ACCOUNT_ID")?).await?
            )
)

let secret_ref_aws = SecretVaultRef::new("test-secret-xRnpry".into()).with_namespace(secret_aws_namespace.clone());
let secret_ref_env = SecretVaultRef::new("user".into()).with_namespace(secret_env_namespace.clone());

vault.register_secrets_refs(vec![&secret_ref_aws, &secret_ref_env]).refresh().await?;

从 GCP/AWS 密钥管理器读取秘密元数据

默认情况下,由于需要更多权限,从秘密中读取元数据(如标签和过期日期)是禁用的。要启用它,请使用选项(GCP 示例)。

// Building the vault
let vault = SecretVaultBuilder::with_source(
    gcp::GcpSecretManagerSource::with_options(
        gcp::GcpSecretManagerSourceOptions::new(config_env_var("PROJECT_ID")?)
            .with_read_metadata(true),
    )
    .await?,
)

安全考虑和风险

OSS

开源代码是通过软件开发者的自愿协作创建的。原始作者许可代码,以便任何人都可以查看、修改和分发其新版本。您应该使用与商业产品相同的程序和工具来管理所有OSS。始终培训您的员工了解网络安全最佳实践,这可以帮助他们安全地使用和管理软件产品。您不应仅依赖个人,特别是像这样的项目,读取敏感信息。

版本控制

请不要使用广泛的版本依赖管理,以免在没有审计更改的情况下自动包含新版本的依赖项。

使用 IAM 和服务帐户在 GCP/AWS 中保护您的秘密

不要将所有秘密暴露给应用程序。使用 IAM 和不同的服务帐户,仅按需提供访问权限。

零化、保护内存和加密并不提供100%的安全性

在协议层(例如,官方亚马逊 SDK)上仍然存在分配,没有 KMS,内存中仍有会话密钥等。

因此,不要认为这是一个针对所有可能攻击的完全安全解决方案。没有在硬件/OS级别(例如,Intel SGX 项目)实现额外的支持,某些攻击的缓解是不可能的。

一般来说,将其视为减轻某些风险的小额外努力,但请记住,这不是您唯一应该依赖的解决方案。

目前可用的最安全设置/配置是

  • GCP 密钥管理器 + KMS 封装加密和 AEAD

因为在 GCP 中,还有额外的努力在 Google Cloud SDK 中提供了与该库的集成。这是 Google 没有为 Rust 提供官方 SDK 的一个意外副作用。

快照

对于性能关键的秘密,有快照支持,减少了加密带来的开销

  • 因此,快照始终解密
  • 异步运行时和可能的网络调用(例如,KMS 等)
  • RwLock 同步

要使秘密可用于快照,您需要显式使用 with_allow_in_snapshots 为秘密引用启用它。有关完整示例,请参阅 hashmap_snapshot.rs 并验证以下性能差异。

性能

测试配置

  • 最多 1000 个生成的秘密
  • CPU: Intel(R) Core(TM) i7-10700K CPU @ 3.80GHz

加密、未加密保险库和快照读取性能的比较

read-secrets-perf-simple-vault
time:   [143.53 ns 144.16 ns 144.77 ns]

read-secrets-perf-encrypted-vault
time:   [338.62 ns 339.29 ns 340.22 ns]

read-secrets-perf-std-hash-snapshot
time:   [89.188 ns 89.221 ns 89.266 ns]

read-secrets-perf-ahash-snapshot
time:   [68.096 ns 68.202 ns 68.339 ns]

无需停机即可轮换应用程序秘密策略

这主要是特定于应用程序的领域,但一般思路是至少有两个秘密版本

  • 当前/最新版本的秘密,将用于您应用程序中的新交易/请求/数据。
  • 之前的版本仍需有效以便交互。

然后您有配置/版本管理两种选项

  • 使用您应用程序中包含这些版本的某些配置,并在需要轮换时重新部署您的应用程序。这意味着它将在开始时触发刷新所有密钥。推荐用于大多数情况,因为这种方法更易于审计且更具声明性。
  • 使用 SecretVaultAutoRefresher (或您自己的实现) 自动更新密钥及其版本,而不需要重新部署。

许可

Apache软件许可(ASL)

作者

Abdulla Abdurakhmanov

依赖项

~4–40MB
~583K SLoC