talos/internal/pkg/etcd/certs.go
Andrey Smirnov 626ef05e60
fix: correct SANs for etcd certs
I would like to rewrite whole cert generation process, but for now a few
fixes:

* client cert doesn't need any SANs
* peer cert should contain only non-localhost SANs
* server cert same as before (localhost + addresses)

See https://etcd.io/docs/v3.5/op-guide/security/ for details.

Signed-off-by: Andrey Smirnov <andrey.smirnov@talos-systems.com>
2022-07-11 14:51:27 +04:00

150 lines
3.8 KiB
Go

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package etcd
import (
stdlibx509 "crypto/x509"
"fmt"
stdlibnet "net"
"os"
"time"
"github.com/talos-systems/crypto/x509"
"github.com/talos-systems/net"
"github.com/talos-systems/talos/pkg/machinery/resources/network"
)
// buildOptions set common certificate options.
func buildOptions(autoSANs, includeLocalhost bool) ([]x509.Option, error) {
ips, err := net.IPAddrs()
if err != nil {
return nil, fmt.Errorf("failed to discover IP addresses: %w", err)
}
ips = net.IPFilter(ips, network.NotSideroLinkStdIP)
if includeLocalhost {
ips = append(ips, stdlibnet.ParseIP("127.0.0.1"))
if net.IsIPv6(ips...) {
ips = append(ips, stdlibnet.ParseIP("::1"))
}
}
hostname, err := os.Hostname()
if err != nil {
return nil, fmt.Errorf("failed to get hostname: %w", err)
}
dnsNames, err := net.DNSNames()
if err != nil {
return nil, fmt.Errorf("failed to get host DNS names: %w", err)
}
if includeLocalhost {
dnsNames = append(dnsNames, "localhost")
}
result := []x509.Option{
x509.NotAfter(time.Now().Add(87600 * time.Hour)),
x509.KeyUsage(stdlibx509.KeyUsageDigitalSignature | stdlibx509.KeyUsageKeyEncipherment),
}
if autoSANs {
result = append(result,
x509.CommonName(hostname),
x509.DNSNames(dnsNames),
x509.IPAddresses(ips),
)
}
return result, nil
}
// GeneratePeerCert generates etcd peer certificate and key from etcd CA.
//
//nolint:dupl
func GeneratePeerCert(etcdCA *x509.PEMEncodedCertificateAndKey) (*x509.PEMEncodedCertificateAndKey, error) {
opts, err := buildOptions(true, false)
if err != nil {
return nil, err
}
opts = append(opts,
x509.ExtKeyUsage([]stdlibx509.ExtKeyUsage{
stdlibx509.ExtKeyUsageServerAuth,
stdlibx509.ExtKeyUsageClientAuth,
}),
)
ca, err := x509.NewCertificateAuthorityFromCertificateAndKey(etcdCA)
if err != nil {
return nil, fmt.Errorf("failed loading CA from config: %w", err)
}
keyPair, err := x509.NewKeyPair(ca, opts...)
if err != nil {
return nil, fmt.Errorf("failed generating peer key pair: %w", err)
}
return x509.NewCertificateAndKeyFromKeyPair(keyPair), nil
}
// GenerateServerCert generates server etcd certificate and key from etcd CA.
//
//nolint:dupl
func GenerateServerCert(etcdCA *x509.PEMEncodedCertificateAndKey) (*x509.PEMEncodedCertificateAndKey, error) {
opts, err := buildOptions(true, true)
if err != nil {
return nil, err
}
opts = append(opts,
x509.ExtKeyUsage([]stdlibx509.ExtKeyUsage{
stdlibx509.ExtKeyUsageServerAuth,
stdlibx509.ExtKeyUsageClientAuth,
}),
)
ca, err := x509.NewCertificateAuthorityFromCertificateAndKey(etcdCA)
if err != nil {
return nil, fmt.Errorf("failed loading CA from config: %w", err)
}
keyPair, err := x509.NewKeyPair(ca, opts...)
if err != nil {
return nil, fmt.Errorf("failed generating client key pair: %w", err)
}
return x509.NewCertificateAndKeyFromKeyPair(keyPair), nil
}
// GenerateClientCert generates client certificate and key from etcd CA.
func GenerateClientCert(etcdCA *x509.PEMEncodedCertificateAndKey, commonName string) (*x509.PEMEncodedCertificateAndKey, error) {
opts, err := buildOptions(false, false)
if err != nil {
return nil, err
}
opts = append(opts, x509.CommonName(commonName))
opts = append(opts,
x509.ExtKeyUsage([]stdlibx509.ExtKeyUsage{
stdlibx509.ExtKeyUsageClientAuth,
}),
)
ca, err := x509.NewCertificateAuthorityFromCertificateAndKey(etcdCA)
if err != nil {
return nil, fmt.Errorf("failed loading CA from config: %w", err)
}
keyPair, err := x509.NewKeyPair(ca, opts...)
if err != nil {
return nil, fmt.Errorf("failed generating client key pair: %w", err)
}
return x509.NewCertificateAndKeyFromKeyPair(keyPair), nil
}