The Problem: When new IIS Application Pools are created and set to use the Application Pool Identity for permissions, I am unsure how to add those identities to User Groups such as Administrator or Performance Counter Users.
The Background: I'm currently writing a C#.NET library which uses Microsoft.Web.Administration in order to do the following:
The context is that this library is to be used by executable installers to provide automated deployment of a web server and web sites/services on Windows Server OSes as part of a larger software deployment. So far, all of the above has been implemented, tested, and is (mostly) functional except for the automation of some permissions that need to be performed on Application Pool / Website creation.
In my method for installing a new website, I create a new Application Pool and force it to use the Application Pool Identity:
static public void InstallSite(string name, string path, int port)
{
Site site;
var appPoolName = ApplicationPoolBaseName + name;
using (var iisManager = new ServerManager())
{
// Set up a custom application pool for any site we run.
if (!iisManager.ApplicationPools.Any(pool => pool.Name.Equals(appPoolName)))
{
iisManager.ApplicationPools.Add(appPoolName);
iisManager.ApplicationPools[appPoolName].ManagedRuntimeVersion = "v4.0";
}
iisManager.CommitChanges();
}
// ... other code here ('site' gets initialized) ...
using (var iisManager = new ServerManager())
{
// Set anonymous auth appropriately
var config = iisManager.GetWebConfiguration(site.Name);
var auth = config.GetSection("system.web/authentication");
auth.SetMetadata("mode", "Windows");
var authSection = config.GetSection("system.webServer/security/authentication/anonymousAuthentication");
authSection.SetAttributeValue("enabled", true);
authSection.SetAttributeValue("userName", string.Empty); // Forces the use of the Pool's Identity.
authSection = config.GetSection("system.webServer/security/authentication/basicAuthentication");
authSection.SetAttributeValue("enabled", false);
authSection = config.GetSection("system.webServer/security/authentication/digestAuthentication");
authSection.SetAttributeValue("enabled", false);
authSection = config.GetSection("system.webServer/security/authentication/windowsAuthentication");
authSection.SetAttributeValue("enabled", false);
iisManager.CommitChanges();
}
// ... other code here ...
}
As I understand it, this would be the best security practice, and I would then add permissions to specific web sites for anything more than minimal system access. Part of this process would be to add these Application Pool identities to User Groups, such as Administrator or Performance Monitor Users. This is where complications arise.
Now, as documented elsewhere, each Application Pool Identity exists in the format of IIS AppPool\\<pool_name>
but this faux-user is not listed through the normal GUI user management controls, and does not seem to be accessible through libraries such as System.DirectoryServices.AccountManagement
when following this example on SO. Also, other questions about the Application Pool Identity seem to relate to referencing it from within a child website, not from within an installation context.
So, does anyone know what the proper methods are for
Thanks for your well-written question. It is exactly the problem that I was trying to solve last night and it gave me enough to go on that I was able finally cobble together an answer that uses only managed code. There were three steps that I found to getting the framework to find and work with the virtual user:
new System.Security.Principal.NTAccount(@"IIS APPPOOL\<appPoolName>")
to get a handle on the account..Translate(typeof (System.Security.Principal.SecurityIdentifier))
to convert it to a SIDPrincipal.FindByIdentity()
treats that SID like it is a group, rather than a userA final working program (Windows Server 2012 for my test) is as follows:
using System;
using System.DirectoryServices.AccountManagement;
namespace WebAdminTest
{
internal class Program
{
private static void Main(string[] args)
{
var user = new System.Security.Principal.NTAccount(@"IIS APPPOOL\10e6c294-9836-44a9-af54-207385846ebf");
var sid = user.Translate(typeof (System.Security.Principal.SecurityIdentifier));
var ctx = new PrincipalContext(ContextType.Machine);
// This is weird - the user SID resolves to a group prinicpal, but it works that way.
var appPoolIdentityGroupPrincipal = GroupPrincipal.FindByIdentity(ctx, IdentityType.Sid, sid.Value);
Console.WriteLine(appPoolIdentityGroupPrincipal.Name);
Console.WriteLine(appPoolIdentityGroupPrincipal.DisplayName);
GroupPrincipal targetGroupPrincipal = GroupPrincipal.FindByIdentity(ctx, "Performance Monitor Users");
// Making appPoolIdentity "group" a member of the "Performance Monitor Users Group"
targetGroupPrincipal.Members.Add(appPoolIdentityGroupPrincipal);
targetGroupPrincipal.Save();
Console.WriteLine("DONE!");
Console.ReadKey();
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With