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

Commit 4615f6d

Browse files
author
Diego Pontoriero
committed
Always secure etcd using TLS, except when self-hosting.
1 parent 558544c commit 4615f6d

File tree

6 files changed

+74
-69
lines changed

6 files changed

+74
-69
lines changed

cmd/bootkube/render.go

Lines changed: 18 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ import (
1818
)
1919

2020
const (
21-
apiOffset = 1
22-
dnsOffset = 10
23-
etcdOffset = 15
24-
defaultServiceBaseIP = "10.3.0.0"
25-
defaultEtcdServers = "http://127.0.0.1:2379"
26-
defaultEtcdTLSServers = "https://127.0.0.1:2379"
21+
apiOffset = 1
22+
dnsOffset = 10
23+
etcdOffset = 15
24+
defaultServiceBaseIP = "10.3.0.0"
25+
defaultEtcdServers = "https://127.0.0.1:2379"
26+
defaultSelfHostedEtcdServers = "http://127.0.0.1:2379"
2727
)
2828

2929
var (
@@ -44,7 +44,6 @@ var (
4444
etcdCertificatePath string
4545
etcdPrivateKeyPath string
4646
etcdServers string
47-
etcdUseTLS bool
4847
apiServers string
4948
altNames string
5049
podCIDR string
@@ -61,8 +60,8 @@ func init() {
6160
cmdRender.Flags().StringVar(&renderOpts.caCertificatePath, "ca-certificate-path", "", "Path to an existing PEM encoded CA. If provided, TLS assets will be generated using this certificate authority.")
6261
cmdRender.Flags().StringVar(&renderOpts.caPrivateKeyPath, "ca-private-key-path", "", "Path to an existing Certificate Authority RSA private key. Required if --ca-certificate is set.")
6362
cmdRender.Flags().StringVar(&renderOpts.etcdCAPath, "etcd-ca-path", "", "Path to an existing PEM encoded CA that will be used for TLS-enabled communication between the apiserver and etcd. Must be used in conjunction with --etcd-certificate-path and --etcd-private-key-path, and must have etcd configured to use TLS with matching secrets.")
64-
cmdRender.Flags().StringVar(&renderOpts.etcdCertificatePath, "etcd-certificate-path", "", "Path to an existing server certificate that will be used for TLS-enabled communication between the apiserver and etcd. Must be used in conjunction with --etcd-ca-path and --etcd-private-key-path, and must have etcd configured to use TLS with matching secrets.")
65-
cmdRender.Flags().StringVar(&renderOpts.etcdPrivateKeyPath, "etcd-private-key-path", "", "Path to an existing server private key that will be used for TLS-enabled communication between the apiserver and etcd. Must be used in conjunction with --etcd-ca-path and --etcd-certificate-path, and must have etcd configured to use TLS with matching secrets.")
63+
cmdRender.Flags().StringVar(&renderOpts.etcdCertificatePath, "etcd-certificate-path", "", "Path to an existing certificate that will be used for TLS-enabled communication between the apiserver and etcd. Must be used in conjunction with --etcd-ca-path and --etcd-private-key-path, and must have etcd configured to use TLS with matching secrets.")
64+
cmdRender.Flags().StringVar(&renderOpts.etcdPrivateKeyPath, "etcd-private-key-path", "", "Path to an existing private key that will be used for TLS-enabled communication between the apiserver and etcd. Must be used in conjunction with --etcd-ca-path and --etcd-certificate-path, and must have etcd configured to use TLS with matching secrets.")
6665
cmdRender.Flags().StringVar(&renderOpts.etcdServers, "etcd-servers", defaultEtcdServers, "List of etcd servers URLs including host:port, comma separated")
6766
cmdRender.Flags().StringVar(&renderOpts.apiServers, "api-servers", "https://127.0.0.1:443", "List of API server URLs including host:port, commma seprated")
6867
cmdRender.Flags().StringVar(&renderOpts.altNames, "api-server-alt-names", "", "List of SANs to use in api-server certificate. Example: 'IP=127.0.0.1,IP=127.0.0.2,DNS=localhost'. If empty, SANs will be extracted from the --api-servers flag.")
@@ -71,7 +70,6 @@ func init() {
7170
cmdRender.Flags().BoolVar(&renderOpts.selfHostKubelet, "experimental-self-hosted-kubelet", false, "(Experimental) Create a self-hosted kubelet daemonset.")
7271
cmdRender.Flags().StringVar(&renderOpts.cloudProvider, "cloud-provider", "", "The provider for cloud services. Empty string for no provider")
7372
cmdRender.Flags().BoolVar(&renderOpts.selfHostedEtcd, "experimental-self-hosted-etcd", false, "(Experimental) Create self-hosted etcd assets.")
74-
cmdRender.Flags().BoolVar(&renderOpts.etcdUseTLS, "etcd-use-tls", false, "If true, uses TLS for etcd. Implicitly true if --etcd-ca-path,--etcd-certificate-path,--etcd-private-key-path are set. If true but those flags are not set etcd TLS certificates will be generated. Not supported if --experimental-self-hosted-etcd=true.")
7573
}
7674

7775
func runCmdRender(cmd *cobra.Command, args []string) error {
@@ -98,12 +96,8 @@ func validateRenderOpts(cmd *cobra.Command, args []string) error {
9896
if (renderOpts.etcdCAPath != "" || renderOpts.etcdCertificatePath != "" || renderOpts.etcdPrivateKeyPath != "") && (renderOpts.etcdCAPath == "" || renderOpts.etcdCertificatePath == "" || renderOpts.etcdPrivateKeyPath == "") {
9997
return errors.New("You must specify either all or none of --etcd-ca-path, --etcd-certificate-path, and --etcd-private-key-path")
10098
}
101-
if renderOpts.etcdCAPath != "" && !renderOpts.etcdUseTLS {
102-
bootkube.UserOutput("etcd TLS certificates specified. Overriding --etcd-use-tls=true\n")
103-
renderOpts.etcdUseTLS = true
104-
}
105-
if renderOpts.etcdUseTLS && renderOpts.selfHostedEtcd {
106-
return errors.New("Cannot use --etcd-use-tls with --experimental-self-hosted-etcd")
99+
if renderOpts.etcdCertificatePath != "" && renderOpts.selfHostedEtcd {
100+
return errors.New("Cannot specify --etcd-certificate-path with --experimental-self-hosted-etcd")
107101
}
108102
if renderOpts.assetDir == "" {
109103
return errors.New("Missing required flag: --asset-dir")
@@ -175,26 +169,18 @@ func flagsToAssetConfig() (c *asset.Config, err error) {
175169
if err != nil {
176170
return nil, err
177171
}
178-
179172
etcdServers = append(etcdServers, etcdServerUrl)
180-
181-
if renderOpts.etcdServers != defaultEtcdServers {
173+
if renderOpts.etcdServers != defaultSelfHostedEtcdServers {
182174
bootkube.UserOutput("--experimental-self-hosted-etcd and --service-cidr set. Overriding --etcd-servers setting with %s\n", etcdServers)
183175
}
184176
} else {
185-
if renderOpts.etcdUseTLS && renderOpts.etcdServers == defaultEtcdServers {
186-
renderOpts.etcdServers = defaultEtcdTLSServers
187-
}
188177
etcdServers, err = parseURLs(renderOpts.etcdServers)
189178
if err != nil {
190179
return nil, err
191180
}
192-
}
193-
194-
if renderOpts.etcdUseTLS {
195181
for _, url := range etcdServers {
196182
if url.Scheme != "https" {
197-
return nil, fmt.Errorf("--etcd-use-tls=true but insecure etcd server endpoint specified: %s\n", url)
183+
return nil, fmt.Errorf("etcd endpoints must use https, got: %s\n", url)
198184
}
199185
}
200186
}
@@ -206,10 +192,10 @@ func flagsToAssetConfig() (c *asset.Config, err error) {
206192
return nil, err
207193
}
208194
}
209-
var etcdServerCert *x509.Certificate
210-
var etcdServerKey *rsa.PrivateKey
195+
var etcdClientCert *x509.Certificate
196+
var etcdClientKey *rsa.PrivateKey
211197
if renderOpts.etcdCertificatePath != "" {
212-
etcdServerKey, etcdServerCert, err = parseCertAndPrivateKeyFromDisk(renderOpts.etcdCertificatePath, renderOpts.etcdPrivateKeyPath)
198+
etcdClientKey, etcdClientCert, err = parseCertAndPrivateKeyFromDisk(renderOpts.etcdCertificatePath, renderOpts.etcdPrivateKeyPath)
213199
if err != nil {
214200
return nil, err
215201
}
@@ -222,10 +208,9 @@ func flagsToAssetConfig() (c *asset.Config, err error) {
222208

223209
return &asset.Config{
224210
EtcdCACert: etcdCACert,
225-
EtcdServerCert: etcdServerCert,
226-
EtcdServerKey: etcdServerKey,
211+
EtcdClientCert: etcdClientCert,
212+
EtcdClientKey: etcdClientKey,
227213
EtcdServers: etcdServers,
228-
EtcdUseTLS: renderOpts.etcdUseTLS,
229214
CACert: caCert,
230215
CAPrivKey: caPrivKey,
231216
APIServers: apiServers,
@@ -234,7 +219,7 @@ func flagsToAssetConfig() (c *asset.Config, err error) {
234219
ServiceCIDR: serviceNet,
235220
APIServiceIP: apiServiceIP,
236221
DNSServiceIP: dnsServiceIP,
237-
ETCDServiceIP: etcdServiceIP,
222+
EtcdServiceIP: etcdServiceIP,
238223
SelfHostKubelet: renderOpts.selfHostKubelet,
239224
CloudProvider: renderOpts.cloudProvider,
240225
SelfHostedEtcd: renderOpts.selfHostedEtcd,

hack/quickstart/init-master.sh

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,19 @@ function configure_etcd() {
2525
[Service]
2626
Environment="ETCD_IMAGE_TAG=v3.1.0"
2727
Environment="ETCD_NAME=controller"
28-
Environment="ETCD_INITIAL_CLUSTER=controller=http://${COREOS_PRIVATE_IPV4}:2380"
29-
Environment="ETCD_INITIAL_ADVERTISE_PEER_URLS=http://${COREOS_PRIVATE_IPV4}:2380"
28+
Environment="ETCD_INITIAL_CLUSTER=controller=https://${COREOS_PRIVATE_IPV4}:2380"
29+
Environment="ETCD_INITIAL_ADVERTISE_PEER_URLS=https://${COREOS_PRIVATE_IPV4}:2380"
3030
Environment="ETCD_ADVERTISE_CLIENT_URLS=https://${COREOS_PRIVATE_IPV4}:2379"
31-
Environment="ETCD_SSL_DIR=/etc/etcd/tls"
3231
Environment="ETCD_LISTEN_CLIENT_URLS=https://0.0.0.0:2379"
33-
Environment="ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380"
32+
Environment="ETCD_LISTEN_PEER_URLS=https://0.0.0.0:2380"
33+
Environment="ETCD_SSL_DIR=/etc/etcd/tls"
3434
Environment="ETCD_TRUSTED_CA_FILE=/etc/ssl/certs/etcd-ca.crt"
35-
Environment="ETCD_CERT_FILE=/etc/ssl/certs/etcd-server.crt"
36-
Environment="ETCD_KEY_FILE=/etc/ssl/certs/etcd-server.key"
35+
Environment="ETCD_CERT_FILE=/etc/ssl/certs/etcd-client.crt"
36+
Environment="ETCD_KEY_FILE=/etc/ssl/certs/etcd-client.key"
3737
Environment="ETCD_CLIENT_CERT_AUTH=true"
38+
Environment="ETCD_PEER_TRUSTED_CA_FILE=/etc/ssl/certs/etcd-ca.crt"
39+
Environment="ETCD_PEER_CERT_FILE=/etc/ssl/certs/etcd-peer.crt"
40+
Environment="ETCD_PEER_KEY_FILE=/etc/ssl/certs/etcd-peer.key"
3841
EOF
3942
}
4043
}
@@ -48,7 +51,7 @@ function init_master_node() {
4851
echo "WARNING: THIS IS NOT YET FULLY WORKING - merely here to make ongoing testing easier"
4952
etcd_render_flags="--experimental-self-hosted-etcd"
5053
else
51-
etcd_render_flags="--etcd-use-tls --etcd-servers=https://${COREOS_PRIVATE_IPV4}:2379"
54+
etcd_render_flags="--etcd-servers=https://${COREOS_PRIVATE_IPV4}:2379"
5255
fi
5356

5457
# Render cluster assets

pkg/asset/asset.go

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@ const (
2020
AssetPathAPIServerKey = "tls/apiserver.key"
2121
AssetPathAPIServerCert = "tls/apiserver.crt"
2222
AssetPathEtcdCA = "tls/etcd-ca.crt"
23-
AssetPathEtcdServerCert = "tls/etcd-server.crt"
24-
AssetPathEtcdServerKey = "tls/etcd-server.key"
23+
AssetPathEtcdClientCert = "tls/etcd-client.crt"
24+
AssetPathEtcdClientKey = "tls/etcd-client.key"
25+
AssetPathEtcdPeerCert = "tls/etcd-peer.crt"
26+
AssetPathEtcdPeerKey = "tls/etcd-peer.key"
2527
AssetPathServiceAccountPrivKey = "tls/service-account.key"
2628
AssetPathServiceAccountPubKey = "tls/service-account.pub"
2729
AssetPathKubeletKey = "tls/kubelet.key"
@@ -59,10 +61,9 @@ const (
5961
// the default set of assets.
6062
type Config struct {
6163
EtcdCACert *x509.Certificate
62-
EtcdServerCert *x509.Certificate
63-
EtcdServerKey *rsa.PrivateKey
64+
EtcdClientCert *x509.Certificate
65+
EtcdClientKey *rsa.PrivateKey
6466
EtcdServers []*url.URL
65-
EtcdUseTLS bool
6667
APIServers []*url.URL
6768
CACert *x509.Certificate
6869
CAPrivKey *rsa.PrivateKey
@@ -71,7 +72,7 @@ type Config struct {
7172
ServiceCIDR *net.IPNet
7273
APIServiceIP net.IP
7374
DNSServiceIP net.IP
74-
ETCDServiceIP net.IP
75+
EtcdServiceIP net.IP
7576
SelfHostKubelet bool
7677
SelfHostedEtcd bool
7778
CloudProvider string
@@ -107,8 +108,8 @@ func NewDefaultAssets(conf Config) (Assets, error) {
107108
as = append(as, tlsAssets...)
108109

109110
// etcd TLS assets.
110-
if conf.EtcdUseTLS {
111-
etcdTLSAssets, err := newEtcdTLSAssets(conf.EtcdCACert, conf.EtcdServerCert, conf.EtcdServerKey, conf.CACert, conf.CAPrivKey, conf.EtcdServers)
111+
if !conf.SelfHostedEtcd {
112+
etcdTLSAssets, err := newEtcdTLSAssets(conf.EtcdCACert, conf.EtcdClientCert, conf.EtcdClientKey, conf.CACert, conf.CAPrivKey, conf.EtcdServers)
112113
if err != nil {
113114
return Assets{}, err
114115
}
@@ -123,7 +124,7 @@ func NewDefaultAssets(conf Config) (Assets, error) {
123124
as = append(as, kubeConfig)
124125

125126
// K8S APIServer secret
126-
apiSecret, err := newAPIServerSecretAsset(as, conf.EtcdUseTLS)
127+
apiSecret, err := newAPIServerSecretAsset(as, conf.SelfHostedEtcd)
127128
if err != nil {
128129
return Assets{}, err
129130
}

pkg/asset/internal/templates.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -171,10 +171,10 @@ spec:
171171
- --bind-address=0.0.0.0
172172
- --client-ca-file=/etc/kubernetes/secrets/ca.crt
173173
- --cloud-provider={{ .CloudProvider }}
174-
{{- if .EtcdUseTLS }}
174+
{{- if not .SelfHostedEtcd }}
175175
- --etcd-cafile=/etc/kubernetes/secrets/etcd-ca.crt
176-
- --etcd-certfile=/etc/kubernetes/secrets/etcd-server.crt
177-
- --etcd-keyfile=/etc/kubernetes/secrets/etcd-server.key
176+
- --etcd-certfile=/etc/kubernetes/secrets/etcd-client.crt
177+
- --etcd-keyfile=/etc/kubernetes/secrets/etcd-client.key
178178
{{- end }}
179179
- --etcd-servers={{ range $i, $e := .EtcdServers }}{{ if $i }},{{end}}{{ $e }}{{end}}
180180
- --insecure-port=8080
@@ -236,10 +236,10 @@ spec:
236236
- --authorization-mode=RBAC
237237
- --bind-address=0.0.0.0
238238
- --client-ca-file=/etc/kubernetes/secrets/ca.crt
239-
{{- if .EtcdUseTLS }}
239+
{{- if not .SelfHostedEtcd }}
240240
- --etcd-cafile=/etc/kubernetes/secrets/etcd-ca.crt
241-
- --etcd-certfile=/etc/kubernetes/secrets/etcd-server.crt
242-
- --etcd-keyfile=/etc/kubernetes/secrets/etcd-server.key
241+
- --etcd-certfile=/etc/kubernetes/secrets/etcd-client.crt
242+
- --etcd-keyfile=/etc/kubernetes/secrets/etcd-client.key
243243
{{- end }}
244244
- --etcd-servers={{ range $i, $e := .EtcdServers }}{{ if $i }},{{end}}{{ $e }}{{end}}{{ if .SelfHostedEtcd }},http://127.0.0.1:12379{{end}}
245245
- --insecure-port=8080
@@ -844,7 +844,7 @@ spec:
844844
selector:
845845
app: etcd
846846
etcd_cluster: kube-etcd
847-
clusterIP: {{ .ETCDServiceIP }}
847+
clusterIP: {{ .EtcdServiceIP }}
848848
ports:
849849
- name: client
850850
port: 2379

pkg/asset/k8s.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,18 +87,18 @@ func newKubeConfigAsset(assets Assets, conf Config) (Asset, error) {
8787
})
8888
}
8989

90-
func newAPIServerSecretAsset(assets Assets, etcdUseTLS bool) (Asset, error) {
90+
func newAPIServerSecretAsset(assets Assets, selfHostedEtcd bool) (Asset, error) {
9191
secretAssets := []string{
9292
AssetPathAPIServerKey,
9393
AssetPathAPIServerCert,
9494
AssetPathServiceAccountPubKey,
9595
AssetPathCACert,
9696
}
97-
if etcdUseTLS {
97+
if !selfHostedEtcd {
9898
secretAssets = append(secretAssets, []string{
9999
AssetPathEtcdCA,
100-
AssetPathEtcdServerCert,
101-
AssetPathEtcdServerKey,
100+
AssetPathEtcdClientCert,
101+
AssetPathEtcdClientKey,
102102
}...)
103103
}
104104

pkg/asset/tls.go

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -115,24 +115,40 @@ func newKubeletKeyAndCert(caCert *x509.Certificate, caPrivKey *rsa.PrivateKey) (
115115
return key, cert, err
116116
}
117117

118-
func newEtcdTLSAssets(etcdCACert, etcdServerCert *x509.Certificate, etcdServerKey *rsa.PrivateKey, caCert *x509.Certificate, caPrivKey *rsa.PrivateKey, etcdServers []*url.URL) ([]Asset, error) {
118+
func newEtcdTLSAssets(etcdCACert, etcdClientCert *x509.Certificate, etcdClientKey *rsa.PrivateKey, caCert *x509.Certificate, caPrivKey *rsa.PrivateKey, etcdServers []*url.URL) ([]Asset, error) {
119+
var assets []Asset
119120
if etcdCACert == nil {
121+
// Use the master CA to generate etcd assets.
122+
etcdCACert = caCert
123+
124+
// Create an etcd client cert.
120125
var err error
121-
etcdServerKey, etcdServerCert, err = newEtcdServerKeyAndCert(caCert, caPrivKey, etcdServers)
126+
etcdClientKey, etcdClientCert, err = newEtcdKeyAndCert(caCert, caPrivKey, "etcd-client", etcdServers)
122127
if err != nil {
123128
return nil, err
124129
}
125-
etcdCACert = caCert
130+
131+
// Create an etcd peer cert (not consumed by self-hosted components).
132+
etcdPeerKey, etcdPeerCert, err := newEtcdKeyAndCert(caCert, caPrivKey, "etcd-peer", etcdServers)
133+
if err != nil {
134+
return nil, err
135+
}
136+
assets = append(assets, []Asset{
137+
{Name: AssetPathEtcdPeerKey, Data: tlsutil.EncodePrivateKeyPEM(etcdPeerKey)},
138+
{Name: AssetPathEtcdPeerCert, Data: tlsutil.EncodeCertificatePEM(etcdPeerCert)},
139+
}...)
126140
}
127141

128-
return []Asset{
142+
assets = append(assets, []Asset{
129143
{Name: AssetPathEtcdCA, Data: tlsutil.EncodeCertificatePEM(etcdCACert)},
130-
{Name: AssetPathEtcdServerKey, Data: tlsutil.EncodePrivateKeyPEM(etcdServerKey)},
131-
{Name: AssetPathEtcdServerCert, Data: tlsutil.EncodeCertificatePEM(etcdServerCert)},
132-
}, nil
144+
{Name: AssetPathEtcdClientKey, Data: tlsutil.EncodePrivateKeyPEM(etcdClientKey)},
145+
{Name: AssetPathEtcdClientCert, Data: tlsutil.EncodeCertificatePEM(etcdClientCert)},
146+
}...)
147+
148+
return assets, nil
133149
}
134150

135-
func newEtcdServerKeyAndCert(caCert *x509.Certificate, caPrivKey *rsa.PrivateKey, etcdServers []*url.URL) (*rsa.PrivateKey, *x509.Certificate, error) {
151+
func newEtcdKeyAndCert(caCert *x509.Certificate, caPrivKey *rsa.PrivateKey, commonName string, etcdServers []*url.URL) (*rsa.PrivateKey, *x509.Certificate, error) {
136152
key, err := tlsutil.NewPrivateKey()
137153
if err != nil {
138154
return nil, nil, err
@@ -147,7 +163,7 @@ func newEtcdServerKeyAndCert(caCert *x509.Certificate, caPrivKey *rsa.PrivateKey
147163
}
148164
}
149165
config := tlsutil.CertConfig{
150-
CommonName: "etcd-server",
166+
CommonName: commonName,
151167
Organization: []string{"etcd"},
152168
AltNames: altNames,
153169
}

0 commit comments

Comments
 (0)