I have the following approach to connect to the key vault in my code:
public static class ConfigurationBuilderExtension
{
public static IConfigurationBuilder AddKeyVaultconfiguration(this IConfigurationBuilder builder)
{
var config = builder.Build();
string name = config["KeyVault:Name"];
string clientId = config["KeyVault:ClientId"];
string clientSecret = config["KeyVault:ClientSecret"];
Verify.NotNullOrEmpty(name, nameof(name));
Verify.NotNullOrEmpty(name, nameof(clientId));
Verify.NotNullOrEmpty(name, nameof(clientSecret));
builder.AddAzureKeyVault($"https://{name}.vault.azure.net/", clientId, clientSecret);
return builder;
}
}
To run this locally, I just adding the user secrets to the project:
{
"KeyVault": {
"Name": "brajzorekeyvault",
"ClientId": "xxxx",
"ClientSecret": "xxxx"
}
}
This works locally.
However, how do I use this approach when I publish this to a app service in Azure? I must in somehow inject the name, clientId and clientSecret? But I don't know which is the best practice approach to do this? Should I create a variable group in Azure devops that consists of these values, and then use these in the piplines?
You should use a managed identity to access the key vault inside the web app to avoid having to inject a secret. See this tutorial
For local development you can link an account in VS that will be used to authenticate against the key vault. See the docs
Using managed identities is best practices, in fact you won't see any offical docs about connecting using the client secret withouth at least a warning to use managed identities.
When we are working with PAAS (Most of resources are PAAS in Azure like App service and KeyVault) in Azure. Most of the time, We do not need to write code or write very less code to access them such as in this case. Do not need to provide any detail like connection string or other details to access key vault in app service, Just do little configuration in azure portal and direct get secret from key vault.
In Azure , they are resources in same resource group which can communicate to each other or authenticate or authorize by just adding object id of app service to keyvault "Access policies". All the headache is on azure of validation. It is very easy, secure and good practice.
Steps are as Follows
Enable Managed Service Identity for your Web App/App Service
a. Select "Identity" from the left-side menu in the Azure Web App/App Service.
b. In the System-assigned tab, Change the "Status" toggle to "On".
c. After a few seconds, Object ID will be available then copy the "Object ID".
Authorize the Web App/App Service to access Your Key Vault
a. Select "Access policies" from the "Key Vault" screen.
b. Click "Add Access Policy".
c. Provide the "Get" and "List" permissions.
d. In the “Select a Principal” option, specify the value for the "Object ID" you
copied earlier for the Azure Web App/App Service.
e. Paste, search and then select it from the list.
f. Click "Add".
g. Click "Save" to persist the changes and complete the process.
Provide Permissions
Copy object Id
Read Azure Key Vault Secrets in .NET Core
a. Install the NuGet Packages
You may install these packages in one of two ways: Either via the NuGet
Package Manager integrated into the Visual Studio 2019 IDE or by running the
following command(s) in the Package Manager Console:
Install-Package Microsoft.Extensions.Azure and Install-Package Azure.Security.KeyVault.Secrets
Note :- In My case , I did not need to install these packages.
b. Access Secrets from AzureKeyVault
Specify the Vault Uri in AppSettings :- Create a section named "KeyVault" in the appsettings.json file and specify a key named "VaultUri" in there as shown below.
appsettings.Development.json
{
"SecretName": "xyz"
}
appsettings.OtherEnv.json
"KeyVault": {
"VaultUri": "https://yourkeyvaulturl.vault.azure.net/"
}
Create KeyVaultManagement class
public class KeyVaultManagement
{
private readonly IConfiguration _config;
public KeyVaultManagement(IConfiguration config)
{
_config= config;
}
public SecretClient SecretClient
{
get
{
return new SecretClient(
new Uri($"{this._config["KeyVault:VaultUri"]}"),
new DefaultAzureCredential()) ;
}
}
}
Write the below code in Program.cs
.ConfigureAppConfiguration((context, config) =>
{
var builtConfig = config.Build();
if (!context.HostingEnvironment.IsDevelopment())
{
config.AddAzureKeyVault(new KeyVaultManagement(builtConfig).SecretClient, new KeyVaultSecretManager());
}
});
Write the below where need to fetch secret.
var valueofSecret = configuration["SecretName"];
configuration is IConfiguration
Documentation of Microsoft for Access Policy of Azure Keyvault
IF YOUR APPLICATION IS NOT APP SERVICE OR IT IS DEVELOPED IN .NET FRAMEWORK
Then Implement KEYVAULT using Certificate
Install Same Nuget Packages
Write the below code in Program.cs. Might need to add package or namespace to use certificate classes
.ConfigureAppConfiguration((context, config) =>
{
var root = config.Build();
var KeyVaultName = root["KeyVaultName"];
var Uri = new Uri($"https://{KeyVaultName}.vault.azure.net/");
var x509Certifcate = CertifcateHelper.GetCertificate(root["Thumprint"],"KeyVaultCertificate");
config.AddAzureKeyVault(Uri , new ClientCertificateCredential(root["ClientTenantId"], root["ClientAppId"], x509Certifcate));
});
Add the below lines in APPSetting
appsettings.Development.json
{
"KeyVaultName": "keyvalutname",
"ClientTenantId": "Get from azure and paste here",
"ClientAppId": "Get from azure and paste here",
"Thumbprint": "Get from keyvalut certificate in azure and paste here";
}
Write the below where need to fetch secret.
var valueofSecret = configuration["SecretName"];
Related
I'm trying to setup healthchecks for some required services to my dotnet core 3.1 API and I'm struggling on Amazon DynamoDB check.
We're using the Xabaril healthcheck packages and the DynamoDb one ask for a DynamoDBOptions that requires the AccessKey, SecretKey and RegionEndpoint.
I know the AWS SDK get this information from the environment Credentials profile configuration:
using Amazon.DynamoDBv2;
//... other usings
public void ConfigureServices(IServiceCollection services)
{
// ... other stufs
services.AddAWSService<IAmazonDynamoDB>();
// ...
}
...But I need get it too in order to set up my dependency healthcheck like this:
services.AddHealthChecks()
.AddDynamoDb(dynamoDbOptions =>
{
dynamoDbOptions .AccessKey = "<???>";
dynamoDbOptions .RegionEndpoint = Amazon.RegionEndpoint.EUWest2; // <???>
dynamoDbOptions .SecretKey = "<???>";
}, "DynamoDB");
How can I get this <???> infos from AWS SDK packages?
After spend some more time in the official docs, I found the topic that covers exactly this need: Accessing credentials and profiles in an application.
To actively retrieve profiles and credentials, use classes from the Amazon.Runtime.CredentialManagement namespace.
In fact, we can use the SharedCredentialsFile class to find a profile in a file that uses the AWS credentials file format, the NetSDKCredentialsFile class to find a profile in the SDK Store or even CredentialProfileStoreChain to search in both.
You can see the examples in the link above. I got this in my case:
private static AWSCredentials GetAccountCredentials(string profileName = "default")
{
var chain = new CredentialProfileStoreChain();
if (chain.TryGetAWSCredentials(profileName, out AWSCredentials awsCredentials))
return awsCredentials;
// ToDo: Error Handler
return null;
}
Yes, the AWS SDKs give programmatic access to IAM AccessKey and SecretKey credentials stored in the local shared AWS credentials file.
I am not a c# dev, but perhaps see the .net sdk AWSCredentialsFactory.GetAWSCredentials method or this blogpost.
I have developed some application and I am using there a external service to send emails (SendGrid). To use this service I need login and password to use SendGrid api. In developmnet environment I have used .Net Core secrets (https://learn.microsoft.com/pl-pl/aspnet/core/security/app-secrets?view=aspnetcore-2.2&tabs=windows) but now after publish I need to deliver login and password in other way. I know that there is a Azure Key Vault, but what if app will be published somwhere else?
FOR PRODUCTION: Use Managed Identity for Azure Resources to avoid storing connection strings. It is a clean solution for managing secrets in Key Vault.
Access Key for Key Vault or other similar resources is never shared, not even to Services or DevOps Engineer to deploy or run the applications in production
Create a Azure Key Vault and store your secrets
Enable System Managed Identity in your Azure App Service. It will register your web application at AAD internally
Search for Managed Service Identity Application ID at Key Vault and allow intended access to it
Initialize connection to your Key Vault by following snippet
Program.cs
using Microsoft.Azure.Services.AppAuthentication;
using Microsoft.Azure.KeyVault;
using Microsoft.Extensions.Configuration.AzureKeyVault;
...
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((context, config) =>
{
if (context.HostingEnvironment.IsProduction())
{
var builtConfig = config.Build();
var azureServiceTokenProvider = new AzureServiceTokenProvider();
var keyVaultClient = new KeyVaultClient(
new KeyVaultClient.AuthenticationCallback(
azureServiceTokenProvider.KeyVaultTokenCallback));
config.AddAzureKeyVault(
$"https://{builtConfig["KeyVaultName"]}.vault.azure.net/",
keyVaultClient,
new DefaultKeyVaultSecretManager());
}
})
.UseStartup<Startup>();
Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
}
Now, secrets from Key Vault will be loaded into Configuration variable. You can use it like, Configuration["YourKeyVaultKeyName"].
FOR DEVELOPMENT: You can optionally use Dotnet-user-secrets tool to store\ manage the secrets in local machine.
I'm trying to integrate AWS API (AWSSDK 2.3.55.2) to my asp.net mvc4 project and I'm not sure what type of credential I should use. Manually i log-in to AWS using the third-party app (okta), so I don't have credentials directly from the AWS. Can I get\generate access key or smth else for login throught API by myself ? Or I should ask my AWS admin anyway to provide some creds ?
What is the simpliest way to login in this situation ?
Now I have smth like:
public static void RestartInstance()
{
var ec2Client = new AmazonEC2Client();
try
{
var response = ec2Client.RebootInstances(new RebootInstancesRequest
{
// Frankfurt
InstanceIds = new List<string> {
"MYInstanceID"
}
});
}
catch (AmazonEC2Exception ex)
{
if ("InvalidInstanceID.NotFound" == ex.ErrorCode)
{
Logger.Instance.Info($"AWS1 Error during rebooting. Please, check the Instance ID Ex: {ex.Message}");
}
}
}
I have 2 choices according to client realization: http://prntscr.com/kt13al . But as far as I understand I cannot use "AWSCredentials", because I don't have this one (I log-in using another app), so I need awsAccessKeyId and awsSecretAccessKey ? Is it right ?
AWS has concept of IAM (Identity Access Management) for authentication and authrozation. AWS IAM documentation.
Locally you need to have AWS Access keys(Access key and Secret access key) generated for your IAM user, this can be done for example from the AWS web console, and you need to configure the credentials. See AWS CLI Documentation for help
If you are running your application in the AWS EC2/ECS/Fargate/Elastic Beanstalk You need to specify IAM Role for the server/service to access private AWS resources. See for example AWS documentation for EC2 IAM
Configuring credentials for C# see documentation
Generally SDK looks for named environment variables for access key and secret key and uses them to access AWS resources.
And yes you need the access key and secret access key to locally use SDK.
I'm trying to understand how to authenticate with Azure during development and production.
For development I followed the instructions here: documentation
I now have a file and an environment variable that the Azure SDK uses for authentication.
However for production I don't know where to put this file. In this case, production is itself a set of Azure Functions which uses the Azure SDK. In the documentation the service principal is stored on C:\.
Should I forgo the environment variable and instead place the service principal file in my src directory (and exclude it from commits of course) and then make sure the file is copied to the output so that it is present for both development and production?
var credentials = SdkContext.AzureCredentialsFactory
.FromFile("service-principle.json"); // same dir as the Azure Function DLLs
As Thomas mentioned that you could add the setting in the Azure function appsetting in the Azure portal.
Then you could use the following command get the credentials. How to use azure function appsettings, please refer to this document.
Note: Need to save the setting after add them. Then we could use SdkContext.AzureCredentialsFactory.FromServicePrincipal(clientId, clientSecret, tenantId, environment: AzureEnvironment.AzureGlobalCloud); to get the credentials.
Following is the demo code.
var clientId = Environment.GetEnvironmentVariable("clientId");
var clientSecret = Environment.GetEnvironmentVariable("clientSecret");
var tenantId = Environment.GetEnvironmentVariable("tenantId");
var credentials = SdkContext.AzureCredentialsFactory.FromServicePrincipal(clientId, clientSecret, tenantId, environment: AzureEnvironment.AzureGlobalCloud);
It is not recommended to publish the Credentials file to azure function, if you still want to do that. You could use the Azure function kudu tool. And Azure function D:\home is shared, you could upload your service-principle.json to the folder you want.
I'm new to AWS SDK and I'm trying to follow the AWS documentation, but gives little to none on what exactly I need to setup.
The official docs tell me to add this to the appsettings.json:
{
"AWS": {
"Profile": "local-test-profile",
"Region": "us-west-2"
}
}
And then create the client:
var options = Configuration.GetAWSOptions();
IAmazonS3 client = options.CreateServiceClient<IAmazonS3>();
This causes an exception to be thrown saying it cannot find the credentials. Where do I put the Api ID and Key? What is this profile?
Please, bear in mind I have no preferences on how to set this up. I'm just trying to follow the official documentation for .NET Core, and their only example doesn't work. The docs seem to imply I should have prior knowledge of many of their terms and settings or that I'm migrating an existing app and already have everything setup.
Can someone please point me to what is missing from this example just to make the API correctly connect to AWS?
Maybe this is too late for you but if you are using docker or have some other environment/setup where it's not possible/easy to use AWS profiles then you can still use environment vars. Eg:
var awsOptions = Configuration.GetAWSOptions();
awsOptions.Credentials = new EnvironmentVariablesAWSCredentials();
services.AddDefaultAWSOptions(awsOptions);
services.AddAWSService<IAmazonS3>();
Then set AWS_ACCESS_KEY_ID & AWS_SECRET_ACCESS_KEY & AWS_REGION in your environment.
It seems that Amazon have made this harder to find in the docs than it needs to be.
Running in AWS for reals is ok because you should be using a role but if your using docker for dev then setting up a profile in the container is a PITA.
The json file is $"appsettings.{env.EnvironmentName}.json", so you should call it appsettings.Development.json and have the environment variable set.
Did you define your"local-test-profile" profile in the AWS credentials file.
Should be in C:\Users\{USERNAME}\.aws\credentials
[local-test-profile]
aws_access_key_id = your_access_key_id
aws_secret_access_key = your_secret_access_key
If you don't want it in the default location, you can set the 'ProfilesLocation' json config file.
This helps to avoid getting credentials from environment using the appsettings for development purpose
var awsOption = Configuration.GetAWSOptions();
awsOption.Credentials = new BasicAWSCredentials(Configuration["AWS:AccessKey"], Configuration["AWS:SecretKey"]);
services.AddDefaultAWSOptions(awsOption);
AWS SDK for .NET uses following order to load credentials:
1. AWSOptions.Credentials property
AWSOptions awsOptions = new AWSOptions
{
Credentials = new BasicAWSCredentials("yourAccessKey", "yourAccessSecret")
};
builder.Services.AddDefaultAWSOptions(awsOptions);
2. AWSOptions.Profile property
AWSOptions awsOptions = new AWSOptions
{
Profile = "custom",
ProfilesLocation = #"c:\temp\credentials"
};
builder.Services.AddDefaultAWSOptions(awsOptions);
If the profile location is not specified, it will look at the default location C:\Users\.aws\credentials.
3. Credential Profile Store Chain
If both AWSOptions.Credentials and AWSOptions.Profile are not supplied or AWSOptions object itself is null. In this case, credential profile name will be loaded from the environment variable AWS_PROFILE.
Profile Name: If there is no such AWS_PROFILE environment variable, then default will be used as a profile name.
Profile Location: C:\Users\.aws\credentials
4. Environment Variables AWS Credentials
If SDK still hasn't got the credentials, then it checks for the following environment variables to load the AWS credentials.
ENVIRONMENT_VARIABLE_ACCESSKEY = "AWS_ACCESS_KEY_ID";
ENVIRONMENT_VARIABLE_SECRETKEY = "AWS_SECRET_ACCESS_KEY";
ENVIRONMENT_VARIABLE_SESSION_TOKEN = "AWS_SESSION_TOKEN";
5. EC2 Instance Profile / ECS Task Profile
Finally, this is the most important place where the SDK looks for the credentials. This would be the best place for the applications that are running in the AWS environment. In this case, SDK loads the AWS credentials from the EC2 instance profile or ECS task role.
I have also written a blog on the same topic, you can checkout that from here - Understanding Credential Loading in AWS SDK for .NET
Same documentation also includes a section for setting up the credentials.
Check it out here http://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/net-dg-config-creds.html
It doesn't give an example of setting up the credentials using the appSettings.json file because they don't think it's the right (secure) way to do it.
Here is from the introduction part of the section about setting up the credentials:
Don't put literal access keys in your application, including the
project's App.config or Web.config file. If you do, you create a risk
of accidentally exposing your credentials if, for example, you upload
the project to a public repository.