Background on Identities in IIS
Table of Contents
- Application Pool Identities
- Default permissions and User rights in wwwroot
- Understanding Configuration Isolation
- IUSR - Anonymous Authentication
- ASP.NET Impersonation
Application Pool Identities
Before explaining what Application Pool Identities are let me explain what an identity is. Identity in simple terms is a windows account. Every process that’s runs in windows runs under an identity. The applications are executed by the worker process using a windows identity. The windows identity that is used is dependent on the application pool identity which can be any of the following accounts:
- Local System: Completely trusted account and has very high privileges and can also access network resources.
- Network Service: Restricted or limited service account that is generally used to run, standard least-privileges services. This account has less privileges than Local System account. This account has access network resources.
- Local Service: Restricted or limited service account that is very similar to Network Service and meant to run standard least-privileged services. This account cannot access network resources.
- ApplicationPoolIdentity: When a new application pool is created, IIS creates a virtual account with the name of the new Application Pool and run the Application’s Pool worker process under this account. This is also a least privileged account.
- Custom Account: In addition to these built-accounts, we can also use a custom account, by specifying the username and password.
Now I am going to explain few scenarios which will give you a clear idea what the differences among these Application Pool identities are.
Scenario 1: Event Log Access
In this scenario I have developed one web application which will create a custom event log (PratZone) and an event log source (PratZone.com) at runtime. Applications that run using any of the identities can write to the event log by using existing event sources, but if they are running under an identity other than Local System they cannot create new event sources because of insufficient registry permissions.
For example if we run the application under Network Service we will get the following security exception.
Upon running the ProcMon trace simultaneously one can easily find that ‘NT AUTHORITY\NETWORK SERVICE’ doesn’t have required Read and Write access privileges to the registry key path HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\ . It is the place in registry where all the settings of an event log are stored.
Scenario 2: Registry Access
Apart from Local System, no other application pool identities have write access to registry. In this scenario I have developed a simple web application that can change and display the name of the Internet time server that Windows is automatically synchronized with. Let’s see what happens if we run this application under ‘Local Service’. You will get an exception and upon checking the ProcMon trace you will find that the application pool identity ‘NT AUTHORITY\LOCAL SERVICE’ doesn’t have Read and Write access in the registry key path HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\DateTime\Servers.
I have checked the event log ‘PratZone’ (which was already created in scenario 1) and found the below error event being logged with an error message saying “Requested registry access is not allowed”.
Exception Type
SecurityException
Message
Requested registry access is not allowed.
Stack Trace
at Microsoft.Win32.RegistryKey.OpenSubKey(String name, Boolean writable)
at Identities.ChangeTimeServer.Page_Load(Object sender, EventArgs e)
at System.Web.UI.Control.LoadRecursive()
at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
at System.Web.UI.Page.ProcessRequest(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
at System.Web.UI.Page.ProcessRequest()
at System.Web.UI.Page.ProcessRequest(HttpContext context)
at ASP.changetimeserver_aspx.ProcessRequest(HttpContext context) in c:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\fd06117a\f8c94323\App_Web_ysqbhk00.2.cs:line 0
at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
Scenario 3: Custom account in Kerberos authentication and in load balanced environment
We have already seen in scenarios 1 and 2 some of the differences among the built-in accounts. Now let’s discuss what a custom account is and how it is advantageous over built-in accounts when dealing with Kerberos authentication and in load balanced environment. With this approach, you run your application in an application pool configured to run using a specific Windows identity. Consider the below diagram where an application is hosted in a load balanced environment consisting of two servers and they are using Kerberos authentication to identify the client.
Please go through the blog on how Kerberos works before going through this scenario.
In order to Kerberos authentication to work you need to setup SPN for both of the servers using their machine$ account. If the application pool is running under a built-in account it presents the machine credentials on the network, i.e. if the machine name is Server1, then it would present itself as Server1$. This machine account automatically gets created when a computer joins a domain. Hence if there are N servers we have to set N number of SPNs corresponding to their respective machine$ account.
Registering a SPN to a machine account
setspn –a HTTP/HOSTNAME MachineAccount$
Example: setspn –a HTTP/pratzone.com Server1$
Hence in order to overcome this disadvantage we can run the application under a custom windows (domain) identity and then set the SPN only to that particular domain account in the domain controller.
Registering a SPN to a domain account
setspn –a HTTP/HOSTNAME domain\account
Example: setspn –a HTTP/pratzone.com contoso.com\prchanda
Default permissions and User rights in wwwroot
IIS 7 and above also makes the process of configuring an application pool identity and making all necessary changes easier. When IIS starts a worker process, it needs to create a token that the process will use. When this token is created, IIS automatically adds the IIS_IUSRS membership to the worker processes token at runtime. The accounts that run as 'application pool identities' no longer need to be an explicit part of the IIS_IUSRS group. If we create a new website and point the physical location to C:\inetpub\wwwroot then the following users/groups get automatically added to its Access Control Lists.
Users / groups | Allowed permissions |
CREATOR OWNER | Special permissions |
SYSTEM | Full control |
Administrators | Full control |
Users | Read & execute, List folder contents, Read |
IIS_USRS | Read & execute |
TrustedInstaller | Full control |
If you want to disable this feature and manually add accounts to the IIS_IUSRS group, disable this feature by setting the manualGroupMembership value to 'true' in applicationHost.config file. The following example shows how this can be done to the DefaultAppPool:
<applicationPools>
<add name="DefaultAppPool">
<processModel manualGroupMembership="true" />
</add>
</applicationPools>
Understanding Configuration Isolation
IIS worker processes do not have Read access to applicationHost.config file. So you must be wondering how are they able to read any of the configuration set in this file?
The answer lies in the configuration isolation feature provided by IIS 7.0 and above. Instead of enabling IIS worker processes to read applicationHost.config directly when reading the configuration file hierarchy, WAS generates filtered copies of this file and each IIS worker process uses these copies as a replacement of applicationHost.config when configuration is read inside the IIS worker process. These files are generated by default in the %SystemDrive% \inetpub\Temp\appPools directory and are named as {AppPoolName}.config. These files are configured to allow access only to the IIS worker processes in the corresponding application pool, by using the IIS APPPOOL\AppPoolName Application Pool SID.
To know more about Security Identifier (SID) you can check this MSDN article.
The reason for doing this is to prevent IIS worker processes from application pool A to be able to read configuration information in applicationHost.config that is intended for application pool B. Because applicationHost.config may contain sensitive information, such as the user name and password for custom application pool identities, as well as user name and password for virtual directories, allowing all application pools to access applicationHost.config would break application pool isolation. If each ApplicationPool would been given direct access to applicationHost.config file, then it could have easily hacked sensitive information of other application pools by simply executing the following command:
appcmd list APPPOOL "DefaultAppPool" /text:*
IUSR – Anonymous Authentication
Anonymous authentication allows users to access the public areas of the website, without prompting the users for a username or password. In IIS 7.0 and above a built-in account, IUSR is used for providing anonymous access. This built-in account does not need a password and will be the default identity that is used when anonymous authentication is enabled. If you look in the applicationHost.config file, you will see the following definition:
This tells IIS to use the new built-in account for all anonymous authentication requests. The biggest advantages are that you:
- No longer need to worry about passwords expiring for this account.
- Can use xcopy /o to copy files along with their ownership and ACL information to different computers seamlessly.
You can also provide anonymous authentication to your website using a specific windows account or Application pool identity instead of IUSR account.
ISUR v/s Connect as…
Connect as… is an option provided by IIS where you can decide what credentials do you want to use to access the website. You can either use the authenticated user credentials or a specific user. To explain the difference between these two in a better way let me give you a scenario.
I have a Default website configured to use anonymous authentication, however I have my website contents on another server and I am using connect as section to access that resource via domain user "Test". Now when the user logins, he is authenticated using IUSR account. However, the website content is accessed via the user credentials mentioned in Connect as… section. To put in simple words, anonymous authentication is the mechanism used by the website to identify a user, but when we use this feature, the user need not has to provide any credentials. However, there might be a scenario like I explained above, where the contents are on a network share, in such cases you cannot use built-in accounts to access network share, but have to use a specific account (domain) to do so.
ASP.NET Impersonation
Literally impersonation means act of pretending to be another person. In technical terms it is an ASP.NET security feature which provides an ability to control the identity under which application code is executed. Impersonation comes into action when ASP.NET executes code in the context of an authenticated and authorized client. IIS provides anonymous access to resources using IUSR account. Once the request is handed over to ASP.NET, the application code is executed using the application pool identity.
When the application uses anonymous authentication and
- If IMPERSONATION is disabled, then the application pool identity is used to execute the application code.
- If IMPERSONATION is enabled, then ‘NT AUTHORITY\IUSR’ is used to execute the application code.
Impersonation can be enabled both through IIS as well through ASP.NET code. When impersonation is enabled through IIS, it adds the following tag in web.config of the application to impersonate the IIS Authenticated Account or User.
<identity impersonate="true" />
To impersonate a specific user for all the requests on all pages of an ASP.NET application, you can specify the userName and password attributes in the <identity> tag of the web.config file for that application.
<identity impersonate="true" userName="accountname" password="password" />
In order to implement impersonation through ASP.NET code you can refer the support KB 306158.
Let’s spawn up the IIS worker process of a test website impersonating a local user ‘Test’ and check if we can find the impersonation account under which the application code being executed. The application pool identity of the application is set to ‘ApplicationPoolIdentity’ and anonymous authentication is provided using IUSR account. We can easily trace the impersonating identity using ProcMon. For example if I inspect one of the ‘CreateFile’ events corresponding to the w3wp.exe process in concern we can find the impersonating account as shown below: