Golang TLS Server、Kube-Apiserver 校驗客戶端證書原理

當我們用Golang寫一個TLS Server的時候,假設給Server端配置了CA證書,那麼Server端一定會校驗客戶端的證書嗎?答案是,即使我們給Server端配置了CA證書,Server端也不一定會校驗客戶端的證書

看一個TLS Server端的例子:

package main

import (
    "log"
    "crypto/tls"
    "net"
    "fmt"
    "crypto/x509"
    "bufio"
    "io/ioutil"
)

func main() {
    log.SetFlags(log.Lshortfile)

    cer, err := tls.LoadX509KeyPair("server.crt", "server.key")
    if err != nil {
        log.Println(err)
        return
    }

    ca, err := ioutil.ReadFile("client-CA.crt")
    
    pool := x509.NewCertPool()
    ok := pool.AppendCertsFromPEM(ca)
	if !ok {
		panic(fmt.Errorf("fail to load ca content"))
	}    

    
    tlsConfig := &tls.Config{
        ClientCAs:    pool,
        ClientAuth:  tls.RequireAnyClientCert,
        Certificates: []tls.Certificate{cer},
    }

    ln, err := tls.Listen("tcp", ":443", tlsConfig) 
    if err != nil {
        log.Println(err)
        return
    }
    defer ln.Close()

    for {
        conn, err := ln.Accept()
        if err != nil {
            log.Println(err)
            continue
        }
        go handleConnection(conn)
    }
}

func handleConnection(conn net.Conn) {
    defer conn.Close()
    r := bufio.NewReader(conn)
    for {
        msg, err := r.ReadString('\n')
        if err != nil {
            log.Println(err)
            return
        }

        println(msg)

        n, err := conn.Write([]byte("world\n"))
        if err != nil {
            log.Println(n, err)
            return
        }
    }
}

 

我們在tlsConfig中可以看到,配置了驗證客戶端正的CA ClientCAs,還有服務端的證書Certificates。除此之外還有一個很重要的字段——ClientAuth,在Golang中,ClientAuth決定了Server端如何驗證客戶端的證書。

// ClientAuthType declares the policy the server will follow for
// TLS Client Authentication.
type ClientAuthType int

const (
	NoClientCert ClientAuthType = iota
	RequestClientCert
	RequireAnyClientCert
	VerifyClientCertIfGiven
	RequireAndVerifyClientCert
)

 

ClientAuth有五種類型,分別是 NoClientCert、RequestClientCert、RequireAnyClientCert、VerifyClientCertIfGiven、RequireAndVerifyClientCert,各自的含義是:

 

  • NoClientCert:忽略任何客戶端證書,即客戶端可以不提供證書。
  • RequestClientCert:要求客戶端提供證書,但是如果客戶端沒有提供證書,服務端還是會繼續處理請求。
  • RequireAnyClientCert:需要客戶端提供證書,但不用ClientCA來驗證證書的有效性。
  • VerifyClientCertIfGiven:如果客戶端提供了證書,則用ClientCA來驗證證書的有效性。 如果客戶端沒提供,則會繼續處理請求。
  • RequireAndVerifyClientCert:需要客戶端提供證書,且會用ClientCA來驗證證書的有效性。

 

在tlsConfig中如果不顯式的指定ClientAuth,則默認值是NoClientCert。即使Server端配置了CA,也不會校驗客戶端證書。

 

在K8s中我們知道Kube-Apiserver是有多種認證方式的,包括賬號密碼、Token、證書等。其實它的ClientAuth設置的就是RequestClientCert。即在Tls這層是不強校驗客戶端證書的。這樣才能保證Tls能接受多種來自客戶端的憑據。

if s.ClientCA != nil {
		// Populate PeerCertificates in requests, but don't reject connections without certificates
		// This allows certificates to be validated by authenticators, while still allowing other auth types
		tlsConfig.ClientAuth = tls.RequestClientCert
	}

 

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