Sustainment.Extensions.Configuration.Amazon 1.0.0-ci-20250706-014624

This is a prerelease version of Sustainment.Extensions.Configuration.Amazon.
dotnet add package Sustainment.Extensions.Configuration.Amazon --version 1.0.0-ci-20250706-014624
                    
NuGet\Install-Package Sustainment.Extensions.Configuration.Amazon -Version 1.0.0-ci-20250706-014624
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Sustainment.Extensions.Configuration.Amazon" Version="1.0.0-ci-20250706-014624" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Sustainment.Extensions.Configuration.Amazon" Version="1.0.0-ci-20250706-014624" />
                    
Directory.Packages.props
<PackageReference Include="Sustainment.Extensions.Configuration.Amazon" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Sustainment.Extensions.Configuration.Amazon --version 1.0.0-ci-20250706-014624
                    
#r "nuget: Sustainment.Extensions.Configuration.Amazon, 1.0.0-ci-20250706-014624"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#addin nuget:?package=Sustainment.Extensions.Configuration.Amazon&version=1.0.0-ci-20250706-014624&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Sustainment.Extensions.Configuration.Amazon&version=1.0.0-ci-20250706-014624&prerelease
                    
Install as a Cake Tool

AWS EC2 Metadata Configuration Provider

Build and Publish NuGet Version NuGet Downloads .NET

A powerful .NET ConfigurationProvider that seamlessly integrates AWS EC2 metadata and Elastic Beanstalk environment information into your application's IConfiguration.

Brought to you by Sustainment.com - Making American Manufacturing Great Again!

🚀 Features

  • Smart Detection: Automatically detects if running on AWS Beanstalk with multiple fallback strategies
  • Multi-Framework Support: Targets .NET 8, 9, and 10
  • Lazy Loading: Efficient resource usage with lazy initialization of AWS clients
  • IMDSv2 Compatible: Works with both enabled and disabled IMDSv2 endpoints
  • Environment-Aware: Supports local development with bypass mechanisms
  • Zero Configuration: Works out-of-the-box with sensible defaults
  • Resilient: Multiple detection methods ensure reliability across different AWS configurations

📦 Installation

Install via NuGet Package Manager:

dotnet add package Sustainment.Extensions.Configuration.Amazon

Or via Package Manager Console:

Install-Package Sustainment.Extensions.Configuration.Amazon

🔧 Quick Start

using Sustainment.Extensions.Configuration.Amazon;

var builder = WebApplication.CreateBuilder(args);

// Add AWS Beanstalk configuration provider
builder.Configuration.AddEC2Metadata();

// Register strongly-typed EnvironmentDetails in DI container
builder.Services.AddBeanstalkEnvironmentDetails(builder.Configuration);

var app = builder.Build();

⚡ Performance Optimization for Beanstalk Deployments

For fastest startup times, set this environment variable in your Beanstalk environment:

elasticbeanstalk_environment_name=your-environment-name

This enables instant detection (microseconds vs seconds) and eliminates network calls during startup. Without this variable, the provider falls back to slower AWS API calls.

Advanced Configuration with DI

using Amazon;
using Sustainment.Extensions.Configuration.Amazon;

var builder = WebApplication.CreateBuilder(args);

// Configure with specific AWS region
builder.Configuration.AddEC2Metadata(config =>
{
    config.Region = RegionEndpoint.USEast1;
    config.UseInstanceProbing = true; // Enable for large AWS accounts (slower)
});

// Register strongly-typed EnvironmentDetails
builder.Services.AddBeanstalkEnvironmentDetails(builder.Configuration);

var app = builder.Build();

Web Host Builder Integration

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            // Only add if actually running on Beanstalk
            if (EC2MetadataConfigurationProvider.IsRunningOnBeanstalk())
            {
                webBuilder.AddBeanstalkConfigurationProvider();
            }
        })
        .ConfigureServices((context, services) =>
        {
            // Register strongly-typed EnvironmentDetails
            services.AddBeanstalkEnvironmentDetails(context.Configuration);
        });

🛠 How It Works

The configuration provider uses a hierarchical detection strategy to determine if it's running on AWS Beanstalk:

Detection Flow

  1. Environment Variables (Instant - Recommended for Production)

    • Checks elasticbeanstalk_environment_islocal for local bypass
    • ⚡ FAST PATH: Looks for elasticbeanstalk_environment_name explicit setting
    • Scans for Beanstalk-specific variables (EB_NODE_COMMAND, EB_CONFIG_APP_CURRENT, etc.)
  2. AWS API Call (3-second timeout - Fallback)

    • Attempts DescribeRegions API call using IAM roles
    • Works even when IMDSv2 is disabled for security
  3. IMDSv2 Fallback (2-second timeout - Last Resort)

    • Last resort check of EC2 metadata endpoint
    • Gracefully handles disabled metadata service

🚀 Performance Impact

Detection Method Startup Time Reliability Recommendation
elasticbeanstalk_environment_name set ~1ms 100% Use in Production
AWS API fallback ~3 seconds 95% ⚠️ Backup method
IMDSv2 fallback ~2 seconds 80% ⚠️ Last resort

Data Collection

When running on Beanstalk, the provider collects:

  • Instance Information: Instance ID, region, tags
  • Environment Details: Application name, environment name, version label
  • Beanstalk Metadata: CNAME, platform ARN, solution stack
  • Resource Information: Load balancer, auto-scaling groups

📋 Configuration Keys

All configuration keys are prefixed with elasticbeanstalk::

Key Description Example
elasticbeanstalk:application-name Beanstalk application name my-web-app
elasticbeanstalk:environment-name Environment name production
elasticbeanstalk:instance-id EC2 instance ID i-1234567890abcdef0
elasticbeanstalk:environment-arn Environment ARN arn:aws:elasticbeanstalk:...
elasticbeanstalk:cname Environment CNAME myapp.us-west-2.elasticbeanstalk.com
elasticbeanstalk:version-label Application version v1.2.3
elasticbeanstalk:platform-arn Platform ARN arn:aws:elasticbeanstalk:...

🌍 Environment Variables

Control the provider's behavior with these environment variables:

Variable Purpose Performance Impact Values
elasticbeanstalk_environment_name 🚀 FASTEST: Explicit environment name ~1ms startup Environment name string
elasticbeanstalk_environment_islocal Skip AWS detection for local dev ~1ms startup true/false

Set this in your Beanstalk environment configuration:

# Enables instant detection - critical for fast startup times
elasticbeanstalk_environment_name=your-production-environment-name

How to set in Beanstalk:

  1. Go to your Beanstalk environment
  2. Configuration → Software → Environment properties
  3. Add: elasticbeanstalk_environment_name = your-environment-name

🏠 Local Development Setup

# Skip AWS detection during local development
export elasticbeanstalk_environment_islocal=true

# Or specify environment name directly for testing
export elasticbeanstalk_environment_name=my-test-environment

⚠️ Without Environment Variables

If neither variable is set, the provider will:

  1. Try AWS API calls (adds ~3 seconds to startup)
  2. Fall back to IMDSv2 check (adds ~2 seconds to startup)
  3. Cache the result for subsequent calls

🔍 Usage Examples

[ApiController]
[Route("[controller]")]
public class InfoController : ControllerBase
{
    private readonly EnvironmentDetails _environmentDetails;

    public InfoController(EnvironmentDetails environmentDetails)
    {
        _environmentDetails = environmentDetails;
    }

    [HttpGet]
    public IActionResult GetEnvironmentInfo()
    {
        if (!_environmentDetails.IsBeanstalkEnvironment)
        {
            return Ok(new { Message = "Not running on Beanstalk" });
        }

        var info = new
        {
            ApplicationName = _environmentDetails.ApplicationName,
            EnvironmentName = _environmentDetails.EnvironmentName,
            InstanceId = _environmentDetails.InstanceId,
            Version = _environmentDetails.VersionLabel,
            EnvironmentArn = _environmentDetails.EnvironmentArn,
            PlatformArn = _environmentDetails.PlatformArn,
            Health = _environmentDetails.Health.ToString(),
            Status = _environmentDetails.Status.ToString()
        };

        return Ok(info);
    }
}

Using EnvironmentDetails in Services

public interface IDeploymentService
{
    string GetCurrentDeployment();
    bool IsProduction();
}

public class DeploymentService : IDeploymentService
{
    private readonly EnvironmentDetails _environmentDetails;
    
    public DeploymentService(EnvironmentDetails environmentDetails)
    {
        _environmentDetails = environmentDetails;
    }
    
    public string GetCurrentDeployment()
    {
        if (!_environmentDetails.IsBeanstalkEnvironment)
            return "local-development";
            
        return $"{_environmentDetails.ApplicationName}-{_environmentDetails.EnvironmentName}-{_environmentDetails.VersionLabel}";
    }
    
    public bool IsProduction()
    {
        return _environmentDetails.EnvironmentName?.ToLower().Contains("prod") == true;
    }
}

// Register in DI
builder.Services.AddScoped<IDeploymentService, DeploymentService>();

Alternative: Traditional Configuration Access

[ApiController]
[Route("[controller]")]
public class LegacyController : ControllerBase
{
    private readonly IConfiguration _configuration;

    public LegacyController(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    [HttpGet]
    public IActionResult GetEnvironmentInfo()
    {
        var info = new
        {
            ApplicationName = _configuration["elasticbeanstalk:application-name"],
            EnvironmentName = _configuration["elasticbeanstalk:environment-name"],
            InstanceId = _configuration["elasticbeanstalk:instance-id"],
            Version = _configuration["elasticbeanstalk:version-label"]
        };

        return Ok(info);
    }
}

Conditional Logic Based on Environment

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // First register the EnvironmentDetails
        services.AddBeanstalkEnvironmentDetails(Configuration);
        
        // Use a factory pattern to conditionally register services
        services.AddScoped<IEmailService>(provider =>
        {
            var environmentDetails = provider.GetRequiredService<EnvironmentDetails>();
            
            if (environmentDetails.IsBeanstalkEnvironment && 
                environmentDetails.EnvironmentName?.ToLower().Contains("prod") == true)
            {
                return new ProductionEmailService();
            }
            
            return new DevelopmentEmailService();
        });
    }
}

Logging with EnvironmentDetails

public class OrderService
{
    private readonly ILogger<OrderService> _logger;
    private readonly EnvironmentDetails _environmentDetails;
    
    public OrderService(ILogger<OrderService> logger, EnvironmentDetails environmentDetails)
    {
        _logger = logger;
        _environmentDetails = environmentDetails;
    }
    
    public async Task ProcessOrder(Order order)
    {
        using var scope = _logger.BeginScope(new Dictionary<string, object>
        {
            ["ApplicationName"] = _environmentDetails.ApplicationName,
            ["EnvironmentName"] = _environmentDetails.EnvironmentName,
            ["InstanceId"] = _environmentDetails.InstanceId,
            ["Version"] = _environmentDetails.VersionLabel
        });
        
        _logger.LogInformation("Processing order {OrderId}", order.Id);
        
        // Process order...
    }
}

🏗 Advanced Scenarios

Instance Probing for Large Accounts

For AWS accounts with many Beanstalk environments, enable instance probing:

builder.Configuration.AddEC2Metadata(config =>
{
    config.UseInstanceProbing = true; // Slower but more thorough
});

Note: This iterates through all environments to find the current instance. Use only when environment name tags are not available.

Custom AWS Region

using Amazon;

builder.Configuration.AddEC2Metadata(config =>
{
    config.Region = RegionEndpoint.EUWest1;
});

Conditional Registration

// Only register when actually needed
if (EC2MetadataConfigurationProvider.IsRunningOnBeanstalk())
{
    builder.Configuration.AddEC2Metadata();
    
    // Register the strongly-typed EnvironmentDetails
    builder.Services.AddBeanstalkEnvironmentDetails(builder.Configuration);
    
    // Also register AWS-specific services
    builder.Services.AddAWSParameterStore();
}
else
{
    // For local development, register an empty EnvironmentDetails
    builder.Services.AddSingleton(new EnvironmentDetails());
}

EnvironmentDetails Properties

The EnvironmentDetails object provides these properties:

public class EnvironmentDetails
{
    public string ApplicationName { get; set; }
    public string Cname { get; set; }
    public DateTimeOffset DateCreated { get; set; }
    public DateTimeOffset DateUpdated { get; set; }
    public string Description { get; set; }
    public string EndpointUrl { get; set; }
    public string EnvironmentArn { get; set; }
    public string EnvironmentId { get; set; }
    public string EnvironmentName { get; set; }
    public EnvironmentHealth Health { get; set; }
    public EnvironmentHealthStatus HealthStatus { get; set; }
    public string InstanceId { get; set; }
    public string PlatformArn { get; set; }
    public EnvironmentResourcesDescription Resources { get; set; }
    public string SolutionStackName { get; set; }
    public EnvironmentStatus Status { get; set; }
    public string TemplateName { get; set; }
    public string VersionLabel { get; set; }
    
    // Convenience property
    public bool IsBeanstalkEnvironment => !string.IsNullOrWhiteSpace(EnvironmentArn);
}

🚦 Build Status

Branch Status Version
Main Main Build Release Version
Develop Develop Build Pre-release

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

Development Setup

  1. Clone the repository
  2. Ensure you have .NET 8+ SDK installed
  3. Run dotnet restore in the src directory
  4. Build with dotnet build
  5. Run tests with dotnet test

Running Locally

Set the local bypass environment variable:

export elasticbeanstalk_environment_islocal=true

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🙋‍♂️ Support

If you encounter any issues or have questions:

  1. Check the Issues page
  2. Create a new issue with detailed information
  3. For urgent matters, contact the maintainers

⭐ If this project helped you, please consider giving it a star!

Product Compatible and additional computed target framework versions.
.NET 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Sustainment.Extensions.Configuration.Amazon:

Package Downloads
Serilog.Enrichers.Amazon

A Serilog Enricher to add AWS Beanstalk runtime metadata to your logs.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0-ci-20250706-014624 42 7/6/2025