保护 Java 服务的服务远程处理通信

安全是通信最为重视的要素之一。 Reliable Services 应用程序框架提供了一些预先生成的通信堆栈和工具供你用来提高安全性。 本文介绍如何在 Java 服务中使用服务远程处理时提高安全性。 它基于现有的示例构建,该示例解释了如何为使用 Java 编写的可靠服务设置远程处理。

若要在 Java 服务中使用服务远程处理时帮助保护服务,请遵循以下步骤:

  1. 创建接口 HelloWorldStateless,用于定义可供服务的远程过程调用使用的方法。 服务将使用 microsoft.serviceFabric.services.remoting.fabricTransport.runtime 包中声明的 FabricTransportServiceRemotingListener。 这是可以提供远程处理功能的 CommunicationListener 实现。

    public interface HelloWorldStateless extends Service {
        CompletableFuture<String> getHelloWorld();
    }
    
    class HelloWorldStatelessImpl extends StatelessService implements HelloWorldStateless {
        @Override
        protected List<ServiceInstanceListener> createServiceInstanceListeners() {
            ArrayList<ServiceInstanceListener> listeners = new ArrayList<>();
            listeners.add(new ServiceInstanceListener((context) -> {
                return new FabricTransportServiceRemotingListener(context,this);
            }));
        return listeners;
        }
    
        public CompletableFuture<String> getHelloWorld() {
            return CompletableFuture.completedFuture("Hello World!");
        }
    }
    
  2. 添加侦听器设置和安全凭据。

    确保要用来帮助保护服务通信的证书安装在群集中的所有节点上。 对于在 Linux 上运行的服务,证书必须以 PEM 格式的文件提供,要么是包含证书和私钥的 .pem 文件,要么是包含证书的 .crt 文件和包含私钥的 .key 文件。 有关详细信息,请参阅 Linux 节点上的 X.509 证书的位置和格式

    有两种方式可用于提供侦听器设置和安全凭据:

    1. 使用配置包提供:

      在 settings.xml 文件中添加名为 TransportSettings 的节。

      <!--Section name should always end with "TransportSettings".-->
      
      <!--Here we are using a prefix "HelloWorldStateless".-->
      
       <Section Name="HelloWorldStatelessTransportSettings">
           <Parameter Name="MaxMessageSize" Value="10000000" />
           <Parameter Name="SecurityCredentialsType" Value="X509_2" />
           <Parameter Name="CertificatePath" Value="/path/to/cert/BD1C71E248B8C6834C151174DECDBDC02DE1D954.crt" />
           <Parameter Name="CertificateProtectionLevel" Value="EncryptandSign" />
           <Parameter Name="CertificateRemoteThumbprints" Value="BD1C71E248B8C6834C151174DECDBDC02DE1D954" />
       </Section>
      
      

      在这种情况下,createServiceInstanceListeners 方法如下所示:

       protected List<ServiceInstanceListener> createServiceInstanceListeners() {
           ArrayList<ServiceInstanceListener> listeners = new ArrayList<>();
           listeners.add(new ServiceInstanceListener((context) -> {
               return new FabricTransportServiceRemotingListener(context,this, FabricTransportRemotingListenerSettings.loadFrom(HelloWorldStatelessTransportSettings));
           }));
           return listeners;
       }
      

      如果将在 settings.xml 中添加 TransportSettings 节而不添加任何前缀,则 FabricTransportListenerSettings 将按默认加载此节中的所有设置。

      <!--"TransportSettings" section without any prefix.-->
      
      <Section Name="TransportSettings">
          ...
      </Section>
      

      在这种情况下,CreateServiceInstanceListeners 方法如下所示:

      protected List<ServiceInstanceListener> createServiceInstanceListeners() {
          ArrayList<ServiceInstanceListener> listeners = new ArrayList<>();
          listeners.add(new ServiceInstanceListener((context) -> {
              return new FabricTransportServiceRemotingListener(context,this);
          }));
          return listeners;
      }
      
  3. 在安全服务上使用远程堆栈(而不是使用 microsoft.serviceFabric.services.remoting.client.ServiceProxyBase 类)调用方法来创建服务代理时,请使用 microsoft.serviceFabric.services.remoting.client.FabricServiceProxyFactory

    如果客户端代码正在作为服务的一部分运行,则可以从 settings.xml 文件中加载 FabricTransportSettings。 创建与服务代码类似的 TransportSettings 节,如上所示。 对客户端代码进行以下更改。

    
    FabricServiceProxyFactory serviceProxyFactory = new FabricServiceProxyFactory(c -> {
            return new FabricTransportServiceRemotingClientFactory(FabricTransportRemotingSettings.loadFrom("TransportPrefixTransportSettings"), null, null, null, null);
        }, null)
    
    HelloWorldStateless client = serviceProxyFactory.createServiceProxy(HelloWorldStateless.class,
        new URI("fabric:/MyApplication/MyHelloWorldService"));
    
    CompletableFuture<String> message = client.getHelloWorld();