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

Commit ab1b6b6

Browse files
authored
Merge pull request #585 from hongchaodeng/flag
selfHostedEtcd: autogen certs from CA cert
2 parents 27b490a + 5a965bc commit ab1b6b6

File tree

3 files changed

+136
-50
lines changed

3 files changed

+136
-50
lines changed

cmd/bootkube/render.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ func validateRenderOpts(cmd *cobra.Command, args []string) error {
100100
return errors.New("You must specify either all or none of --etcd-ca-path, --etcd-certificate-path, and --etcd-private-key-path")
101101
}
102102
if renderOpts.etcdCertificatePath != "" && renderOpts.selfHostedEtcd {
103-
return errors.New("Cannot specify --etcd-certificate-path with --experimental-self-hosted-etcd")
103+
return errors.New("Cannot specify --etcd-certificate-path with --experimental-self-hosted-etcd." +
104+
" Self-hosted etcd + TLS will auto-generate certs based on root CA cert.")
104105
}
105106
if renderOpts.assetDir == "" {
106107
return errors.New("Missing required flag: --asset-dir")
@@ -211,7 +212,7 @@ func flagsToAssetConfig() (c *asset.Config, err error) {
211212
}
212213
}
213214

214-
if etcdUseTLS && etcdCACert == nil {
215+
if etcdUseTLS && etcdCACert == nil && !renderOpts.selfHostedEtcd {
215216
bootkube.UserOutput("NOTE: --etcd-servers=%s but --etcd-ca-path, --etcd-certificate-path, and --etcd-private-key-path were not set. Bootkube will create etcd certificates under '%s/tls'. You must configure etcd to use these certificates before invoking 'bootkube run'.\n", renderOpts.etcdServers, renderOpts.assetDir)
216217
}
217218

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: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,14 +148,82 @@ func newEtcdTLSAssets(etcdCACert, etcdClientCert *x509.Certificate, etcdClientKe
148148
return assets, nil
149149
}
150150

151+
// newSelfHostedEtcdTLSAssets automatically generates three suites of x509 certificates (CA, key, cert)
152+
// for self-hosted etcd related components. Two suites are used by etcd members' client and peer ports;
153+
// one is used via etcd client to talk to etcd by operator, apiserver.
154+
// Self-hosted etcd doesn't allow user to specify etcd certs.
155+
func newSelfHostedEtcdTLSAssets(etcdSvcIP, bootEtcdSvcIP string, caCert *x509.Certificate, caPrivKey *rsa.PrivateKey) (Assets, error) {
156+
// TODO: This method uses tlsutil.NewSignedCertificate() which will create certs for both client and server auth.
157+
// We can limit on finer granularity.
158+
159+
var assets []Asset
160+
161+
key, cert, err := newKeyAndCert(caCert, caPrivKey, "etcd member client", []string{
162+
etcdSvcIP,
163+
bootEtcdSvcIP,
164+
"127.0.0.1",
165+
"localhost",
166+
"*.kube-etcd.kube-system.svc.cluster.local",
167+
"kube-etcd-client.kube-system.svc.cluster.local",
168+
})
169+
if err != nil {
170+
return nil, err
171+
}
172+
assets = append(assets, []Asset{
173+
{Name: AssetPathSelfHostedEtcdMemberClientCA, Data: tlsutil.EncodeCertificatePEM(caCert)},
174+
{Name: AssetPathSelfHostedEtcdMemberClientKey, Data: tlsutil.EncodePrivateKeyPEM(key)},
175+
{Name: AssetPathSelfHostedEtcdMemberClientCert, Data: tlsutil.EncodeCertificatePEM(cert)},
176+
}...)
177+
178+
key, cert, err = newKeyAndCert(caCert, caPrivKey, "etcd member peer", []string{
179+
bootEtcdSvcIP,
180+
"*.kube-etcd.kube-system.svc.cluster.local",
181+
"kube-etcd-client.kube-system.svc.cluster.local",
182+
})
183+
if err != nil {
184+
return nil, err
185+
}
186+
assets = append(assets, []Asset{
187+
{Name: AssetPathSelfHostedEtcdMemberPeerCA, Data: tlsutil.EncodeCertificatePEM(caCert)},
188+
{Name: AssetPathSelfHostedEtcdMemberPeerKey, Data: tlsutil.EncodePrivateKeyPEM(key)},
189+
{Name: AssetPathSelfHostedEtcdMemberPeerCert, Data: tlsutil.EncodeCertificatePEM(cert)},
190+
}...)
191+
192+
key, cert, err = newKeyAndCert(caCert, caPrivKey, "operator etcd client", nil)
193+
if err != nil {
194+
return nil, err
195+
}
196+
assets = append(assets, []Asset{
197+
{Name: AssetPathSelfHostedOperatorEtcdCA, Data: tlsutil.EncodeCertificatePEM(caCert)},
198+
{Name: AssetPathSelfHostedOperatorEtcdKey, Data: tlsutil.EncodePrivateKeyPEM(key)},
199+
{Name: AssetPathSelfHostedOperatorEtcdCert, Data: tlsutil.EncodeCertificatePEM(cert)},
200+
}...)
201+
// for APIServer
202+
assets = append(assets, []Asset{
203+
{Name: AssetPathEtcdCA, Data: tlsutil.EncodeCertificatePEM(caCert)},
204+
{Name: AssetPathEtcdClientKey, Data: tlsutil.EncodePrivateKeyPEM(key)},
205+
{Name: AssetPathEtcdClientCert, Data: tlsutil.EncodeCertificatePEM(cert)},
206+
}...)
207+
208+
return assets, nil
209+
}
210+
151211
func newEtcdKeyAndCert(caCert *x509.Certificate, caPrivKey *rsa.PrivateKey, commonName string, etcdServers []*url.URL) (*rsa.PrivateKey, *x509.Certificate, error) {
212+
addrs := make([]string, len(etcdServers))
213+
for i := range etcdServers {
214+
addrs[i] = etcdServers[i].Host
215+
}
216+
return newKeyAndCert(caCert, caPrivKey, commonName, addrs)
217+
}
218+
219+
func newKeyAndCert(caCert *x509.Certificate, caPrivKey *rsa.PrivateKey, commonName string, addrs []string) (*rsa.PrivateKey, *x509.Certificate, error) {
152220
key, err := tlsutil.NewPrivateKey()
153221
if err != nil {
154222
return nil, nil, err
155223
}
156224
var altNames tlsutil.AltNames
157-
for _, etcdServer := range etcdServers {
158-
hostname := stripPort(etcdServer.Host)
225+
for _, addr := range addrs {
226+
hostname := stripPort(addr)
159227
if ip := net.ParseIP(hostname); ip != nil {
160228
altNames.IPs = append(altNames.IPs, ip)
161229
} else {

0 commit comments

Comments
 (0)