Recently while setting up a secondary ASP.NET site on a Windows Server 2008 R2 machine, I encountered a perplexing issue with RSA key container permissions. The error message "The RSA key container could not be opened" appeared despite using identical application pool configurations.
The setup involves:
- Windows Server 2008 R2
- ASP.NET 4.0 application
- Connection strings encrypted using RSA
- Multiple application pools with same identity
- Existing working site in Default App Pool
- New site failing with custom App Pool
First, I verified the application pool identity:
// Check application pool identity in IIS
// Both pools use the same domain account: dmz\UserName
Then attempted to grant permissions using:
aspnet_regiis -pa "KeyContainerName" "dmz\UserName"
But received "The RSA key container was not found" error.
The most confusing part was the conflicting messages:
aspnet_regiis -pi "KeyContainerName" "c:\keys.xml" → "Object already exists"
aspnet_regiis -pz "KeyContainerName" → "RSA key container was not found"
After extensive research, here's what worked:
1. Verify Key Container Existence
First, confirm if the key container actually exists:
// C# code to check key container existence
using System.Security.Cryptography;
try
{
var cspParams = new CspParameters
{
Flags = CspProviderFlags.UseMachineKeyStore,
KeyContainerName = "KeyContainerName"
};
using (var rsa = new RSACryptoServiceProvider(cspParams))
{
// If no exception, container exists
Console.WriteLine("Container exists and is accessible");
}
}
catch (CryptographicException ex)
{
Console.WriteLine($"Error accessing container: {ex.Message}");
}
2. Machine-Level vs User-Level Containers
The key issue was the container being created at user level rather than machine level. To fix:
// Recreate container with machine-level flag
aspnet_regiis -pz "KeyContainerName"
aspnet_regiis -pi "KeyContainerName" "c:\keys.xml" -exp
aspnet_regiis -pa "KeyContainerName" "NT AUTHORITY\NETWORK SERVICE"
aspnet_regiis -pa "KeyContainerName" "dmz\UserName"
3. Permission Inheritance Problem
For applications running under different identities:
// Grant permissions to all required accounts
aspnet_regiis -pa "KeyContainerName" "IIS AppPool\DefaultAppPool"
aspnet_regiis -pa "KeyContainerName" "IIS AppPool\NewAppPool"
To ensure everything works:
- Restart IIS:
iisreset
- Verify in both application pools
- Check Event Viewer for any cryptographic errors
For future deployments:
// PowerShell script to automate key container setup
$containerName = "KeyContainerName"
$keyFile = "C:\keys.xml"
$accounts = @("IIS AppPool\DefaultAppPool", "dmz\UserName")
aspnet_regiis -pz $containerName
aspnet_regiis -pi $containerName $keyFile -exp
foreach ($account in $accounts) {
aspnet_regiis -pa $containerName $account
}
Remember to store your key file securely and include proper error handling in production scripts.
When deploying a secondary ASP.NET application on Windows Server 2008 R2 with identical application pool configurations to the primary site, the system fails to access the existing RSA key container despite using the same identity credentials. The error chain reveals contradictory messages:
1. Failed RSA container access in new app pool (error: "could not be opened") 2. Failed permission assignment (error: "container was not found") 3. Failed import attempt (error: "Object already exists") 4. Failed deletion attempt (error: "container was not found")
The system maintains RSA key containers in two distinct locations:
Machine-level: C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys User-level: C:\Users\[username]\AppData\Roaming\Microsoft\Crypto\RSA
When the aspnet_regiis -pi
command reports "Object already exists" while -pz
claims it doesn't, this typically indicates:
- The container exists in machine storage but has restricted ACLs
- The executing context lacks permissions to view/access the container
- Possible cryptographic service provider (CSP) mismatch
Step 1: Verify actual container existence
# PowerShell command to list machine-level containers Get-ChildItem -Path "C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys" | Where-Object { $_.Name -match "[0-9a-f]{32}" } | ForEach-Object { $acl = Get-Acl $_.FullName [PSCustomObject]@{ File = $_.Name Owner = $acl.Owner Access = $acl.Access | Where-Object { $_.IdentityReference -like "*YOUR_USER*" } } }
Step 2: Corrective actions for common scenarios
# Scenario 1: Reset container permissions (admin PowerShell) $containerPath = "C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys\[CONTAINER_GUID]" $userAccount = "DOMAIN\USER" $acl = Get-Acl $containerPath $rule = New-Object System.Security.AccessControl.FileSystemAccessRule( $userAccount, "FullControl", "Allow") $acl.AddAccessRule($rule) Set-Acl -Path $containerPath -AclObject $acl # Scenario 2: Recreate container with proper inheritance aspnet_regiis -pz "KeyContainerName" aspnet_regiis -pi "KeyContainerName" "C:\keys.xml" -exp aspnet_regiis -pa "KeyContainerName" "DOMAIN\USER"
When standard approaches fail, consider these diagnostic steps:
# Check CSP provider compatibility $rsa = New-Object System.Security.Cryptography.RSACryptoServiceProvider $rsa.CspKeyContainerInfo.MachineKeyStore = $true $rsa.CspKeyContainerInfo.KeyContainerName = "KeyContainerName" $rsa.PersistKeyInCsp = $true $rsa.Clear() # Verify DPAPI protection scope Add-Type -AssemblyName System.Web [System.Web.Configuration.MachineKeySection]::DecryptConfig( "connectionStrings", "RsaProtectedConfigurationProvider", "KeyContainerName")
- Always specify -exp flag during container creation for exportable keys
- Configure identical
settings across web.config files - Document container GUIDs and permission assignments
- Consider using Azure Key Vault for modern deployments