Proteggere le comunicazioni remote in un servizio C#
La sicurezza è uno degli aspetti essenziali della comunicazione. Il framework di applicazioni di Reliable Services offre alcuni stack e strumenti predefiniti che è possibile usare per migliorare la sicurezza. Questo articolo discute come migliorare la sicurezza quando si usa la comunicazione remota in un servizio C#. Verrà usato un esempio esistente che spiega come configurare la comunicazione remota per Reliable Services in C#.
Per proteggere un servizio quando si usa la comunicazione remota con i servizi C#, seguire questa procedura:
Creare un'interfaccia,
IHelloWorldStateful
, che definisce i metodi che saranno disponibili per la Remote Procedure Call del servizio. Il servizio userà il metodoFabricTransportServiceRemotingListener
, dichiarato nello spazio dei nomiMicrosoft.ServiceFabric.Services.Remoting.FabricTransport.Runtime
. Si tratta di un’implementazioneICommunicationListener
che fornisce funzionalità di accesso remoto.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!"); } }
Aggiungere le impostazioni del listener e le credenziali di sicurezza.
Assicurarsi che il certificato da usare per proteggere le comunicazioni dei servizi sia installato in tutti i nodi del 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:
Specificarle direttamente nel codice del servizio:
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; }
Specificarle tramite un pacchetto di configurazione:
Aggiungere una sezione denominata
TransportSettings
nel file settings.xml.<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: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.<!--"TransportSettings" section .--> <Section Name="TransportSettings"> ... </Section>
In questo caso il metodo
CreateServiceReplicaListeners
avrà un aspetto analogo al seguente:protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners() { return new[] { return new[]{ new ServiceReplicaListener( (context) => new FabricTransportServiceRemotingListener(context,this))}; }; }
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, usareMicrosoft.ServiceFabric.Services.Remoting.Client.ServiceProxyFactory
. SpecificareFabricTransportRemotingSettings
, che contieneSecurityCredentials
.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. Creare una sezione HelloWorldClientTransportSettings simile al codice del servizio, come illustrato in precedenza. Apportare le modifiche seguenti al codice client: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. Creare quindi una sezione TransportSettings in tale 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.In questo caso il codice precedente risulta ancora più semplice:
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.