Background 
      
        
        
        
      
      I got the task of setting up CI.  It was decided to use the transformation of configuration files and store confidential data in encrypted form.  You can encrypt and decrypt them using the Key Container. 
      
        
        
        
      
    
      
        
        
        
      
      Key container 
      
        
        
        
      
      Every Windows OS has sets of generated keys.  The key is generated either on the account or on the machine.  The keys generated by the machine can be viewed along this path C: \ ProgramData \ Microsoft \ Crypto \ RSA \ MachineKeys.  This is where the key that we will create next will go. 
      
        
        
        
      
    
      
        
        
        
      
      Key creation 
      
        
        
        
      
      We start cmd from the administrator and switch to the directory with aspnet_regiis, I have C: \ Windows \ Microsoft.NET \ Framework64 \ v4.0.30319 
      
        
        
        
      
    
      
        
        
        
      
      Execute the command 
      
        
        
        
      
    
      
        
        
        
      
    aspnet_regiis -pc "TestKey" -exp
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
 
      
        
        
        
      
      exp - is added so that you can export the key in the future 
      
        
        
        
      
      TestKey - the name of our Key Container 
      
        
        
        
      
    
      
        
        
        
      
      Key Export 
      
        
        
        
      
      Team 
      
        
        
        
      
    
      
        
        
        
      
     aspnet_regiis -px "TestKey" :\TestKey.xml -pri
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
 
      
        
        
        
      
      TestKey - name Key Container 
      
        
        
        
      
      C: \ TestKey.xml - the path where the file will be exported 
      
        
        
        
      
      pri - add a private key to export 
      
        
        
        
      
    
      
        
        
        
      
      Import key 
      
        
        
        
      
      Team 
      
        
        
        
      
    
      
        
        
        
      
     aspnet_regiis -pi "TestKey" :\TestKey.xml
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
 
      
        
        
        
      
      TestKey - name Key Container 
      
        
        
        
      
      C: \ TestKey.xml - the path from where the file will be exported 
      
        
        
        
      
    
      
        
        
        
      
      Setting Rights 
      
        
        
        
      
      In order for your application or IIS to work with key container, you need to configure rights for it. 
      
        
        
        
      
    
      
        
        
        
      
      This is done by the team 
      
        
        
        
      
    
      
        
        
        
      
     aspnet_regiis -pa "TestKey" "NT AUTHORITY\NETWORK SERVICE"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
 
      
        
        
        
      
      TestKey - name Key Container 
      
        
        
        
      
      NT AUTHORITY \ NETWORK SERVICE - who will be given access to the key 
      
        
        
        
      
    
      
        
        
        
      
      By default, IIS has ApplicationPoolIdentity for the pool. 
      
        
        
        
      
    
      
        
        
        
      
      The Microsoft documentation (see link 2) describes ApplicationPoolIdentity as: 
      
        
        
        
      
    
      
        
        
        
      
    -   ApplicationPoolIdentity : When a new application pool is created, IIS creates a virtual account that has the name of the new application pool and that runs the application pool worker process under this account.  This is also a least-privileged account.  
      Therefore, for IIS to be able to decrypt the config, Identity must be configured in the pool for the account, or you can select "NETWORK SERVICE" and give it rights. 
      
        
        
        
      
    
      
        
        
        
      
      Adding a section to config 
      
        
        
        
      
     <configProtectedData defaultProvider="RsaProtectedConfigurationProvider"> <providers> <add name="CustomRsaProtectedConfigurationProvider" type="System.Configuration.RsaProtectedConfigurationProvider,System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" description="Uses RsaCryptoServiceProvider to encrypt and decrypt" keyContainerName="TestKey" cspProviderName="" useMachineContainer="true" useOAEP="false"/> </providers> </configProtectedData>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
      Also key container and RsaProtectedConfigurationProvider are defined globally in files 
      
        
        
        
      
    
      
        
        
        
      
      C: \ Windows \ Microsoft.NET \ Framework \ v4.0.30319 \ Config \ machine.config, C: \ Windows \ Microsoft.NET \ Framework64 \ v4.0.30319 \ Config \ machine.config 
      
        
        
        
      
    
      
        
        
        
      
     <configProtectedData defaultProvider="RsaProtectedConfigurationProvider"> <providers> <add name="RsaProtectedConfigurationProvider" type="System.Configuration.RsaProtectedConfigurationProvider,System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" description="Uses RsaCryptoServiceProvider to encrypt and decrypt" keyContainerName="NetFrameworkConfigurationKey" cspProviderName="" useMachineContainer="true" useOAEP="false"/> <add name="DataProtectionConfigurationProvider" type="System.Configuration.DpapiProtectedConfigurationProvider,System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" description="Uses CryptProtectData and CryptUnProtectData Windows APIs to encrypt and decrypt" useMachineProtection="true" keyEntropy=""/> </providers> </configProtectedData>
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
      Encryption 
      
        
        
        
      
      Encryption itself can be done in three ways. 
      
        
        
        
      
    
      
        
        
        
      
      Command Line Encryption 
      
        
        
        
      
     aspnet_regiis.exe -pef connectionStrings :\Site -prov "CustomRsaProtectedConfigurationProvider"
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
 
      
        
        
        
      
      C: \ Site - path to the file with the config. 
      
        
        
        
      
    
      
        
        
        
      
      CustomRsaProtectedConfigurationProvider - our provider specified in the config called key container. 
      
        
        
        
      
    
      
        
        
        
      
      Encryption through a written application 
      
        
        
        
      
     private static string provider = "CustomRsaProtectedConfigurationProvider"; public static void ProtectConfiguration() { Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); ConfigurationSection connStrings = config.ConnectionStrings; if (connStrings != null && !connStrings.SectionInformation.IsProtected && !connStrings.ElementInformation.IsLocked) { connStrings.SectionInformation.ProtectSection(provider); connStrings.SectionInformation.ForceSave = true; config.Save(ConfigurationSaveMode.Full); } } public static void UnProtectConfiguration(string path) { Configuration config = ConfigurationManager.OpenExeConfiguration(path); ConfigurationSection connStrings = config.ConnectionStrings; if (connStrings != null && connStrings.SectionInformation.IsProtected && !connStrings.ElementInformation.IsLocked) { connStrings.SectionInformation.UnprotectSection(); } }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
      Bicycle 
      
        
        
        
      
      When there is a file transformation and you need to encrypt sections separately from the entire config, then only a self-written version is suitable.  We create an instance of the RsaProtectedConfigurationProvider class, take a node from xml and encrypt it separately, then replace the original xml node with our encrypted one and save the result. 
      
        
        
        
      
    
      
        
        
        
      
     public void Protect(string filePath, string sectionName = null) { XmlDocument xmlDocument = new XmlDocument { PreserveWhitespace = true }; xmlDocument.Load(filePath); if (xmlDocument.DocumentElement == null) { throw new InvalidXmlException($"Invalid Xml document"); } sectionName = !string.IsNullOrEmpty(sectionName) ? sectionName : xmlDocument.DocumentElement.Name; var xmlElement = xmlDocument.GetElementsByTagName(sectionName)[0] as XmlElement; var config = new NameValueCollection { { "keyContainerName", _settings.KeyContainerName }, { "useMachineContainer", _settings.UseMachineContainer ? "true" : "false" } }; var rsaProvider = new RsaProtectedConfigurationProvider(); rsaProvider.Initialize(_encryptionProviderSettings.ProviderName, config); var encryptedData = rsaProvider.Encrypt(xmlElement); encryptedData = xmlDocument.ImportNode(encryptedData, true); var createdXmlElement = xmlDocument.CreateElement(sectionName); var xmlAttribute = xmlDocument.CreateAttribute("configProtectionProvider"); xmlAttribute.Value = _encryptionProviderSettings.ProviderName; createdXmlElement.Attributes.Append(xmlAttribute); createdXmlElement.AppendChild(encryptedData); if (createdXmlElement.ParentNode == null || createdXmlElement.ParentNode.NodeType == XmlNodeType.Document || xmlDocument.DocumentElement == null) { XmlDocument docNew = new XmlDocument { InnerXml = createdXmlElement.OuterXml }; docNew.Save(filePath); } else { xmlDocument.DocumentElement.ReplaceChild(createdXmlElement, xmlElement); xmlDocument.Save(filePath); } }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
      
        
        
        
      
      References 
      
        
        
        
      
      1.docs.microsoft.com/en-us/previous-versions/53tyfkaw 
      
        
        
        
      
      2.support.microsoft.com/en-za/help/4466942/understanding-identities-in-iis