.NET 6.0 Web API의 클라이언트 인증서 인증

12972 단어

요약



이 기사에서는 클라이언트 인증서 인증을 지원하는 .NET 6.0 Web API 샘플 코드를 공유합니다. The sample code은 전송 계층 보안 프로토콜(RFC5246)에 작성된 핸드셰이크 프로토콜의 인증서 요청과 유사한 .NETMicrosoft.AspNetCore.Authentication.Certificate의 내장 기능을 활용합니다.

목차



  • Concept
  • Web server - Local machine (Kestrel)
  • Web server - Azure App Service
  • Authentication event
  • Certificate validation
  • Configuration - Local machine
  • Configuration - Azure App Service

  • Sample request
  • Self-signed certificate

  • 개념

    • Web Server requires a client certificate and validate the certificate is trusted during TLS handshake.
    • CertificateAuthenticationOptions handler checks the certificate type.
    • CertificateValidationService validates the pfx file or thumbprint.
    • Controller has to have [Authorize] attribute because it deals with the context determined in TLS handshake and Authentication/Authorization middleware.


    웹 서버 - 로컬 컴퓨터(Kestrel)

    • Configure Kestrel server for a local run so it requires a client certificate during TLS handshake
    • Microsoft.AspNetCore.Server.Kestrel.Https.ClientCertificateMode has options such as RequireCertificate and AllowCertificate . Once you set RequireCertificate , any request without a client certificate is declined.
    • A self-signed certificate does not work without AllowAnyClientCertificate() method.
    Program.cs

    builder.Services.Configure<KestrelServerOptions>(options =>
    {
        options.ConfigureHttpsDefaults(options =>
        {
            options.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
            options.AllowAnyClientCertificate();
        });
    
    });
    


    웹 서버 - Azure 앱 서비스

    • When the application code is deployed in Azure App Service, it requires another Web Server configuration than Kestrel in Program.cs .
    • Azure App Service has configuration that accepts and requires a client certificate in the request from the client application.
    • Set clientCertEnabled: true and clientCertMode: 'Required' in your bicep file.
    • It looks you do not need to specify self-signed certificate for Azure App Service.
    Bicep example

    resource AppServiceCert 'Microsoft.Web/sites@2021-03-01' = {
      name: appsrv_name_cert
      location: location
      kind: 'app'
      identity: {
        type: 'SystemAssigned'
      }
      properties: {
        serverFarmId: AppServicePlanCert.id
        httpsOnly: true
        clientCertEnabled: true
        clientCertMode: 'Required'
        siteConfig: {
          netFrameworkVersion: '6.0'
          http20Enabled: true
          minTlsVersion: '1.2'
        }
      }
    }
    


    인증 이벤트

    • An event handler CertificateAuthenticationEvents is triggered during a TLS handshake, which is written with builder.Services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme) in Program.cs .
    • A self-signed certificate requires CertificateAuthenticationOptions.AllowedCertificateTypes property to be All or SelfSigned .
    • The CertificateAuthenticationOptions handler calls CertificateValidationService and set the context success or fail.
    • If the validation fails, it returns 403 forbidden during the TLS handshake before it reaches .NET application.
    Program.cs

    builder.Services.AddAuthentication(
            CertificateAuthenticationDefaults.AuthenticationScheme)
        .AddCertificate(options =>
        {
            options.AllowedCertificateTypes = CertificateTypes.All;
            options.Events = new CertificateAuthenticationEvents
            {
                OnCertificateValidated = context =>
                {
                    var validationService = context.HttpContext.RequestServices
                        .GetRequiredService<ICertificateValidationService>();
                    if (validationService.ValidateCertificate(context.ClientCertificate))
                    {
                        context.Success();
                    }
                    else
                    {
                        context.Fail("Invalid certificate");
                    }
                    return Task.CompletedTask;
                }
            };
        });
    


    인증서 유효성 검사

    • CertificateValidationService handles the certificate validation and returns true/false to CertificateAuthenticationOptions handler.
    • To validate an incoming client certificate, the Web API app config has Pfx file path and Pfx password, or the certificate thumbprint.
    • If the Web API instance does not have the Pfx file, for example, if it is deployed in Azure App Service, the service validates if the incoming certificate thumbprint is identical with the one in the app config.
    CertificateValidationService

    public bool ValidateCertificate(X509Certificate2 clientCertificate)
    {
        X509Certificate2 expectedCertificate;
        string pfxFilePath = this.configuration.GetValue<string>("Certificate:PfxFilePath");
        string pfxFilePassword = this.configuration.GetValue<string>("Certificate:PfxFilePassword");
    
        if (File.Exists(Path.Combine(Directory.GetCurrentDirectory(), pfxFilePath)))
        {
            expectedCertificate = new X509Certificate2(
                Path.Combine(Directory.GetCurrentDirectory(), pfxFilePath), pfxFilePassword);
            return clientCertificate.Thumbprint == expectedCertificate.Thumbprint;
        }
        else
        {
            return clientCertificate.Thumbprint == this.configuration.GetValue<string>("Certificate:Thumbprint");
        }
    }
    


    구성 - 로컬 머신

    For local run, you will set the Pfx file path and password or thumbprint in appsettings.json or appsettings.Development.json

    appsettings.json 예시

    "Certificate": {
       "PfxFilePath": "certificates/sample.pfx",
       "PfxFilePassword": "{Pfx file password if needed}",
       "Thumbprint": "6B132..."
    }
    


    구성 - Azure 앱 서비스

    • It is difficult to have the Pfx file in Azure App Service, and then it can validate with the thumbprint.
    • The thumbprint should be stored in Azure Key Vault and the App Service extracts it through Key Vault reference.
    Bicep example

    resource AppServiceConfigCert 'Microsoft.Web/sites/config@2021-03-01' = {
      name: '${AppServiceCert.name}/appsettings'
      properties: {
        'Certificate:PfxFilePath': ''
        'Certificate:PfxFilePassword': ''
        'Certificate:Thumbprint': '@Microsoft.KeyVault(VaultName=${kv_name};SecretName=${kvsecret_name_cert_thumbprint})'
        'WEBSITE_RUN_FROM_PACKAGE': 1
      }
    }
    


    샘플 요청

    • It seems bash does not have a feature to send a pfx file. So I tried with a cert file and private key.
    • Powershell supports sending a pfx file. It requires a password after calling Invoke-RestMethod , if needed.

    Bash

    curl {App URL}/Weatherforecast/RequireAuth \
       --cert ./sample.crt \
       --key ./sample.key \
       --insecure
    

    Powershell

    $parameters = @{
        Method  = 'GET'
        Uri     = '{App URL}/Weatherforecast/RequireAuth'
        Certificate  = (Get-PfxCertificate '.\sample.pfx')
    }
    Invoke-RestMethod @parameters
    

    자체 서명된 인증서

    Here is just my note of how to generate a self-signed certificate with openssl.

    PEM DER PKCS#12
    Data format Base64 ASCII Binary Binary
    Extension .cer .pem .crt .key .cer .der .pfx .p12


    개인 키: sample.key공개 키: sample_public.key인증서 서명 요청: sample.csr인증서(PEM): sample.crt인증서(PKCS#12): sample.pfx
    개인 키 만들기

    openssl genrsa -out sample.key 2048
    


    개인 키에서 공개 키 만들기

    openssl rsa -in sample.key -pubout -out sample_public.key
    


    CSR 만들기

    openssl req -new -key sample.key -out sample.csr
    


    인증서 생성(PEM)

    openssl x509 -signkey sample.key -in sample.csr -req -days 365 -out sample.crt
    


    인증서 생성(PKCS#12)

    openssl pkcs12 -export -inkey sample.key -in sample.crt -out sample.pfx
    

    좋은 웹페이지 즐겨찾기