Skip to content
This repository was archived by the owner on Jul 30, 2021. It is now read-only.

Commit 2e8fd95

Browse files
committed
selfHostedEtcd: autogen certs from CA cert
1 parent 27b490a commit 2e8fd95

File tree

3 files changed

+129
-51
lines changed

3 files changed

+129
-51
lines changed

cmd/bootkube/render.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,6 @@ func validateRenderOpts(cmd *cobra.Command, args []string) error {
9999
if (renderOpts.etcdCAPath != "" || renderOpts.etcdCertificatePath != "" || renderOpts.etcdPrivateKeyPath != "") && (renderOpts.etcdCAPath == "" || renderOpts.etcdCertificatePath == "" || renderOpts.etcdPrivateKeyPath == "") {
100100
return errors.New("You must specify either all or none of --etcd-ca-path, --etcd-certificate-path, and --etcd-private-key-path")
101101
}
102-
if renderOpts.etcdCertificatePath != "" && renderOpts.selfHostedEtcd {
103-
return errors.New("Cannot specify --etcd-certificate-path with --experimental-self-hosted-etcd")
104-
}
105102
if renderOpts.assetDir == "" {
106103
return errors.New("Missing required flag: --asset-dir")
107104
}

pkg/asset/asset.go

Lines changed: 63 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -15,48 +15,57 @@ import (
1515
)
1616

1717
const (
18-
AssetPathSecrets = "tls"
19-
AssetPathCAKey = "tls/ca.key"
20-
AssetPathCACert = "tls/ca.crt"
21-
AssetPathAPIServerKey = "tls/apiserver.key"
22-
AssetPathAPIServerCert = "tls/apiserver.crt"
23-
AssetPathEtcdCA = "tls/etcd-ca.crt"
24-
AssetPathEtcdClientCert = "tls/etcd-client.crt"
25-
AssetPathEtcdClientKey = "tls/etcd-client.key"
26-
AssetPathEtcdPeerCert = "tls/etcd-peer.crt"
27-
AssetPathEtcdPeerKey = "tls/etcd-peer.key"
28-
AssetPathServiceAccountPrivKey = "tls/service-account.key"
29-
AssetPathServiceAccountPubKey = "tls/service-account.pub"
30-
AssetPathKubeletKey = "tls/kubelet.key"
31-
AssetPathKubeletCert = "tls/kubelet.crt"
32-
AssetPathKubeConfig = "auth/kubeconfig"
33-
AssetPathManifests = "manifests"
34-
AssetPathKubelet = "manifests/kubelet.yaml"
35-
AssetPathProxy = "manifests/kube-proxy.yaml"
36-
AssetPathKubeFlannel = "manifests/kube-flannel.yaml"
37-
AssetPathKubeFlannelCfg = "manifests/kube-flannel-cfg.yaml"
38-
AssetPathAPIServerSecret = "manifests/kube-apiserver-secret.yaml"
39-
AssetPathAPIServer = "manifests/kube-apiserver.yaml"
40-
AssetPathControllerManager = "manifests/kube-controller-manager.yaml"
41-
AssetPathControllerManagerSecret = "manifests/kube-controller-manager-secret.yaml"
42-
AssetPathControllerManagerDisruption = "manifests/kube-controller-manager-disruption.yaml"
43-
AssetPathScheduler = "manifests/kube-scheduler.yaml"
44-
AssetPathSchedulerDisruption = "manifests/kube-scheduler-disruption.yaml"
45-
AssetPathKubeDNSDeployment = "manifests/kube-dns-deployment.yaml"
46-
AssetPathKubeDNSSvc = "manifests/kube-dns-svc.yaml"
47-
AssetPathSystemNamespace = "manifests/kube-system-ns.yaml"
48-
AssetPathCheckpointer = "manifests/pod-checkpointer.yaml"
49-
AssetPathEtcdOperator = "manifests/etcd-operator.yaml"
50-
AssetPathEtcdSvc = "manifests/etcd-service.yaml"
51-
AssetPathKenc = "manifests/kube-etcd-network-checkpointer.yaml"
52-
AssetPathKubeSystemSARoleBinding = "manifests/kube-system-rbac-role-binding.yaml"
53-
AssetPathBootstrapManifests = "bootstrap-manifests"
54-
AssetPathBootstrapAPIServer = "bootstrap-manifests/bootstrap-apiserver.yaml"
55-
AssetPathBootstrapControllerManager = "bootstrap-manifests/bootstrap-controller-manager.yaml"
56-
AssetPathBootstrapScheduler = "bootstrap-manifests/bootstrap-scheduler.yaml"
57-
AssetPathBootstrapEtcd = "bootstrap-manifests/bootstrap-etcd.yaml"
58-
AssetPathBootstrapEtcdService = "etcd/bootstrap-etcd-service.json"
59-
AssetPathMigrateEtcdCluster = "etcd/migrate-etcd-cluster.json"
18+
AssetPathSecrets = "tls"
19+
AssetPathCAKey = "tls/ca.key"
20+
AssetPathCACert = "tls/ca.crt"
21+
AssetPathAPIServerKey = "tls/apiserver.key"
22+
AssetPathAPIServerCert = "tls/apiserver.crt"
23+
AssetPathEtcdCA = "tls/etcd-ca.crt"
24+
AssetPathEtcdClientCert = "tls/etcd-client.crt"
25+
AssetPathEtcdClientKey = "tls/etcd-client.key"
26+
AssetPathEtcdPeerCert = "tls/etcd-peer.crt"
27+
AssetPathEtcdPeerKey = "tls/etcd-peer.key"
28+
AssetPathSelfHostedOperatorEtcdCA = "tls/operator/etcd-ca-crt.pem"
29+
AssetPathSelfHostedOperatorEtcdCert = "tls/operator/etcd-crt.pem"
30+
AssetPathSelfHostedOperatorEtcdKey = "tls/operator/etcd-key.pem"
31+
AssetPathSelfHostedEtcdMemberClientCA = "tls/etcdMember/client-ca-crt.pem"
32+
AssetPathSelfHostedEtcdMemberClientCert = "tls/etcdMember/client-crt.pem"
33+
AssetPathSelfHostedEtcdMemberClientKey = "tls/etcdMember/client-key.pem"
34+
AssetPathSelfHostedEtcdMemberPeerCA = "tls/etcdMember/peer-ca-crt.pem"
35+
AssetPathSelfHostedEtcdMemberPeerCert = "tls/etcdMember/peer-crt.pem"
36+
AssetPathSelfHostedEtcdMemberPeerKey = "tls/etcdMember/peer-key.pem"
37+
AssetPathServiceAccountPrivKey = "tls/service-account.key"
38+
AssetPathServiceAccountPubKey = "tls/service-account.pub"
39+
AssetPathKubeletKey = "tls/kubelet.key"
40+
AssetPathKubeletCert = "tls/kubelet.crt"
41+
AssetPathKubeConfig = "auth/kubeconfig"
42+
AssetPathManifests = "manifests"
43+
AssetPathKubelet = "manifests/kubelet.yaml"
44+
AssetPathProxy = "manifests/kube-proxy.yaml"
45+
AssetPathKubeFlannel = "manifests/kube-flannel.yaml"
46+
AssetPathKubeFlannelCfg = "manifests/kube-flannel-cfg.yaml"
47+
AssetPathAPIServerSecret = "manifests/kube-apiserver-secret.yaml"
48+
AssetPathAPIServer = "manifests/kube-apiserver.yaml"
49+
AssetPathControllerManager = "manifests/kube-controller-manager.yaml"
50+
AssetPathControllerManagerSecret = "manifests/kube-controller-manager-secret.yaml"
51+
AssetPathControllerManagerDisruption = "manifests/kube-controller-manager-disruption.yaml"
52+
AssetPathScheduler = "manifests/kube-scheduler.yaml"
53+
AssetPathSchedulerDisruption = "manifests/kube-scheduler-disruption.yaml"
54+
AssetPathKubeDNSDeployment = "manifests/kube-dns-deployment.yaml"
55+
AssetPathKubeDNSSvc = "manifests/kube-dns-svc.yaml"
56+
AssetPathSystemNamespace = "manifests/kube-system-ns.yaml"
57+
AssetPathCheckpointer = "manifests/pod-checkpointer.yaml"
58+
AssetPathEtcdOperator = "manifests/etcd-operator.yaml"
59+
AssetPathEtcdSvc = "manifests/etcd-service.yaml"
60+
AssetPathKenc = "manifests/kube-etcd-network-checkpointer.yaml"
61+
AssetPathKubeSystemSARoleBinding = "manifests/kube-system-rbac-role-binding.yaml"
62+
AssetPathBootstrapManifests = "bootstrap-manifests"
63+
AssetPathBootstrapAPIServer = "bootstrap-manifests/bootstrap-apiserver.yaml"
64+
AssetPathBootstrapControllerManager = "bootstrap-manifests/bootstrap-controller-manager.yaml"
65+
AssetPathBootstrapScheduler = "bootstrap-manifests/bootstrap-scheduler.yaml"
66+
AssetPathBootstrapEtcd = "bootstrap-manifests/bootstrap-etcd.yaml"
67+
AssetPathBootstrapEtcdService = "etcd/bootstrap-etcd-service.json"
68+
AssetPathMigrateEtcdCluster = "etcd/migrate-etcd-cluster.json"
6069
)
6170

6271
var (
@@ -133,11 +142,19 @@ func NewDefaultAssets(conf Config) (Assets, error) {
133142

134143
// etcd TLS assets.
135144
if conf.EtcdUseTLS {
136-
etcdTLSAssets, err := newEtcdTLSAssets(conf.EtcdCACert, conf.EtcdClientCert, conf.EtcdClientKey, conf.CACert, conf.CAPrivKey, conf.EtcdServers)
137-
if err != nil {
138-
return Assets{}, err
145+
if conf.SelfHostedEtcd {
146+
tlsAssets, err := newSelfHostedEtcdTLSAssets(conf.EtcdServiceIP.String(), conf.BootEtcdServiceIP.String(), conf.CACert, conf.CAPrivKey)
147+
if err != nil {
148+
return nil, err
149+
}
150+
as = append(as, tlsAssets...)
151+
} else {
152+
etcdTLSAssets, err := newEtcdTLSAssets(conf.EtcdCACert, conf.EtcdClientCert, conf.EtcdClientKey, conf.CACert, conf.CAPrivKey, conf.EtcdServers)
153+
if err != nil {
154+
return Assets{}, err
155+
}
156+
as = append(as, etcdTLSAssets...)
139157
}
140-
as = append(as, etcdTLSAssets...)
141158
}
142159

143160
// K8S kubeconfig

pkg/asset/tls.go

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,14 +148,78 @@ func newEtcdTLSAssets(etcdCACert, etcdClientCert *x509.Certificate, etcdClientKe
148148
return assets, nil
149149
}
150150

151+
func newSelfHostedEtcdTLSAssets(etcdSvcIP, bootEtcdSvcIP string, caCert *x509.Certificate, caPrivKey *rsa.PrivateKey) (Assets, error) {
152+
// TODO: This method uses tlsutil.NewSignedCertificate() which will create certs for both client and server auth.
153+
// We can limit on finer granularity.
154+
155+
var assets []Asset
156+
157+
key, cert, err := newKeyAndCert(caCert, caPrivKey, "etcd member client", []string{
158+
etcdSvcIP,
159+
bootEtcdSvcIP,
160+
"127.0.0.1",
161+
"localhost",
162+
"*.kube-etcd.kube-system.svc.cluster.local",
163+
"kube-etcd-client.kube-system.svc.cluster.local",
164+
})
165+
if err != nil {
166+
return nil, err
167+
}
168+
assets = append(assets, []Asset{
169+
{Name: AssetPathSelfHostedEtcdMemberClientCA, Data: tlsutil.EncodeCertificatePEM(caCert)},
170+
{Name: AssetPathSelfHostedEtcdMemberClientKey, Data: tlsutil.EncodePrivateKeyPEM(key)},
171+
{Name: AssetPathSelfHostedEtcdMemberClientCert, Data: tlsutil.EncodeCertificatePEM(cert)},
172+
}...)
173+
174+
key, cert, err = newKeyAndCert(caCert, caPrivKey, "etcd member peer", []string{
175+
bootEtcdSvcIP,
176+
"*.kube-etcd.kube-system.svc.cluster.local",
177+
"kube-etcd-client.kube-system.svc.cluster.local",
178+
})
179+
if err != nil {
180+
return nil, err
181+
}
182+
assets = append(assets, []Asset{
183+
{Name: AssetPathSelfHostedEtcdMemberPeerCA, Data: tlsutil.EncodeCertificatePEM(caCert)},
184+
{Name: AssetPathSelfHostedEtcdMemberPeerKey, Data: tlsutil.EncodePrivateKeyPEM(key)},
185+
{Name: AssetPathSelfHostedEtcdMemberPeerCert, Data: tlsutil.EncodeCertificatePEM(cert)},
186+
}...)
187+
188+
key, cert, err = newKeyAndCert(caCert, caPrivKey, "operator etcd client", nil)
189+
if err != nil {
190+
return nil, err
191+
}
192+
assets = append(assets, []Asset{
193+
{Name: AssetPathSelfHostedOperatorEtcdCA, Data: tlsutil.EncodeCertificatePEM(caCert)},
194+
{Name: AssetPathSelfHostedOperatorEtcdKey, Data: tlsutil.EncodePrivateKeyPEM(key)},
195+
{Name: AssetPathSelfHostedOperatorEtcdCert, Data: tlsutil.EncodeCertificatePEM(cert)},
196+
}...)
197+
// for APIServer
198+
assets = append(assets, []Asset{
199+
{Name: AssetPathEtcdCA, Data: tlsutil.EncodeCertificatePEM(caCert)},
200+
{Name: AssetPathEtcdClientKey, Data: tlsutil.EncodePrivateKeyPEM(key)},
201+
{Name: AssetPathEtcdClientCert, Data: tlsutil.EncodeCertificatePEM(cert)},
202+
}...)
203+
204+
return assets, nil
205+
}
206+
151207
func newEtcdKeyAndCert(caCert *x509.Certificate, caPrivKey *rsa.PrivateKey, commonName string, etcdServers []*url.URL) (*rsa.PrivateKey, *x509.Certificate, error) {
208+
addrs := make([]string, len(etcdServers))
209+
for i := range etcdServers {
210+
addrs[i] = etcdServers[i].Host
211+
}
212+
return newKeyAndCert(caCert, caPrivKey, commonName, addrs)
213+
}
214+
215+
func newKeyAndCert(caCert *x509.Certificate, caPrivKey *rsa.PrivateKey, commonName string, addrs []string) (*rsa.PrivateKey, *x509.Certificate, error) {
152216
key, err := tlsutil.NewPrivateKey()
153217
if err != nil {
154218
return nil, nil, err
155219
}
156220
var altNames tlsutil.AltNames
157-
for _, etcdServer := range etcdServers {
158-
hostname := stripPort(etcdServer.Host)
221+
for _, addr := range addrs {
222+
hostname := stripPort(addr)
159223
if ip := net.ParseIP(hostname); ip != nil {
160224
altNames.IPs = append(altNames.IPs, ip)
161225
} else {

0 commit comments

Comments
 (0)