We have a website deployed on two web apps on Azure : a production and a pre-production version.
The website at certain time creates a container to host RSA keys, using the below code :
// -----------------------------
// Part 1 : Initialize csp params
// -----------------------------
const int PROVIDER_RSA_FULL = 1;
const string CONTAINER_NAME = "OurKeyContainer";
CspParameters cspParams;
cspParams = new CspParameters(PROVIDER_RSA_FULL);
cspParams.KeyContainerName = CONTAINER_NAME;
cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
cspParams.ProviderName = "Microsoft Strong Cryptographic Provider";
// --------------------------------------------------
// Part 2 : A try to set folder access rights to "everyone"
// --------------------------------------------------
// http://whowish-programming.blogspot.fr/2010/10/systemsecuritycryptographycryptographic.html
// http://stackoverflow.com/questions/5013881/c-sharp-how-do-i-get-the-everybody-user
var sid = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
var rule = new CryptoKeyAccessRule(sid, CryptoKeyRights.FullControl, AccessControlType.Allow);
cspParams.CryptoKeySecurity = new CryptoKeySecurity();
cspParams.CryptoKeySecurity.SetAccessRule(rule);
return new RSACryptoServiceProvider(cspParams);
The issue is that this code works only for one of the website, the one that was first launched actually. The second one threw a CryptographicException "Object already exists".
After googling , the issue seems to be caused by users executing the website that do not have right to access the key container, but unfortunately the recommended fix (implemented in Part 2 on our code above) does not work ..
Any idea or advice ?
Thanks
Riana
I think the problem is that you are basically trying to create a Machine wide container with the same name two times. I am assuming that the pre-prod
and prod
environments are on the same machine, perhaps as deployment slots in your App Service? I could replicate your problem with this setup at least. There are some other setups that could produce the same situation I guess, but this is the most likely.
There are three things you can change in this setup that will produce different results:
For identity we can use either Everyone
(as you have tried) or Current
which we can get from WindowsIdentity
private IdentityReference GetWindowsIdentity()
{
return System.Security.Principal.WindowsIdentity.GetCurrent().User;
}
private IdentityReference GetEveryoneIdentity()
{
return new SecurityIdentifier(WellKnownSidType.WorldSid, null);
}
The container store can be either machine wide
or just for the current user
// machine wide store
var cspParams = new CspParameters(PROVIDER_RSA_FULL)
{
...
Flags = CspProviderFlags.UseMachineKeyStore;
...
};
// default store
var cspParams = new CspParameters(PROVIDER_RSA_FULL)
{
...
Flags = CspProviderFlags.UseDefaultKeyContainer;
...
};
And for the store name we can choose something, in your case you choose the same but we can set something that is unique for the identity as well
KeyContainerName = "OurKeyContainer",
KeyContainerName = $"OurKeyContainer-{identity}",
The different combinations will produce different results:
Everyone identity, machine wide store, same container name Fails on one of the slots with System.Security.Cryptography.CryptographicException: Object already exists.
Everyone identity, machine wide store, container per identity OK
Everyone identity, user store, same container name Fails on both of the slots with System.Security.Cryptography.CryptographicException: The system cannot find the file specified.
Everyone identity, user store, container per identity OK
Current identity, machine wide store, same container name Fails on one of the slots with System.Security.Cryptography.CryptographicException: Object already exists.
Current identity, machine wide store, container per identity OK
Current identity, user store, same container name Fails on both of the slots with System.Security.Cryptography.CryptographicException: The system cannot find the file specified.
Current identity, user store, container per identity Fails on both of the slots with System.Security.Cryptography.CryptographicException: The system cannot find the file specified.
So, to summarize, changing the name of the container to include something that is unique for the environment will fix the problem. It doesn't have to be the identity (but you will get one identity per App Service you are running on a machine so it is fairly safe), it could be the name of the environment if you set it as an ENVIRONMENT VARIABLE
in your App Service and make sure it is set to pre-prod
and prod
respectively.