Proteggere le comunicazioni remote in un servizio C#Secure service remoting communications in a C# service

La sicurezza è uno degli aspetti essenziali delle comunicazioni.Security is one of the most important aspects of communication. Il framework di applicazioni di Reliable Services offre alcuni stack e strumenti predefiniti che è possibile usare per migliorare la sicurezza.The Reliable Services application framework provides a few prebuilt communication stacks and tools that you can use to improve security. Questo articolo discute come migliorare la sicurezza quando si usa la comunicazione remota in un servizio C#.This article discusses how to improve security when you're using service remoting in a C# service. Verrà usato un esempio esistente che spiega come configurare la comunicazione remota per Reliable Services in C#.It builds on an existing example that explains how to set up remoting for reliable services written in C#.

Per proteggere un servizio quando si usa la comunicazione remota con i servizi C#, seguire questa procedura:To help secure a service when you're using service remoting with C# services, follow these steps:

  1. Creare un'interfaccia, IHelloWorldStateful, che definisce i metodi che saranno disponibili per la Remote Procedure Call del servizio.Create an interface, IHelloWorldStateful, that defines the methods that will be available for a remote procedure call on your service. Il servizio userà il metodo FabricTransportServiceRemotingListener, dichiarato nello spazio dei nomi Microsoft.ServiceFabric.Services.Remoting.FabricTransport.Runtime.Your service will use FabricTransportServiceRemotingListener, which is declared in the Microsoft.ServiceFabric.Services.Remoting.FabricTransport.Runtime namespace. Si tratta di un’implementazione ICommunicationListener che fornisce funzionalità di accesso remoto.This is an ICommunicationListener implementation that provides remoting capabilities.

    public interface IHelloWorldStateful : IService
    {
        Task<string> GetHelloWorld();
    }
    
    internal class HelloWorldStateful : StatefulService, IHelloWorldStateful
    {
        protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
        {
            return new[]{
                    new ServiceReplicaListener(
                        (context) => new FabricTransportServiceRemotingListener(context,this))};
        }
    
        public Task<string> GetHelloWorld()
        {
            return Task.FromResult("Hello World!");
        }
    }
    
  2. Aggiungere le impostazioni del listener e le credenziali di sicurezza.Add listener settings and security credentials.

    Assicurarsi che il certificato da usare per proteggere le comunicazioni dei servizi sia installato in tutti i nodi del cluster.Make sure the certificate that you want to use to help secure your service communication is installed on all the nodes in the cluster.

    Nota

    Sui nodi Linux, il certificato deve essere presente come file formattati PEM nella directory /var/lib/sfcerts. Per altre informazioni, vedere Percorso e formato dei certificati X.509 nei nodi Linux.

    Esistono due modi per specificare le impostazioni del listener e le credenziali di sicurezza:There are two ways that you can provide listener settings and security credentials:

    1. Specificarle direttamente nel codice del servizio:Provide them directly in the service code:

      protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
      {
          FabricTransportRemotingListenerSettings  listenerSettings = new FabricTransportRemotingListenerSettings
          {
              MaxMessageSize = 10000000,
              SecurityCredentials = GetSecurityCredentials()
          };
          return new[]
          {
              new ServiceReplicaListener(
                  (context) => new FabricTransportServiceRemotingListener(context,this,listenerSettings))
          };
      }
      
      private static SecurityCredentials GetSecurityCredentials()
      {
          // Provide certificate details.
          var x509Credentials = new X509Credentials
          {
              FindType = X509FindType.FindByThumbprint,
              FindValue = "4FEF3950642138446CC364A396E1E881DB76B48C",
              StoreLocation = StoreLocation.LocalMachine,
              StoreName = "My",
              ProtectionLevel = ProtectionLevel.EncryptAndSign
          };
          x509Credentials.RemoteCommonNames.Add("ServiceFabric-Test-Cert");
          x509Credentials.RemoteCertThumbprints.Add("9FEF3950642138446CC364A396E1E881DB76B483");
          return x509Credentials;
      }
      
    2. Specificarle tramite un pacchetto di configurazione:Provide them by using a config package:

      Aggiungere una sezione denominata TransportSettings nel file settings.xml.Add a named TransportSettings section in the settings.xml file.

      <Section Name="HelloWorldStatefulTransportSettings">
          <Parameter Name="MaxMessageSize" Value="10000000" />
          <Parameter Name="SecurityCredentialsType" Value="X509" />
          <Parameter Name="CertificateFindType" Value="FindByThumbprint" />
          <Parameter Name="CertificateFindValue" Value="4FEF3950642138446CC364A396E1E881DB76B48C" />
          <Parameter Name="CertificateRemoteThumbprints" Value="9FEF3950642138446CC364A396E1E881DB76B483" />
          <Parameter Name="CertificateStoreLocation" Value="LocalMachine" />
          <Parameter Name="CertificateStoreName" Value="My" />
          <Parameter Name="CertificateProtectionLevel" Value="EncryptAndSign" />
          <Parameter Name="CertificateRemoteCommonNames" Value="ServiceFabric-Test-Cert" />
      </Section>
      

      In questo caso il metodo CreateServiceReplicaListeners avrà un aspetto analogo al seguente:In this case, the CreateServiceReplicaListeners method will look like this:

      protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
      {
          return new[]
          {
              new ServiceReplicaListener(
                  (context) => new FabricTransportServiceRemotingListener(
                      context,this,FabricTransportRemotingListenerSettings .LoadFrom("HelloWorldStatefulTransportSettings")))
          };
      }
      

      Se si aggiunge una sezione TransportSettings al file settings.xml, FabricTransportRemotingListenerSettings caricherà tutte le impostazioni da questa sezione per impostazione predefinita.If you add a TransportSettings section in the settings.xml file , FabricTransportRemotingListenerSettings will load all the settings from this section by default.

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

      In questo caso il metodo CreateServiceReplicaListeners avrà un aspetto analogo al seguente:In this case, the CreateServiceReplicaListeners method will look like this:

      protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
      {
          return new[]
          {
              return new[]{
                      new ServiceReplicaListener(
                          (context) => new FabricTransportServiceRemotingListener(context,this))};
          };
      }
      
  3. Quando si chiamano metodi in un servizio protetto tramite lo stack di comunicazione remota, anziché usare la classe Microsoft.ServiceFabric.Services.Remoting.Client.ServiceProxy per creare un proxy del servizio, usare Microsoft.ServiceFabric.Services.Remoting.Client.ServiceProxyFactory.When you call methods on a secured service by using the remoting stack, instead of using the Microsoft.ServiceFabric.Services.Remoting.Client.ServiceProxy class to create a service proxy, use Microsoft.ServiceFabric.Services.Remoting.Client.ServiceProxyFactory. Specificare FabricTransportRemotingSettings, che contiene SecurityCredentials.Pass in FabricTransportRemotingSettings, which contains SecurityCredentials.

    
    var x509Credentials = new X509Credentials
    {
        FindType = X509FindType.FindByThumbprint,
        FindValue = "9FEF3950642138446CC364A396E1E881DB76B483",
        StoreLocation = StoreLocation.LocalMachine,
        StoreName = "My",
        ProtectionLevel = ProtectionLevel.EncryptAndSign
    };
    x509Credentials.RemoteCommonNames.Add("ServiceFabric-Test-Cert");
    x509Credentials.RemoteCertThumbprints.Add("4FEF3950642138446CC364A396E1E881DB76B48C");
    
    FabricTransportRemotingSettings transportSettings = new FabricTransportRemotingSettings
    {
        SecurityCredentials = x509Credentials,
    };
    
    ServiceProxyFactory serviceProxyFactory = new ServiceProxyFactory(
        (c) => new FabricTransportServiceRemotingClientFactory(transportSettings));
    
    IHelloWorldStateful client = serviceProxyFactory.CreateServiceProxy<IHelloWorldStateful>(
        new Uri("fabric:/MyApplication/MyHelloWorldService"));
    
    string message = await client.GetHelloWorld();
    

    Se il codice client viene eseguito come parte del servizio, è possibile caricare FabricTransportRemotingSettings dal file settings.xml.If the client code is running as part of a service, you can load FabricTransportRemotingSettings from the settings.xml file. Creare una sezione HelloWorldClientTransportSettings simile al codice del servizio, come illustrato in precedenza.Create a HelloWorldClientTransportSettings section that is similar to the service code, as shown earlier. Apportare le modifiche seguenti al codice client:Make the following changes to the client code:

    ServiceProxyFactory serviceProxyFactory = new ServiceProxyFactory(
        (c) => new FabricTransportServiceRemotingClientFactory(FabricTransportRemotingSettings.LoadFrom("HelloWorldClientTransportSettings")));
    
    IHelloWorldStateful client = serviceProxyFactory.CreateServiceProxy<IHelloWorldStateful>(
        new Uri("fabric:/MyApplication/MyHelloWorldService"));
    
    string message = await client.GetHelloWorld();
    

    Se il client non è in esecuzione come parte di un servizio, è possibile creare un file client_name.settings.xml nello stesso percorso del file client_name.exe.If the client is not running as part of a service, you can create a client_name.settings.xml file in the same location where the client_name.exe is. Creare quindi una sezione TransportSettings in tale file.Then create a TransportSettings section in that file.

    Come con il servizio, se si aggiunge una sezione TransportSettings nel file settings.xml/client_name.settings.xml del client, FabricTransportRemotingSettings carica tutte le impostazioni da questa sezione per impostazione predefinita.Similar to the service, if you add a TransportSettings section in client settings.xml/client_name.settings.xml, FabricTransportRemotingSettings loads all the settings from this section by default.

    In questo caso il codice precedente risulta ancora più semplice:In that case, the earlier code is even further simplified:

    
    IHelloWorldStateful client = ServiceProxy.Create<IHelloWorldStateful>(
                 new Uri("fabric:/MyApplication/MyHelloWorldService"));
    
    string message = await client.GetHelloWorld();
    

Come passaggio successivo, vedere API Web con OWIN in Reliable Services.As a next step, read Web API with OWIN in Reliable Services.