IdentityServer4 shared X509 certificate at AWS - c#

I have IdentityServer4 endpoint as AWS Lambda and I need to share signing/validation certificate between lambda instances.
This is a current workarnound:
var identityServer = services.AddIdentityServer(options => {});
if (env.IsDevelopment())
{
identityServer.AddDeveloperSigningCredential();
}
else
{
identityServer.AddSigningCredential(GetIdentityServerCertificate(Configuration));
and
private static X509Certificate2 GetIdentityServerCertificate(
IConfiguration configuration
)
{
var pfxSecret = System.Environment.GetEnvironmentVariable("CERT_PRIVATE");
var pfxBytes = Convert.FromBase64String(pfxSecret);
var certificate = new X509Certificate2(pfxBytes);
return certificate;
}
Does AWS have any product suitable for storing certificates?
Thanks!

You can store private key of a certificate in AWS Secrets Manager.
Here you can find some additional inforamtion how to use AWS Secrets Manager for storing certificates.

Related

How to add ssl certificate to .Net core Project with Kestrel

I'm trying to add an ssl certificate to .net core project with Kestral.
I have tried to configure ssl certificate pfx file path and the password on appsettings.json file, this solution worked for me but I want to store the password on a vault so I have tried to set the cert path and password on the CreateHostBuilder method using
webBuilder.ConfigureKestrel(options => {
var port = 5002;
var pfxFilePath = #"path\certificate.pfx";
var pfxPassword = "pass";
options.Listen(IPAddress.Any, port, listenOptions => {
listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
listenOptions.UseHttps(pfxFilePath, pfxPassword);
});
});
but I got ERR_CONNECTION_REFUSED error message.

How to Import PfxCertificate to Docker Container Certificate Store(aspnet:3.1-nanoserver-1903 and aspnet:3.1-alpine3.12)

I have this .net core 3.1 application which needs to encrypt some appsettings values using a pfx certificate.
So currently I have this middleware in the startup.cs
services.AddDataProtection()
.SetApplicationName(Configuration["Encryptconfig:applicationname"])
.SetDefaultKeyLifetime(TimeSpan.FromDays(int.Parse(Configuration["Encryptconfig:keyexpiry"])))
.PersistKeysToFileSystem(new DirectoryInfo(Configuration["Encryptconfig:persistpath"]))
.ProtectKeysWithCertificate(Configuration["Encryptconfig:certificatehash"]);
When I run the application this throws and error like below.
{"A certificate with the thumbprint '6F6EBF0237B0GBF61AC3F1A508E430FF9D03788C' could not be found."}
But when I read the certificate manually and pass it to the middleware it works perfectly.
public static X509Certificate2 FindCertificate(string thumbprint)
{
try
{
X509Store certStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);
certStore.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certCollection = certStore.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
if (certCollection.Count > 0)
{
X509Certificate2 cert = certCollection[0];
return cert;
}
certStore.Close();
return null;
}
catch (Exception)
{
return null;
}
}
and change startup code like this.
services.AddDataProtection()
.SetApplicationName(Configuration["Encryptconfig:applicationname"])
.SetDefaultKeyLifetime(TimeSpan.FromDays(int.Parse(Configuration["Encryptconfig:keyexpiry"])))
.PersistKeysToFileSystem(new DirectoryInfo(Configuration["Encryptconfig:persistpath"]))
.ProtectKeysWithCertificate(FindCertificate(Configuration["Encryptconfig:certificatehash"]));
Question : I am running this application on docker(aspnet:3.1-nanoserver-1903) environment on testing and docker(aspnet:3.1-alpine3.12) environment on production.I need to add my pfxcertificate to the docker certificate store. I tried different methods but none of them actually works. Is there any way to add pfxcertificate to docker container certificate store using Dockerfile?
Note: I can do something like the below code to add the certificate to the docker container at the code level. But I need to do this using Dockerfile.
public static void AddCertificate(byte[] pfxFileBytes, string pfxPassword)
{
using (var certificate = new X509Certificate2(pfxFileBytes, pfxPassword, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet))
using (var store = new X509Store(StoreName.My, StoreLocation.LocalMachine, OpenFlags.ReadWrite))
{
store.Add(certificate);
store.Close();
}
}
I am struggling with these for days now. Any help is appreciated. Thanks all.

Microsoft.Azure.KeyVault.Models.KeyVaultErrorException: 'Access denied to first party service.'

I am new to Azure Cloud and trying to follow one tutorial on how to connect with Azure Key Vault. Here is the link for the tutorial.
Program.cs
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.ConfigureAppConfiguration((context, config) =>
{
var builtConfig = config.Build();
var vaultName = builtConfig["VaultName"];
var keyVaultClient = new KeyVaultClient(async (authority, resource, scope) =>
{
var credential = new DefaultAzureCredential(false);
var token = credential.GetToken(
new Azure.Core.TokenRequestContext(
new[] { "https://vault.azure.net/.default" }));
return token.Token;
});
config.AddAzureKeyVault(vaultName, keyVaultClient, new DefaultKeyVaultSecretManager());
});
appsettings.json
"VaultName": "https://connectionstringkeyvault.vault.azure.net/"
In Azure, I have created a Key Vault with the name ConnectionStringKeyVault and I have defined a secret as well.
This is the access policy that I have created in Key Vault:
And, I have created a storage account with the following details:
But, whenever I try to execute my code I am getting the below exception:
What am I doing wrong?
Solution 1:
To fix access denied you need to configure Active Directory permissions. Grant access to KeyVault.
1. Using PowerShell Run the command:
Set-AzureRmKeyVaultAccessPolicy -VaultName 'XXXXXXX' -ServicePrincipalName XXXXX -PermissionsToKeys decrypt,sign,get,unwrapKey
2. Using the Azure portal
Open Key Vaults
Select Access Policies from the Key Vault resource blade.
Click the [+ Add Access Policy] button at the top of the blade
Click Select Principal to select the application you created earlier
From the Key permissions drop down, select "Decrypt", "Sign", "Get",
"UnwrapKey" permissions
Save changes
Solution 2:
According to https://learn.microsoft.com/en-us/dotnet/api/overview/azure/identity-readme, Try with replacing the DefaultAzureCredential with ChainedTokenCredential, the key value secret was successfully retrieved.
Example code:
var cred = new ChainedTokenCredential(new ManagedIdentityCredential(), new AzureCliCredential());
SecretClient client = new SecretClient(new Uri(keyvaultUri), cred);
Response<KeyVaultSecret> secret = await client.GetSecretAsync("kv-sec-test");
For more details refer this document

Generate access token to authenticate Azure Active directory App

I am using Azure Active Directory App to authenticate my rest endpoint deployed on Azure.
I was using pfx cert type and below code to generate access token so that my endpoint can be accessed through that access token.
var authority = string.Format(authorityUri, credentialConfigOptions.TenantId);
var authContext = new AuthenticationContext(authority);
X509Certificate2 certificate = default;using (var store = new X509Store(StoreName.My, StoreLocation.CurrentUser, OpenFlags.ReadOnly))
{
var certificateCollection = store.Certificates.Find(X509FindType.FindBySubjectName, credentialConfigOptions.CertificateName, false);
if (certificateCollection.Count > 0)
{
certificate = certificateCollection[0];
}
};
var clientAssertionCertificate = new ClientAssertionCertificate(credentialConfigOptions.AppId, certificate);
AuthenticationResult token = await authContext.AcquireTokenAsync(appId, clientAssertionCertificate);
return token?.AccessToken;
Now I have to use PEM cert type instead of pfx cert type so I am getting issues while converting PEM format to X509Certificate2.
How can I generate access token with PEM certificate?
If you use Net 5.0, we can directly create X509Certificate2 with a cert and key with method X509Certificate2.CreateFromPemFile(<certpath>,<keypath>). For more details, please refer to here.
If you use other versions, we can create an X509Certificate2 with cert file then import private key with method CopyWithPrivateKey. At last we create Certificate with code
new X509Certificate2(pubKey.Export(X509ContentType.Pfx)). For more details, please refer to here.

Client Certificate Mapping Authentication in self-hosted Owin endpoint

Is it possible (and if so, how?) to configure a self hosted owin endpoint to use client certificate mapping authentication with A/D? IIS has this feature link, but so far I have not found an equivalent for self-hosted endpoints.
The way in which I have gotten this to work though (bearing in mind this approach is probably not 100% foolproof), is a 2-step process by using a combination of authenticationSchemeSelectorDelegate and OWIN.
This will choose the appropriate AuthenticationScheme (allowing requests containing a cert through, otherwise deferring to NTLM authentication)
public void Configuration(IAppBuilder appBuilder)
{
var listener = (HttpListener)appBuilder.Properties[typeof(HttpListener).FullName];
listener.AuthenticationSchemeSelectorDelegate += AuthenticationSchemeSelectorDelegate;
}
private AuthenticationSchemes AuthenticationSchemeSelectorDelegate(HttpListenerRequest httpRequest)
{
if (!httpRequest.IsSecureConnection) return AuthenticationSchemes.Ntlm;
var clientCert = httpRequest.GetClientCertificate();
if (clientCert == null) return AuthenticationSchemes.Ntlm;
else return AuthenticationSchemes.Anonymous;
}
This will read the contents of the cert and populate the "server.User" environment variable accordingly
public class CertificateAuthenticator
{
readonly Func<IDictionary<string, object>, Task> _appFunc;
public CertificateAuthenticator(Func<IDictionary<string, object>, Task> appFunc)
{
_appFunc = appFunc;
}
public Task Invoke(IDictionary<string, object> environment)
{
// Are we authenticated already (NTLM)
var user = environment["server.User"] as IPrincipal;
if (user != null && user.Identity.IsAuthenticated) return _appFunc.Invoke(environment);
var context = environment["System.Net.HttpListenerContext"] as HttpListenerContext;
if (context == null) return _appFunc.Invoke(environment);
var clientCertificate = context.Request.GetClientCertificate();
// Parse out username from certificate
var identity = new GenericPrincipal
(
new GenericIdentity(username), new string[0]
);
environment["server.User"] = identity;
}
}
Is there not a better/standardized way?
I have not seen any standard components built for this yet. That said, it should be possible to clean up your code a little:
You don't need to downcast to HttpListenerContext to get the client cert. The client cert should already be available in the OWIN environment under "ssl.ClientCertificate". See https://katanaproject.codeplex.com/wikipage?title=OWIN%20Keys. You'll also want to check ssl.ClientCertificateErrors because the cert may not have passed all validation checks.
You don't need the AuthenticationSchemeSelectorDelegate code. You could just set the listner.AuthenticationSchemes = NTLM | Anonymous. Then you add a middleware after your cert middleware that returns a 401 if server.User is not valid.

Categories