0
votes

I have a Service Fabric Stateless Asp.Net Core service.

The service works with an HTTP endpoint. I need to support an HTTPS endpoint along with the HTTP

My steps so far:

  1. Added the certificate to Azure KeyVault
  2. Updated ApplicationManifest.xml with:

    <Policies>
      <EndpointBindingPolicy EndpointRef="ServiceEndpointHttps" CertificateRef="Certificate" />
    </Policies>
    

And at the end

<Certificates>
    <EndpointCertificate X509StoreName="MY" X509FindValue="XXXX" Name="Certificate" />
  </Certificates>
  1. Added the Endpoint in ServiceManifest.xml with port 443

I'm now left with enabling the HTTPS endpoint. In Program.cs I have this:

  public static void Main(string[] args)
        {
            ServiceRuntime.RegisterServiceAsync("MyType", context => new WebHostingService(context, "ServiceEndpoint")).GetAwaiter().GetResult();

            Thread.Sleep(Timeout.Infinite);
        }
 internal sealed class WebHostingService : StatelessService, ICommunicationListener
        {
            private readonly string _endpointName;

            private IWebHost _webHost;

            public WebHostingService(StatelessServiceContext serviceContext, string endpointName)
                : base(serviceContext)
            {
                _endpointName = endpointName;
            }

            #region StatelessService

            protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
            {
                return new[] { new ServiceInstanceListener(_ => this) };
            }

            #endregion StatelessService

            #region ICommunicationListener

            void ICommunicationListener.Abort()
            {
                _webHost?.Dispose();
            }

            Task ICommunicationListener.CloseAsync(CancellationToken cancellationToken)
            {
                _webHost?.Dispose();

                return Task.FromResult(true);
            }

            Task<string> ICommunicationListener.OpenAsync(CancellationToken cancellationToken)
            {
                var endpoint = FabricRuntime.GetActivationContext().GetEndpoint(_endpointName);

                string serverUrl = $"{endpoint.Protocol}://{FabricRuntime.GetNodeContext().IPAddressOrFQDN}:{endpoint.Port}";

                _webHost = new WebHostBuilder().UseKestrel()
                                               .UseContentRoot(Directory.GetCurrentDirectory())
                                               .UseStartup<Startup>()
                                               .UseUrls(serverUrl)
                                               .Build();

                _webHost.Start();

                return Task.FromResult(serverUrl);
            }

            #endregion ICommunicationListener
        }

How can I register the HTTPS endpoint here?

Adding a second ServiceRuntime.RegisterServiceAsync doesn't work.

Also, After enabling it, how I do install (from the portal or powershell) the certificates from KeyVault to the Virtual Machines Scale sets that are already deployed and running?

3

3 Answers

2
votes

You can actually use Kestrel + HTTPS + Service Fabric, but it's more of an adventure.

1) you need to find the certificate yourself (see below) 2) if you test on your local machine, you need to add the certificate to LocalMachine and also make sure you give permissions to NETWORK SERVICE (mmc \ Certificate \ Local Machine \ Personal \ Cert, Right-click All-tasks \ Manage Private Keys...)

        private X509Certificate2 FindCertificate(string thumbprint)
        {
            X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
            try
            {
                store.Open(OpenFlags.ReadOnly);
                X509Certificate2Collection col = store.Certificates.Find(X509FindType.FindByThumbprint,
                    thumbprint, false); // Don't validate certs, since the test root isn't installed.
                if (col == null || col.Count == 0)
                    return null;
                return col[0];
            }
            finally
            {
                store.Close();
            }
        }

        Task<string> ICommunicationListener.OpenAsync(CancellationToken cancellationToken)
        {
            var endpoint = FabricRuntime.GetActivationContext().GetEndpoint(_endpointName);

            string serverUrl = $"{endpoint.Protocol}://{FabricRuntime.GetNodeContext().IPAddressOrFQDN}:{endpoint.Port}";

            _webHost = new WebHostBuilder().UseKestrel(options =>
                                            {
                                                options.UseHttps(FindCertificate("<thumbprint-remove-magic-character at the beginning if copy&paste from MMC>"));
                                            })
0
votes

I have just encountered this over the weekend. I followed some advice as to not use Kestrel but WebListener instead thus:

new WebHostBuilder()
.UseWebListener()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.UseUrls($"{endpoint.Protocol}://+:{endpoint.Port}")
.Build();

Also note the use of + for the url instead of FabricRuntime.GetNodeContext().IPAddressOrFQDN

Hope this helps.

0
votes

I resolved using an Azure Application Gateway.