Cryptyx.Gcp.Secrets.Extensions
0.1.1
dotnet add package Cryptyx.Gcp.Secrets.Extensions --version 0.1.1
NuGet\Install-Package Cryptyx.Gcp.Secrets.Extensions -Version 0.1.1
<PackageReference Include="Cryptyx.Gcp.Secrets.Extensions" Version="0.1.1" />
<PackageVersion Include="Cryptyx.Gcp.Secrets.Extensions" Version="0.1.1" />
<PackageReference Include="Cryptyx.Gcp.Secrets.Extensions" />
paket add Cryptyx.Gcp.Secrets.Extensions --version 0.1.1
#r "nuget: Cryptyx.Gcp.Secrets.Extensions, 0.1.1"
#:package Cryptyx.Gcp.Secrets.Extensions@0.1.1
#addin nuget:?package=Cryptyx.Gcp.Secrets.Extensions&version=0.1.1
#tool nuget:?package=Cryptyx.Gcp.Secrets.Extensions&version=0.1.1
Cryptyx.Gcp.Secrets.Extensions
Enterprise-grade Microsoft.Extensions.Configuration provider for Google Cloud Secret Manager.
Features
| Feature | Description |
|---|---|
| Drop-in API | AddGcpSecretManager() extension methods for IConfigurationBuilder |
| Prefix Manager | Built-in PrefixGcpSecretManager for multi-service secret isolation (e.g., SERVICEA--KEY) |
| Custom Secret Manager | Implement IGcpSecretManager to control filtering and key mapping |
| Automatic Reload | Polls GCP at configurable intervals; consumers get live updates via IOptionsSnapshot<T> / IOptionsMonitor<T> |
| Workload Identity | First-class support for GKE Workload Identity, Cloud Run, and GCE metadata server |
| Service Account Keys | Authenticate with JSON key files or inline JSON credentials |
| Application Default Credentials | Seamless local dev via gcloud auth application-default login |
| GCP Label Filters | Pre-filter secrets server-side using GCP label expressions |
| Multi-target | Supports .NET 6, .NET 8, .NET 9, and .NET 10 |
Installation
dotnet add package Cryptyx.Gcp.Secrets.Extensions
Quick Start
Minimal — Application Default Credentials (ADC)
var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddGcpSecretManager("my-gcp-project-id");
var app = builder.Build();
// Secrets are now available via Configuration
var connectionString = app.Configuration["Database:ConnectionString"];
Workload Identity Federation (GKE / Cloud Run)
No code changes needed — Workload Identity is handled automatically by Application Default Credentials when running on GKE or Cloud Run with Workload Identity configured:
// Works automatically on GKE with Workload Identity, Cloud Run, or GCE
builder.Configuration.AddGcpSecretManager("my-gcp-project-id");
Service Account JSON Key File
builder.Configuration.AddGcpSecretManager(
"my-gcp-project-id",
jsonCredentialPath: "/secrets/service-account.json");
Pre-configured Client
var client = new SecretManagerServiceClientBuilder
{
JsonCredentials = Environment.GetEnvironmentVariable("GCP_CREDENTIALS_JSON")
}.Build();
builder.Configuration.AddGcpSecretManager("my-gcp-project-id", client);
Prefix Secret Manager (Built-in)
The library ships with PrefixGcpSecretManager — a built-in implementation that filters secrets by a prefix and maps the remaining segments to hierarchical configuration keys using a configurable delimiter (default --):
// Secrets: SERVICEA--DatabaseHost, SERVICEA--Database--Host--Port, SERVICEB--ApiKey
builder.Configuration.AddGcpSecretManager(options =>
{
options.ProjectId = "my-gcp-project-id";
options.Manager = new PrefixGcpSecretManager("SERVICEA");
});
// Result:
// "DatabaseHost" → config["DatabaseHost"]
// "Database--Host--Port" → config["Database:Host:Port"]
// SERVICEB--ApiKey → skipped (wrong prefix)
| GCP Secret Name | Prefix | Config Key |
|---|---|---|
SERVICEA--KEY |
SERVICEA |
KEY |
SERVICEA--KEY--SUBKEY--SUBKEY1 |
SERVICEA |
KEY:SUBKEY:SUBKEY1 |
SERVICEB--KEY |
SERVICEA |
(filtered out) |
Custom delimiter:
options.Manager = new PrefixGcpSecretManager("SERVICEA", "_");
// SERVICEA_KEY_SUBKEY → KEY:SUBKEY
No prefix (delimiter-only mode):
options.Manager = new PrefixGcpSecretManager();
// KEY--SUBKEY--SUBKEY1 → KEY:SUBKEY:SUBKEY1
Custom Secret Manager
Implement IGcpSecretManager to control which secrets are loaded and how they map to configuration keys. This is useful for prefix-based filtering, environment isolation, or any custom key transformation:
public class PrefixSecretManager : IGcpSecretManager
{
private readonly string _prefix;
public PrefixSecretManager(string prefix)
=> _prefix = $"{prefix}-";
public bool Load(Secret secret)
=> secret.SecretName.SecretId.StartsWith(_prefix, StringComparison.OrdinalIgnoreCase);
public string GetKey(Secret secret)
=> secret.SecretName.SecretId[_prefix.Length..]
.Replace("__", ConfigurationPath.KeyDelimiter);
}
// Usage:
builder.Configuration.AddGcpSecretManager(options =>
{
options.ProjectId = "my-gcp-project-id";
options.Manager = new PrefixSecretManager("MyApp");
});
With secrets named MyApp-Database__Host and MyApp-Database__Port, the above produces configuration keys Database:Host and Database:Port.
Automatic Secret Reload
Periodically poll GCP Secret Manager for updated values. Configuration consumers using IOptionsSnapshot<T> or IOptionsMonitor<T> automatically receive the updated values:
builder.Configuration.AddGcpSecretManager(options =>
{
options.ProjectId = "my-gcp-project-id";
options.ReloadInterval = TimeSpan.FromMinutes(5);
});
Note: The minimum reload interval is 30 seconds to prevent excessive API calls and cost overruns. Intervals shorter than 30 seconds are automatically clamped.
GCP Label Filters
Pre-filter secrets server-side using GCP Secret Manager's label filter syntax:
builder.Configuration.AddGcpSecretManager(options =>
{
options.ProjectId = "my-gcp-project-id";
options.Filter = "labels.env=production";
});
Full Configuration Example
using Cryptyx.Gcp.Secrets.Extensions;
var builder = WebApplication.CreateBuilder(args);
if (builder.Environment.IsProduction())
{
builder.Configuration.AddGcpSecretManager(options =>
{
options.ProjectId = builder.Configuration["GCP:ProjectId"]!;
options.ReloadInterval = TimeSpan.FromMinutes(5);
options.Manager = new PrefixSecretManager("MyApp");
options.Filter = "labels.env=production";
});
}
var app = builder.Build();
app.MapGet("/", (IConfiguration config) => $"DB: {config["Database:Host"]}");
app.Run();
Secret Naming Conventions
DefaultGcpSecretManager (double underscore __)
| GCP Secret Name | Configuration Key |
|---|---|
ConnectionString |
ConnectionString |
Database__Host |
Database:Host |
App__Logging__Level |
App:Logging:Level |
Convention: Use double underscores (
__) for hierarchical configuration keys, following the same pattern as environment variable configuration in .NET.
PrefixGcpSecretManager (double dash --)
| GCP Secret Name | Prefix | Configuration Key |
|---|---|---|
SERVICEA--KEY |
SERVICEA |
KEY |
SERVICEA--DB--Host |
SERVICEA |
DB:Host |
SERVICEA--DB--Host--Port |
SERVICEA |
DB:Host:Port |
SERVICEB--KEY |
SERVICEA |
(skipped) |
Authentication Methods
| Method | When to Use | Configuration |
|---|---|---|
| Application Default Credentials (ADC) | Local development, CI/CD | gcloud auth application-default login |
| Workload Identity | GKE, Cloud Run (production) | Automatic via ADC |
| GCE Metadata Server | Compute Engine VMs | Automatic via ADC |
| Service Account JSON Key | Non-GCP environments | options.JsonCredentialPath or options.JsonCredentialContent |
| Pre-configured Client | Advanced scenarios, impersonation | options.Client |
Target Frameworks
- .NET 6.0 (LTS)
- .NET 8.0 (LTS)
- .NET 9.0
- .NET 10.0
Contributing
Contributions are welcome! Please read CONTRIBUTING.md before submitting a pull request.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
This project is licensed under the MIT License — see the LICENSE file for details.
Security
If you discover a security vulnerability, please report it responsibly by emailing security@gcpsecretmanager.dev instead of opening a public issue.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Google.Cloud.SecretManager.V1 (>= 2.7.0)
- Microsoft.Extensions.Configuration (>= 8.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0)
-
net6.0
- Google.Cloud.SecretManager.V1 (>= 2.7.0)
- Microsoft.Extensions.Configuration (>= 8.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0)
-
net8.0
- Google.Cloud.SecretManager.V1 (>= 2.7.0)
- Microsoft.Extensions.Configuration (>= 8.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0)
-
net9.0
- Google.Cloud.SecretManager.V1 (>= 2.7.0)
- Microsoft.Extensions.Configuration (>= 8.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|
Initial release with full GCP Secret Manager configuration provider support.