https 与 Service Fabric 本地群集管理器

Posted

技术标签:

【中文标题】https 与 Service Fabric 本地群集管理器【英文标题】:https with Service Fabric Local Cluster Manager 【发布时间】:2021-08-22 11:05:44 【问题描述】:

我开发 Service Fabric 应用程序,并且我在本地安装了 Service Fabric SDK,它提供了有用的 Service Fabric 本地集群管理器 (servicefabriclocalclustermanager.exe)(如果是稀疏的)。默认情况下,这似乎只支持http。没有明显的方法可以从 UI 创建 https 集群。我做了一些研究,并设法为自己创建了一个 https 集群,但为了做到这一点,我必须手动修改 ClusterConfig.json 文件并运行 CreateServiceFabricCluster.ps1 powershell 脚本。这不与 Service Fabric 本地集群管理器集成,如果我想操作它,我基本上必须使用 powershell 命令。这是可以管理的,但如果可能的话,使用系统托盘小部件会容易得多。

有没有办法将 Service Fabric 本地集群管理器与为 https 配置的本地集群一起使用?我知道 C:\Program Files\Microsoft SDKs\Service Fabric\ClusterSetup 中有一大堆脚本,这似乎是 Service Fabric 本地集群管理器用来配置与之交互的集群的内容,并且有安全版本那些脚本,但我不知道如何使用它们。

【问题讨论】:

我对此的第一个看法是询问您为什么需要这样做。本地集群管理器旨在用于本地开发目的。在 Azure 上运行的集群管理器默认配置为使用 HTTPS(因为您将必要的证书设置为该配置的一部分)。您打算使用本地 HTTPS 实现什么目标? 我们有一个大型遗留应用程序,我们目前正在将其转变为一组服务结构微服务(慢慢地)。我们最近开始为该应用程序使用 https,这在 prod 中很好,我们的微服务也是 https。然而,我们的开发环境现在是 https 应用程序和 http 微服务的尴尬组合。一些微服务具有我们通过 iframe 嵌入到主应用程序中的 UI。这不再有效,因为 iframe 内容是不安全的,而主机是安全的。我无法更改大应用程序,只能更改我的 SF 集群。 我想我仍然不理解对集群管理器的依赖,因为它只是启动用于监控集群的 SF explorer。 HTTPS 实际上应该只关注单个服务,而这只是确保您为每个服务提供可用的端点 + 服务设置的问题。您选择如何监控它(使用 SFX 或其他工具)应该与此无关。 无论如何,它并不涉及开发集群本身,但您可能会在 standalone guidance 中找到一些有用的提示,因为它提到了您将用于在其上创建安全集群的各种安全脚本-前提。但同样,请注意,它还提到此证书保护集群维护操作(例如通过 SFX 或 PowerShell),您自己的应用程序不一定要依赖它。 谢谢。我已经使用独立的文档来达到我现在的位置,并且它有点工作。我想真正的问题是我们在服务结构中使用了反向代理,而这需要使用 https 进行设置。我可以做到,它工作正常,但工作流程不是很好。我会继续加油的。如果由我决定,我会将主应用程序设置回 http 并完全避免这个问题,但是嘿嘿...... :) 【参考方案1】:

这是我使用了一段时间的解决方案。

这里的关键是创建自己的自定义 Https 证书定位器 并使用它根据您的 环境。例如,在本地使用默认值是有意义的 localhost 由 Visual Studio 工具创建的 HTTPS 证书。在 您可能需要根据其他环境识别正确的证书 一些标准,例如它的通用名称

覆盖CreateServiceInstanceListeners 无状态服务中的CreateServiceInstanceListeners 操作以配置https 端口。这也是您提供自定义 HttpsCertificateLocator 实现的地方。

protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()

    return new ServiceInstanceListener[]
    
        new ServiceInstanceListener(serviceContext =>
            new KestrelCommunicationListener(serviceContext, "ServiceEndpoint", (url, listener) =>
            
                return new WebHostBuilder()
                    .UseKestrel(opt =>
                    
                        int port = serviceContext.CodePackageActivationContext.GetEndpoint("ServiceEndpoint").Port;
                        opt.Listen(IPAddress.IPv6Any, port, listenOptions =>
                        
                            listenOptions.UseHttps(new HttpsCertificateLocator().GetHttpsCertificateFromStore());
                        );
                    )
                      

示例 HTTPS 证书定位器

public class HttpsCertificateLocator : BaseHttpsCertificateLocator, IHttpsCertificateLocator

    private readonly string[] _cNsToTryInOrderOfPriority;
    private readonly bool _isDevelopment;
    private const string Development = nameof(Development);

    public HttpsCertificateLocator(string environmentName = null, string[] cNsToTryInOrderOfPriority = null)
    
        _cNsToTryInOrderOfPriority = cNsToTryInOrderOfPriority ?? CommonCertificates.Intranet.DefaultCNs;

        var environment = string.IsNullOrWhiteSpace(environmentName)
            ? (System.Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? Development)
            : environmentName;

        _isDevelopment = string.Compare(environment, Development, StringComparison.OrdinalIgnoreCase) == 0;
    

    /// <summary>
    /// If environment is Development, finds and returns the ASP .NET Core HTTPS development certificate in development environment.
    /// In other developments, returns a HTTPS certificate that is assumed installed on all Service Fabric cluster nodes
    /// </summary>
    public X509Certificate2 GetHttpsCertificateFromStore(bool httpsMandatory = true)
    
        if (_isDevelopment)
        
            return ReturnDevCertificate(httpsMandatory);
        

        using (X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine))
        
            store.Open(OpenFlags.ReadOnly);
            var certCollection = store.Certificates;

            foreach (var subjectName in _cNsToTryInOrderOfPriority)
            
                var matchingCerts = certCollection.Find(X509FindType.FindBySubjectDistinguishedName, subjectName, true);
                if (matchingCerts.Count > 0)
                
                    return EnsureMostRecentCertificate(matchingCerts, subjectName, httpsMandatory);
                
            

            return EnsureMostRecentCertificate(
                new X509Certificate2Collection(), 
                _cNsToTryInOrderOfPriority.LastOrDefault() ?? "<NONE SPECIFIED>",
                httpsMandatory);
        
    

以上代码继承自BaseHttpsCertificateLocator。它提供了额外的功能来定位默认的开发localhost HTTPs 证书。它还具有查找最新证书的代码(开始滚动证书时必须处理的事情)。

public abstract class BaseHttpsCertificateLocator

    protected X509Certificate2 ReturnDevCertificate(bool httpsMandatory)
    
        // Note: AspNet Core should auto generate/install this X509 cert on dev PCs
        const string aspNetHttpsOid = "1.3.6.1.4.1.311.84.1.1";
        const string cnLocalhost = "CN=localhost";

        using (X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine))
        
            store.Open(OpenFlags.ReadOnly);
            var certCollection = store.Certificates;
            var currentCerts = certCollection.Find(X509FindType.FindByExtension, aspNetHttpsOid, true);
            var matchingCerts = currentCerts.Find(X509FindType.FindByIssuerDistinguishedName, cnLocalhost, true);
            return EnsureMostRecentCertificate(matchingCerts, cnLocalhost, httpsMandatory);
        
    

    protected X509Certificate2 EnsureMostRecentCertificate(
        X509Certificate2Collection marchingCerts,
        string cnName,
        bool httpsMandatory)
    
        if (marchingCerts.Count == 0)
        
            return httpsMandatory
                ? throw new SecurityException($"Unable to locate HTTPS X509 cert `cnName`")
                : default(X509Certificate2);
        

        if (marchingCerts.Count > 1)
        
            return marchingCerts.Cast<X509Certificate2>().OrderByDescending(x => x.NotAfter).First();
        

        return marchingCerts[0];
    

【讨论】:

这看起来像是为单个应用程序启用了 https,对吗?如果是这样,那是我可以做的,但不幸的是,它并不能解决我的问题。我正在寻找的是一种使用 https 获取整个集群的方法。 Service Fabric Explorer、Service Fabric Cluster Manager、反向代理(对我们来说最重要的是反向代理)一切。在我们的开发环境中,应用程序是通过反向代理访问的,主要是因为它很好地映射到我们设置 API 管理内容的方式,因此是整个集群方法。 正确 - 每个应用程序。如果要提供端到端的 https 加密,则必须在单个应用程序级别进行;您当然可以为所有应用重复使用相同的通配符证书。除此之外,只有其他方式是通过反向代理 - 使用 SF 反向代理或第 3 方。不幸的是,不确定如何破解本地集群管理器以使用 https。

以上是关于https 与 Service Fabric 本地群集管理器的主要内容,如果未能解决你的问题,请参考以下文章

Service Fabric小白入门记录 本地Service Fabric集群安装及设置

在本地部署 Service Fabric 项目:“FABRIC_E_IMAGEBUILDER_UNEXPECTED_ERROR”

在 Linux 中创建 Azure Service Fabric 本地集群

您是不是可以在本地调试 Service Fabric 群集?

在 Service Fabric 中通过 HTTPS 调用 WCF:请求被中止:无法创建 SSL/TLS 安全通道

Mac 上的 Service Fabric Docker 仅公开一个端口