Akka-CQRS (13) - SSL / TLS for gRPC and HTTPS: self-signed certificate generated and used

  Up to now, we have completed the POS network integration platform and front end. But then again: Network Security Platform system is essential. The previous blog where we try to achieve a gRPC ssl / tls-Fi, but how to use the test certificate has not produced clear. Now ws akka-http developed also face problems setting up and using the HTTPS. So, especially out of this blog to discuss issues digital certificates.

In the formal production environment digital certificate should be issued by a third party notary public CA, we need to apply to the CA. Digital certificate application, issuance and verification process as follows:

1 ) public service ⽅ S submitted to a third party institution ⽅ CA, organize information, Information of persons (domain name) and other information to apply for certification (no need to provide the private key) 

2 ) CA verify applicant information provided by various means authenticity, such as the existence of the organization, business is legitimate, whether the ownership of a domain name 

3 ) as information for approval, CA will issue certification documents to the applicant - certificate. Certificate contains the following information: applicant's public key, and organize information Information of persons applicant, the issuing authority CA information, effective next time the file information, certificate serial number, production ⽣ contains a signature algorithm of Health: First, hash function to calculate the message digest of the certificate disclosed in plaintext, and then, using the CA private key to encrypt the message digest into ⾏, this signature is the encrypted files 

. 4 when) C client request to the server S, S returns the certificate file 

5 ) the client files related information C read out in the certificate, mining use the same hash function computed message digest, and then, using the corresponding CA public key decrypted signature data message digest of the certificate contrast, if yes, can confirm the legitimacy of the certificate, the public key legal 

6 ) client C and inspection certificates related to domain name information, valid time information, etc. 

7 ) client C should be built trusted CA certificate information (including the public), if the CA is not trust, it can not find the corresponding CA certificate, the certificate will be judged illegal 

8 ) corresponding built-in CA certificate called the root certificate issuer and Use by The same, with a CA signature private key Your Own, i.e. the self-signed certificate (public key certificate is the CA's public key, the public key signature can be used to verify certificate, certificate No need for additional parts ⼀)

An SSL encryption server in the communication channel is as follows:

1 ) The client sends a request to the server C S 

2 ) the server S returns to the certificate and the public key C, as part of the public key certificate transmission 

3 ) the validity of the client certificate and the public key C of the test, if valid , and the ⽣ to share a public key encryption key sent to the server S use 

. 4 ) using the S server private key to decrypt the data, and the shared key encrypted using the received data, sent to the client C 

. 5 ) client using the terminal C using the shared key to decrypt the data 

. 6 ) establishment of the SSL encrypted communication channel ...

It should be said, scenarios requiring authentication at the client much. This situation requires a digital certificate stored on the client side. Like Alipay and some banks clients are generally required to install the certificate.

Well, back or how to generate a self-signed certificate demonstration of it. The following is a standard process to generate a self-signed certificate using the openssl command:

In the process of generating certificates and keys for all systems to be consistent answer questions. Let's assume that a unified code is: 123456

1, generates a root private key: rootCA.key: openssl genrsa -des3 -out rootCA.key 2048 

2, the root certificate application rootCA.csr: openssl req -new -key rootCA.key -out rootCA.csr

3, the root certificate generation request with rootCA.crt rootCA.csr: openssl x509 -req -days 365 -sha256 -extensions v3_ca -signkey rootCA.key -in rootCA.csr -out rootCA.crt

4、pem根证书 rootCA.pem:openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.pem

5, create ⼀ a v3.ext files, the purpose is to generate X509 v3 certificates, the main purpose is to specify subjectAltName options:

  authorityKeyIdentifier=keyid,issuer
  basicConstraints=CA:FALSE
  keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
  subjectAltName = @alt_names
  [alt_names]
  DNS.1 = localhost
  IP.1 = "192.168.11.189"  
  IP.5 = "192.168.0.189"
  IP.2 = "132.232.229.60"
  IP.3 = "118.24.165.225"
  IP.4 = "129.28.108.238"

Note subjectAltName, which are to be trusted address or domain name.

6, building certificate key server.key: openssl req -new -sha256 -nodes -out server.csr -newkey rsa: 2048 -keyout server.key

7, rootCA server.crt generate self-signed certificate with a root certificate: openssl x509 -req -in server.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out server.crt -days 500 -sha256 -extfile v3.ext

This process is repeated above need to answer the same questions, annoying. Profiles can be used to generate a one-time:

First build a ssl.cnf file:

  [req]
  prompt = no
  default_bits = 4096
  default_md = sha256
  distinguished_name = dn
  x509_extensions = v3_req
  [dn]
  C=CN
  ST=GuangDong
  L=ShenZhen
  O=Bayakala
  OU=POS
  CN=www.bayakala.com
  emailAddress=admin@localhost
  [v3_req]
  keyUsage=keyEncipherment, dataEncipherment
  extendedKeyUsage=serverAuth
  subjectAltName=@alt_names
  [alt_names]
  DNS.1 = localhost
  IP.1 = "192.168.11.189"  
  IP.5 = "192.168.0.189"
  IP.2 = "132.232.229.60"
  IP.3 = "118.24.165.225"
  IP.4 = "129.28.108.238"

然后:openssl req -new -newkey rsa:2048 -sha1 -days 3650 -nodes -x509 -keyout server.key -out server.crt -config ssl.cnf

一个指令同时产生需要的server.crt,server.key。

除aubjectAltName外还要关注CN这个字段,它就是我们经常会遇到系统提问:你确定信任“域名”吗?中这个域名,也就是对外界开放的一个使用了数字证书的域名。

把crt,key抄写到main/resources目录下,然后在gRPC服务器配置证书:

trait gRPCServer {
  
  val serverCrtFile = new File(getClass.getClassLoader.getResource("server.crt").getPath)
  val serverKeyFile = new File(getClass.getClassLoader.getResource("server.key").getPath)

  def runServer(service: ServerServiceDefinition): Unit = {
    val server = NettyServerBuilder
      .forPort(50051)
      .addService(service)
      .useTransportSecurity(serverCrtFile,serverKeyFile)
      .build
      .start
    // make sure our server is stopped when jvm is shut down
    Runtime.getRuntime.addShutdownHook(new Thread() {
      override def run(): Unit = {
        server.shutdown()
        server.awaitTermination()
      }
    })
  }

}

启动gRPC服务,运作正常。在看看客户端代码:

    val clientCrtFile = new File(getClass.getClassLoader.getResource("server.crt").getPath)
 //或者   val clientCrtFile = new File(getClass.getClassLoader.getResource("rootCA.pem").getPath)

//这样也行 val clientCrtFile: InputStream = getClass.getClassLoader.getResourceAsStream("rootCA.pem")

    val sslContextBuilder = GrpcSslContexts.forClient().trustManager(clientCrtFile)

    //build connection channel
    val channel = NettyChannelBuilder
      .forAddress("192.168.11.189",50051)
      .negotiationType(NegotiationType.TLS)
      .sslContext(sslContextBuilder.build())
//      .overrideAuthority("192.168.1.3")
      .build()

测试连接,gRPC SSL/TLS成功!

现在开始了解一下https证书的配置使用方法吧。看了一下akka-http关于server端HTTPS设置的例子,证书是嵌在HttpsConnectionContext类型里面的。还有就是akka-http使用的https证书格式只支持pkcs12,所以需要把上面用openssl产生的自签名证书server.crt转成server.p12。这个转换又需要先产生证书链certificate-chain chain.pem:

1)产生certificate-chain:  cat server.crt rootCA.crt > chain.pem

2) server.crt转换成server.p12: openssl pkcs12 -export -name servercrt -in chain.pem -inkey server.key -out server.p12

https server 测试代码:

//#imports
import java.io.InputStream
import java.security.{ SecureRandom, KeyStore }
import javax.net.ssl.{ SSLContext, TrustManagerFactory, KeyManagerFactory }

import akka.actor.ActorSystem
import akka.http.scaladsl.server.{ Route, Directives }
import akka.http.scaladsl.{ ConnectionContext, HttpsConnectionContext, Http }
import akka.stream.ActorMaterializer
import akka.http.scaladsl.Http
import akka.http.scaladsl.server.Directives._

//#imports


object HttpsDemo extends App {

  implicit val httpSys = ActorSystem("httpSystem")
  implicit val httpMat = ActorMaterializer()
  implicit val httpEC = httpSys.dispatcher
  

    val password: Array[Char] = "123456".toCharArray // do not store passwords in code, read them from somewhere safe!

    val ks: KeyStore = KeyStore.getInstance("PKCS12")
    val keystore: InputStream = getClass.getClassLoader.getResourceAsStream("server.p12")
    ks.load(keystore, password)

    val keyManagerFactory: KeyManagerFactory = KeyManagerFactory.getInstance("SunX509")
    keyManagerFactory.init(ks, password)

    val tmf: TrustManagerFactory = TrustManagerFactory.getInstance("SunX509")
    tmf.init(ks)

    val sslContext: SSLContext = SSLContext.getInstance("TLS")
    sslContext.init(keyManagerFactory.getKeyManagers, tmf.getTrustManagers, new SecureRandom)
    val https: HttpsConnectionContext = ConnectionContext.https(sslContext)


  val route = get { complete("Hello world!") }

  val (port, host) = (50081,"192.168.11.189")

  val bindingFuture = Http().bindAndHandle(route,host,port,connectionContext = https)

  println(s"Https Server running at $host $port. Press any key to exit ...")

  scala.io.StdIn.readLine()


  bindingFuture.flatMap(_.unbind())
    .onComplete(_ => httpSys.terminate())

}

用safari连接https://192.168.11.189:50081/, 弹出窗口一堆废话后还是成功连接上了。

 

Guess you like

Origin www.cnblogs.com/tiger-xc/p/11075240.html