kubelet: Add --bootstrap-kubeconfig to get TLS client cert.

Add --bootstrap-kubeconfig flag to kubelet. If the flag is non-empty
and --kubeconfig doesn't exist, then the kubelet will use the bootstrap
kubeconfig to create rest client and generate certificate signing request
to request a client cert from API server.

Once succeeds, the result cert will be written down to
--cert-dir/kubelet-client.crt, and the kubeconfig will be populated with
certfile, keyfile path pointing to the result certificate file, key file.
(The key file is generated before creating the CSR).
This commit is contained in:
Yifan Gu
2016-08-12 18:06:48 -07:00
parent 5801fa5f4d
commit 26babd4eba
5 changed files with 319 additions and 44 deletions

View File

@@ -26,9 +26,7 @@ import (
"encoding/pem"
"errors"
"fmt"
"io/ioutil"
"net"
"os"
"k8s.io/kubernetes/pkg/apis/certificates"
)
@@ -49,49 +47,39 @@ func ParseCertificateRequestObject(obj *certificates.CertificateSigningRequest)
}
// NewCertificateRequest generates a PEM-encoded CSR using the supplied private
// key file, subject, and SANs. If the private key file does not exist, it generates a
// new ECDSA P256 key to use and writes it to the keyFile path.
func NewCertificateRequest(keyFile string, subject *pkix.Name, dnsSANs []string, ipSANs []net.IP) ([]byte, error) {
// key data, subject, and SANs. If the private key data is empty, it generates a
// new ECDSA P256 key to use and returns it together with the CSR data.
func NewCertificateRequest(keyData []byte, subject *pkix.Name, dnsSANs []string, ipSANs []net.IP) (csr []byte, key []byte, err error) {
var privateKey interface{}
var privateKeyPemBlock *pem.Block
if _, err := os.Stat(keyFile); os.IsNotExist(err) {
if len(keyData) == 0 {
privateKey, err = ecdsa.GenerateKey(elliptic.P256(), cryptorand.Reader)
if err != nil {
return nil, err
return nil, nil, err
}
ecdsaKey := privateKey.(*ecdsa.PrivateKey)
derBytes, err := x509.MarshalECPrivateKey(ecdsaKey)
if err != nil {
return nil, err
return nil, nil, err
}
pemBlock := &pem.Block{
privateKeyPemBlock = &pem.Block{
Type: "EC PRIVATE KEY",
Bytes: derBytes,
}
err = ioutil.WriteFile(keyFile, pem.EncodeToMemory(pemBlock), os.FileMode(0600))
if err != nil {
return nil, err
}
} else {
privateKeyPemBlock, _ = pem.Decode(keyData)
}
keyBytes, err := ioutil.ReadFile(keyFile)
if err != nil {
return nil, err
}
var block *pem.Block
var sigType x509.SignatureAlgorithm
block, _ = pem.Decode(keyBytes)
switch block.Type {
switch privateKeyPemBlock.Type {
case "EC PRIVATE KEY":
privateKey, err = x509.ParseECPrivateKey(block.Bytes)
privateKey, err = x509.ParseECPrivateKey(privateKeyPemBlock.Bytes)
if err != nil {
return nil, err
return nil, nil, err
}
ecdsaKey := privateKey.(*ecdsa.PrivateKey)
switch ecdsaKey.Curve.Params().BitSize {
@@ -103,9 +91,9 @@ func NewCertificateRequest(keyFile string, subject *pkix.Name, dnsSANs []string,
sigType = x509.ECDSAWithSHA256
}
case "RSA PRIVATE KEY":
privateKey, err = x509.ParsePKCS1PrivateKey(block.Bytes)
privateKey, err = x509.ParsePKCS1PrivateKey(privateKeyPemBlock.Bytes)
if err != nil {
return nil, err
return nil, nil, err
}
rsaKey := privateKey.(*rsa.PrivateKey)
keySize := rsaKey.N.BitLen()
@@ -118,7 +106,7 @@ func NewCertificateRequest(keyFile string, subject *pkix.Name, dnsSANs []string,
sigType = x509.SHA256WithRSA
}
default:
return nil, fmt.Errorf("unsupported key type: %s", block.Type)
return nil, nil, fmt.Errorf("unsupported key type: %s", privateKeyPemBlock.Type)
}
template := &x509.CertificateRequest{
@@ -128,15 +116,15 @@ func NewCertificateRequest(keyFile string, subject *pkix.Name, dnsSANs []string,
IPAddresses: ipSANs,
}
csr, err := x509.CreateCertificateRequest(cryptorand.Reader, template, privateKey)
csr, err = x509.CreateCertificateRequest(cryptorand.Reader, template, privateKey)
if err != nil {
return nil, err
return nil, nil, err
}
pemBlock := &pem.Block{
csrPemBlock := &pem.Block{
Type: "CERTIFICATE REQUEST",
Bytes: csr,
}
return pem.EncodeToMemory(pemBlock), nil
return pem.EncodeToMemory(csrPemBlock), pem.EncodeToMemory(privateKeyPemBlock), nil
}