go-go-micro安全tls


title: go-go-micro安全tls
categories: Go
tags: [go, 微服務, tls, 安全]
date: 2019-10-11 17:42:57
comments: false

go-go-micro安全tls


前篇

a


內置的 tls 證書

是用 micro 默認的 tls 非常簡單, 只需要 transport.Secure(true) 即可

func main() {
	service := micro.NewService(
		...
		micro.Transport(
			transport.NewTransport(
				transport.Secure(true),
			),
		),
	)
}

自定義 tls 證書

參考: https://studygolang.com/articles/15331

生成 CA 根證書

爲了保證證書的可靠性和有效性,在這裏可引入 CA 頒發的根證書的概念。其遵守 X.509 標準

根證書(root certificate)是屬於根證書頒發機構(CA)的公鑰證書。我們可以通過驗證 CA 的簽名從而信任 CA ,任何人都可以得到 CA 的證書(含公鑰),用以驗證它所簽發的證書(客戶端、服務端)

  1. 生成 Key: ca.key

    $ openssl genrsa -out ca.key 2048
    
  2. 生成密鑰: ca.pem

    $ openssl req -new -x509 -days 7200 -key ca.key -out ca.pem
    
    Country Name (2 letter code) [AU]:aa // // 填一堆信息
    State or Province Name (full name) [Some-State]:bb
    Locality Name (eg, city) []:cc
    Organization Name (eg, company) [Internet Widgits Pty Ltd]:dd
    Organizational Unit Name (eg, section) []:ee
    Common Name (e.g. server FQDN or YOUR name) []:ff
    Email Address []:gg
    

生成 Server 證書

  1. 生成 Key: server.key

    $ openssl ecparam -genkey -name secp384r1 -out server.key
    
  2. 生成 CSR: server.csr

    $ openssl req -new -key server.key -out server.csr
    
    Country Name (2 letter code) [AU]:aa // 填一堆信息
    State or Province Name (full name) [Some-State]:bb
    Locality Name (eg, city) []:cc
    Organization Name (eg, company) [Internet Widgits Pty Ltd]:dd
    Organizational Unit Name (eg, section) []:ee
    Common Name (e.g. server FQDN or YOUR name) []:ff
    Email Address []:gg
    
    Please enter the following 'extra' attributes
    to be sent with your certificate request
    A challenge password []:helloworld
    An optional company name []:aa
    
  3. 生成 ip 白名單文件: extfile.cnf

    $ echo subjectAltName = IP:192.168.1.190 > extfile.cnf
    
    • extfile.cnf 文件內容

      subjectAltName = IP:192.168.1.190
      

      如果有多個 ip,用 , 分割

      subjectAltName = IP:192.168.1.191,IP:192.168.1.190,IP:192.168.1.192
      
  4. 基於 CA 簽發: server.pem

    $ openssl x509 -req -sha256 -CA ca.pem -CAkey ca.key -CAcreateserial -days 3650 -in server.csr -out server.pem -extfile extfile.cnf
    
    Signature ok
    subject=C = aa, ST = bb, L = cc, O = dd, OU = ee, CN = ff, emailAddress = gg
    Getting CA Private Key
    
    • 如果少了訪問的 ip 白名單文件 ( -extfile extfile.cnf ) , 客戶端請求報錯: doesn't contain any IP SANs

最後生成一堆東西

├─conf
│      ca.key
│      ca.pem
│      ca.srl
│      extfile.cnf
│      server.csr
│      server.key
│      server.pem

代碼

參考: test_secure_tls

客戶端 和 服務器 都是用相同的證書即可 server.pem, server.key

server
func loadTlsConfig() *tls.Config {
	cert, err := tls.LoadX509KeyPair("../conf/server.pem", "../conf/server.key")
	if err != nil {
		log.Fatalf("tls.LoadX509KeyPair err: %v", err)
	}

	certPool := x509.NewCertPool()
	ca, err := ioutil.ReadFile("../conf/ca.pem")
	if err != nil {
		log.Fatalf("ioutil.ReadFile err: %v", err)
	}

	if ok := certPool.AppendCertsFromPEM(ca); !ok {
		log.Fatalf("certPool.AppendCertsFromPEM err")
	}

	tlsCfg := &tls.Config{
		Certificates:       []tls.Certificate{cert},
		ClientAuth:         tls.RequireAndVerifyClientCert,
		ClientCAs:          certPool,
		InsecureSkipVerify: false,
	}
	return tlsCfg
}

func main() {
	service := micro.NewService(
		...
		micro.Transport(
			transport.NewTransport(
				transport.TLSConfig(loadTlsConfig()),
			),
		),
	)

}

client
func loadTlsConfig() *tls.Config {
	cert, err := tls.LoadX509KeyPair("../conf/server.pem", "../conf/server.key")
	if err != nil {
		log.Fatalf("tls.LoadX509KeyPair err: %v", err)
	}

	certPool := x509.NewCertPool()
	ca, err := ioutil.ReadFile("../conf/ca.pem")
	if err != nil {
		log.Fatalf("ioutil.ReadFile err: %v", err)
	}

	if ok := certPool.AppendCertsFromPEM(ca); !ok {
		log.Fatalf("certPool.AppendCertsFromPEM err")
	}

	tlsCfg := &tls.Config{
		Certificates:       []tls.Certificate{cert},
		RootCAs:            certPool,
		InsecureSkipVerify: false,
	}
	return tlsCfg
}

func init() {
	client.DefaultClient.Init(
		client.Transport(
			transport.NewTransport(
				transport.TLSConfig(loadTlsConfig()),
			),
		),
	)
}

func main() {
	cl := hello.NewSayService("go.micro.srv.greeter", client.DefaultClient)

	rsp, err := cl.Hello(context.TODO(), &hello.Request{
		Name: "John",
	})
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println("--- recv srv, msg:", rsp.Msg)
}

踩坑

  • 客戶端請求報錯: doesn't contain any IP SANs

    參考: https://codeday.me/bug/20190105/485233.html

    是因爲 [生成 Server 證書](#生成 Server 證書) 中的 第4步 中沒有指定可訪問的 ip 白名單文件. ( -extfile extfile.cnf )

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章