Comunicações remotas de serviço segura num serviço Java

A segurança é um dos aspetos mais importantes da comunicação. A arquitetura da aplicação Reliable Services fornece algumas pilhas e ferramentas de comunicação pré-criadas que pode utilizar para melhorar a segurança. Este artigo aborda como melhorar a segurança quando está a utilizar a comunicação remota do serviço num serviço Java. Baseia-se num exemplo existente que explica como configurar a comunicação remota para serviços fiáveis escritos em Java.

Para ajudar a proteger um serviço quando estiver a utilizar a comunicação remota do serviço com serviços Java, siga estes passos:

  1. Crie uma interface, HelloWorldStateless, que defina os métodos que estarão disponíveis para uma chamada de procedimento remoto no seu serviço. O seu serviço utilizará FabricTransportServiceRemotingListener, que é declarado no microsoft.serviceFabric.services.remoting.fabricTransport.runtime pacote. Esta é uma implementação CommunicationListener que fornece capacidades remotas.

    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. Adicione as definições do serviço de escuta e as credenciais de segurança.

    Certifique-se de que o certificado que pretende utilizar para ajudar a proteger a comunicação do serviço está instalado em todos os nós do cluster. Para serviços em execução no Linux, o certificado tem de estar disponível como um ficheiro com formato PEM; um .pem ficheiro que contenha o certificado e a chave privada ou um .crt ficheiro que contenha o certificado e um .key ficheiro que contenha a chave privada. Para saber mais, veja Localização e formato dos certificados X.509 nos nós do Linux.

    Existem duas formas de fornecer as definições do serviço de escuta e as credenciais de segurança:

    1. Forneça-os através de um pacote de configuração:

      Adicione uma secção com nome TransportSettings no ficheiro settings.xml.

      <!--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>
      
      

      Neste caso, o método terá o createServiceInstanceListeners seguinte aspeto:

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

      Se adicionar uma TransportSettings secção no ficheiro settings.xml sem qualquer prefixo, FabricTransportListenerSettings carregará todas as definições desta secção por predefinição.

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

      Neste caso, o método terá o CreateServiceInstanceListeners seguinte aspeto:

      protected List<ServiceInstanceListener> createServiceInstanceListeners() {
          ArrayList<ServiceInstanceListener> listeners = new ArrayList<>();
          listeners.add(new ServiceInstanceListener((context) -> {
              return new FabricTransportServiceRemotingListener(context,this);
          }));
          return listeners;
      }
      
  3. Quando chamar métodos num serviço seguro através da pilha remota, em vez de utilizar a microsoft.serviceFabric.services.remoting.client.ServiceProxyBase classe para criar um proxy de serviço, utilize microsoft.serviceFabric.services.remoting.client.FabricServiceProxyFactory.

    Se o código de cliente estiver em execução como parte de um serviço, pode carregar FabricTransportSettings a partir do ficheiro de settings.xml. Crie uma secção TransportSettings semelhante ao código de serviço, conforme mostrado anteriormente. Efetue as seguintes alterações ao código de cliente:

    
    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();