| 
									
										
										
										
											2018-06-12 21:09:47 +11:00
										 |  |  | package main | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2020-04-22 17:36:04 +02:00
										 |  |  | 	"crypto" | 
					
						
							| 
									
										
										
										
											2018-06-19 17:48:28 +11:00
										 |  |  | 	"crypto/rand" | 
					
						
							|  |  |  | 	"encoding/base32" | 
					
						
							| 
									
										
										
										
											2018-06-16 22:45:27 +11:00
										 |  |  | 	"encoding/json" | 
					
						
							|  |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2018-08-09 15:07:53 +02:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2018-06-12 21:09:47 +11:00
										 |  |  | 	"io/ioutil" | 
					
						
							| 
									
										
										
										
											2018-08-09 15:07:53 +02:00
										 |  |  | 	"net" | 
					
						
							| 
									
										
										
										
											2018-06-12 21:09:47 +11:00
										 |  |  | 	"os" | 
					
						
							| 
									
										
										
										
											2018-06-16 22:45:27 +11:00
										 |  |  | 	"path/filepath" | 
					
						
							| 
									
										
										
										
											2019-04-13 10:36:58 +01:00
										 |  |  | 	"sort" | 
					
						
							| 
									
										
										
										
											2019-01-22 11:44:11 +13:00
										 |  |  | 	"sync" | 
					
						
							| 
									
										
										
										
											2020-04-22 17:36:04 +02:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2018-06-12 21:09:47 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-19 16:57:22 +01:00
										 |  |  | 	"github.com/cespare/xxhash" | 
					
						
							| 
									
										
										
										
											2020-04-22 17:36:04 +02:00
										 |  |  | 	"github.com/cloudflare/cfssl/certinfo" | 
					
						
							| 
									
										
										
										
											2018-06-16 22:45:27 +11:00
										 |  |  | 	"github.com/cloudflare/cfssl/config" | 
					
						
							|  |  |  | 	"github.com/cloudflare/cfssl/csr" | 
					
						
							|  |  |  | 	"github.com/cloudflare/cfssl/helpers" | 
					
						
							|  |  |  | 	"github.com/cloudflare/cfssl/initca" | 
					
						
							| 
									
										
										
										
											2019-01-22 11:44:11 +13:00
										 |  |  | 	"github.com/cloudflare/cfssl/log" | 
					
						
							| 
									
										
										
										
											2018-06-16 22:45:27 +11:00
										 |  |  | 	"github.com/cloudflare/cfssl/signer" | 
					
						
							|  |  |  | 	"github.com/cloudflare/cfssl/signer/local" | 
					
						
							| 
									
										
										
										
											2018-08-09 15:07:53 +02:00
										 |  |  | 	"k8s.io/apimachinery/pkg/util/validation" | 
					
						
							|  |  |  | 	"k8s.io/apimachinery/pkg/util/validation/field" | 
					
						
							| 
									
										
										
										
											2018-06-12 21:09:47 +11:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-22 11:44:11 +13:00
										 |  |  | var ( | 
					
						
							|  |  |  | 	secretData *SecretData | 
					
						
							| 
									
										
										
										
											2019-12-03 11:03:20 +01:00
										 |  |  | 	DontSave   = false | 
					
						
							| 
									
										
										
										
											2019-01-22 11:44:11 +13:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-16 22:45:27 +11:00
										 |  |  | type SecretData struct { | 
					
						
							| 
									
										
										
										
											2019-01-22 11:44:11 +13:00
										 |  |  | 	l sync.Mutex | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-19 16:57:22 +01:00
										 |  |  | 	prevHash uint64 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-16 22:45:27 +11:00
										 |  |  | 	clusters map[string]*ClusterSecrets | 
					
						
							|  |  |  | 	changed  bool | 
					
						
							|  |  |  | 	config   *config.Config | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type ClusterSecrets struct { | 
					
						
							| 
									
										
										
										
											2019-12-03 11:03:20 +01:00
										 |  |  | 	CAs         map[string]*CA | 
					
						
							|  |  |  | 	Tokens      map[string]string | 
					
						
							|  |  |  | 	Passwords   map[string]string | 
					
						
							|  |  |  | 	SSHKeyPairs map[string][]SSHKeyPair | 
					
						
							| 
									
										
										
										
											2018-06-16 22:45:27 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type CA struct { | 
					
						
							|  |  |  | 	Key  []byte | 
					
						
							|  |  |  | 	Cert []byte | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Signed map[string]*KeyCert | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type KeyCert struct { | 
					
						
							| 
									
										
										
										
											2018-07-06 11:13:56 +11:00
										 |  |  | 	Key     []byte | 
					
						
							|  |  |  | 	Cert    []byte | 
					
						
							|  |  |  | 	ReqHash string | 
					
						
							| 
									
										
										
										
											2018-06-16 22:45:27 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-22 11:44:11 +13:00
										 |  |  | func secretDataPath() string { | 
					
						
							|  |  |  | 	return filepath.Join(*dataDir, "secret-data.json") | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func loadSecretData(config *config.Config) (err error) { | 
					
						
							|  |  |  | 	log.Info("Loading secret data") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-16 22:45:27 +11:00
										 |  |  | 	sd := &SecretData{ | 
					
						
							|  |  |  | 		clusters: make(map[string]*ClusterSecrets), | 
					
						
							|  |  |  | 		changed:  false, | 
					
						
							|  |  |  | 		config:   config, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-22 11:44:11 +13:00
										 |  |  | 	ba, err := ioutil.ReadFile(secretDataPath()) | 
					
						
							| 
									
										
										
										
											2018-06-16 22:45:27 +11:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		if os.IsNotExist(err) { | 
					
						
							|  |  |  | 			sd.changed = true | 
					
						
							| 
									
										
										
										
											2019-01-22 11:44:11 +13:00
										 |  |  | 			err = nil | 
					
						
							|  |  |  | 			secretData = sd | 
					
						
							|  |  |  | 			return | 
					
						
							| 
									
										
										
										
											2018-06-16 22:45:27 +11:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-01-22 11:44:11 +13:00
										 |  |  | 		return | 
					
						
							| 
									
										
										
										
											2018-06-16 22:45:27 +11:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-22 11:44:11 +13:00
										 |  |  | 	if err = json.Unmarshal(ba, &sd.clusters); err != nil { | 
					
						
							|  |  |  | 		return | 
					
						
							| 
									
										
										
										
											2018-06-16 22:45:27 +11:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-19 16:57:22 +01:00
										 |  |  | 	sd.prevHash = xxhash.Sum64(ba) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-22 11:44:11 +13:00
										 |  |  | 	secretData = sd | 
					
						
							|  |  |  | 	return | 
					
						
							| 
									
										
										
										
											2018-06-16 22:45:27 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (sd *SecretData) Changed() bool { | 
					
						
							|  |  |  | 	return sd.changed | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-19 16:57:22 +01:00
										 |  |  | func (sd *SecretData) Save() (err error) { | 
					
						
							| 
									
										
										
										
											2019-12-03 11:03:20 +01:00
										 |  |  | 	if DontSave { | 
					
						
							| 
									
										
										
										
											2019-12-19 16:57:22 +01:00
										 |  |  | 		return | 
					
						
							| 
									
										
										
										
											2019-12-03 11:03:20 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-22 11:44:11 +13:00
										 |  |  | 	sd.l.Lock() | 
					
						
							|  |  |  | 	defer sd.l.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-16 22:45:27 +11:00
										 |  |  | 	ba, err := json.Marshal(sd.clusters) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2019-12-19 16:57:22 +01:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	h := xxhash.Sum64(ba) | 
					
						
							|  |  |  | 	if h == sd.prevHash { | 
					
						
							|  |  |  | 		return | 
					
						
							| 
									
										
										
										
											2018-06-16 22:45:27 +11:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-12-19 16:57:22 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	log.Info("Saving secret data") | 
					
						
							|  |  |  | 	err = ioutil.WriteFile(secretDataPath(), ba, 0600) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err == nil { | 
					
						
							|  |  |  | 		sd.prevHash = h | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return | 
					
						
							| 
									
										
										
										
											2018-06-16 22:45:27 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-13 10:36:58 +01:00
										 |  |  | func newClusterSecrets() *ClusterSecrets { | 
					
						
							|  |  |  | 	return &ClusterSecrets{ | 
					
						
							|  |  |  | 		CAs:       make(map[string]*CA), | 
					
						
							|  |  |  | 		Tokens:    make(map[string]string), | 
					
						
							|  |  |  | 		Passwords: make(map[string]string), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-16 22:45:27 +11:00
										 |  |  | func (sd *SecretData) cluster(name string) (cs *ClusterSecrets) { | 
					
						
							|  |  |  | 	cs, ok := sd.clusters[name] | 
					
						
							|  |  |  | 	if ok { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-22 11:44:11 +13:00
										 |  |  | 	sd.l.Lock() | 
					
						
							|  |  |  | 	defer sd.l.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	log.Info("secret-data: new cluster: ", name) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-13 10:36:58 +01:00
										 |  |  | 	cs = newClusterSecrets() | 
					
						
							| 
									
										
										
										
											2018-06-16 22:45:27 +11:00
										 |  |  | 	sd.clusters[name] = cs | 
					
						
							|  |  |  | 	sd.changed = true | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-13 10:36:58 +01:00
										 |  |  | func (sd *SecretData) Passwords(cluster string) (passwords []string) { | 
					
						
							|  |  |  | 	cs := sd.cluster(cluster) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	passwords = make([]string, 0, len(cs.Passwords)) | 
					
						
							|  |  |  | 	for name := range cs.Passwords { | 
					
						
							|  |  |  | 		passwords = append(passwords, name) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sort.Strings(passwords) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (sd *SecretData) Password(cluster, name string) (password string) { | 
					
						
							|  |  |  | 	cs := sd.cluster(cluster) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if cs.Passwords == nil { | 
					
						
							|  |  |  | 		cs.Passwords = make(map[string]string) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	password = cs.Passwords[name] | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (sd *SecretData) SetPassword(cluster, name, password string) { | 
					
						
							|  |  |  | 	cs := sd.cluster(cluster) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if cs.Passwords == nil { | 
					
						
							|  |  |  | 		cs.Passwords = make(map[string]string) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cs.Passwords[name] = password | 
					
						
							|  |  |  | 	sd.changed = true | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-19 17:48:28 +11:00
										 |  |  | func (sd *SecretData) Token(cluster, name string) (token string, err error) { | 
					
						
							|  |  |  | 	cs := sd.cluster(cluster) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	token = cs.Tokens[name] | 
					
						
							|  |  |  | 	if token != "" { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-22 11:44:11 +13:00
										 |  |  | 	sd.l.Lock() | 
					
						
							|  |  |  | 	defer sd.l.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	log.Info("secret-data: new token in cluster ", cluster, ": ", name) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-19 17:48:28 +11:00
										 |  |  | 	b := make([]byte, 16) | 
					
						
							|  |  |  | 	_, err = rand.Read(b) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	token = base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(b) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cs.Tokens[name] = token | 
					
						
							|  |  |  | 	sd.changed = true | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-22 17:36:04 +02:00
										 |  |  | func (sd *SecretData) RenewCACert(cluster, name string) (err error) { | 
					
						
							|  |  |  | 	cs := sd.cluster(cluster) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ca := cs.CAs[name] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-27 06:25:51 +01:00
										 |  |  | 	var signer crypto.Signer | 
					
						
							|  |  |  | 	signer, err = helpers.ParsePrivateKeyPEM(ca.Key) | 
					
						
							| 
									
										
										
										
											2020-04-22 17:36:04 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-27 06:42:39 +01:00
										 |  |  | 	newCert, _, err := initca.NewFromSigner(newCACertReq(), signer) | 
					
						
							| 
									
										
										
										
											2020-04-22 17:36:04 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sd.l.Lock() | 
					
						
							|  |  |  | 	defer sd.l.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cs.CAs[name].Cert = newCert | 
					
						
							|  |  |  | 	sd.changed = true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-27 06:25:51 +01:00
										 |  |  | func newCACertReq() *csr.CertificateRequest { | 
					
						
							|  |  |  | 	return &csr.CertificateRequest{ | 
					
						
							|  |  |  | 		CN: "Direktil Local Server", | 
					
						
							|  |  |  | 		KeyRequest: &csr.KeyRequest{ | 
					
						
							|  |  |  | 			A: "ecdsa", | 
					
						
							|  |  |  | 			S: 521, // 256, 384, 521 | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		Names: []csr.Name{ | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				C: "NC", | 
					
						
							|  |  |  | 				O: "novit.nc", | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-16 22:45:27 +11:00
										 |  |  | func (sd *SecretData) CA(cluster, name string) (ca *CA, err error) { | 
					
						
							| 
									
										
										
										
											2023-01-27 06:13:05 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	defer func() { | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			err = fmt.Errorf("cluster %s CA %s: %w", cluster, name, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-16 22:45:27 +11:00
										 |  |  | 	cs := sd.cluster(cluster) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ca, ok := cs.CAs[name] | 
					
						
							|  |  |  | 	if ok { | 
					
						
							| 
									
										
										
										
											2020-04-22 17:36:04 +02:00
										 |  |  | 		checkErr := checkCertUsable(ca.Cert) | 
					
						
							| 
									
										
										
										
											2020-04-22 18:40:30 +02:00
										 |  |  | 		if checkErr != nil { | 
					
						
							| 
									
										
										
										
											2020-04-22 17:36:04 +02:00
										 |  |  | 			log.Infof("secret-data cluster %s: CA %s: regenerating certificate: %v", cluster, name, checkErr) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			err = sd.RenewCACert(cluster, name) | 
					
						
							| 
									
										
										
										
											2023-01-27 06:13:05 +01:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				err = fmt.Errorf("renew: %w", err) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2020-04-22 17:36:04 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-16 22:45:27 +11:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-22 11:44:11 +13:00
										 |  |  | 	sd.l.Lock() | 
					
						
							|  |  |  | 	defer sd.l.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	log.Info("secret-data: new CA in cluster ", cluster, ": ", name) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-27 06:25:51 +01:00
										 |  |  | 	req := newCACertReq() | 
					
						
							| 
									
										
										
										
											2018-06-16 22:45:27 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	cert, _, key, err := initca.New(req) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2023-01-27 06:13:05 +01:00
										 |  |  | 		err = fmt.Errorf("initca: %w", err) | 
					
						
							| 
									
										
										
										
											2018-06-16 22:45:27 +11:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ca = &CA{ | 
					
						
							|  |  |  | 		Key:    key, | 
					
						
							|  |  |  | 		Cert:   cert, | 
					
						
							|  |  |  | 		Signed: make(map[string]*KeyCert), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cs.CAs[name] = ca | 
					
						
							|  |  |  | 	sd.changed = true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-22 17:36:04 +02:00
										 |  |  | func checkCertUsable(certPEM []byte) error { | 
					
						
							|  |  |  | 	cert, err := certinfo.ParseCertificatePEM(certPEM) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	certDuration := cert.NotAfter.Sub(cert.NotBefore) | 
					
						
							|  |  |  | 	delayBeforeRegen := certDuration / 3 // TODO allow configuration | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if cert.NotAfter.Sub(time.Now()) < delayBeforeRegen { | 
					
						
							|  |  |  | 		return errors.New("too old") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-16 22:45:27 +11:00
										 |  |  | func (sd *SecretData) KeyCert(cluster, caName, name, profile, label string, req *csr.CertificateRequest) (kc *KeyCert, err error) { | 
					
						
							| 
									
										
										
										
											2018-08-09 15:07:53 +02:00
										 |  |  | 	for idx, host := range req.Hosts { | 
					
						
							|  |  |  | 		if ip := net.ParseIP(host); ip != nil { | 
					
						
							|  |  |  | 			// valid IP (v4 or v6) | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if host == "*" { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if errs := validation.IsDNS1123Subdomain(host); len(errs) == 0 { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if errs := validation.IsWildcardDNS1123Subdomain(host); len(errs) == 0 { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		path := field.NewPath(cluster, name, "hosts").Index(idx) | 
					
						
							|  |  |  | 		return nil, fmt.Errorf("%v: %q is not an IP or FQDN", path, host) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-16 22:45:27 +11:00
										 |  |  | 	if req.CA != nil { | 
					
						
							|  |  |  | 		err = errors.New("no CA section allowed here") | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ca, err := sd.CA(cluster, caName) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-22 17:36:04 +02:00
										 |  |  | 	logPrefix := fmt.Sprintf("secret-data: cluster %s: CA %s:", cluster, caName) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-06 11:13:56 +11:00
										 |  |  | 	rh := hash(req) | 
					
						
							| 
									
										
										
										
											2018-06-16 22:45:27 +11:00
										 |  |  | 	kc, ok := ca.Signed[name] | 
					
						
							| 
									
										
										
										
											2018-07-06 11:13:56 +11:00
										 |  |  | 	if ok && rh == kc.ReqHash { | 
					
						
							| 
									
										
										
										
											2020-04-22 17:36:04 +02:00
										 |  |  | 		err = checkCertUsable(kc.Cert) | 
					
						
							|  |  |  | 		if err == nil { | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		log.Infof("%s regenerating certificate: ", err) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-22 11:44:11 +13:00
										 |  |  | 	} else if ok { | 
					
						
							| 
									
										
										
										
											2020-04-22 17:36:04 +02:00
										 |  |  | 		log.Infof("%s CSR changed for %s: hash=%q previous=%q", name, rh, kc.ReqHash) | 
					
						
							| 
									
										
										
										
											2019-01-22 11:44:11 +13:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2020-04-22 17:36:04 +02:00
										 |  |  | 		log.Infof("%s new CSR for %s", logPrefix, name) | 
					
						
							| 
									
										
										
										
											2018-06-16 22:45:27 +11:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-22 11:44:11 +13:00
										 |  |  | 	sd.l.Lock() | 
					
						
							|  |  |  | 	defer sd.l.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-16 22:45:27 +11:00
										 |  |  | 	sgr, err := ca.Signer(sd.config.Signing) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	generator := &csr.Generator{Validator: func(_ *csr.CertificateRequest) error { return nil }} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	csr, key, err := generator.ProcessRequest(req) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	signReq := signer.SignRequest{ | 
					
						
							|  |  |  | 		Request: string(csr), | 
					
						
							|  |  |  | 		Profile: profile, | 
					
						
							|  |  |  | 		Label:   label, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cert, err := sgr.Sign(signReq) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	kc = &KeyCert{ | 
					
						
							| 
									
										
										
										
											2018-07-06 11:13:56 +11:00
										 |  |  | 		Key:     key, | 
					
						
							|  |  |  | 		Cert:    cert, | 
					
						
							|  |  |  | 		ReqHash: rh, | 
					
						
							| 
									
										
										
										
											2018-06-16 22:45:27 +11:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ca.Signed[name] = kc | 
					
						
							|  |  |  | 	sd.changed = true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (ca *CA) Signer(policy *config.Signing) (result *local.Signer, err error) { | 
					
						
							|  |  |  | 	caCert, err := helpers.ParseCertificatePEM(ca.Cert) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	caKey, err := helpers.ParsePrivateKeyPEM(ca.Key) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return local.NewSigner(caKey, caCert, signer.DefaultSigAlgo(caKey), policy) | 
					
						
							|  |  |  | } |