Blog

How to Filter AWS Secrets by App in .NET (Step-by-Step)

By default, connecting AWS Secrets Manager to a .NET application pulls down every secret in the vault on startup. That works when you have one app. When you have multiple applications sharing an AWS account—or several environments like Dev, Test, and Prod running side by side—it becomes a liability.

The fix is straightforward: a naming convention for secrets plus two configuration options in your .NET startup code. The result is leaner applications that load only what they need.

The Problem With the Default Setup

The built-in .NET configuration provider for AWS Secrets Manager grabs all secrets on initialization. This creates three practical issues in shared environments:

  • Startup bloat.** More secrets means longer load times, especially as the vault grows.
  • Collision risk.** Applications can accidentally consume configuration meant for other services.
  • Security exposure.** A misconfigured app might load credentials it shouldn't access.

Filtering isn't enabled by default—you have to set it up explicitly.

Organizing Secrets With a Naming Convention

The solution starts in AWS. Instead of flat names like `WeatherForecast__Count`, prefix secrets with the environment and application name.

For app-specific secrets:

`Environment/ApplicationName/SecretName`

Example: `Test/WeatherApp/WeatherForecast__Count`

For shared secrets:

`Environment/Shared/SecretName`

Example: `Test/Shared/WeatherForecast__ApiKey`

This hierarchy gives your code concrete prefixes to match against.

Updating the .NET Startup Code

In your application startup, define which prefixes are relevant based on the current environment:

“`csharp

Var targetPrefixes = new[]

$"{hostEnv}/WeatherApp/",

$"{hostEnv}/Shared/";

Builder.Configuration.AddSecretsManager(configurator: options =>

{

Options.PollingInterval = TimeSpan.FromMinutes(30);

Options.KeyGenerator = (_, secretPath) =>

{

Var match = targetPrefixes.First(secretPath.StartsWith);

Return secretPath.Substring(match.Length).Replace("__", ":");

};

Options.SecretFilter = entry =>

TargetPrefixes.Any(prefix => entry.Name.StartsWith(prefix));

});

“`

SecretFilter** checks each secret name against your target prefixes. Only matching secrets get loaded.

KeyGenerator** strips the prefix and converts double highlights to colons, matching .NET's hierarchical configuration format.

The polling interval keeps everything current—rotated credentials sync automatically without restarts.

Who Should Use This

Scenario Use Filtered Secrets?
Single app, single environment Optional—adds overhead for little gain
Multiple apps, shared AWS account Yes—prevents configuration collisions
Dev/Test/Prod in one account Yes—keeps environments cleanly isolated
Microservices sharing credentials Yes—use Shared prefix for common secrets

Our Analysis

This approach trades a naming discipline requirement for long-term operational clarity. The cost is modest: adopting the prefix convention early costs little; retrofitting later costs more.

The main risk is inconsistency. If one team member creates a secret without the correct prefix, it silently fails to load, causing runtime configuration errors. Automated checks or infrastructure-as-code templates can mitigate this.

The prefix-based filtering works consistently across .NET Core, .NET 5, .NET 6, and .NET 7.

Key takeaways

  • Prefix secrets with `Environment/ApplicationName/` or `Environment/Shared/` to enable filtering
  • Set `SecretFilter` in your .NET configuration to load only relevant secrets by prefix
  • Use `KeyGenerator` to strip prefixes and convert naming conventions for .NET's config system
  • This reduces startup time, limits credential exposure, and keeps multi-app environments organized

Frequently asked questions

Does this work with .NET Core and .NET 5/6/7?

Yes. The AddSecretsManager extension method and configuration options work across all modern .NET versions.

Will my secrets still auto-refresh after rotation?

Yes. The polling interval continues checking for updates and refreshes loaded secrets automatically.

What happens if a secret name doesn't match any prefix?

It's skipped entirely. Your application won't crash, but you'll get a configuration error at runtime if your code expects that secret to exist.

Can I filter by environment variable instead of hardcoding it?

Yes. The example uses the configured hosting environment name, which can come from environment variables or other configuration sources.

Does this affect secrets shared across applications?

No. Shared secrets load fine as long as their prefix is included in your target prefixes list.

Related