Merge pull request #12429 from tangcong/fix-cert-exp

*: add self-signed-cert-validity flag to fix cert expire issue
This commit is contained in:
Gyuho Lee 2020-10-30 11:41:23 -07:00 committed by GitHub
commit 170af891d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 41 additions and 11 deletions

View File

@ -142,7 +142,8 @@ Note that any `etcd_debugging_*` metrics are experimental and subject to change.
- Fix [server panic in slow writes warnings](https://github.com/etcd-io/etcd/issues/12197).
- Fixed via [PR#12238](https://github.com/etcd-io/etcd/pull/12238).
- [Fix server panic](https://github.com/etcd-io/etcd/pull/12288) when force-new-cluster flag is enabled in a cluster which had learner node.
- Add [`--self-signed-cert-validity`](https://github.com/etcd-io/etcd/pull/12429) flag to support setting certificate expiration time.
- Notice, certificates generated by etcd are valid for 1 year by default when specifying the auto-tls or peer-auto-tls option.
### Package `runtime`

View File

@ -196,8 +196,9 @@ The etcd members will form a cluster and all communication between members in th
## Example 4: Automatic self-signed transport security
For cases where communication encryption, but not authentication, is needed, etcd supports encrypting its messages with automatically generated self-signed certificates. This simplifies deployment because there is no need for managing certificates and keys outside of etcd.
**NOTE:** When you specify ClientAutoTLS and PeerAutoTLS, the validity period of the client certificate and peer certificate automatically generated by etcd is only 1 year. You can specify the --self-signed-cert-validity flag to set the validity period of the certificate in years.
For cases where communication encryption, but not authentication, is needed, etcd supports encrypting its messages with automatically generated self-signed certificates. This simplifies deployment because there is no need for managing certificates and keys outside of etcd.
Configure etcd to use self-signed certificates for client and peer connections with the flags `--auto-tls` and `--peer-auto-tls`:
```sh

View File

@ -114,8 +114,16 @@ func (info TLSInfo) Empty() bool {
return info.CertFile == "" && info.KeyFile == ""
}
func SelfCert(lg *zap.Logger, dirpath string, hosts []string, additionalUsages ...x509.ExtKeyUsage) (info TLSInfo, err error) {
func SelfCert(lg *zap.Logger, dirpath string, hosts []string, selfSignedCertValidity uint, additionalUsages ...x509.ExtKeyUsage) (info TLSInfo, err error) {
info.Logger = lg
if selfSignedCertValidity == 0 {
err = fmt.Errorf("selfSignedCertValidity is invalid,it should be greater than 0")
info.Logger.Warn(
"cannot generate cert",
zap.Error(err),
)
return
}
err = fileutil.TouchDirAll(dirpath)
if err != nil {
if info.Logger != nil {
@ -154,13 +162,20 @@ func SelfCert(lg *zap.Logger, dirpath string, hosts []string, additionalUsages .
SerialNumber: serialNumber,
Subject: pkix.Name{Organization: []string{"etcd"}},
NotBefore: time.Now(),
NotAfter: time.Now().Add(365 * (24 * time.Hour)),
NotAfter: time.Now().Add(time.Duration(selfSignedCertValidity) * 365 * (24 * time.Hour)),
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: append([]x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, additionalUsages...),
BasicConstraintsValid: true,
}
if info.Logger != nil {
info.Logger.Warn(
"automatically generate certificates",
zap.Time("certificate-validity-bound-not-after", tmpl.NotAfter),
)
}
for _, host := range hosts {
h, _, _ := net.SplitHostPort(host)
if ip := net.ParseIP(h); ip != nil {
@ -227,7 +242,7 @@ func SelfCert(lg *zap.Logger, dirpath string, hosts []string, additionalUsages .
if info.Logger != nil {
info.Logger.Info("created key file", zap.String("path", keyPath))
}
return SelfCert(lg, dirpath, hosts)
return SelfCert(lg, dirpath, hosts, selfSignedCertValidity)
}
// baseConfig is called on initial TLS handshake start.

View File

@ -37,7 +37,7 @@ func createSelfCertEx(host string, additionalUsages ...x509.ExtKeyUsage) (*TLSIn
if terr != nil {
return nil, nil, terr
}
info, err := SelfCert(zap.NewExample(), d, []string{host + ":0"}, additionalUsages...)
info, err := SelfCert(zap.NewExample(), d, []string{host + ":0"}, 1, additionalUsages...)
if err != nil {
return nil, nil, err
}
@ -366,7 +366,7 @@ func TestNewListenerTLSInfoSelfCert(t *testing.T) {
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)
tlsinfo, err := SelfCert(zap.NewExample(), tmpdir, []string{"127.0.0.1"})
tlsinfo, err := SelfCert(zap.NewExample(), tmpdir, []string{"127.0.0.1"}, 1)
if err != nil {
t.Fatal(err)
}

View File

@ -184,6 +184,10 @@ type Config struct {
ClientAutoTLS bool
PeerTLSInfo transport.TLSInfo
PeerAutoTLS bool
// SelfSignedCertValidity specifies the validity period of the client and peer certificates
// that are automatically generated by etcd when you specify ClientAutoTLS and PeerAutoTLS,
// the unit is year, and the default is 1
SelfSignedCertValidity uint
// CipherSuites is a list of supported TLS cipher suites between
// client/server and peers. If empty, Go auto-populates the list.
@ -731,7 +735,7 @@ func (cfg *Config) ClientSelfCert() (err error) {
for i, u := range cfg.LCUrls {
chosts[i] = u.Host
}
cfg.ClientTLSInfo, err = transport.SelfCert(cfg.logger, filepath.Join(cfg.Dir, "fixtures", "client"), chosts)
cfg.ClientTLSInfo, err = transport.SelfCert(cfg.logger, filepath.Join(cfg.Dir, "fixtures", "client"), chosts, cfg.SelfSignedCertValidity)
if err != nil {
return err
}
@ -750,7 +754,7 @@ func (cfg *Config) PeerSelfCert() (err error) {
for i, u := range cfg.LPUrls {
phosts[i] = u.Host
}
cfg.PeerTLSInfo, err = transport.SelfCert(cfg.logger, filepath.Join(cfg.Dir, "fixtures", "peer"), phosts)
cfg.PeerTLSInfo, err = transport.SelfCert(cfg.logger, filepath.Join(cfg.Dir, "fixtures", "peer"), phosts, cfg.SelfSignedCertValidity)
if err != nil {
return err
}

View File

@ -207,6 +207,7 @@ func newConfig() *config {
fs.BoolVar(&cfg.ec.PeerTLSInfo.ClientCertAuth, "peer-client-cert-auth", false, "Enable peer client cert authentication.")
fs.StringVar(&cfg.ec.PeerTLSInfo.TrustedCAFile, "peer-trusted-ca-file", "", "Path to the peer server TLS trusted CA file.")
fs.BoolVar(&cfg.ec.PeerAutoTLS, "peer-auto-tls", false, "Peer TLS using generated certificates")
fs.UintVar(&cfg.ec.SelfSignedCertValidity, "self-signed-cert-validity", 1, "The validity period of the client and peer certificates, unit is year")
fs.StringVar(&cfg.ec.PeerTLSInfo.CRLFile, "peer-crl-file", "", "Path to the peer certificate revocation list file.")
fs.StringVar(&cfg.ec.PeerTLSInfo.AllowedCN, "peer-cert-allowed-cn", "", "Allowed CN for inter peer authentication.")
fs.StringVar(&cfg.ec.PeerTLSInfo.AllowedHostname, "peer-cert-allowed-hostname", "", "Allowed TLS hostname for inter peer authentication.")

View File

@ -393,7 +393,7 @@ func startProxy(cfg *config) error {
}
listenerTLS := cfg.ec.ClientTLSInfo
if cfg.ec.ClientAutoTLS && cTLS {
listenerTLS, err = transport.SelfCert(cfg.ec.GetLogger(), filepath.Join(cfg.ec.Dir, "clientCerts"), cHosts)
listenerTLS, err = transport.SelfCert(cfg.ec.GetLogger(), filepath.Join(cfg.ec.Dir, "clientCerts"), cHosts, cfg.ec.SelfSignedCertValidity)
if err != nil {
lg.Fatal("failed to initialize self-signed client cert", zap.Error(err))
}

View File

@ -76,6 +76,7 @@ var (
grpcProxyListenKey string
grpcProxyListenAutoTLS bool
grpcProxyListenCRL string
selfSignedCertValidity uint
grpcProxyAdvertiseClientURL string
grpcProxyResolverPrefix string
@ -149,6 +150,7 @@ func newGRPCProxyStartCommand() *cobra.Command {
cmd.Flags().StringVar(&grpcProxyListenCA, "trusted-ca-file", "", "verify certificates of TLS-enabled secure proxy using this CA bundle")
cmd.Flags().BoolVar(&grpcProxyListenAutoTLS, "auto-tls", false, "proxy TLS using generated certificates")
cmd.Flags().StringVar(&grpcProxyListenCRL, "client-crl-file", "", "proxy client certificate revocation list file.")
cmd.Flags().UintVar(&selfSignedCertValidity, "self-signed-cert-validity", 1, "The validity period of the proxy certificates, unit is year")
// experimental flags
cmd.Flags().BoolVar(&grpcProxyEnableOrdering, "experimental-serializable-ordering", false, "Ensure serializable reads have monotonically increasing store revisions across endpoints.")
@ -189,7 +191,7 @@ func startGRPCProxy(cmd *cobra.Command, args []string) {
if tlsinfo == nil && grpcProxyListenAutoTLS {
host := []string{"https://" + grpcProxyListenAddr}
dir := filepath.Join(grpcProxyDataDir, "fixtures", "proxy")
autoTLS, err := transport.SelfCert(lg, dir, host)
autoTLS, err := transport.SelfCert(lg, dir, host, selfSignedCertValidity)
if err != nil {
log.Fatal(err)
}
@ -254,6 +256,10 @@ func checkArgs() {
fmt.Fprintln(os.Stderr, fmt.Errorf("invalid advertise-client-url %q", grpcProxyAdvertiseClientURL))
os.Exit(1)
}
if grpcProxyListenAutoTLS && selfSignedCertValidity == 0 {
fmt.Fprintln(os.Stderr, fmt.Errorf("selfSignedCertValidity is invalid,it should be greater than 0"))
os.Exit(1)
}
}
func mustNewClient(lg *zap.Logger) *clientv3.Client {

View File

@ -150,6 +150,8 @@ Security:
Allowed TLS hostname for inter peer authentication.
--peer-auto-tls 'false'
Peer TLS using self-generated certificates if --peer-key-file and --peer-cert-file are not provided.
--self-signed-cert-validity '1'
The validity period of the client and peer certificates that are automatically generated by etcd when you specify ClientAutoTLS and PeerAutoTLS, the unit is year, and the default is 1.
--peer-crl-file ''
Path to the peer certificate revocation list file.
--cipher-suites ''