AWS SDK for .NET
Config
This file contains the profiles.
∼/.aws/config |
[default] region = eu-central-1 [profile Profile1] sso_start_url = https://my-sso-portal.awsapps.com/start sso_region = us-west-1 sso_account_id = 111122223333 sso_role_name = SampleRole region = eu-central-1 output = yaml-stream services = local-dynamodb [services local-dynamodb] dynamodb = endpoint_url = http://localhost:8000 |
aws sso login --profile Profile1 |
Define the AWS_PROFILE in an env var while starting the project.
Properties\launchSettings.json |
{ "profiles": { "MyProfile1": { "commandName": "Project", "launchBrowser": true, "launchUrl": "swagger", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development", "AWS_PROFILE": "Profile1" }, "applicationUrl": "https://localhost:5001;http://localhost:5000" } } |
Credentials
This file contains credentials linked to profiles.
∼/.aws/credentials |
[default] aws_access_key_id = ... aws_secret_access_key = ... aws_session_token = ... [Profile1] key = value |
Example .NET applications
var ssoCreds = this.LoadSsoCredentials("Profile1"); var token = new AmazonSecurityTokenServiceClient(ssoCreds); var caller = await token.GetCallerIdentityAsync(new GetCallerIdentityRequest()); this.userId = caller?.UserId.Substring(caller.UserId.IndexOf(":") + 1) ?? string.Empty; var userNames = await this.GetIamUserNamesAsync(ssoCreds); var bucketNames = await this.GetS3BucketNames(ssoCreds); private AWSCredentials LoadSsoCredentials(string profile) { var chain = new CredentialProfileStoreChain(); if (!chain.TryGetAWSCredentials(profile, out var credentials)) { errors.Add($"Failed to find the {profile} profile"); } // set ClientName and launch a browser window that prompts the SSO user to complete an SSO login // if the session doesn't already have a valid SSO token. if (credentials is SSOAWSCredentials ssoCredentials) { ssoCredentials.Options.ClientName = "Example-SSO-App"; ssoCredentials.Options.SsoVerificationCallback = args => { Process.Start(new ProcessStartInfo { FileName = args.VerificationUriComplete, UseShellExecute = true }); }; } return credentials; } private async Task<IReadOnlyCollection<string>> GetIamUserNamesAsync(AWSCredentials ssoCreds) { var iamClient = new AmazonIdentityManagementServiceClient(ssoCreds); var listResponse = await iamClient.ListUsersAsync(); return listResponse.Users.Select(x => x.UserName).ToList(); } private async Task<IReadOnlyCollection<string>> GetS3BucketNames(AWSCredentials ssoCreds) { var s3Client = new AmazonS3Client(ssoCreds); // Amazon.Runtime.AmazonClientException: 'No RegionEndpoint or ServiceURL configured // define a default profile in config with a region var listResponse = await s3Client.ListBucketsAsync(); return listResponse.Buckets.Select(x => x.BucketName).ToList(); } |
Install the following nuget packages: AWSSDK.Core AWSSDK.SecurityToken AWSSDK.SSO AWSSDK.SSOOIDC
For IAM users: AWSSDK.IdentityManagement
For S3 buckets: AWSSDK.S3
Load .NET configuration from Secrets Manager
AmazonSecretsManagerConfigurationProvider.cs |
public class AmazonSecretsManagerConfigurationProvider : ConfigurationProvider { private readonly string secretName; public AmazonSecretsManagerConfigurationProvider(string secretName) { this.secretName = secretName; } public override void Load() { var secret = GetSecret(); Data = JsonSerializer.Deserialize<Dictionary<string, string>>(secret)!; } private string GetSecret() { var request = new GetSecretValueRequest { SecretId = this.secretName }; using (var client = new AmazonSecretsManagerClient()) { var response = client.GetSecretValueAsync(request).Result; return response.SecretString; } } } |
AmazonSecretsManagerConfigurationSource.cs |
public class AmazonSecretsManagerConfigurationSource : IConfigurationSource { private readonly string secretName; public AmazonSecretsManagerConfigurationSource(string secretName) { this.secretName = secretName; } public IConfigurationProvider Build(IConfigurationBuilder builder) { return new AmazonSecretsManagerConfigurationProvider(this.secretName); } } |
ConfigurationBuilderExtensions.cs |
public static class ConfigurationBuilderExtensions { public static void AddAmazonSecretsManager( this IConfigurationBuilder configurationBuilder, string secretName) { var configurationSource = new AmazonSecretsManagerConfigurationSource(secretName); configurationBuilder.Add(configurationSource); } } |
Program.cs |
builder.Configuration.AddAmazonSecretsManager("Secret name"); var secretValue = builder.Configuration["Secret key"]; |
Authentication with Cognito JWT Token
Program.cs |
builder.Services.AddCognitoIdentity(); builder.Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { options.Authority = builder.Configuration["AWSCognito:Authority"]; options.Audience = builder.Configuration["AWSCognito:UserPoolClientId"]; options.TokenValidationParameters.AudienceValidator = (audiences, securityToken, validationParameters) => { // This is necessary because Cognito access tokens doesn't have "aud" claim. // Instead the audience is set in "client_id" var jwt = (JsonWebToken)securityToken; var audience = jwt.Claims.FirstOrDefault(x => x.Type == "client_id" || x.Type == "aud"); if (audience is null) return false; return validationParameters.ValidAudience == audience.Value; }; }); |
Install the following nuget packages: Amazon.AspNetCore.Identity.Cognito
aws-aspnet-cognito-identity-provider
Cognito is not a fully OIDC-compliant provider |
Get user info from Cognito in an ASP.NET web API
Usually a web API is called with an Access Token which doesn't contain information regarding the user but instead authorizations for actions.
Program.cs |
builder.Services.AddHttpContextAccessor() .AddAWSService<IAmazonCognitoIdentityProvider>(); |
<filebox fn='ApplicationUserProvider.cs'> private readonly IHttpContextAccessor httpContextAccessor; private readonly IAmazonCognitoIdentityProvider cognitoService;
public ApplicationUserProvider(IHttpContextAccessor httpContextAccessor, IAmazonCognitoIdentityProvider cognitoService) {
this.httpContextAccessor = httpContextAccessor; this.cognitoService = cognitoService;
}
public async Task GetUserInfo() {
var accessToken = await httpContextAccessor.HttpContext!.GetTokenAsync(OpenIdConnectParameterNames.AccessToken); // "access_token" if (accessToken is not null) { var userResponse = await cognitoService.GetUserAsync(new GetUserRequest { AccessToken = accessToken }); }
} </kode>