mirror of https://github.com/k3s-io/k3s
Refactor utils that deal with certs
- merge `pkg/util/{crypto,certificates}` - add funcs from `github.com/kubernetes-incubator/bootkube/pkg/tlsutil` - ensure naming of funcs is fairly consistentpull/6/head
parent
892a6d7af5
commit
386fae4592
|
@ -74,8 +74,8 @@ import (
|
|||
quotainstall "k8s.io/kubernetes/pkg/quota/install"
|
||||
"k8s.io/kubernetes/pkg/runtime/serializer"
|
||||
"k8s.io/kubernetes/pkg/serviceaccount"
|
||||
certutil "k8s.io/kubernetes/pkg/util/cert"
|
||||
"k8s.io/kubernetes/pkg/util/configz"
|
||||
"k8s.io/kubernetes/pkg/util/crypto"
|
||||
"k8s.io/kubernetes/pkg/util/wait"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
@ -482,7 +482,7 @@ func StartControllers(s *options.CMServer, kubeClient *client.Client, kubeconfig
|
|||
if err != nil {
|
||||
return fmt.Errorf("error reading root-ca-file at %s: %v", s.RootCAFile, err)
|
||||
}
|
||||
if _, err := crypto.CertsFromPEM(rootCA); err != nil {
|
||||
if _, err := certutil.ParseCertsPEM(rootCA); err != nil {
|
||||
return fmt.Errorf("error parsing root-ca-file at %s: %v", s.RootCAFile, err)
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -30,8 +30,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
||||
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
|
||||
"k8s.io/kubernetes/pkg/kubelet/util/csr"
|
||||
utilcertificates "k8s.io/kubernetes/pkg/util/certificates"
|
||||
"k8s.io/kubernetes/pkg/util/crypto"
|
||||
certutil "k8s.io/kubernetes/pkg/util/cert"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -97,7 +96,7 @@ func bootstrapClientCert(kubeconfigPath string, bootstrapPath string, certDir st
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := crypto.WriteCertToPath(certPath, certData); err != nil {
|
||||
if err := certutil.WriteCert(certPath, certData); err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
|
@ -171,11 +170,11 @@ func loadOrGenerateKeyFile(keyPath string) (data []byte, wasGenerated bool, err
|
|||
return nil, false, fmt.Errorf("error loading key from %s: %v", keyPath, err)
|
||||
}
|
||||
|
||||
generatedData, err := utilcertificates.GeneratePrivateKey()
|
||||
generatedData, err := certutil.MakeEllipticPrivateKeyPEM()
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("error generating key: %v", err)
|
||||
}
|
||||
if err := crypto.WriteKeyToPath(keyPath, generatedData); err != nil {
|
||||
if err := certutil.WriteKey(keyPath, generatedData); err != nil {
|
||||
return nil, false, fmt.Errorf("error writing key to %s: %v", keyPath, err)
|
||||
}
|
||||
return generatedData, true, nil
|
||||
|
|
|
@ -61,9 +61,9 @@ import (
|
|||
"k8s.io/kubernetes/pkg/kubelet/server"
|
||||
kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
certutil "k8s.io/kubernetes/pkg/util/cert"
|
||||
utilconfig "k8s.io/kubernetes/pkg/util/config"
|
||||
"k8s.io/kubernetes/pkg/util/configz"
|
||||
"k8s.io/kubernetes/pkg/util/crypto"
|
||||
"k8s.io/kubernetes/pkg/util/flock"
|
||||
kubeio "k8s.io/kubernetes/pkg/util/io"
|
||||
"k8s.io/kubernetes/pkg/util/mount"
|
||||
|
@ -486,8 +486,8 @@ func InitializeTLS(kc *componentconfig.KubeletConfiguration) (*server.TLSOptions
|
|||
if kc.TLSCertFile == "" && kc.TLSPrivateKeyFile == "" {
|
||||
kc.TLSCertFile = path.Join(kc.CertDirectory, "kubelet.crt")
|
||||
kc.TLSPrivateKeyFile = path.Join(kc.CertDirectory, "kubelet.key")
|
||||
if !crypto.FoundCertOrKey(kc.TLSCertFile, kc.TLSPrivateKeyFile) {
|
||||
if err := crypto.GenerateSelfSignedCert(nodeutil.GetHostname(kc.HostnameOverride), kc.TLSCertFile, kc.TLSPrivateKeyFile, nil, nil); err != nil {
|
||||
if !certutil.CanReadCertOrKey(kc.TLSCertFile, kc.TLSPrivateKeyFile) {
|
||||
if err := certutil.GenerateSelfSignedCert(nodeutil.GetHostname(kc.HostnameOverride), kc.TLSCertFile, kc.TLSPrivateKeyFile, nil, nil); err != nil {
|
||||
return nil, fmt.Errorf("unable to generate self signed cert: %v", err)
|
||||
}
|
||||
glog.V(4).Infof("Using self-signed cert (%s, %s)", kc.TLSCertFile, kc.TLSPrivateKeyFile)
|
||||
|
|
|
@ -59,7 +59,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/healthz"
|
||||
quotainstall "k8s.io/kubernetes/pkg/quota/install"
|
||||
"k8s.io/kubernetes/pkg/serviceaccount"
|
||||
"k8s.io/kubernetes/pkg/util/crypto"
|
||||
certutil "k8s.io/kubernetes/pkg/util/cert"
|
||||
"k8s.io/kubernetes/pkg/util/wait"
|
||||
|
||||
"k8s.io/kubernetes/contrib/mesos/pkg/profile"
|
||||
|
@ -315,7 +315,7 @@ func (s *CMServer) Run(_ []string) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("error reading root-ca-file at %s: %v", s.RootCAFile, err)
|
||||
}
|
||||
if _, err := crypto.CertsFromPEM(rootCA); err != nil {
|
||||
if _, err := certutil.ParseCertsPEM(rootCA); err != nil {
|
||||
return fmt.Errorf("error parsing root-ca-file at %s: %v", s.RootCAFile, err)
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -156,9 +156,8 @@ pkg/storage
|
|||
pkg/storage/etcd3
|
||||
pkg/storage/storagebackend/factory
|
||||
pkg/util/async
|
||||
pkg/util/certificates
|
||||
pkg/util/cert
|
||||
pkg/util/codeinspector
|
||||
pkg/util/crypto
|
||||
pkg/util/flock
|
||||
pkg/util/flushwriter
|
||||
pkg/util/goroutinemap
|
||||
|
|
|
@ -21,7 +21,7 @@ import (
|
|||
|
||||
apivalidation "k8s.io/kubernetes/pkg/api/validation"
|
||||
"k8s.io/kubernetes/pkg/apis/certificates"
|
||||
certutil "k8s.io/kubernetes/pkg/util/certificates"
|
||||
certutil "k8s.io/kubernetes/pkg/util/cert"
|
||||
"k8s.io/kubernetes/pkg/util/validation/field"
|
||||
)
|
||||
|
||||
|
@ -29,7 +29,7 @@ import (
|
|||
// PEM-encoded PKCS#10 certificate signing request. If this is invalid, we must
|
||||
// not accept the CSR for further processing.
|
||||
func validateCSR(obj *certificates.CertificateSigningRequest) error {
|
||||
csr, err := certutil.ParseCertificateRequestObject(obj)
|
||||
csr, err := certutil.ParseCSR(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/auth/authenticator"
|
||||
"k8s.io/kubernetes/pkg/auth/authenticator/bearertoken"
|
||||
"k8s.io/kubernetes/pkg/serviceaccount"
|
||||
"k8s.io/kubernetes/pkg/util/crypto"
|
||||
certutil "k8s.io/kubernetes/pkg/util/cert"
|
||||
"k8s.io/kubernetes/plugin/pkg/auth/authenticator/password/keystone"
|
||||
"k8s.io/kubernetes/plugin/pkg/auth/authenticator/password/passwordfile"
|
||||
"k8s.io/kubernetes/plugin/pkg/auth/authenticator/request/basicauth"
|
||||
|
@ -183,7 +183,7 @@ func newServiceAccountAuthenticator(keyfile string, lookup bool, serviceAccountG
|
|||
|
||||
// newAuthenticatorFromClientCAFile returns an authenticator.Request or an error
|
||||
func newAuthenticatorFromClientCAFile(clientCAFile string) (authenticator.Request, error) {
|
||||
roots, err := crypto.CertPoolFromFile(clientCAFile)
|
||||
roots, err := certutil.NewPool(clientCAFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/util/crypto"
|
||||
certutil "k8s.io/kubernetes/pkg/util/cert"
|
||||
"k8s.io/kubernetes/pkg/util/flowcontrol"
|
||||
"k8s.io/kubernetes/pkg/version"
|
||||
)
|
||||
|
@ -261,7 +261,7 @@ func InClusterConfig() (*Config, error) {
|
|||
}
|
||||
tlsClientConfig := TLSClientConfig{}
|
||||
rootCAFile := "/var/run/secrets/kubernetes.io/serviceaccount/" + api.ServiceAccountRootCAKey
|
||||
if _, err := crypto.CertPoolFromFile(rootCAFile); err != nil {
|
||||
if _, err := certutil.NewPool(rootCAFile); err != nil {
|
||||
glog.Errorf("Expected to load root CA config from %s, but got err: %v", rootCAFile, err)
|
||||
} else {
|
||||
tlsClientConfig.CAFile = rootCAFile
|
||||
|
|
|
@ -30,7 +30,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/client/record"
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
utilcertificates "k8s.io/kubernetes/pkg/util/certificates"
|
||||
certutil "k8s.io/kubernetes/pkg/util/cert"
|
||||
utilruntime "k8s.io/kubernetes/pkg/util/runtime"
|
||||
"k8s.io/kubernetes/pkg/util/wait"
|
||||
"k8s.io/kubernetes/pkg/util/workqueue"
|
||||
|
@ -241,7 +241,7 @@ func (cc *CertificateController) maybeAutoApproveCSR(csr *certificates.Certifica
|
|||
return csr, nil
|
||||
}
|
||||
|
||||
x509cr, err := utilcertificates.ParseCertificateRequestObject(csr)
|
||||
x509cr, err := certutil.ParseCSR(csr)
|
||||
if err != nil {
|
||||
utilruntime.HandleError(fmt.Errorf("unable to parse csr %q: %v", csr.Name, err))
|
||||
return csr, nil
|
||||
|
|
|
@ -45,7 +45,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/genericapiserver/options"
|
||||
"k8s.io/kubernetes/pkg/registry/generic"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/util/crypto"
|
||||
certutil "k8s.io/kubernetes/pkg/util/cert"
|
||||
utilnet "k8s.io/kubernetes/pkg/util/net"
|
||||
utilruntime "k8s.io/kubernetes/pkg/util/runtime"
|
||||
"k8s.io/kubernetes/pkg/util/sets"
|
||||
|
@ -291,7 +291,7 @@ func (s *GenericAPIServer) Run(options *options.ServerRunOptions) {
|
|||
}
|
||||
|
||||
if len(options.ClientCAFile) > 0 {
|
||||
clientCAs, err := crypto.CertPoolFromFile(options.ClientCAFile)
|
||||
clientCAs, err := certutil.NewPool(options.ClientCAFile)
|
||||
if err != nil {
|
||||
glog.Fatalf("Unable to load client CA file: %v", err)
|
||||
}
|
||||
|
@ -311,8 +311,8 @@ func (s *GenericAPIServer) Run(options *options.ServerRunOptions) {
|
|||
alternateDNS := []string{"kubernetes.default.svc", "kubernetes.default", "kubernetes"}
|
||||
// It would be nice to set a fqdn subject alt name, but only the kubelets know, the apiserver is clueless
|
||||
// alternateDNS = append(alternateDNS, "kubernetes.default.svc.CLUSTER.DNS.NAME")
|
||||
if !crypto.FoundCertOrKey(options.TLSCertFile, options.TLSPrivateKeyFile) {
|
||||
if err := crypto.GenerateSelfSignedCert(s.ClusterIP.String(), options.TLSCertFile, options.TLSPrivateKeyFile, alternateIPs, alternateDNS); err != nil {
|
||||
if !certutil.CanReadCertOrKey(options.TLSCertFile, options.TLSPrivateKeyFile) {
|
||||
if err := certutil.GenerateSelfSignedCert(s.ClusterIP.String(), options.TLSCertFile, options.TLSPrivateKeyFile, alternateIPs, alternateDNS); err != nil {
|
||||
glog.Errorf("Unable to generate self signed cert: %v", err)
|
||||
} else {
|
||||
glog.Infof("Using self-signed cert (%s, %s)", options.TLSCertFile, options.TLSPrivateKeyFile)
|
||||
|
|
|
@ -48,7 +48,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/kubelet/qos"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
"k8s.io/kubernetes/pkg/types"
|
||||
utilcertificates "k8s.io/kubernetes/pkg/util/certificates"
|
||||
certutil "k8s.io/kubernetes/pkg/util/cert"
|
||||
"k8s.io/kubernetes/pkg/util/intstr"
|
||||
"k8s.io/kubernetes/pkg/util/sets"
|
||||
|
||||
|
@ -1965,7 +1965,7 @@ func (p *CertificateSigningRequestDescriber) Describe(namespace, name string, de
|
|||
return "", err
|
||||
}
|
||||
|
||||
cr, err := utilcertificates.ParseCertificateRequestObject(csr)
|
||||
cr, err := certutil.ParseCSR(csr)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Error parsing CSR: %v", err)
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/apis/certificates"
|
||||
unversionedcertificates "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/certificates/unversioned"
|
||||
"k8s.io/kubernetes/pkg/fields"
|
||||
utilcertificates "k8s.io/kubernetes/pkg/util/certificates"
|
||||
certutil "k8s.io/kubernetes/pkg/util/cert"
|
||||
"k8s.io/kubernetes/pkg/watch"
|
||||
)
|
||||
|
||||
|
@ -39,11 +39,11 @@ func RequestNodeCertificate(client unversionedcertificates.CertificateSigningReq
|
|||
CommonName: fmt.Sprintf("system:node:%s", nodeName),
|
||||
}
|
||||
|
||||
privateKey, err := utilcertificates.ParsePrivateKey(privateKeyData)
|
||||
privateKey, err := certutil.ParsePrivateKeyPEM(privateKeyData)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid private key for certificate request: %v", err)
|
||||
}
|
||||
csr, err := utilcertificates.NewCertificateRequest(privateKey, subject, nil, nil)
|
||||
csr, err := certutil.MakeCSR(privateKey, subject, nil, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to generate certificate request: %v", err)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cert
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
cryptorand "crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
rsaKeySize = 2048
|
||||
duration365d = time.Hour * 24 * 365
|
||||
)
|
||||
|
||||
// Config containes the basic fields required for creating a certificate
|
||||
type Config struct {
|
||||
CommonName string
|
||||
Organization []string
|
||||
AltNames AltNames
|
||||
}
|
||||
|
||||
// AltNames contains the domain names and IP addresses that will be added
|
||||
// to the API Server's x509 certificate SubAltNames field. The values will
|
||||
// be passed directly to the x509.Certificate object.
|
||||
type AltNames struct {
|
||||
DNSNames []string
|
||||
IPs []net.IP
|
||||
}
|
||||
|
||||
// NewPrivateKey creates an RSA private key
|
||||
func NewPrivateKey() (*rsa.PrivateKey, error) {
|
||||
return rsa.GenerateKey(cryptorand.Reader, rsaKeySize)
|
||||
}
|
||||
|
||||
// NewSelfSignedCACert creates a CA certificate
|
||||
func NewSelfSignedCACert(cfg Config, key *rsa.PrivateKey) (*x509.Certificate, error) {
|
||||
now := time.Now()
|
||||
tmpl := x509.Certificate{
|
||||
SerialNumber: new(big.Int).SetInt64(0),
|
||||
Subject: pkix.Name{
|
||||
CommonName: cfg.CommonName,
|
||||
Organization: cfg.Organization,
|
||||
},
|
||||
NotBefore: now.UTC(),
|
||||
NotAfter: now.Add(duration365d * 10).UTC(),
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
|
||||
BasicConstraintsValid: true,
|
||||
IsCA: true,
|
||||
}
|
||||
|
||||
certDERBytes, err := x509.CreateCertificate(cryptorand.Reader, &tmpl, &tmpl, key.Public(), key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return x509.ParseCertificate(certDERBytes)
|
||||
}
|
||||
|
||||
// NewSignedCert creates a signed certificate using the given CA certificate and key
|
||||
func NewSignedCert(cfg Config, key *rsa.PrivateKey, caCert *x509.Certificate, caKey *rsa.PrivateKey) (*x509.Certificate, error) {
|
||||
serial, err := cryptorand.Int(cryptorand.Reader, new(big.Int).SetInt64(math.MaxInt64))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
certTmpl := x509.Certificate{
|
||||
Subject: pkix.Name{
|
||||
CommonName: cfg.CommonName,
|
||||
Organization: caCert.Subject.Organization,
|
||||
},
|
||||
DNSNames: cfg.AltNames.DNSNames,
|
||||
IPAddresses: cfg.AltNames.IPs,
|
||||
SerialNumber: serial,
|
||||
NotBefore: caCert.NotBefore,
|
||||
NotAfter: time.Now().Add(duration365d).UTC(),
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
|
||||
}
|
||||
certDERBytes, err := x509.CreateCertificate(cryptorand.Reader, &certTmpl, caCert, key.Public(), caKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return x509.ParseCertificate(certDERBytes)
|
||||
}
|
||||
|
||||
// MakeEllipticPrivateKeyPEM creates an ECDSA private key
|
||||
func MakeEllipticPrivateKeyPEM() ([]byte, error) {
|
||||
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), cryptorand.Reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
derBytes, err := x509.MarshalECPrivateKey(privateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
privateKeyPemBlock := &pem.Block{
|
||||
Type: "EC PRIVATE KEY",
|
||||
Bytes: derBytes,
|
||||
}
|
||||
return pem.EncodeToMemory(privateKeyPemBlock), nil
|
||||
}
|
||||
|
||||
// GenerateSelfSignedCert creates a self-signed certificate and key for the given host.
|
||||
// Host may be an IP or a DNS name
|
||||
// You may also specify additional subject alt names (either ip or dns names) for the certificate
|
||||
// The certificate will be created with file mode 0644. The key will be created with file mode 0600.
|
||||
// If the certificate or key files already exist, they will be overwritten.
|
||||
// Any parent directories of the certPath or keyPath will be created as needed with file mode 0755.
|
||||
func GenerateSelfSignedCert(host, certPath, keyPath string, alternateIPs []net.IP, alternateDNS []string) error {
|
||||
priv, err := rsa.GenerateKey(cryptorand.Reader, 2048)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
template := x509.Certificate{
|
||||
SerialNumber: big.NewInt(1),
|
||||
Subject: pkix.Name{
|
||||
CommonName: fmt.Sprintf("%s@%d", host, time.Now().Unix()),
|
||||
},
|
||||
NotBefore: time.Now(),
|
||||
NotAfter: time.Now().Add(time.Hour * 24 * 365),
|
||||
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
BasicConstraintsValid: true,
|
||||
IsCA: true,
|
||||
}
|
||||
|
||||
if ip := net.ParseIP(host); ip != nil {
|
||||
template.IPAddresses = append(template.IPAddresses, ip)
|
||||
} else {
|
||||
template.DNSNames = append(template.DNSNames, host)
|
||||
}
|
||||
|
||||
template.IPAddresses = append(template.IPAddresses, alternateIPs...)
|
||||
template.DNSNames = append(template.DNSNames, alternateDNS...)
|
||||
|
||||
derBytes, err := x509.CreateCertificate(cryptorand.Reader, &template, &template, &priv.PublicKey, priv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Generate cert
|
||||
certBuffer := bytes.Buffer{}
|
||||
if err := pem.Encode(&certBuffer, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Generate key
|
||||
keyBuffer := bytes.Buffer{}
|
||||
if err := pem.Encode(&keyBuffer, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := WriteCert(certPath, certBuffer.Bytes()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := WriteKey(keyPath, keyBuffer.Bytes()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package certificates
|
||||
package cert
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
|
@ -31,8 +31,8 @@ import (
|
|||
"k8s.io/kubernetes/pkg/apis/certificates"
|
||||
)
|
||||
|
||||
// ParseCertificateRequestObject extracts the CSR from the API object and decodes it.
|
||||
func ParseCertificateRequestObject(obj *certificates.CertificateSigningRequest) (*x509.CertificateRequest, error) {
|
||||
// ParseCSR extracts the CSR from the API object and decodes it.
|
||||
func ParseCSR(obj *certificates.CertificateSigningRequest) (*x509.CertificateRequest, error) {
|
||||
// extract PEM from request object
|
||||
pemBytes := obj.Spec.Request
|
||||
block, _ := pem.Decode(pemBytes)
|
||||
|
@ -46,48 +46,9 @@ func ParseCertificateRequestObject(obj *certificates.CertificateSigningRequest)
|
|||
return csr, nil
|
||||
}
|
||||
|
||||
// GeneratePrivateKey returns PEM data containing a generated ECDSA private key
|
||||
func GeneratePrivateKey() ([]byte, error) {
|
||||
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), cryptorand.Reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
derBytes, err := x509.MarshalECPrivateKey(privateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
privateKeyPemBlock := &pem.Block{
|
||||
Type: "EC PRIVATE KEY",
|
||||
Bytes: derBytes,
|
||||
}
|
||||
return pem.EncodeToMemory(privateKeyPemBlock), nil
|
||||
}
|
||||
|
||||
// ParsePrivateKey returns a private key parsed from a PEM block in the supplied data.
|
||||
// Recognizes PEM blocks for "EC PRIVATE KEY" and "RSA PRIVATE KEY"
|
||||
func ParsePrivateKey(keyData []byte) (interface{}, error) {
|
||||
for {
|
||||
var privateKeyPemBlock *pem.Block
|
||||
privateKeyPemBlock, keyData = pem.Decode(keyData)
|
||||
if privateKeyPemBlock == nil {
|
||||
// we read all the PEM blocks and didn't recognize one
|
||||
return nil, fmt.Errorf("no private key PEM block found")
|
||||
}
|
||||
|
||||
switch privateKeyPemBlock.Type {
|
||||
case "EC PRIVATE KEY":
|
||||
return x509.ParseECPrivateKey(privateKeyPemBlock.Bytes)
|
||||
case "RSA PRIVATE KEY":
|
||||
return x509.ParsePKCS1PrivateKey(privateKeyPemBlock.Bytes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NewCertificateRequest generates a PEM-encoded CSR using the supplied private key, subject, and SANs.
|
||||
// MakeCSR generates a PEM-encoded CSR using the supplied private key, subject, and SANs.
|
||||
// privateKey must be a *ecdsa.PrivateKey or *rsa.PrivateKey.
|
||||
func NewCertificateRequest(privateKey interface{}, subject *pkix.Name, dnsSANs []string, ipSANs []net.IP) (csr []byte, err error) {
|
||||
func MakeCSR(privateKey interface{}, subject *pkix.Name, dnsSANs []string, ipSANs []net.IP) (csr []byte, err error) {
|
||||
var sigType x509.SignatureAlgorithm
|
||||
|
||||
switch privateKey := privateKey.(type) {
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package certificates
|
||||
package cert
|
||||
|
||||
import (
|
||||
"crypto/x509/pkix"
|
||||
|
@ -23,7 +23,7 @@ import (
|
|||
"testing"
|
||||
)
|
||||
|
||||
func TestNewCertificateRequest(t *testing.T) {
|
||||
func TestMakeCSR(t *testing.T) {
|
||||
keyFile := "testdata/dontUseThisKey.pem"
|
||||
subject := &pkix.Name{
|
||||
CommonName: "kube-worker",
|
||||
|
@ -35,11 +35,11 @@ func TestNewCertificateRequest(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
key, err := ParsePrivateKey(keyData)
|
||||
key, err := ParsePrivateKeyPEM(keyData)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = NewCertificateRequest(key, subject, dnsSANs, ipSANs)
|
||||
_, err = MakeCSR(key, subject, dnsSANs, ipSANs)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cert
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// CanReadCertOrKey returns true if the certificate or key files already exists,
|
||||
// otherwise returns false.
|
||||
func CanReadCertOrKey(certPath, keyPath string) bool {
|
||||
if canReadFile(certPath) || canReadFile(keyPath) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// If the file represented by path exists and
|
||||
// readable, returns true otherwise returns false.
|
||||
func canReadFile(path string) bool {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
defer f.Close()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// WriteCert writes the pem-encoded certificate data to certPath.
|
||||
// The certificate file will be created with file mode 0644.
|
||||
// If the certificate file already exists, it will be overwritten.
|
||||
// The parent directory of the certPath will be created as needed with file mode 0755.
|
||||
func WriteCert(certPath string, data []byte) error {
|
||||
if err := os.MkdirAll(filepath.Dir(certPath), os.FileMode(0755)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ioutil.WriteFile(certPath, data, os.FileMode(0644)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteKey writes the pem-encoded key data to keyPath.
|
||||
// The key file will be created with file mode 0600.
|
||||
// If the key file already exists, it will be overwritten.
|
||||
// The parent directory of the keyPath will be created as needed with file mode 0755.
|
||||
func WriteKey(keyPath string, data []byte) error {
|
||||
if err := os.MkdirAll(filepath.Dir(keyPath), os.FileMode(0755)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ioutil.WriteFile(keyPath, data, os.FileMode(0600)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewPool returns an x509.CertPool containing the certificates in the given PEM-encoded file.
|
||||
// Returns an error if the file could not be read, a certificate could not be parsed, or if the file does not contain any certificates
|
||||
func NewPool(filename string) (*x509.CertPool, error) {
|
||||
certs, err := certsFromFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pool := x509.NewCertPool()
|
||||
for _, cert := range certs {
|
||||
pool.AddCert(cert)
|
||||
}
|
||||
return pool, nil
|
||||
}
|
||||
|
||||
// certsFromFile returns the x509.Certificates contained in the given PEM-encoded file.
|
||||
// Returns an error if the file could not be read, a certificate could not be parsed, or if the file does not contain any certificates
|
||||
func certsFromFile(file string) ([]*x509.Certificate, error) {
|
||||
if len(file) == 0 {
|
||||
return nil, errors.New("error reading certificates from an empty filename")
|
||||
}
|
||||
pemBlock, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
certs, err := ParseCertsPEM(pemBlock)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading %s: %s", file, err)
|
||||
}
|
||||
return certs, nil
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cert
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// EncodePublicKeyPEM returns PEM-endcode public data
|
||||
func EncodePublicKeyPEM(key *rsa.PublicKey) ([]byte, error) {
|
||||
der, err := x509.MarshalPKIXPublicKey(key)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
block := pem.Block{
|
||||
Type: "PUBLIC KEY",
|
||||
Bytes: der,
|
||||
}
|
||||
return pem.EncodeToMemory(&block), nil
|
||||
}
|
||||
|
||||
// EncodePrivateKeyPEM returns PEM-encoded private key data
|
||||
func EncodePrivateKeyPEM(key *rsa.PrivateKey) []byte {
|
||||
block := pem.Block{
|
||||
Type: "RSA PRIVATE KEY",
|
||||
Bytes: x509.MarshalPKCS1PrivateKey(key),
|
||||
}
|
||||
return pem.EncodeToMemory(&block)
|
||||
}
|
||||
|
||||
// EncodeCertPEM returns PEM-endcoded certificate data
|
||||
func EncodeCertPEM(cert *x509.Certificate) []byte {
|
||||
block := pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: cert.Raw,
|
||||
}
|
||||
return pem.EncodeToMemory(&block)
|
||||
}
|
||||
|
||||
// ParsePrivateKeyPEM returns a private key parsed from a PEM block in the supplied data.
|
||||
// Recognizes PEM blocks for "EC PRIVATE KEY" and "RSA PRIVATE KEY"
|
||||
func ParsePrivateKeyPEM(keyData []byte) (interface{}, error) {
|
||||
for {
|
||||
var privateKeyPemBlock *pem.Block
|
||||
privateKeyPemBlock, keyData = pem.Decode(keyData)
|
||||
if privateKeyPemBlock == nil {
|
||||
// we read all the PEM blocks and didn't recognize one
|
||||
return nil, fmt.Errorf("no private key PEM block found")
|
||||
}
|
||||
|
||||
switch privateKeyPemBlock.Type {
|
||||
case "EC PRIVATE KEY":
|
||||
return x509.ParseECPrivateKey(privateKeyPemBlock.Bytes)
|
||||
case "RSA PRIVATE KEY":
|
||||
return x509.ParsePKCS1PrivateKey(privateKeyPemBlock.Bytes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ParseCertsPEM returns the x509.Certificates contained in the given PEM-encoded byte array
|
||||
// Returns an error if a certificate could not be parsed, or if the data does not contain any certificates
|
||||
func ParseCertsPEM(pemCerts []byte) ([]*x509.Certificate, error) {
|
||||
ok := false
|
||||
certs := []*x509.Certificate{}
|
||||
for len(pemCerts) > 0 {
|
||||
var block *pem.Block
|
||||
block, pemCerts = pem.Decode(pemCerts)
|
||||
if block == nil {
|
||||
break
|
||||
}
|
||||
// Only use PEM "CERTIFICATE" blocks without extra headers
|
||||
if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
cert, err := x509.ParseCertificate(block.Bytes)
|
||||
if err != nil {
|
||||
return certs, err
|
||||
}
|
||||
|
||||
certs = append(certs, cert)
|
||||
ok = true
|
||||
}
|
||||
|
||||
if !ok {
|
||||
return certs, errors.New("could not read any certificates")
|
||||
}
|
||||
return certs, nil
|
||||
}
|
|
@ -1,212 +0,0 @@
|
|||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
// FoundCertOrKey returns true if the certificate or key files already exists,
|
||||
// otherwise returns false.
|
||||
func FoundCertOrKey(certPath, keyPath string) bool {
|
||||
if canReadFile(certPath) || canReadFile(keyPath) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// If the file represented by path exists and
|
||||
// readable, returns true otherwise returns false.
|
||||
func canReadFile(path string) bool {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
defer f.Close()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// GenerateSelfSignedCert creates a self-signed certificate and key for the given host.
|
||||
// Host may be an IP or a DNS name
|
||||
// You may also specify additional subject alt names (either ip or dns names) for the certificate
|
||||
// The certificate will be created with file mode 0644. The key will be created with file mode 0600.
|
||||
// If the certificate or key files already exist, they will be overwritten.
|
||||
// Any parent directories of the certPath or keyPath will be created as needed with file mode 0755.
|
||||
func GenerateSelfSignedCert(host, certPath, keyPath string, alternateIPs []net.IP, alternateDNS []string) error {
|
||||
priv, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
template := x509.Certificate{
|
||||
SerialNumber: big.NewInt(1),
|
||||
Subject: pkix.Name{
|
||||
CommonName: fmt.Sprintf("%s@%d", host, time.Now().Unix()),
|
||||
},
|
||||
NotBefore: time.Now(),
|
||||
NotAfter: time.Now().Add(time.Hour * 24 * 365),
|
||||
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
BasicConstraintsValid: true,
|
||||
IsCA: true,
|
||||
}
|
||||
|
||||
if ip := net.ParseIP(host); ip != nil {
|
||||
template.IPAddresses = append(template.IPAddresses, ip)
|
||||
} else {
|
||||
template.DNSNames = append(template.DNSNames, host)
|
||||
}
|
||||
|
||||
template.IPAddresses = append(template.IPAddresses, alternateIPs...)
|
||||
template.DNSNames = append(template.DNSNames, alternateDNS...)
|
||||
|
||||
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Generate cert
|
||||
certBuffer := bytes.Buffer{}
|
||||
if err := pem.Encode(&certBuffer, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Generate key
|
||||
keyBuffer := bytes.Buffer{}
|
||||
if err := pem.Encode(&keyBuffer, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write cert
|
||||
if err := WriteCertToPath(certPath, certBuffer.Bytes()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write key
|
||||
if err := WriteKeyToPath(keyPath, keyBuffer.Bytes()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteCertToPath writes the pem-encoded certificate data to certPath.
|
||||
// The certificate file will be created with file mode 0644.
|
||||
// If the certificate file already exists, it will be overwritten.
|
||||
// The parent directory of the certPath will be created as needed with file mode 0755.
|
||||
func WriteCertToPath(certPath string, data []byte) error {
|
||||
if err := os.MkdirAll(filepath.Dir(certPath), os.FileMode(0755)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ioutil.WriteFile(certPath, data, os.FileMode(0644)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteKeyToPath writes the pem-encoded key data to keyPath.
|
||||
// The key file will be created with file mode 0600.
|
||||
// If the key file already exists, it will be overwritten.
|
||||
// The parent directory of the keyPath will be created as needed with file mode 0755.
|
||||
func WriteKeyToPath(keyPath string, data []byte) error {
|
||||
if err := os.MkdirAll(filepath.Dir(keyPath), os.FileMode(0755)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ioutil.WriteFile(keyPath, data, os.FileMode(0600)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CertPoolFromFile returns an x509.CertPool containing the certificates in the given PEM-encoded file.
|
||||
// Returns an error if the file could not be read, a certificate could not be parsed, or if the file does not contain any certificates
|
||||
func CertPoolFromFile(filename string) (*x509.CertPool, error) {
|
||||
certs, err := certificatesFromFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pool := x509.NewCertPool()
|
||||
for _, cert := range certs {
|
||||
pool.AddCert(cert)
|
||||
}
|
||||
return pool, nil
|
||||
}
|
||||
|
||||
// certificatesFromFile returns the x509.Certificates contained in the given PEM-encoded file.
|
||||
// Returns an error if the file could not be read, a certificate could not be parsed, or if the file does not contain any certificates
|
||||
func certificatesFromFile(file string) ([]*x509.Certificate, error) {
|
||||
if len(file) == 0 {
|
||||
return nil, errors.New("error reading certificates from an empty filename")
|
||||
}
|
||||
pemBlock, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
certs, err := CertsFromPEM(pemBlock)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading %s: %s", file, err)
|
||||
}
|
||||
return certs, nil
|
||||
}
|
||||
|
||||
// CertsFromPEM returns the x509.Certificates contained in the given PEM-encoded byte array
|
||||
// Returns an error if a certificate could not be parsed, or if the data does not contain any certificates
|
||||
func CertsFromPEM(pemCerts []byte) ([]*x509.Certificate, error) {
|
||||
ok := false
|
||||
certs := []*x509.Certificate{}
|
||||
for len(pemCerts) > 0 {
|
||||
var block *pem.Block
|
||||
block, pemCerts = pem.Decode(pemCerts)
|
||||
if block == nil {
|
||||
break
|
||||
}
|
||||
// Only use PEM "CERTIFICATE" blocks without extra headers
|
||||
if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
cert, err := x509.ParseCertificate(block.Bytes)
|
||||
if err != nil {
|
||||
return certs, err
|
||||
}
|
||||
|
||||
certs = append(certs, cert)
|
||||
ok = true
|
||||
}
|
||||
|
||||
if !ok {
|
||||
return certs, errors.New("could not read any certificates")
|
||||
}
|
||||
return certs, nil
|
||||
}
|
|
@ -40,7 +40,7 @@ import (
|
|||
"github.com/coreos/go-oidc/oidc"
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/kubernetes/pkg/auth/user"
|
||||
"k8s.io/kubernetes/pkg/util/crypto"
|
||||
certutil "k8s.io/kubernetes/pkg/util/cert"
|
||||
"k8s.io/kubernetes/pkg/util/net"
|
||||
"k8s.io/kubernetes/pkg/util/runtime"
|
||||
)
|
||||
|
@ -112,7 +112,7 @@ func New(opts OIDCOptions) (*OIDCAuthenticator, error) {
|
|||
|
||||
var roots *x509.CertPool
|
||||
if opts.CAFile != "" {
|
||||
roots, err = crypto.CertPoolFromFile(opts.CAFile)
|
||||
roots, err = certutil.NewPool(opts.CAFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to read the CA file: %v", err)
|
||||
}
|
||||
|
|
|
@ -826,7 +826,7 @@ k8s.io/kubernetes/pkg/util/async,spxtr,1
|
|||
k8s.io/kubernetes/pkg/util/atomic,kargakis,1
|
||||
k8s.io/kubernetes/pkg/util/bandwidth,thockin,1
|
||||
k8s.io/kubernetes/pkg/util/cache,thockin,1
|
||||
k8s.io/kubernetes/pkg/util/certificates,karlkfi,1
|
||||
k8s.io/kubernetes/pkg/util/cert,karlkfi,1
|
||||
k8s.io/kubernetes/pkg/util/clock,zmerlynn,1
|
||||
k8s.io/kubernetes/pkg/util/config,girishkalele,1
|
||||
k8s.io/kubernetes/pkg/util/configz,ixdy,1
|
||||
|
|
|
Loading…
Reference in New Issue