内容纲要
certchain.go的源码学习
credentials 结构体持有证书相关的各种 path
Dapr credentials package中的 certchain.go 文件的源码学习,credentials 结构体持有证书相关的各种 path。
CertChain 结构体定义
CertChain 结构体持有证书信任链的PEM值:
// CertChain holds the certificate trust chain PEM values
type CertChain struct {
RootCA []byte
Cert []byte
Key []byte
}
装载证书的LoadFromDisk 方法
LoadFromDisk 方法从给定目录中读取 CertChain:
// LoadFromDisk retruns a CertChain from a given directory
func LoadFromDisk(rootCertPath, issuerCertPath, issuerKeyPath string) (*CertChain, error) {
rootCert, err := ioutil.ReadFile(rootCertPath)
if err != nil {
return nil, err
}
cert, err := ioutil.ReadFile(issuerCertPath)
if err != nil {
return nil, err
}
key, err := ioutil.ReadFile(issuerKeyPath)
if err != nil {
return nil, err
}
return &CertChain{
RootCA: rootCert,
Cert: cert,
Key: key,
}, nil
}
使用场景
placement 的 main.go 中,如果 mTLS 开启了,则会读取 tls 证书:
func loadCertChains(certChainPath string) *credentials.CertChain {
tlsCreds := credentials.NewTLSCredentials(certChainPath)
log.Info("mTLS enabled, getting tls certificates")
// try to load certs from disk, if not yet there, start a watch on the local filesystem
chain, err := credentials.LoadFromDisk(tlsCreds.RootCertPath(), tlsCreds.CertPath(), tlsCreds.KeyPath())
......
}
operator 的 operator.go 中,也会判断,如果 MTLSEnabled :
var certChain *credentials.CertChain
if o.config.MTLSEnabled {
log.Info("mTLS enabled, getting tls certificates")
// try to load certs from disk, if not yet there, start a watch on the local filesystem
chain, err := credentials.LoadFromDisk(o.config.Credentials.RootCertPath(), o.config.Credentials.CertPath(), o.config.Credentials.KeyPath())
......
}
备注:上面两段代码重复度极高,最好能重构一下。
sentry 中也有调用:
func (c *defaultCA) validateAndBuildTrustBundle() (*trustRootBundle, error) {
var (
issuerCreds *certs.Credentials
rootCertBytes []byte
issuerCertBytes []byte
)
// certs exist on disk or getting created, load them when ready
if !shouldCreateCerts(c.config) {
err := detectCertificates(c.config.RootCertPath)
if err != nil {
return nil, err
}
certChain, err := credentials.LoadFromDisk(c.config.RootCertPath, c.config.IssuerCertPath, c.config.IssuerKeyPath)
if err != nil {
return nil, errors.Wrap(err, "error loading cert chain from disk")
}
TODO: 证书相关的细节后面单独细看。
credentials.go的源码学习
credentials 结构体持有证书相关的各种 path
Dapr credentials package中的 credentials.go文件的源码学习,credentials 结构体持有证书相关的各种 path。
TLSCredentials 结构体定义
只有一个字段 credentialsPath:
// TLSCredentials holds paths for credentials
type TLSCredentials struct {
credentialsPath string
}
构造方法很简单:
// NewTLSCredentials returns a new TLSCredentials
func NewTLSCredentials(path string) TLSCredentials {
return TLSCredentials{
credentialsPath: path,
}
}
获取相关 path 的方法
获取 credentialsPath,这个path中保存有 TLS 证书:
// Path returns the directory holding the TLS credentials
func (t *TLSCredentials) Path() string {
return t.credentialsPath
}
分别获取 root cert / cert / cert key 的 path:
// RootCertPath returns the file path for the root cert
func (t *TLSCredentials) RootCertPath() string {
return filepath.Join(t.credentialsPath, RootCertFilename)
}
// CertPath returns the file path for the cert
func (t *TLSCredentials) CertPath() string {
return filepath.Join(t.credentialsPath, IssuerCertFilename)
}
// KeyPath returns the file path for the cert key
func (t *TLSCredentials) KeyPath() string {
return filepath.Join(t.credentialsPath, IssuerKeyFilename)
}
tls.go的源码学习
从 cert/key 中装载 tls.config 对象
Dapr credentials package中的 tls.go文件的源码学习,从 cert/key 中装载 tls.config 对象。
TLSConfigFromCertAndKey() 方法
TLSConfigFromCertAndKey() 方法从 PEM 格式中有效的 cert/key 对中返回 tls.config 对象:
// TLSConfigFromCertAndKey return a tls.config object from valid cert/key pair in PEM format.
func TLSConfigFromCertAndKey(certPem, keyPem []byte, serverName string, rootCA *x509.CertPool) (*tls.Config, error) {
cert, err := tls.X509KeyPair(certPem, keyPem)
if err != nil {
return nil, err
}
// nolint:gosec
config := &tls.Config{
InsecureSkipVerify: false,
RootCAs: rootCA,
ServerName: serverName,
Certificates: []tls.Certificate{cert},
}
return config, nil
}
grpc.go的源码学习
获取服务器端选项和客户端选项
Dapr credentials package中的 grpc.go文件的源码学习,获取服务器端选项和客户端选项。
GetServerOptions() 方法
func GetServerOptions(certChain *CertChain) ([]grpc.ServerOption, error) {
opts := []grpc.ServerOption{}
if certChain == nil {
return opts, nil
}
cp := x509.NewCertPool()
cp.AppendCertsFromPEM(certChain.RootCA)
cert, err := tls.X509KeyPair(certChain.Cert, certChain.Key)
if err != nil {
return opts, nil
}
// nolint:gosec
config := &tls.Config{
ClientCAs: cp,
// Require cert verification
ClientAuth: tls.RequireAndVerifyClientCert,
Certificates: []tls.Certificate{cert},
}
opts = append(opts, grpc.Creds(credentials.NewTLS(config)))
return opts, nil
}
GetClientOptions() 方法
func GetClientOptions(certChain *CertChain, serverName string) ([]grpc.DialOption, error) {
opts := []grpc.DialOption{}
if certChain != nil {
cp := x509.NewCertPool()
ok := cp.AppendCertsFromPEM(certChain.RootCA)
if !ok {
return nil, errors.New("failed to append PEM root cert to x509 CertPool")
}
config, err := TLSConfigFromCertAndKey(certChain.Cert, certChain.Key, serverName, cp)
if err != nil {
return nil, errors.Wrap(err, "failed to create tls config from cert and key")
}
opts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(config)))
} else {
opts = append(opts, grpc.WithInsecure())
}
return opts, nil
}
TODO: 好吧,细节后面看,加密我不熟。