当我们用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
}

本文深入探讨了使用Golang实现TLS Server时,如何通过不同的ClientAuth策略来控制是否及如何验证客户端证书,揭示了即使配置了CA证书,Server端也不一定会校验客户端证书的细节。

4993

被折叠的 条评论
为什么被折叠?



