diff --git a/nodeup/pkg/model/protokube.go b/nodeup/pkg/model/protokube.go index c198bcdc3ea05..4f60a3866bb5c 100644 --- a/nodeup/pkg/model/protokube.go +++ b/nodeup/pkg/model/protokube.go @@ -69,12 +69,12 @@ func (t *ProtokubeBuilder) Build(c *fi.ModelBuilderContext) error { // retrieve the etcd peer certificates and private keys from the keystore if t.UseEtcdTLS() { - for _, x := range []string{"etcd", "etcd-client"} { + for _, x := range []string{"etcd", "etcd-peer", "etcd-client"} { if err := t.BuildCertificateTask(c, x, fmt.Sprintf("%s.pem", x)); err != nil { return err } } - for _, x := range []string{"etcd", "etcd-client"} { + for _, x := range []string{"etcd", "etcd-peer", "etcd-client"} { if err := t.BuildPrivateKeyTask(c, x, fmt.Sprintf("%s-key.pem", x)); err != nil { return err } @@ -290,8 +290,8 @@ func (t *ProtokubeBuilder) ProtokubeFlags(k8sVersion semver.Version) (*Protokube // check if we are using tls and add the options to protokube if t.UseEtcdTLS() { f.PeerTLSCaFile = s(filepath.Join(t.PathSrvKubernetes(), "ca.crt")) - f.PeerTLSCertFile = s(filepath.Join(t.PathSrvKubernetes(), "etcd.pem")) - f.PeerTLSKeyFile = s(filepath.Join(t.PathSrvKubernetes(), "etcd-key.pem")) + f.PeerTLSCertFile = s(filepath.Join(t.PathSrvKubernetes(), "etcd-peer.pem")) + f.PeerTLSKeyFile = s(filepath.Join(t.PathSrvKubernetes(), "etcd-peer-key.pem")) f.TLSCAFile = s(filepath.Join(t.PathSrvKubernetes(), "ca.crt")) f.TLSCertFile = s(filepath.Join(t.PathSrvKubernetes(), "etcd.pem")) f.TLSKeyFile = s(filepath.Join(t.PathSrvKubernetes(), "etcd-key.pem")) diff --git a/pkg/model/pki.go b/pkg/model/pki.go index eb5c86e0d5900..2c0eec9bb3a6b 100644 --- a/pkg/model/pki.go +++ b/pkg/model/pki.go @@ -121,18 +121,48 @@ func (b *PKIModelBuilder) Build(c *fi.ModelBuilderContext) error { // that mutual tls used to verify between the peers we don't want certificates for kubernetes able to act as a peer. // For clients assuming we are using etcdv3 is can switch on user authentication and map the common names for auth. if b.UseEtcdTLS() { - alternativeNames := []string{fmt.Sprintf("*.internal.%s", b.ClusterName()), "localhost", "127.0.0.1"} + servingNames := []string{fmt.Sprintf("*.internal.%s", b.ClusterName()), "localhost", "127.0.0.1"} // @question should wildcard's be here instead of generating per node. If we ever provide the // ability to resize the master, this will become a blocker c.AddTask(&fitasks.Keypair{ - AlternateNames: alternativeNames, + AlternateNames: servingNames, Lifecycle: b.Lifecycle, Name: fi.String("etcd"), Subject: "cn=etcd", + // TODO: Can this be "server" now that we're not using it for peer connectivity? + Type: "clientServer", + Signer: defaultCA, + Format: format, + }) + + // For peer authentication, the same cert is used both as a client + // cert and as a server cert (which is unusual). Moreover, etcd + // 3.2 introduces some breaking changes to certificate validation + // where it tries to match any IP or DNS names to the client IP + // (including reverse DNS lookups!) We _could_ include a wildcard + // reverse DNS name e.g. *.ec2.internal for EC2, but it seems + // better just to list the names that we expect peer connectivity + // to happen on. + var peerNames []string + for _, etcdCluster := range b.Cluster.Spec.EtcdClusters { + prefix := "etcd-" + etcdCluster.Name + "-" + if prefix == "etcd-main-" { + prefix = "etcd-" + } + for _, m := range etcdCluster.Members { + peerNames = append(peerNames, prefix+m.Name+".internal."+b.ClusterName()) + } + } + c.AddTask(&fitasks.Keypair{ + AlternateNames: peerNames, + Lifecycle: b.Lifecycle, + Name: fi.String("etcd-peer"), + Subject: "cn=etcd-peer", Type: "clientServer", Signer: defaultCA, Format: format, }) + c.AddTask(&fitasks.Keypair{ Name: fi.String("etcd-client"), Lifecycle: b.Lifecycle,