mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-11-03 23:40:03 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			507 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			507 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
/*
 | 
						||
Copyright 2016 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 pkiutil
 | 
						||
 | 
						||
import (
 | 
						||
	"crypto"
 | 
						||
	cryptorand "crypto/rand"
 | 
						||
	"crypto/rsa"
 | 
						||
	"crypto/x509"
 | 
						||
	"crypto/x509/pkix"
 | 
						||
	"encoding/pem"
 | 
						||
	"fmt"
 | 
						||
	"io/ioutil"
 | 
						||
	"net"
 | 
						||
	"os"
 | 
						||
	"path/filepath"
 | 
						||
	"time"
 | 
						||
 | 
						||
	"github.com/pkg/errors"
 | 
						||
 | 
						||
	"k8s.io/apimachinery/pkg/util/validation"
 | 
						||
	certutil "k8s.io/client-go/util/cert"
 | 
						||
	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
 | 
						||
	kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
 | 
						||
	kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
 | 
						||
	"k8s.io/kubernetes/pkg/registry/core/service/ipallocator"
 | 
						||
)
 | 
						||
 | 
						||
// NewCertificateAuthority creates new certificate and private key for the certificate authority
 | 
						||
func NewCertificateAuthority(config *certutil.Config) (*x509.Certificate, *rsa.PrivateKey, error) {
 | 
						||
	key, err := certutil.NewPrivateKey()
 | 
						||
	if err != nil {
 | 
						||
		return nil, nil, errors.Wrap(err, "unable to create private key")
 | 
						||
	}
 | 
						||
 | 
						||
	cert, err := certutil.NewSelfSignedCACert(*config, key)
 | 
						||
	if err != nil {
 | 
						||
		return nil, nil, errors.Wrap(err, "unable to create self-signed certificate")
 | 
						||
	}
 | 
						||
 | 
						||
	return cert, key, nil
 | 
						||
}
 | 
						||
 | 
						||
// NewCertAndKey creates new certificate and key by passing the certificate authority certificate and key
 | 
						||
func NewCertAndKey(caCert *x509.Certificate, caKey *rsa.PrivateKey, config *certutil.Config) (*x509.Certificate, *rsa.PrivateKey, error) {
 | 
						||
	key, err := certutil.NewPrivateKey()
 | 
						||
	if err != nil {
 | 
						||
		return nil, nil, errors.Wrap(err, "unable to create private key")
 | 
						||
	}
 | 
						||
 | 
						||
	cert, err := certutil.NewSignedCert(*config, key, caCert, caKey)
 | 
						||
	if err != nil {
 | 
						||
		return nil, nil, errors.Wrap(err, "unable to sign certificate")
 | 
						||
	}
 | 
						||
 | 
						||
	return cert, key, nil
 | 
						||
}
 | 
						||
 | 
						||
// NewCSRAndKey generates a new key and CSR and that could be signed to create the given certificate
 | 
						||
func NewCSRAndKey(config *certutil.Config) (*x509.CertificateRequest, *rsa.PrivateKey, error) {
 | 
						||
	key, err := certutil.NewPrivateKey()
 | 
						||
	if err != nil {
 | 
						||
		return nil, nil, errors.Wrap(err, "unable to create private key")
 | 
						||
	}
 | 
						||
 | 
						||
	csr, err := NewCSR(*config, key)
 | 
						||
	if err != nil {
 | 
						||
		return nil, nil, errors.Wrap(err, "unable to generate CSR")
 | 
						||
	}
 | 
						||
 | 
						||
	return csr, key, nil
 | 
						||
}
 | 
						||
 | 
						||
// HasServerAuth returns true if the given certificate is a ServerAuth
 | 
						||
func HasServerAuth(cert *x509.Certificate) bool {
 | 
						||
	for i := range cert.ExtKeyUsage {
 | 
						||
		if cert.ExtKeyUsage[i] == x509.ExtKeyUsageServerAuth {
 | 
						||
			return true
 | 
						||
		}
 | 
						||
	}
 | 
						||
	return false
 | 
						||
}
 | 
						||
 | 
						||
// WriteCertAndKey stores certificate and key at the specified location
 | 
						||
func WriteCertAndKey(pkiPath string, name string, cert *x509.Certificate, key *rsa.PrivateKey) error {
 | 
						||
	if err := WriteKey(pkiPath, name, key); err != nil {
 | 
						||
		return errors.Wrap(err, "couldn't write key")
 | 
						||
	}
 | 
						||
 | 
						||
	return WriteCert(pkiPath, name, cert)
 | 
						||
}
 | 
						||
 | 
						||
// WriteCert stores the given certificate at the given location
 | 
						||
func WriteCert(pkiPath, name string, cert *x509.Certificate) error {
 | 
						||
	if cert == nil {
 | 
						||
		return errors.New("certificate cannot be nil when writing to file")
 | 
						||
	}
 | 
						||
 | 
						||
	certificatePath := pathForCert(pkiPath, name)
 | 
						||
	if err := certutil.WriteCert(certificatePath, certutil.EncodeCertPEM(cert)); err != nil {
 | 
						||
		return errors.Wrapf(err, "unable to write certificate to file %s", certificatePath)
 | 
						||
	}
 | 
						||
 | 
						||
	return nil
 | 
						||
}
 | 
						||
 | 
						||
// WriteKey stores the given key at the given location
 | 
						||
func WriteKey(pkiPath, name string, key *rsa.PrivateKey) error {
 | 
						||
	if key == nil {
 | 
						||
		return errors.New("private key cannot be nil when writing to file")
 | 
						||
	}
 | 
						||
 | 
						||
	privateKeyPath := pathForKey(pkiPath, name)
 | 
						||
	if err := certutil.WriteKey(privateKeyPath, certutil.EncodePrivateKeyPEM(key)); err != nil {
 | 
						||
		return errors.Wrapf(err, "unable to write private key to file %s", privateKeyPath)
 | 
						||
	}
 | 
						||
 | 
						||
	return nil
 | 
						||
}
 | 
						||
 | 
						||
// WriteCSR writes the pem-encoded CSR data to csrPath.
 | 
						||
// The CSR file will be created with file mode 0644.
 | 
						||
// If the CSR file already exists, it will be overwritten.
 | 
						||
// The parent directory of the csrPath will be created as needed with file mode 0755.
 | 
						||
func WriteCSR(csrDir, name string, csr *x509.CertificateRequest) error {
 | 
						||
	if csr == nil {
 | 
						||
		return errors.New("certificate request cannot be nil when writing to file")
 | 
						||
	}
 | 
						||
 | 
						||
	csrPath := pathForCSR(csrDir, name)
 | 
						||
	if err := os.MkdirAll(filepath.Dir(csrPath), os.FileMode(0755)); err != nil {
 | 
						||
		return errors.Wrapf(err, "failed to make directory %s", filepath.Dir(csrPath))
 | 
						||
	}
 | 
						||
 | 
						||
	if err := ioutil.WriteFile(csrPath, EncodeCSRPEM(csr), os.FileMode(0644)); err != nil {
 | 
						||
		return errors.Wrapf(err, "unable to write CSR to file %s", csrPath)
 | 
						||
	}
 | 
						||
 | 
						||
	return nil
 | 
						||
}
 | 
						||
 | 
						||
// WritePublicKey stores the given public key at the given location
 | 
						||
func WritePublicKey(pkiPath, name string, key *rsa.PublicKey) error {
 | 
						||
	if key == nil {
 | 
						||
		return errors.New("public key cannot be nil when writing to file")
 | 
						||
	}
 | 
						||
 | 
						||
	publicKeyBytes, err := certutil.EncodePublicKeyPEM(key)
 | 
						||
	if err != nil {
 | 
						||
		return err
 | 
						||
	}
 | 
						||
	publicKeyPath := pathForPublicKey(pkiPath, name)
 | 
						||
	if err := certutil.WriteKey(publicKeyPath, publicKeyBytes); err != nil {
 | 
						||
		return errors.Wrapf(err, "unable to write public key to file %s", publicKeyPath)
 | 
						||
	}
 | 
						||
 | 
						||
	return nil
 | 
						||
}
 | 
						||
 | 
						||
// CertOrKeyExist returns a boolean whether the cert or the key exists
 | 
						||
func CertOrKeyExist(pkiPath, name string) bool {
 | 
						||
	certificatePath, privateKeyPath := PathsForCertAndKey(pkiPath, name)
 | 
						||
 | 
						||
	_, certErr := os.Stat(certificatePath)
 | 
						||
	_, keyErr := os.Stat(privateKeyPath)
 | 
						||
	if os.IsNotExist(certErr) && os.IsNotExist(keyErr) {
 | 
						||
		// The cert or the key did not exist
 | 
						||
		return false
 | 
						||
	}
 | 
						||
 | 
						||
	// Both files exist or one of them
 | 
						||
	return true
 | 
						||
}
 | 
						||
 | 
						||
// CSROrKeyExist returns true if one of the CSR or key exists
 | 
						||
func CSROrKeyExist(csrDir, name string) bool {
 | 
						||
	csrPath := pathForCSR(csrDir, name)
 | 
						||
	keyPath := pathForKey(csrDir, name)
 | 
						||
 | 
						||
	_, csrErr := os.Stat(csrPath)
 | 
						||
	_, keyErr := os.Stat(keyPath)
 | 
						||
 | 
						||
	return !(os.IsNotExist(csrErr) && os.IsNotExist(keyErr))
 | 
						||
}
 | 
						||
 | 
						||
// TryLoadCertAndKeyFromDisk tries to load a cert and a key from the disk and validates that they are valid
 | 
						||
func TryLoadCertAndKeyFromDisk(pkiPath, name string) (*x509.Certificate, *rsa.PrivateKey, error) {
 | 
						||
	cert, err := TryLoadCertFromDisk(pkiPath, name)
 | 
						||
	if err != nil {
 | 
						||
		return nil, nil, errors.Wrap(err, "failed to load certificate")
 | 
						||
	}
 | 
						||
 | 
						||
	key, err := TryLoadKeyFromDisk(pkiPath, name)
 | 
						||
	if err != nil {
 | 
						||
		return nil, nil, errors.Wrap(err, "failed to load key")
 | 
						||
	}
 | 
						||
 | 
						||
	return cert, key, nil
 | 
						||
}
 | 
						||
 | 
						||
// TryLoadCertFromDisk tries to load the cert from the disk and validates that it is valid
 | 
						||
func TryLoadCertFromDisk(pkiPath, name string) (*x509.Certificate, error) {
 | 
						||
	certificatePath := pathForCert(pkiPath, name)
 | 
						||
 | 
						||
	certs, err := certutil.CertsFromFile(certificatePath)
 | 
						||
	if err != nil {
 | 
						||
		return nil, errors.Wrapf(err, "couldn't load the certificate file %s", certificatePath)
 | 
						||
	}
 | 
						||
 | 
						||
	// We are only putting one certificate in the certificate pem file, so it's safe to just pick the first one
 | 
						||
	// TODO: Support multiple certs here in order to be able to rotate certs
 | 
						||
	cert := certs[0]
 | 
						||
 | 
						||
	// Check so that the certificate is valid now
 | 
						||
	now := time.Now()
 | 
						||
	if now.Before(cert.NotBefore) {
 | 
						||
		return nil, errors.New("the certificate is not valid yet")
 | 
						||
	}
 | 
						||
	if now.After(cert.NotAfter) {
 | 
						||
		return nil, errors.New("the certificate has expired")
 | 
						||
	}
 | 
						||
 | 
						||
	return cert, nil
 | 
						||
}
 | 
						||
 | 
						||
// TryLoadKeyFromDisk tries to load the key from the disk and validates that it is valid
 | 
						||
func TryLoadKeyFromDisk(pkiPath, name string) (*rsa.PrivateKey, error) {
 | 
						||
	privateKeyPath := pathForKey(pkiPath, name)
 | 
						||
 | 
						||
	// Parse the private key from a file
 | 
						||
	privKey, err := certutil.PrivateKeyFromFile(privateKeyPath)
 | 
						||
	if err != nil {
 | 
						||
		return nil, errors.Wrapf(err, "couldn't load the private key file %s", privateKeyPath)
 | 
						||
	}
 | 
						||
 | 
						||
	// Allow RSA format only
 | 
						||
	var key *rsa.PrivateKey
 | 
						||
	switch k := privKey.(type) {
 | 
						||
	case *rsa.PrivateKey:
 | 
						||
		key = k
 | 
						||
	default:
 | 
						||
		return nil, errors.Errorf("the private key file %s isn't in RSA format", privateKeyPath)
 | 
						||
	}
 | 
						||
 | 
						||
	return key, nil
 | 
						||
}
 | 
						||
 | 
						||
// TryLoadCSRAndKeyFromDisk tries to load the CSR and key from the disk
 | 
						||
func TryLoadCSRAndKeyFromDisk(pkiPath, name string) (*x509.CertificateRequest, *rsa.PrivateKey, error) {
 | 
						||
	csrPath := pathForCSR(pkiPath, name)
 | 
						||
 | 
						||
	csr, err := CertificateRequestFromFile(csrPath)
 | 
						||
	if err != nil {
 | 
						||
		return nil, nil, errors.Wrapf(err, "couldn't load the certificate request %s", csrPath)
 | 
						||
	}
 | 
						||
 | 
						||
	key, err := TryLoadKeyFromDisk(pkiPath, name)
 | 
						||
	if err != nil {
 | 
						||
		return nil, nil, errors.Wrap(err, "couldn't load key file")
 | 
						||
	}
 | 
						||
 | 
						||
	return csr, key, nil
 | 
						||
}
 | 
						||
 | 
						||
// TryLoadPrivatePublicKeyFromDisk tries to load the key from the disk and validates that it is valid
 | 
						||
func TryLoadPrivatePublicKeyFromDisk(pkiPath, name string) (*rsa.PrivateKey, *rsa.PublicKey, error) {
 | 
						||
	privateKeyPath := pathForKey(pkiPath, name)
 | 
						||
 | 
						||
	// Parse the private key from a file
 | 
						||
	privKey, err := certutil.PrivateKeyFromFile(privateKeyPath)
 | 
						||
	if err != nil {
 | 
						||
		return nil, nil, errors.Wrapf(err, "couldn't load the private key file %s", privateKeyPath)
 | 
						||
	}
 | 
						||
 | 
						||
	publicKeyPath := pathForPublicKey(pkiPath, name)
 | 
						||
 | 
						||
	// Parse the public key from a file
 | 
						||
	pubKeys, err := certutil.PublicKeysFromFile(publicKeyPath)
 | 
						||
	if err != nil {
 | 
						||
		return nil, nil, errors.Wrapf(err, "couldn't load the public key file %s", publicKeyPath)
 | 
						||
	}
 | 
						||
 | 
						||
	// Allow RSA format only
 | 
						||
	k, ok := privKey.(*rsa.PrivateKey)
 | 
						||
	if !ok {
 | 
						||
		return nil, nil, errors.Errorf("the private key file %s isn't in RSA format", privateKeyPath)
 | 
						||
	}
 | 
						||
 | 
						||
	p := pubKeys[0].(*rsa.PublicKey)
 | 
						||
 | 
						||
	return k, p, nil
 | 
						||
}
 | 
						||
 | 
						||
// PathsForCertAndKey returns the paths for the certificate and key given the path and basename.
 | 
						||
func PathsForCertAndKey(pkiPath, name string) (string, string) {
 | 
						||
	return pathForCert(pkiPath, name), pathForKey(pkiPath, name)
 | 
						||
}
 | 
						||
 | 
						||
func pathForCert(pkiPath, name string) string {
 | 
						||
	return filepath.Join(pkiPath, fmt.Sprintf("%s.crt", name))
 | 
						||
}
 | 
						||
 | 
						||
func pathForKey(pkiPath, name string) string {
 | 
						||
	return filepath.Join(pkiPath, fmt.Sprintf("%s.key", name))
 | 
						||
}
 | 
						||
 | 
						||
func pathForPublicKey(pkiPath, name string) string {
 | 
						||
	return filepath.Join(pkiPath, fmt.Sprintf("%s.pub", name))
 | 
						||
}
 | 
						||
 | 
						||
func pathForCSR(pkiPath, name string) string {
 | 
						||
	return filepath.Join(pkiPath, fmt.Sprintf("%s.csr", name))
 | 
						||
}
 | 
						||
 | 
						||
// GetAPIServerAltNames builds an AltNames object for to be used when generating apiserver certificate
 | 
						||
func GetAPIServerAltNames(cfg *kubeadmapi.InitConfiguration) (*certutil.AltNames, error) {
 | 
						||
	// advertise address
 | 
						||
	advertiseAddress := net.ParseIP(cfg.LocalAPIEndpoint.AdvertiseAddress)
 | 
						||
	if advertiseAddress == nil {
 | 
						||
		return nil, errors.Errorf("error parsing LocalAPIEndpoint AdvertiseAddress %v: is not a valid textual representation of an IP address",
 | 
						||
			cfg.LocalAPIEndpoint.AdvertiseAddress)
 | 
						||
	}
 | 
						||
 | 
						||
	// internal IP address for the API server
 | 
						||
	_, svcSubnet, err := net.ParseCIDR(cfg.Networking.ServiceSubnet)
 | 
						||
	if err != nil {
 | 
						||
		return nil, errors.Wrapf(err, "error parsing CIDR %q", cfg.Networking.ServiceSubnet)
 | 
						||
	}
 | 
						||
 | 
						||
	internalAPIServerVirtualIP, err := ipallocator.GetIndexedIP(svcSubnet, 1)
 | 
						||
	if err != nil {
 | 
						||
		return nil, errors.Wrapf(err, "unable to get first IP address from the given CIDR (%s)", svcSubnet.String())
 | 
						||
	}
 | 
						||
 | 
						||
	// create AltNames with defaults DNSNames/IPs
 | 
						||
	altNames := &certutil.AltNames{
 | 
						||
		DNSNames: []string{
 | 
						||
			cfg.NodeRegistration.Name,
 | 
						||
			"kubernetes",
 | 
						||
			"kubernetes.default",
 | 
						||
			"kubernetes.default.svc",
 | 
						||
			fmt.Sprintf("kubernetes.default.svc.%s", cfg.Networking.DNSDomain),
 | 
						||
		},
 | 
						||
		IPs: []net.IP{
 | 
						||
			internalAPIServerVirtualIP,
 | 
						||
			advertiseAddress,
 | 
						||
		},
 | 
						||
	}
 | 
						||
 | 
						||
	// add cluster controlPlaneEndpoint if present (dns or ip)
 | 
						||
	if len(cfg.ControlPlaneEndpoint) > 0 {
 | 
						||
		if host, _, err := kubeadmutil.ParseHostPort(cfg.ControlPlaneEndpoint); err == nil {
 | 
						||
			if ip := net.ParseIP(host); ip != nil {
 | 
						||
				altNames.IPs = append(altNames.IPs, ip)
 | 
						||
			} else {
 | 
						||
				altNames.DNSNames = append(altNames.DNSNames, host)
 | 
						||
			}
 | 
						||
		} else {
 | 
						||
			return nil, errors.Wrapf(err, "error parsing cluster controlPlaneEndpoint %q", cfg.ControlPlaneEndpoint)
 | 
						||
		}
 | 
						||
	}
 | 
						||
 | 
						||
	appendSANsToAltNames(altNames, cfg.APIServer.CertSANs, kubeadmconstants.APIServerCertName)
 | 
						||
 | 
						||
	return altNames, nil
 | 
						||
}
 | 
						||
 | 
						||
// GetEtcdAltNames builds an AltNames object for generating the etcd server certificate.
 | 
						||
// `advertise address` and localhost are included in the SAN since this is the interfaces the etcd static pod listens on.
 | 
						||
// The user can override the listen address with `Etcd.ExtraArgs` and add SANs with `Etcd.ServerCertSANs`.
 | 
						||
func GetEtcdAltNames(cfg *kubeadmapi.InitConfiguration) (*certutil.AltNames, error) {
 | 
						||
	// advertise address
 | 
						||
	advertiseAddress := net.ParseIP(cfg.LocalAPIEndpoint.AdvertiseAddress)
 | 
						||
	if advertiseAddress == nil {
 | 
						||
		return nil, errors.Errorf("error parsing LocalAPIEndpoint AdvertiseAddress %q: is not a valid textual representation of an IP address", cfg.LocalAPIEndpoint.AdvertiseAddress)
 | 
						||
	}
 | 
						||
 | 
						||
	// create AltNames with defaults DNSNames/IPs
 | 
						||
	altNames := &certutil.AltNames{
 | 
						||
		DNSNames: []string{cfg.NodeRegistration.Name, "localhost"},
 | 
						||
		IPs:      []net.IP{advertiseAddress, net.IPv4(127, 0, 0, 1), net.IPv6loopback},
 | 
						||
	}
 | 
						||
 | 
						||
	if cfg.Etcd.Local != nil {
 | 
						||
		appendSANsToAltNames(altNames, cfg.Etcd.Local.ServerCertSANs, kubeadmconstants.EtcdServerCertName)
 | 
						||
	}
 | 
						||
 | 
						||
	return altNames, nil
 | 
						||
}
 | 
						||
 | 
						||
// GetEtcdPeerAltNames builds an AltNames object for generating the etcd peer certificate.
 | 
						||
// Hostname and `API.AdvertiseAddress` are included if the user chooses to promote the single node etcd cluster into a multi-node one (stacked etcd).
 | 
						||
// The user can override the listen address with `Etcd.ExtraArgs` and add SANs with `Etcd.PeerCertSANs`.
 | 
						||
func GetEtcdPeerAltNames(cfg *kubeadmapi.InitConfiguration) (*certutil.AltNames, error) {
 | 
						||
	// advertise address
 | 
						||
	advertiseAddress := net.ParseIP(cfg.LocalAPIEndpoint.AdvertiseAddress)
 | 
						||
	if advertiseAddress == nil {
 | 
						||
		return nil, errors.Errorf("error parsing LocalAPIEndpoint AdvertiseAddress %v: is not a valid textual representation of an IP address",
 | 
						||
			cfg.LocalAPIEndpoint.AdvertiseAddress)
 | 
						||
	}
 | 
						||
 | 
						||
	// create AltNames with defaults DNSNames/IPs
 | 
						||
	altNames := &certutil.AltNames{
 | 
						||
		DNSNames: []string{cfg.NodeRegistration.Name, "localhost"},
 | 
						||
		IPs:      []net.IP{advertiseAddress, net.IPv4(127, 0, 0, 1), net.IPv6loopback},
 | 
						||
	}
 | 
						||
 | 
						||
	if cfg.Etcd.Local != nil {
 | 
						||
		appendSANsToAltNames(altNames, cfg.Etcd.Local.PeerCertSANs, kubeadmconstants.EtcdPeerCertName)
 | 
						||
	}
 | 
						||
 | 
						||
	return altNames, nil
 | 
						||
}
 | 
						||
 | 
						||
// appendSANsToAltNames parses SANs from as list of strings and adds them to altNames for use on a specific cert
 | 
						||
// altNames is passed in with a pointer, and the struct is modified
 | 
						||
// valid IP address strings are parsed and added to altNames.IPs as net.IP's
 | 
						||
// RFC-1123 compliant DNS strings are added to altNames.DNSNames as strings
 | 
						||
// certNames is used to print user facing warnings and should be the name of the cert the altNames will be used for
 | 
						||
func appendSANsToAltNames(altNames *certutil.AltNames, SANs []string, certName string) {
 | 
						||
	for _, altname := range SANs {
 | 
						||
		if ip := net.ParseIP(altname); ip != nil {
 | 
						||
			altNames.IPs = append(altNames.IPs, ip)
 | 
						||
		} else if len(validation.IsDNS1123Subdomain(altname)) == 0 {
 | 
						||
			altNames.DNSNames = append(altNames.DNSNames, altname)
 | 
						||
		} else {
 | 
						||
			fmt.Printf(
 | 
						||
				"[certificates] WARNING: '%s' was not added to the '%s' SAN, because it is not a valid IP or RFC-1123 compliant DNS entry\n",
 | 
						||
				altname,
 | 
						||
				certName,
 | 
						||
			)
 | 
						||
		}
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
// EncodeCSRPEM returns PEM-encoded CSR data
 | 
						||
func EncodeCSRPEM(csr *x509.CertificateRequest) []byte {
 | 
						||
	block := pem.Block{
 | 
						||
		Type:  certutil.CertificateRequestBlockType,
 | 
						||
		Bytes: csr.Raw,
 | 
						||
	}
 | 
						||
	return pem.EncodeToMemory(&block)
 | 
						||
}
 | 
						||
 | 
						||
func parseCSRPEM(pemCSR []byte) (*x509.CertificateRequest, error) {
 | 
						||
	block, _ := pem.Decode(pemCSR)
 | 
						||
	if block == nil {
 | 
						||
		return nil, fmt.Errorf("data doesn't contain a valid certificate request")
 | 
						||
	}
 | 
						||
 | 
						||
	if block.Type != certutil.CertificateRequestBlockType {
 | 
						||
		var block *pem.Block
 | 
						||
		return nil, fmt.Errorf("expected block type %q, but PEM had type %v", certutil.CertificateRequestBlockType, block.Type)
 | 
						||
	}
 | 
						||
 | 
						||
	return x509.ParseCertificateRequest(block.Bytes)
 | 
						||
}
 | 
						||
 | 
						||
// CertificateRequestFromFile returns the CertificateRequest from a given PEM-encoded file.
 | 
						||
// Returns an error if the file could not be read or if the CSR could not be parsed.
 | 
						||
func CertificateRequestFromFile(file string) (*x509.CertificateRequest, error) {
 | 
						||
	pemBlock, err := ioutil.ReadFile(file)
 | 
						||
	if err != nil {
 | 
						||
		return nil, errors.Wrap(err, "failed to read file")
 | 
						||
	}
 | 
						||
 | 
						||
	csr, err := parseCSRPEM(pemBlock)
 | 
						||
	if err != nil {
 | 
						||
		return nil, fmt.Errorf("error reading certificate request file %s: %v", file, err)
 | 
						||
	}
 | 
						||
	return csr, nil
 | 
						||
}
 | 
						||
 | 
						||
// NewCSR creates a new CSR
 | 
						||
func NewCSR(cfg certutil.Config, key crypto.Signer) (*x509.CertificateRequest, error) {
 | 
						||
	template := &x509.CertificateRequest{
 | 
						||
		Subject: pkix.Name{
 | 
						||
			CommonName:   cfg.CommonName,
 | 
						||
			Organization: cfg.Organization,
 | 
						||
		},
 | 
						||
		DNSNames:    cfg.AltNames.DNSNames,
 | 
						||
		IPAddresses: cfg.AltNames.IPs,
 | 
						||
	}
 | 
						||
 | 
						||
	csrBytes, err := x509.CreateCertificateRequest(cryptorand.Reader, template, key)
 | 
						||
 | 
						||
	if err != nil {
 | 
						||
		return nil, errors.Wrap(err, "failed to create a CSR")
 | 
						||
	}
 | 
						||
 | 
						||
	return x509.ParseCertificateRequest(csrBytes)
 | 
						||
}
 |