MRCollective / AzureWebFarm

MsDeploy enabled Web Farm using Web Roles in Azure based on Windows Azure Accelerator for Web Roles and including a background worker execution model
Other
19 stars 4 forks source link

SNI support in binding #7

Open kallex opened 10 years ago

kallex commented 10 years ago

SNI (Server Name Indication) has been supported in IIS 8. It's the feature that allows using multiple SSL certs on same endpoint.

This feature allows using multiple wildcard certs on same endpoint - effectively removing the requirement for endpoint-per-SSL-cert.

Any plans to support it? Or is it already supported, not mentioned in basic readme parts yet.

kallex commented 10 years ago

Update: I digged through the code, and found the SslFlags in Bindings, and candidate for the spot to include them. Haven't tested yet myself (trying to asap), but here's where I got:

File IISManager.cs, line 208 - captured the new binding and set it's SslFlags:

if (cert != null) { _logger.InfoFormat("Adding Binding '{0}' for website '{1}' with Binding Information '{2}' and Certificate '{3}'", binding.Id, site.Name, binding.BindingInformation, cert.Thumbprint); var addedBinding = iisSite.Bindings.Add(binding.BindingInformation, cert.GetCertHash(), StoreName.My.ToString()); // Set SslFlags, TODO: Conditional binding info addedBinding.SslFlags = SslFlags.Sni; }

Update 2: The SslFlags property (with proper values) was there for the intellisense to find, before I started to gather the Microsoft.Web. assemblies for the build. I'm entering unfamiliar territory of where-to-get-the-Microsoft.Web assemblies...

mikoskinen commented 10 years ago

I have a version of AzureWebFarm which includes the SNI support. The code just needs some cleaning, which I've been planning to do for the past 3 months or so...

The SNI requires changes to couple places, all in IISManager.cs. First is when a completely new site is created:

                    if (cert != null)
                    {
                        _logger.InfoFormat("Adding website '{0}' with Binding Information '{1}' and Certificate '{2}'", site.Name, defaultBinding.BindingInformation, cert.Thumbprint);

                        iisSite = serverManager.Sites.Add(
                            siteName,
                            defaultBinding.BindingInformation,
                            sitePath,
                            cert.GetCertHash(), StoreName.My.ToString(), SslFlags.Sni);
                    }

Second change is for a new binding:

                        if (cert != null)
                        {
                            _logger.InfoFormat("Adding Binding '{0}' for website '{1}' with Binding Information '{2}' and Certificate '{3}'", binding.Id, site.Name, binding.BindingInformation, cert.Thumbprint);
                            iisSite.Bindings.Add(binding.BindingInformation, cert.GetCertHash(), StoreName.My.ToString(), SslFlags.Sni);
                        }

There's one more change I did. As the main web site has a HTTPS binding with a certificate, this binding will interfere with the SNI bindings created for other web sites. You'll get certificate errors for the SNI bindings. I ended up just deleting the HTTPS binding of the main site. I did this by adding the following code into the top of the UpdateSites:

            var iisSites = serverManager.Sites;

            _logger.DebugFormat("Sites list from IIS: {0}", string.Join(",", iisSites.Select(s => s.Name)));

            var mainSite =
                iisSites.FirstOrDefault(
                    x => x.Name.Equals(AzureRoleEnvironment.RoleWebsiteName(), StringComparison.OrdinalIgnoreCase));

            if (mainSite != null)
            {
                _logger.DebugFormat("Trying to delete the https binding's from main site: {0}.", mainSite.Name);

                var sslBinding = mainSite.Bindings.FirstOrDefault(x => string.Equals(x.Protocol, "https"));
                if (sslBinding == null)
                {
                    _logger.DebugFormat("The main site {0} doesn't have SSL Certificate set.", mainSite.Name);
                }
                else
                {
                    mainSite.Bindings.Remove(sslBinding);
                    try
                    {
                        _logger.DebugFormat("Committing updates to IIS for site '{0}'", mainSite.Name);
                        serverManager.CommitChanges();
                    }
                    catch (Exception e)
                    {
                        _logger.ErrorFormat(e, "Error committing changes for site '{0}'", mainSite.Name);
                    }
                }
            }
robdmoore commented 10 years ago

This is awesome guys!

I'll definitely look into this with Matt and try and get it into the codebase :)

Eta is probably a month or two though sorry!

If you send through a PR I'm happy to merge it and get it in earlier though.

Only thing is, I'd want to make SNI opt in (and possibly opt in per-site if that's possible - or it it all or nothing?).

kallex commented 10 years ago

For what I gathered of SNI support in IIS, it also allows CSS (common certificate store), that to me looked like normal filesystem share.

While Azure WebFarm already handles certs on its own, that CSS might bring flexibility to cert management on certain dynamicly-added-binding scenarios.

mikoskinen commented 10 years ago

It's possible to make SNI opt-in for the installation. But AFAIK, if it's enabled, it must be enabled for all the sites in that installation. I can recheck this.

Regarding Centralized Certificate Store, it's slightly different thing from SNI. You can use SNI with CCS or without it. What CCS enables is that you can copy certificates into web share and use them from there, instead of installing certificates to every server. But, CCS isn't needed with Azure Cloud Services as Azure automatically installs the certificates to all the servers.

robdmoore commented 10 years ago

Cool - if you can find that out it would be great. If it's an all-or-nothing opt-in then I'd want to put it in the .cscfg probably?

Thanks for clarifying about CCS :)

kallex commented 10 years ago

Mikael, could you share your code (and care to help me with Microsoft.Web.* issues with build)?

Or is it already available in that form forked perhaps?

I'm deploying right now/Monday a version where I effectively need the SNI functionality.

kallex commented 10 years ago

Thanks to Mikael for helping with Microsoft.Web.* parts and the code parts in the thread, I migrated to my quite recently refreshed fork at: https://github.com/abstractiondev/AzureWebFarm

Completely untested by me, and also not including the assemblies, as I'm not sure where they need to be "officially" get to be redistributed properly. I'll put this bit into reality-test on Monday and report back...

kallex commented 10 years ago

Early real-world results are positive - it works! I'm not sure if there is an issue with changing bindings (by changing cert), I'll keep looking to that... and there seems to be need to support that CCS as well.

Rigth now the way I got it to work there is problem with certain scenarios: the certificates need to be introduced at the deployment so that they end up to webroles. They cannot be assigned for binding if they're not present. For scenarios where one ends up deploying certs and sites dynamically later on, this is a problem.

There might be something I'm missing in updating certs on roles more dynamic fashion... so I keep investigating a bit.