Segredos, chaves e certificados com uma única API: troque de cofre sem mudar o código, criptografe sem expor chaves e audite cada acesso sem registrar valores.
Azure Key Vault · HashiCorp Vault/OpenBao · AWS Secrets Manager · Google Secret Manager · Infisical · Provedor Encadeado (Fallback) · Segredos sincronizados (ESO, CSI, Vault Agent, Bitwarden) · Em memória · .NET 10 · Native AOT
📥 Instalação · 🚀 Início rápido · 📚 Documentação · 📝 Changelog · ⚙️ CI/CD
- ✨ Por que usar
- 📦 Pacotes
- 🧬 Ecossistema TEC
- 📥 Instalação
- 🚀 Início rápido
- 🧭 O que tem dentro
- 📚 Documentação
- ⚡ Compatibilidade
- 🛡️ Segurança
- 🧪 Testes
- 🤝 Contribuição
- 🏷️ Versionamento
- 📄 Licença
| Sem o TEC.Vault | Com o TEC.Vault |
|---|---|
| Cada aplicação usa o SDK do cofre direto, com erro, retentativa e log diferentes | Uma API única (ISecretReader, IKeyCryptography, ICertificateReader...) com o mesmo comportamento em qualquer cofre |
| Trocar de cofre exige reescrever o acesso a segredos | Trocar de cofre é trocar o appsettings.{Ambiente}.json ("Vault": { "Provider": "HashiCorpVault" }), sem recompilar |
| Exceções do SDK chegam ao cliente com URL do cofre e identidade | Todo método retorna Result/Result<T> com códigos de VaultErrors; falhas de infraestrutura saem ocultas (HTTP 502) |
Client secret no appsettings para abrir o cofre |
Autenticação sem segredo (identidade gerenciada, federada, Kubernetes); credencial de desenvolvedor só em Development |
| Valores vazando em log por interpolação ou pelo SDK | Valores nunca em log, ToString() mascarado, nomes recusados só como tamanho + HMAC |
| Chave privada baixada para assinar ou cifrar | A chave fica no cofre: cifra, wrap e assinatura no próprio cofre; envelope para dados grandes |
| Cofre real até para rodar localmente | Provedor em memória completo (criptografia real), bloqueado fora de Development |
- ✅ Seguro por padrão: entrada validada antes de chamar o cofre, limites contra DoS (listagens, respostas, arquivos), auditoria de escritas e downloads de chave privada.
- ✅ Escolha por configuração: provedor por família (segredos, chaves, certificados), leitura estrita e compatível com AOT; erro de digitação derruba a subida, não a primeira requisição.
- ✅ Completo: CRUD, versões, lixeira, backup, geração e rotação de segredos, envelope, certificados (criação, importação PFX/PEM, PKI),
IConfigurationcom recarga, cache com proteção contra stampede, health check e telemetria. - ✅ Extensível:
VaultProviderBasee a base HTTP sem SDK, com testes de contrato prontos para um provedor novo.
| Pacote | Para que serve | Quando instalar | Depende de |
|---|---|---|---|
TEC.Vault |
Interfaces, modelos, VaultErrors, validação, auditoria, métricas, cache, IConfiguration, health check, envelope, provedor encadeado, escolha por configuração e base para provedores |
Vem com qualquer provedor; sozinho só para escrever um provedor ou uma biblioteca que recebe ISecretReader |
TEC.Core, Polly.Core, Microsoft.Extensions.* (sem SDK de nuvem) |
TEC.Vault.AzureKeyVault |
Azure Key Vault: segredos, chaves e certificados, autenticação sem segredo | Aplicações no Azure | TEC.Vault, Azure.Identity, Azure.Security.KeyVault.* |
TEC.Vault.AwsSecretsManager |
AWS Secrets Manager: leitura, gravação, tags e versionamento nativo HTTP com SigV4 (sem SDK pesado, 100% Native AOT); credenciais por IRSA, container do ECS/EKS, IMDSv2 ou variáveis, renovadas antes de expirar | Aplicações na AWS (EKS, ECS, EC2) ou multi-cloud | TEC.Vault (HTTP SigV4, sem SDK) |
TEC.Vault.GoogleSecretManager |
Google Cloud Secret Manager: leitura, gravação, exclusão, labels, habilitar/desabilitar versões e metadados via API REST v1 nativa (Service Account JSON ou Metadata Server GKE/Cloud Run, 100% Native AOT) | Aplicações no Google Cloud (GKE, Cloud Run, GCE) ou multi-cloud | TEC.Vault (HTTP REST v1, sem SDK) |
TEC.Vault.HashiCorpVault |
HashiCorp Vault e OpenBao: KV v2 com lixeira, Transit, certificados com PKI; login Kubernetes, JWT, AppRole ou token | HashiCorp Vault/OpenBao (on-premises, Kubernetes, HCP) | TEC.Vault (HTTP, sem SDK) |
TEC.Vault.Infisical |
Infisical (nuvem ou self-hosted): leitura e gravação de segredos | Aplicações que leem e gravam no Infisical pela API | TEC.Vault (HTTP, sem SDK) |
TEC.Vault.Synced |
Segredos já entregues por um agente: pasta montada, variáveis de ambiente, arquivo JSON/.env (só leitura) | External Secrets, CSI driver, Vault Agent, infisical run, bws run (Bitwarden) |
TEC.Vault |
TEC.Vault.InMemory |
Cofre em memória com o mesmo comportamento dos reais | Desenvolvimento local e testes (bloqueado fora de Development) | TEC.Vault |
Os oito pacotes saem sempre com a mesma versão e trazem lib/net10.0, a documentação XML em português e um README próprio.
flowchart BT
Core["🧰 TEC.Core<br/><sub>Result, erros, utilitários</sub>"]
Vault["🔐 TEC.Vault<br/><sub>segredos, chaves, certificados</sub>"]
Cqrs["🧭 TEC.Cqrs<br/><sub>commands, queries, pipeline</sub>"]
Sec["🛡️ TEC.Security<br/><sub>autenticação, autorização</sub>"]
Obs["📡 TEC.Observability<br/><sub>traces, métricas, logs</sub>"]
Orm["🗄️ TEC.ORM<br/><sub>persistência</sub>"]
Vault --> Core
Cqrs --> Core
Sec --> Core
Sec --> Vault
Orm --> Core
Orm --> Cqrs
Orm --> Vault
classDef atual fill:#512BD4,color:#fff,stroke:#512BD4,stroke-width:2px
class Vault atual
O TEC.Vault guarda tudo o que é sensível no ecossistema e depende só do TEC.Core: as outras bibliotecas pedem segredos, chaves e certificados a ele em vez de lê-los da configuração.
| Componente | Relação com o TEC.Vault |
|---|---|
| 🧰 TEC.Core | Dependência: Result/Error, Guard, gerador seguro de segredos, AES-GCM do envelope, HMAC, BoundedFileReader, SensitiveDataMasker |
| 🛡️ TEC.Security | Consumidor: lê o certificado, a chave ou o segredo da aplicação por ICertificateReader, IKeyCryptography ou ISecretReader |
| 🗄️ TEC.ORM | Consumidor: lê a string de conexão do cofre por ISecretReader |
| 🧭 TEC.Cqrs | Independente; handlers podem injetar ISecretReader/IKeyCryptography e propagar o Result |
| 📡 TEC.Observability | Sem dependência de pacote: assina o ActivitySource e o Meter TEC.Vault e expõe o health check |
Os pacotes estão no GitHub Packages da organização tudoemcodigo, que sempre exige autenticação (mesmo para leitura). Crie um PAT classic com o escopo read:packages, registre a origem com o nome tec-interno e instale só os provedores que a aplicação pode usar (cada um traz o TEC.Vault junto):
dotnet nuget add source https://nuget.pkg.github.com/tudoemcodigo/index.json -n tec-interno -u <usuario> -p <PAT>
dotnet add package TEC.Vault.AzureKeyVault --version 0.0.1
dotnet add package TEC.Vault.AwsSecretsManager --version 0.0.1
dotnet add package TEC.Vault.GoogleSecretManager --version 0.0.1
dotnet add package TEC.Vault.HashiCorpVault --version 0.0.1
dotnet add package TEC.Vault.Infisical --version 0.0.1
dotnet add package TEC.Vault.Synced --version 0.0.1
dotnet add package TEC.Vault.InMemory --version 0.0.1Important
Versão atual: 0.0.1. Para evitar dependency confusion, mapeie TEC.* só para a origem tec-interno no nuget.config da aplicação (packageSourceMapping).
1. Escolha o cofre de cada ambiente no appsettings (endereço não é segredo; nenhum segredo vai aqui):
// appsettings.Development.json: cofre em memória, sem infraestrutura
{ "Vault": { "Provider": "InMemory", "InMemory": { "InitialSecrets": { "parceiro-api-token": "token-local" } } } }// appsettings.Production.json: Azure Key Vault com identidade gerenciada
{ "Vault": { "Provider": "AzureKeyVault", "AzureKeyVault": { "VaultUri": "https://<nome-do-cofre>.vault.azure.net/" } } }2. Registre o cofre e o health check, declarando os provedores disponíveis:
using TEC.Vault.AzureKeyVault;
using TEC.Vault.DependencyInjection;
using TEC.Vault.HealthChecks;
using TEC.Vault.InMemory;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddTecVault(builder.Configuration.GetSection("Vault"), providers => providers
.AddInMemory() // escolhido em Development
.AddAzureKeyVault()); // escolhido em produção
builder.Services.AddHealthChecks().AddTecVault(); // tags "ready" e "vault"
var app = builder.Build();
app.MapHealthChecks("/health/ready");
app.Run();3. Injete só a interface de que precisa e trate o Result:
using TEC.Core.Common.Results;
using TEC.Vault.Abstractions;
public sealed class PartnerClient(ISecretReader vault) // só lê: injete o leitor
{
public async Task<Result> CallAsync(CancellationToken cancellationToken)
{
var token = await vault.GetSecretAsync("parceiro-api-token", cancellationToken: cancellationToken);
if (token.IsFailure)
return token.ToFailure(); // NotFound, ExternalService... já padronizados
// use token.Value.Value; nunca registre em log (ToString() já mascara)
return Result.Success();
}
}Provedor desconhecido, chave digitada errado ou endereço inválido derrubam a subida com InvalidOperationException (citando o caminho da chave). Registro em código (AddTecVault(vault => vault.UseAzureKeyVault(...))), outros provedores e todas as opções: 📚 documentação.
flowchart LR
APP["Aplicação"] --> I["Interfaces<br/>ISecretReader · IKeyCryptography · ICertificateReader ..."]
I -. opcional .-> C["Cache de segredos"]
I --> B["VaultProviderBase<br/>validação · Result · auditoria · métricas"]
C --> B
SEL["Vault:Provider<br/>catálogo de provedores"] -. escolhe .-> B
B --> AZ["AzureKeyVault"] --> KV[("Azure Key Vault")]
B --> AWS["AwsSecretsManager"] --> ASM[("AWS Secrets Manager")]
B --> GCP["GoogleSecretManager"] --> GSM[("Google Secret Manager")]
B --> HC["HashiCorpVault"] --> HV[("HashiCorp Vault<br/>OpenBao")]
B --> INF["Infisical"] --> IS[("Infisical")]
B --> CHN["ChainedSecrets"] --> FB["Fallback em Camadas"]
B --> SYN["Synced / Variáveis"]
AGT["Agente externo / Variáveis<br/>ESO · CSI · Vault Agent · bws · env"] --> SYN
B --> MEM["InMemory"]
| Família | Leitura | Gestão | Extras | Opcionais |
|---|---|---|---|---|
| 🔑 Segredos | ISecretReader |
ISecretStore |
GenerateSecretAsync, RotateSecretAsync |
ISecretRecycleBin, ISecretBackup |
| 🔐 Chaves | IKeyReader |
IKeyStore |
IKeyCryptography, EncryptEnvelopeAsync |
IKeyRecycleBin, IKeyBackup |
| 📜 Certificados | ICertificateReader |
ICertificateStore |
Importação PFX/PEM, emissão por PKI | ICertificateRecycleBin, ICertificateBackup |
| 💓 Saúde | IVaultHealthProbe |
— | AddHealthChecks().AddTecVault() |
— |
| Provedor | Segredos | Chaves | Certificados | Lixeira | Backup |
|---|---|---|---|---|---|
| Azure Key Vault | ✅ | ✅ | ✅ | ✅ | ✅ |
| HashiCorp Vault / OpenBao | ✅ KV v2 | ✅ Transit | ✅ KV + PKI | ✅ | — |
| AWS Secrets Manager | ✅ | — | — | — | — |
| Google Secret Manager | ✅ | — | — | — | — |
| Infisical | ✅ | — | — | — | — |
| Encadeado (Chained) | ✅ fallback | — | — | — | — |
| Synced (Directory, EnvironmentVariables, SecretsFile) | ✅ só leitura | — | — | — | — |
| Em memória | ✅ | ✅ | ✅ | ✅ | ✅ |
AddTecVault registra cada interface que o provedor implementa apontando para a mesma instância (singleton, thread-safe); pedir uma interface que o provedor não oferece falha na resolução do DI, não em tempo de execução.
| Arquivo | O que responde |
|---|---|
| 🔑 Segredos | Como ler, gravar, versionar, gerar, rotacionar, recuperar e fazer backup de segredos |
| 🔐 Chaves | Como criar e rotacionar chaves, cifrar, assinar e usar criptografia envelope |
| 📜 Certificados | Como criar, importar (PFX/PEM), baixar e gerenciar certificados |
| 🧩 Injeção de dependências | O que AddTecVault registra, VaultBuilder, VaultStores |
| ⚙️ Escolha do cofre pela configuração | Como escolher o provedor por ambiente no appsettings e todas as chaves Vault:* |
| 🧾 Segredos no IConfiguration | Como carregar segredos como configuração, com recarga incremental |
| 💾 Cache e health check | Como ligar o cache de segredos e o health check |
| 🌐 Azure Key Vault | Opções, autenticação, RBAC e limites do provedor Azure |
| 🏛️ HashiCorp Vault | KV v2, Transit, PKI, login, política de menor privilégio, OpenBao |
| 🟣 Infisical | Universal Auth, Kubernetes Auth, versões, tags e permissões |
| ☁️ AWS Secrets Manager | SigV4 nativo, JSON protocol 1.1 sem SDK, IRSA, container do ECS/EKS, IMDSv2 e chaves de variáveis, erros da AWS |
| 🔷 Google Secret Manager | API REST v1 nativa, token em variável, Service Account JSON com token_uri conferido, Google Metadata Server (GKE, Cloud Run), labels |
| 🔗 Provedor Encadeado | Fallback ordenado multicamadas (ex.: variáveis de ambiente para cofre remoto) |
| 🌐 Segredos em Variáveis de Ambiente | Guia dedicado para segredos em variáveis de ambiente, normalização de nomes, isolamento de escopo e fallback |
| 📂 Synced | Pasta, variáveis e arquivo entregues por agentes, com receitas (ESO, CSI, Vault Agent, bws run) |
| 🧠 Em memória | Cofre local para desenvolvimento e testes, e a trava de ambiente |
| 🧱 Novo provedor | Como escrever um provedor (VaultProviderBase, base HTTP, catálogo, testes de contrato) |
| 📈 Observabilidade | Spans, métricas (tec.vault.*; os nomes vault.* estão obsoletos) e eventos de log (EventId 7000–7999) |
| 🔁 Resiliência | Retentativa e circuit breaker: o que abre o circuito, opções e telemetria |
| 🏛️ ADRs | Registros de Decisões Arquiteturais |
| ❌ Erros | Códigos de VaultErrors, HTTP, conversão por provedor e exceções de configuração |
| 🛡️ Segurança | Modelo de ameaças, controles, limites, riscos residuais e checklist |
| 🧪 Testes | Categorias, como rodar local, integração e carga, variáveis TEC_TESTES_*/TEC_CARGA_* |
| 💻 Desenvolvimento local | Como compilar (feed tec-interno por padrão, repositórios vizinhos sob demanda) e regenerar lock files |
| 🧰 Samples | Escolha do cofre por ambiente e gerador de carga |
| ⚙️ CI/CD | Workflows, gatilhos, Variables e como publicar |
| Item | Suporte |
|---|---|
| .NET | net10.0 (LTS) |
| Native AOT / trimming | ✅ IsAotCompatible em todos os pacotes; sem binding nem JSON por reflexão (configuração lida com VaultSettings, JSON com source generator/Utf8JsonWriter) ¹ |
Sem ICU (InvariantGlobalization) |
✅ testado no CI |
| HTTP | HashiCorp Vault, Infisical, AWS e Google usam VaultHttpClient com SocketsHttpHandler de vida longa e renovação de conexões (sem IHttpClientFactory), retentativa, tempo limite também na leitura do corpo e teto de resposta (resiliência) |
| Cofres testados de verdade | HashiCorp Vault em container (KV v2, Transit, PKI) a cada PR; Key Vault de testes na main |
| Sistemas | Windows, Linux e macOS; Kubernetes (service account, volumes montados) |
¹ O Azure.Core gera avisos de trimming só no decodificador de PKCS#8 EC, usado por credenciais com certificado EC em PEM; ManagedIdentity, WorkloadIdentity e Developer não passam por ele.
Zero Trust: nome, versão, tags e respostas do cofre são tratados como não confiáveis. Endereços HTTPS validados (o token nunca vai a outro servidor), autenticação sem segredo, entrada validada antes da chamada, listagens limitadas (MaxListItems, padrão 10.000), respostas e arquivos de credencial com teto, valores nunca em log e erros de infraestrutura ocultos do cliente, em todos os provedores. A fonte de IConfiguration exige um prefixo por aplicação (Prefix), para que um segredo alheio não sobrescreva uma chave da configuração.
Caution
Conceda à identidade da aplicação só o papel mínimo (ex.: Key Vault Secrets User para apenas ler) e ative proteção contra purge no cofre de produção. Modelo de ameaças, permissões por provedor e checklist: docs/seguranca.md. Vulnerabilidades: não abra issue pública; escreva para roberto@roberto.inf.br.
dotnet test --project TEC.Vault.Tests -c Release # unitários + integração (pula sem ambiente)
dotnet test --project TEC.Vault.LoadTests -c Release --treenode-filter "/*/*/*/*[Category=Carga-CI]" # carga rápidaPara a integração com HashiCorp Vault, suba um container descartável na porta 18200 e prepare-o com .github/scripts/vault-dev.sh (passo a passo em docs/testes.md).
Testes unitários em TEC.Vault.Tests (TUnit, com testes de contrato, fuzzing e vazamento sob carga), 37 de integração ([Category=Integracao]: HashiCorp Vault real em container e Key Vault de testes, pulados com motivo sem ambiente), 7 de carga rápida (Carga-CI) e 13 pesados (Carga-Pesada), estes de carga só sob demanda no performance.yml (manual: tempo em runner compartilhado é ruidoso e não bloqueia PR nem versão). Detalhes em docs/testes.md.
Branch a partir da main → código e testes (inclusive entradas inválidas) → dotnet test (com e sem ICU) → CHANGELOG e docs/ atualizados → pull request com o check ci / ci-ok verde. Como compilar (credencial do feed tec-interno, modo local com -p:TecUseLocalProjects=true): docs/desenvolvimento.md.
SemVer, uma versão para os oito pacotes (Directory.Build.props). Enquanto for 0.x, mudanças incompatíveis podem ocorrer em versões MINOR; um membro novo em interface conta como incompatível (quebra provedores de terceiros). Cada merge na main publica a prévia <Version>-preview.N; versões estáveis e -rc.N saem só pelo workflow Publicar versão (CI/CD).
Apache 2.0 — consulte NOTICE para informações de atribuição. Criado e mantido por Roberto Oliveira, equipe Tudo em Código · github.com/tudoemcodigo