en / de
Expertisen
Methoden
Dienstleistungen
Referenzen
Jobs & Karriere
Firma
Technologie-Trends TechCast WebCast TechBlog News Events Academy

gRPC Tutorial Teil 5: Client-Zertifikat Authentifizierung

Wenn gRPC nur im Backend verwendet wird, bietet eine sichere Verbindung mit zusätzlicher Client-Zertifikat Authentifizierung meistens ausreichende Sicherheit. Mit dieser Form der Authentifizierung wird nicht nur die Identität des Servers, sondern auch diejenige des Clients bestätigt, um sicher zu gehen, dass sich kein Fremdprogramm mit dem Server verbindet. Dieses Tutorial zeigt Schritt für Schritt wie man den gRPC Server und Client einrichtet (mit selbstsignierten Zertifikaten) für Client-Zertifikat Authentifizierung.

Der Code zum Beispiel kann man hier herunterladen.

Client-Zertifikat Authentifizierung

Ein digitales Client-Zertifikat ist im Grunde eine Datei, die mit einem Passwort geschützt und in eine Client-Anwendung geladen wird (normalerweise als PKCS12-Dateien mit der Erweiterung ‘.p12’ oder ‘.pfx’).

Ein digitales Zertifikat enthält relevante Informationen wie eine digitale Signatur, Ablaufdatum, Name des Issuers, Name der CA (Certificate Authority), Sperrstatus (revocation), SSL/TLS-Versionsnummer, Seriennummer und möglicherweise weitere Informationen, die alle nach dem X.509-Standard strukturiert sind.

Ein Client-Zertifikat ist ein spezieller Zertifikat-Typ mit dem Ziel, seine Identität für einen anderen Rechner nachzuweisen, in unserem Fall also für den Server. Man erkennt den Zweck eines Zertifikates an Hand der OID (Object Identifier), welche eine Folge von Zahlen ist. Das Zertifikatfeld ‘Enhanced Key Usage’ eines Client-Zertifikates enthält die OID ‘1.3.6.1.5.5.7.3.2’.

Enhanced Key Usage for Client Certificate

Enhanced Key Usage for Client Certificate

Mit dem Suchwort ‘cert’ im Windows Startmenu erscheint ‘Manage computer certificates’, welches die Microsoft Management Konsole öffnet. Mit einem Doppelklick aufs Zertifikat erscheinen die detaillierten Informationen wie oben im Bild.

Zu Beginn einer SSL- oder TLS-Sitzung kann der Server (falls so konfiguriert) vom Client ein Client-Zertifikat verlangen. Nach dem Empfang des Zertifikats identifiziert der Server die Quelle des Zertifikats und entscheidet, ob dem Client der Zugriff erlaubt werden soll.

Selbstsignierte Zertifikate erstellen

Normalerweise werden Zertifikaten von Zertifizierungsstellen (‘certificate authority’ oder ‘certification authority’, kurz CA) ausgestellt (z.B. Verisign, Thawte, etc.). Für unser Beispiel werden wir selber die Zertifikate generieren. Es gibt verschiedene Wege selber Zertifikate zu generieren: Powershell, online Tools, OpenSSL, etc. In diesem Beitrag wird OpenSSL verwendet.

OpenSSL installieren

Die binäre Dateien des OpenSSL Tools stehen als ZIP-Datei zur Verfügung auf ‹https://sourceforge.net/projects/openssl‹ oder als Installer auf ‹https://slproweb.com/products/Win32OpenSSL.html‹. Lade die letzte Version des Installers ‘Win64OpenSSL_Light-1_1_0L.exe’ (oder höher) herunter und führe den Installer aus. Wichtig ist, dass ‘openssl.exe’ und ‘openssl.cnf’ sich nach der Installation im Verzeichnis ‘C:\OpenSSL-Win64\bin’ befinden.

Zertifikate generieren

Im Beispiel gibt es einen Unterordner ‘Certs’ in dem alle OpenSSL Tool Input- und Output-Dateien gespeichert werden.

Die Inhalte des Zertifikatfeldes ‘Enhanced Key Usage’ müssen für das OpenSSL Tool in einer externen Datei definiert werden. In diesem Verzeichnis eine Textdatei ‘openssl-ext.cnf’ mit folgendem Inhalt erstellen:

[client_ssl]
extendedKeyUsage = clientAuth

[server_ssl]
extendedKeyUsage = serverAuth

Eine zweite Datei namens ‘create_certs.cmd’ mit folgendem Inhalt erstellen:

set OPENSSL_CONF=c:\OpenSSL-Win64\bin\openssl.cfg   

echo Generate CA key:
c:\OpenSSL-Win64\bin\openssl genrsa -passout pass:P@ssw0rd -des3 -out root.key 4096

echo Generate CA certificate:
c:\OpenSSL-Win64\bin\openssl req -passin pass:P@ssw0rd -new -x509 -days 3650 -key root.key -out root.crt -subj "/C=CH/ST=LU/L=Root D4/O=Noser Engineering AG/OU=www.noser.com/CN=Noser RpcWithCertificates Root"

echo Generate server key:
c:\OpenSSL-Win64\bin\openssl genrsa -passout pass:P@ssw0rd -des3 -out server.key 4096

echo Generate server signing request:
c:\OpenSSL-Win64\bin\openssl req -passin pass:P@ssw0rd -new -key server.key -out server.csr -subj "/C=CH/ST=LU/L=Root D4/O=Noser Engineering AG/OU=www.noser.com/CN=localhost"

echo Self-sign server certificate:
c:\OpenSSL-Win64\bin\openssl x509 -req -passin pass:P@ssw0rd -days 3650 -extensions server_ssl -extfile openssl-ext.cnf  -in server.csr -CA root.crt -CAkey root.key -set_serial 01 -out server.crt

echo Remove passphrase from server key:
c:\OpenSSL-Win64\bin\openssl rsa -passin pass:P@ssw0rd -in server.key -out server.key

echo Generate client key
c:\OpenSSL-Win64\bin\openssl genrsa -passout pass:P@ssw0rd -des3 -out client.key 4096

echo Generate client signing request:
c:\OpenSSL-Win64\bin\openssl req -passin pass:P@ssw0rd -new -key client.key -out client.csr -subj "/C=CH/ST=LU/L=Root D4/O=Noser Engineering AG/OU=www.noser.com/CN=localhost"

echo Self-sign client certificate:
c:\OpenSSL-Win64\bin\openssl x509 -req -passin pass:P@ssw0rd -days 3650 -extensions client_ssl -extfile openssl-ext.cnf -in client.csr -CA root.crt -CAkey root.key -set_serial 01 -out client.crt

echo Remove passphrase from client key:
c:\OpenSSL-Win64\bin\openssl rsa -passin pass:P@ssw0rd -in client.key -out client.key

c:\OpenSSL-Win64\bin\openssl pkcs12 -export -in root.crt -inkey root.key -out root.pfx -passout pass:P@ssw0rd -passin pass:P@ssw0rd -name "Noser Engineering self-signed root cert"

c:\OpenSSL-Win64\bin\openssl pkcs12 -export -in server.crt -inkey server.key -out server.pfx -passout pass:P@ssw0rd -name "Noser Engineering self-signed server cert"

c:\OpenSSL-Win64\bin\openssl pkcs12 -export -in client.crt -inkey client.key -out client.pfx -passout pass:P@ssw0rd -name "Noser Engineering self-signed client cert"

pause

Nach dem Ausführen des oberen Skripts hat das Verzeichnis folgenden Inhalt:

OpenSSL Ausgabe

OpenSSL Ausgabe

Das Skript generiert verschiedene (Zwischen-)Dateien, wovon für uns nur 3 wichtig sind:

  1. root.pfx (friendly name ‘Noser Engineering self-signed root cert’)
  2. server.pfx (friendly name ‘Noser Engineering self-signed server cert’)
  3. client.pfx (friendly name ‘Noser Engineering self-signed client cert’)

Die Datei ‘root.pfx’ enthält das Zertifikat mit ‘Intended Purposes All’ und wird zum Signieren des Server- und Client-Zertifikates verwendet. Das Server-Zertifikat hat ‘Intended Purposes Server Authentication’ und das Client-Zertifikat hat ‘Intended Purposes Client Authentication’. Das Server-Zertifikat wird später im gRPC Server geladen und das Client-Zertifikat im Client-Programm. Alle drei Zertifikate müssen aber zuerst auf dem Rechner installiert werden.

Installieren der Zertifikate

Da es nicht möglich ist mit OpenSSL den ‘friendly name’ in einer ‘crt’-Datei zu generieren, verwenden wir die ‘pfx’-Datei zum Installieren der Zertifikate.
Doppelklick auf root.pfx und wähle ‘Local Machine’.

Importieren Zertifikat

Importieren Zertifikat

Das Passwort einfügen (P@ssw0rd).

Importieren Zertifikat

Importieren Zertifikat: Passwort spezifizieren

Für das Root-Zertifikate den ‘Trusted Root Certification Authorities’ Store wählen.

Importieren Zertifikat: Store auswählen

Importieren Zertifikat: Trusted Root Store auswählen

Alle Schritte für ‘server.pfx’ und ‘client.pfx’ wiederholen mit dem Unterschied, dass ‘Intermediate Certification Authorities’ als Store gewählt werden soll.

Zertifikat Importieren: Intermediate Store auswählen

Zertifikat Importieren: Intermediate Store auswählen

Danach die Microsoft Management Konsole öffnen durch Eingabe von ‘cert’ im Windows Startmenü. Es erscheint ‘Manage computer certificates’ in den Ergebnissen, welches die Konsole öffnet.
Das Root-Zertifikat soll sich jetzt in ‘Trusted Root Certification Authorities’ befinden.

Root Zertifikat im Root Store

Root Zertifikat im Root Store

Und das Server- und Client-Zertifikat in ‘Intermediate Certification Authorities’.

Client- und Server-Zertifikat in intermediate Store

Client- und Server-Zertifikat in intermediate Store

gRPC Server Einrichten

Beim Server muss die Client-Zertifikat Authentifizierung aktiviert werden und das Server-Zertifikat installiert werden.

Als erste muss die Datei ‘server.pfx’ im Projekt kopiert werden und mit ins Ausgabeverzeichnis kopiert werden.

Inkludieren server.pfx Datei im Projekt

Inkludieren server.pfx Datei im Projekt

Passwort und Dateiname werden in appsettings.json in einer neuen Sektion ‘Certificate’ definiert:

{
    "Logging": {
…
    },
    "Certificate": {
        "File": "server.pfx",
        "Password": "P@ssw0rd"
    }
}

In der program.cs Datei wird der Kestrel-Server für die Sicherheitsvorkehrungen konfiguriert:

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
            webBuilder.ConfigureKestrel(
                opt =>
                {
                    var config = (IConfiguration)opt.ApplicationServices.GetService(typeof(IConfiguration));
                    var cert = new X509Certificate2(
                        config["Certificate:File"], config["Certificate:Password"]);
                    opt.ConfigureHttpsDefaults(
                    h =>
                    {
                        h.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
                        h.CheckCertificateRevocation = false;
                        h.ServerCertificate = cert;
                    });

                });
        });

Dazu wird ein X509-Zertifikat aus der ‘pfx’-Datei erstellt, zugewiesen und die Client-Zertifikat Authentifizierung eingeschaltet. Da selbstsignierte Zertifikate nicht widerrufen werden können, wird CheckCertificateRevocation ausgeschaltet.

In startup.cs muss der Authentication-Service hinzugefügt und konfiguriert werden.

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
        .AddCertificate(
            opt =>
            {
                opt.AllowedCertificateTypes = CertificateTypes.All;
                opt.RevocationMode = X509RevocationMode.NoCheck; // Just for development
            });
    services.AddAuthorization();
    services.AddControllers();
    services.AddGrpc(opt => { opt.EnableDetailedErrors = true; });
}

Als letzter Schritt muss der Zugriff auf den gRPC Service mit dem ‘Authorize’-Attribute verriegelt werden.

[Authorize(AuthenticationSchemes = CertificateAuthenticationDefaults.AuthenticationScheme)]
public class DemoServiceRpc : DemoService.DemoServiceBase
{
    public override Task<NameMessage> ExchangeNames(NameMessage request, ServerCallContext context)
    {
        NameMessage result = new NameMessage
        {
            Name = $"Hello {request.Name} from {Assembly.GetExecutingAssembly().FullName}"
        };
        return Task.FromResult(result);
    }
}

gRPC Client Einrichten

Auch beim Client-Programm muss die ‘pfx’-Datei im Ausgabeverzeichnis landen.

Inkludieren der client.pfx Datei im Projekt

Inkludieren der client.pfx Datei im Projekt

Die Sektion ‘Service’ in appsettings.json wird erweitert mit dem Passwort und dem Datei-Namen.

{
  "Logging": {
  "LogLevel": {
    "Default": "Information",
    "Microsoft": "Warning",
    "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "Service": {
    "CustomerId": 1,
    "DelayInterval": 3000,
    "ServiceUrl": "https://localhost:5001",
    "CertFileName": "client.pfx",
    "CertPassword": "P@ssw0rd" 
  }
}

Es ist nur möglich, Zertifikate zum HttpClientHandler zu zuweisen. Deshalb wird neu in worker.cs ein HttpClientHandler erstellt, das Zertifikat geladen, zugewiesen und mit dem Handler als Parameter der HttpClient erstellt.

protected DemoService.DemoServiceClient Client
{
    get
    {
        if (_client == null)
        {
            var cert = new X509Certificate2(
                _config["Service:CertFileName"], 
                _config["Service:CertPassword"]);
            var handler = new HttpClientHandler();
            handler.ClientCertificates.Add(cert);
            var client = new HttpClient(handler); 
            var opt = new GrpcChannelOptions()
            {
                HttpClient = client,
                LoggerFactory = _loggerFactory
            };
            ChannelBase channel = GrpcChannel.ForAddress(_config["Service:ServiceUrl"], opt);
            _client = new DemoService.DemoServiceClient(channel);
        }
        return _client;
    }
}

Wenn alle Schritte richtig durchlaufen sind, funktioniert die Client-Server Kommunikation wie vorher.  Die Ursachen von eventuellen Problemen sind leider nur sehr schwer zu finden. Im folgenden Beispiel wurde das Root-Zertifikat mit der Microsoft Management Console gelöscht. Beim Verbinden des Clients erscheint dann folgende Ausgabe.

Ausgabe vom gRPC Client wenn Zertifikat nich i.O. ist

Ausgabe vom gRPC Client wenn Zertifikat nicht i.O. ist

Die Fehlermeldung ‘The remote certificate is invalid according to the validation procedure’ kommt bei jedem Authentifizierungsproblem und ist nicht sehr hilfreich.

Fazit

Dieses Beispiel zeigt, dass es relativ wenig Schritte braucht um Client-Zertifikat Authentifizierung in den gRPC Server und Client einzubauen. Die Praxis zeigt aber auch, dass es sehr mühsam ist einen Fehler zu finden, falls die Absicherung der Kommunikation nicht auf Anhieb funktioniert.
Im nächsten Blog wird die Absicherung mit Access Tokens erklärt. Diese Technologie versichert den Server, dass der Client authentifiziert und autorisiert, ist um nur die erlaubte Funktionalität des APIs zu benutzen.

← Voriger Post
Nächster Post →
Kommentare

4 Antworten zu “gRPC Tutorial Teil 5: Client-Zertifikat Authentifizierung”

  1. […] ← Vorige Post Nächster Post → […]

  2. […] erstellt (ClientCertificateMode.NoCertificate). Client-Zertifikat Authentifizierung wird im nächsten Blog erklärt und sorgt dafür, dass der Server den Client authentifiziert bevor der Client auf die […]

Schreiben Sie einen Kommentar

Ihre E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Newsletter - aktuelle Angebote, exklusive Tipps und spannende Neuigkeiten

 Jetzt anmelden
NACH OBEN
Zur Webcast Übersicht