mirror of https://github.com/kubernetes/kops.git
				
				
				
			Merge pull request #3838 from justinsb/avoid_list_for_keypairs_3
Automatic merge from submit-queue. Use bundles when loading keysets This avoids the need to list directories, which is problematic on GCE. It also makes for a more consistent experience; we can move nodeup to use the bundle always, and we can move writing to the Mirror task, so that VFS & kops-server are more similar. Builds on #3837
This commit is contained in:
		
						commit
						e17127bd50
					
				|  | @ -129,6 +129,7 @@ go_binary( | |||
| 
 | ||||
| go_test( | ||||
|     name = "go_default_test", | ||||
|     size = "small", | ||||
|     srcs = [ | ||||
|         "create_cluster_integration_test.go", | ||||
|         "create_cluster_test.go", | ||||
|  |  | |||
|  | @ -44,10 +44,12 @@ go_library( | |||
|         "//dnsprovider/pkg/dnsprovider:go_default_library", | ||||
|         "//pkg/acls:go_default_library", | ||||
|         "//pkg/apis/kops:go_default_library", | ||||
|         "//pkg/apis/kops/v1alpha2:go_default_library", | ||||
|         "//pkg/assets:go_default_library", | ||||
|         "//pkg/client/clientset_generated/clientset/typed/kops/internalversion:go_default_library", | ||||
|         "//pkg/cloudinstances:go_default_library", | ||||
|         "//pkg/diff:go_default_library", | ||||
|         "//pkg/kopscodecs:go_default_library", | ||||
|         "//pkg/pki:go_default_library", | ||||
|         "//pkg/sshcredentials:go_default_library", | ||||
|         "//upup/pkg/fi/utils:go_default_library", | ||||
|  | @ -59,12 +61,14 @@ go_library( | |||
|         "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", | ||||
|         "//vendor/k8s.io/apimachinery/pkg/api/validation:go_default_library", | ||||
|         "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", | ||||
|         "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", | ||||
|         "//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library", | ||||
|     ], | ||||
| ) | ||||
| 
 | ||||
| go_test( | ||||
|     name = "go_default_test", | ||||
|     size = "small", | ||||
|     srcs = [ | ||||
|         "dryruntarget_test.go", | ||||
|         "vfs_castore_test.go", | ||||
|  |  | |||
|  | @ -30,8 +30,11 @@ import ( | |||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/golang/glog" | ||||
| 	"k8s.io/apimachinery/pkg/runtime" | ||||
| 	"k8s.io/kops/pkg/acls" | ||||
| 	"k8s.io/kops/pkg/apis/kops" | ||||
| 	"k8s.io/kops/pkg/apis/kops/v1alpha2" | ||||
| 	"k8s.io/kops/pkg/kopscodecs" | ||||
| 	"k8s.io/kops/pkg/pki" | ||||
| 	"k8s.io/kops/pkg/sshcredentials" | ||||
| 	"k8s.io/kops/util/pkg/vfs" | ||||
|  | @ -89,7 +92,7 @@ func (s *VFSCAStore) readCAKeypairs(id string) (*keyset, *keyset, error) { | |||
| 		return cached.certificates, cached.privateKeys, nil | ||||
| 	} | ||||
| 
 | ||||
| 	caCertificates, err := s.loadCertificates(s.buildCertificatePoolPath(id)) | ||||
| 	caCertificates, err := s.loadCertificates(s.buildCertificatePoolPath(id), true) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | @ -97,7 +100,7 @@ func (s *VFSCAStore) readCAKeypairs(id string) (*keyset, *keyset, error) { | |||
| 	var caPrivateKeys *keyset | ||||
| 
 | ||||
| 	if caCertificates != nil { | ||||
| 		caPrivateKeys, err = s.loadPrivateKeys(s.buildPrivateKeyPoolPath(id)) | ||||
| 		caPrivateKeys, err = s.loadPrivateKeys(s.buildPrivateKeyPoolPath(id), true) | ||||
| 		if err != nil { | ||||
| 			return nil, nil, err | ||||
| 		} | ||||
|  | @ -137,7 +140,7 @@ func BuildCAX509Template() *x509.Certificate { | |||
| 
 | ||||
| // Creates and stores CA keypair
 | ||||
| // Should be called with the mutex held, to prevent concurrent creation of different keys
 | ||||
| func (c *VFSCAStore) generateCACertificate(id string) (*keyset, *keyset, error) { | ||||
| func (c *VFSCAStore) generateCACertificate(name string) (*keyset, *keyset, error) { | ||||
| 	template := BuildCAX509Template() | ||||
| 
 | ||||
| 	caRsaKey, err := rsa.GenerateKey(crypto_rand.Reader, 2048) | ||||
|  | @ -153,59 +156,173 @@ func (c *VFSCAStore) generateCACertificate(id string) (*keyset, *keyset, error) | |||
| 	} | ||||
| 
 | ||||
| 	t := time.Now().UnixNano() | ||||
| 	serial := pki.BuildPKISerial(t) | ||||
| 	serial := pki.BuildPKISerial(t).String() | ||||
| 
 | ||||
| 	keyPath := c.buildPrivateKeyPath(id, serial) | ||||
| 	err = c.storePrivateKey(caPrivateKey, keyPath) | ||||
| 	err = c.storePrivateKey(name, &keysetItem{id: serial, privateKey: caPrivateKey}) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	// Make double-sure it round-trips
 | ||||
| 	privateKeys, err := c.loadPrivateKeys(c.buildPrivateKeyPoolPath(id)) | ||||
| 	privateKeys, err := c.loadPrivateKeys(c.buildPrivateKeyPoolPath(name), true) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 	if privateKeys == nil || privateKeys.primary == nil || privateKeys.primary.id != serial.String() { | ||||
| 	if privateKeys == nil || privateKeys.primary == nil || privateKeys.primary.id != serial { | ||||
| 		return nil, nil, fmt.Errorf("failed to round-trip CA private key") | ||||
| 	} | ||||
| 
 | ||||
| 	certPath := c.buildCertificatePath(id, serial) | ||||
| 	err = c.storeCertificate(caCertificate, certPath) | ||||
| 	err = c.storeCertificate(name, &keysetItem{id: serial, certificate: caCertificate}) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	// Make double-sure it round-trips
 | ||||
| 	certificates, err := c.loadCertificates(c.buildCertificatePoolPath(id)) | ||||
| 	certificates, err := c.loadCertificates(c.buildCertificatePoolPath(name), true) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if certificates == nil || certificates.primary == nil || certificates.primary.id != serial.String() { | ||||
| 	if certificates == nil || certificates.primary == nil || certificates.primary.id != serial { | ||||
| 		return nil, nil, fmt.Errorf("failed to round-trip CA certifiacate") | ||||
| 	} | ||||
| 
 | ||||
| 	return certificates, privateKeys, nil | ||||
| } | ||||
| 
 | ||||
| func (c *VFSCAStore) buildCertificatePoolPath(id string) vfs.Path { | ||||
| 	return c.basedir.Join("issued", id) | ||||
| func (c *VFSCAStore) buildCertificatePoolPath(name string) vfs.Path { | ||||
| 	return c.basedir.Join("issued", name) | ||||
| } | ||||
| 
 | ||||
| func (c *VFSCAStore) buildCertificatePath(id string, serial *big.Int) vfs.Path { | ||||
| 	return c.basedir.Join("issued", id, serial.String()+".crt") | ||||
| func (c *VFSCAStore) buildCertificatePath(name string, id string) vfs.Path { | ||||
| 	return c.basedir.Join("issued", name, id+".crt") | ||||
| } | ||||
| 
 | ||||
| func (c *VFSCAStore) buildPrivateKeyPoolPath(id string) vfs.Path { | ||||
| 	return c.basedir.Join("private", id) | ||||
| func (c *VFSCAStore) buildPrivateKeyPoolPath(name string) vfs.Path { | ||||
| 	return c.basedir.Join("private", name) | ||||
| } | ||||
| 
 | ||||
| func (c *VFSCAStore) buildPrivateKeyPath(id string, serial *big.Int) vfs.Path { | ||||
| 	return c.basedir.Join("private", id, serial.String()+".key") | ||||
| func (c *VFSCAStore) buildPrivateKeyPath(name string, id string) vfs.Path { | ||||
| 	return c.basedir.Join("private", name, id+".key") | ||||
| } | ||||
| 
 | ||||
| func (c *VFSCAStore) loadCertificates(p vfs.Path) (*keyset, error) { | ||||
| func (c *VFSCAStore) parseKeysetYaml(data []byte) (*kops.Keyset, error) { | ||||
| 	codecs := kopscodecs.Codecs | ||||
| 	yaml, ok := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), "application/yaml") | ||||
| 	if !ok { | ||||
| 		glog.Fatalf("no YAML serializer registered") | ||||
| 	} | ||||
| 	decoder := codecs.DecoderToVersion(yaml.Serializer, kops.SchemeGroupVersion) | ||||
| 
 | ||||
| 	defaultReadVersion := v1alpha2.SchemeGroupVersion.WithKind("Keyset") | ||||
| 
 | ||||
| 	object, _, err := decoder.Decode(data, &defaultReadVersion, nil) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("error parsing keyset: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	keyset, ok := object.(*kops.Keyset) | ||||
| 	if !ok { | ||||
| 		return nil, fmt.Errorf("object was not a keyset, was a %T", object) | ||||
| 	} | ||||
| 	return keyset, nil | ||||
| } | ||||
| 
 | ||||
| // loadCertificatesBundle loads a keyset from the path
 | ||||
| // Returns (nil, nil) if the file is not found
 | ||||
| // Bundles avoid the need for a list-files permission, which can be tricky on e.g. GCE
 | ||||
| func (c *VFSCAStore) loadKeysetBundle(p vfs.Path) (*keyset, error) { | ||||
| 	data, err := p.ReadFile() | ||||
| 	if err != nil { | ||||
| 		if os.IsNotExist(err) { | ||||
| 			return nil, nil | ||||
| 		} else { | ||||
| 			return nil, fmt.Errorf("unable to read bundle %q: %v", p, err) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	o, err := c.parseKeysetYaml(data) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("error parsing bundle %q: %v", p, err) | ||||
| 	} | ||||
| 
 | ||||
| 	keyset, err := parseKeyset(o) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("error mapping bundle %q: %v", p, err) | ||||
| 	} | ||||
| 
 | ||||
| 	return keyset, nil | ||||
| } | ||||
| 
 | ||||
| // writeKeysetBundle writes a keyset bundle to VFS
 | ||||
| func (c *VFSCAStore) writeKeysetBundle(p vfs.Path, name string, keyset *keyset, includePrivateMaterial bool) error { | ||||
| 	p = p.Join("keyset.yaml") | ||||
| 
 | ||||
| 	o := &v1alpha2.Keyset{} | ||||
| 	o.Name = name | ||||
| 	o.Spec.Type = v1alpha2.SecretTypeKeypair | ||||
| 
 | ||||
| 	for _, ki := range keyset.items { | ||||
| 		oki := v1alpha2.KeysetItem{ | ||||
| 			Id: ki.id, | ||||
| 		} | ||||
| 
 | ||||
| 		if ki.certificate != nil { | ||||
| 			var publicMaterial bytes.Buffer | ||||
| 			if _, err := ki.certificate.WriteTo(&publicMaterial); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			oki.PublicMaterial = publicMaterial.Bytes() | ||||
| 		} | ||||
| 
 | ||||
| 		if includePrivateMaterial && ki.privateKey != nil { | ||||
| 			var privateMaterial bytes.Buffer | ||||
| 			if _, err := ki.privateKey.WriteTo(&privateMaterial); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 
 | ||||
| 			oki.PrivateMaterial = privateMaterial.Bytes() | ||||
| 		} | ||||
| 
 | ||||
| 		o.Spec.Keys = append(o.Spec.Keys, oki) | ||||
| 	} | ||||
| 
 | ||||
| 	var objectData bytes.Buffer | ||||
| 	{ | ||||
| 		codecs := kopscodecs.Codecs | ||||
| 		yaml, ok := runtime.SerializerInfoForMediaType(codecs.SupportedMediaTypes(), "application/yaml") | ||||
| 		if !ok { | ||||
| 			glog.Fatalf("no YAML serializer registered") | ||||
| 		} | ||||
| 		encoder := codecs.EncoderForVersion(yaml.Serializer, v1alpha2.SchemeGroupVersion) | ||||
| 
 | ||||
| 		if err := encoder.Encode(o, &objectData); err != nil { | ||||
| 			return fmt.Errorf("error serializing keyset: %v", err) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	acl, err := acls.GetACL(p, c.cluster) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return p.WriteFile(objectData.Bytes(), acl) | ||||
| } | ||||
| 
 | ||||
| func (c *VFSCAStore) loadCertificates(p vfs.Path, useBundle bool) (*keyset, error) { | ||||
| 	// Attempt to load prebuilt bundle, which avoids having to list files, which is a permission that can be hard to
 | ||||
| 	// give on GCE / other clouds
 | ||||
| 	if useBundle { | ||||
| 		bundlePath := p.Join("keyset.yaml") | ||||
| 		bundle, err := c.loadKeysetBundle(bundlePath) | ||||
| 		if err != nil { | ||||
| 			glog.Warningf("unable to read bundle %q, falling back to directory-list method: %v", bundlePath, err) | ||||
| 		} else if bundle == nil { | ||||
| 			glog.Infof("no certificate bundle %q, falling back to directory-list method", bundlePath) | ||||
| 		} else { | ||||
| 			return bundle, nil | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	keyset := &keyset{ | ||||
| 		items: make(map[string]*keysetItem), | ||||
| 	} | ||||
|  | @ -219,13 +336,18 @@ func (c *VFSCAStore) loadCertificates(p vfs.Path) (*keyset, error) { | |||
| 	} | ||||
| 
 | ||||
| 	for _, f := range files { | ||||
| 		id := f.Base() | ||||
| 		if strings.HasSuffix(id, ".yaml") { | ||||
| 			// ignore bundle
 | ||||
| 			continue | ||||
| 		} | ||||
| 		id = strings.TrimSuffix(id, ".crt") | ||||
| 
 | ||||
| 		cert, err := c.loadOneCertificate(f) | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("error loading certificate %q: %v", f, err) | ||||
| 		} | ||||
| 
 | ||||
| 		id := f.Base() | ||||
| 		id = strings.TrimSuffix(id, ".crt") | ||||
| 		keyset.items[id] = &keysetItem{ | ||||
| 			id:          id, | ||||
| 			certificate: cert, | ||||
|  | @ -286,14 +408,14 @@ func (c *VFSCAStore) FindKeypair(id string) (*pki.Certificate, *pki.PrivateKey, | |||
| 	return cert, key, nil | ||||
| } | ||||
| 
 | ||||
| func (c *VFSCAStore) FindCert(id string) (*pki.Certificate, error) { | ||||
| func (c *VFSCAStore) FindCert(name string) (*pki.Certificate, error) { | ||||
| 	var certs *keyset | ||||
| 
 | ||||
| 	var err error | ||||
| 	p := c.buildCertificatePoolPath(id) | ||||
| 	certs, err = c.loadCertificates(p) | ||||
| 	p := c.buildCertificatePoolPath(name) | ||||
| 	certs, err = c.loadCertificates(p, true) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("error in 'FindCert' attempting to load cert %q: %v", id, err) | ||||
| 		return nil, fmt.Errorf("error in 'FindCert' attempting to load cert %q: %v", name, err) | ||||
| 	} | ||||
| 
 | ||||
| 	var cert *pki.Certificate | ||||
|  | @ -304,14 +426,14 @@ func (c *VFSCAStore) FindCert(id string) (*pki.Certificate, error) { | |||
| 	return cert, nil | ||||
| } | ||||
| 
 | ||||
| func (c *VFSCAStore) FindCertificatePool(id string) (*CertificatePool, error) { | ||||
| func (c *VFSCAStore) FindCertificatePool(name string) (*CertificatePool, error) { | ||||
| 	var certs *keyset | ||||
| 
 | ||||
| 	var err error | ||||
| 	p := c.buildCertificatePoolPath(id) | ||||
| 	certs, err = c.loadCertificates(p) | ||||
| 	p := c.buildCertificatePoolPath(name) | ||||
| 	certs, err = c.loadCertificates(p, true) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("error in 'FindCertificatePool' attempting to load cert %q: %v", id, err) | ||||
| 		return nil, fmt.Errorf("error in 'FindCertificatePool' attempting to load cert %q: %v", name, err) | ||||
| 	} | ||||
| 
 | ||||
| 	pool := &CertificatePool{} | ||||
|  | @ -466,24 +588,28 @@ func (c *VFSCAStore) IssueCert(signer string, id string, serial *big.Int, privat | |||
| 	} | ||||
| 
 | ||||
| 	// Make double-sure it round-trips
 | ||||
| 	p := c.buildCertificatePath(id, serial) | ||||
| 	p := c.buildCertificatePath(id, serial.String()) | ||||
| 	return c.loadOneCertificate(p) | ||||
| } | ||||
| 
 | ||||
| func (c *VFSCAStore) StoreKeypair(id string, cert *pki.Certificate, privateKey *pki.PrivateKey) error { | ||||
| 	serial := cert.Certificate.SerialNumber | ||||
| func (c *VFSCAStore) StoreKeypair(name string, cert *pki.Certificate, privateKey *pki.PrivateKey) error { | ||||
| 	serial := cert.Certificate.SerialNumber.String() | ||||
| 
 | ||||
| 	ki := &keysetItem{ | ||||
| 		id:          serial, | ||||
| 		certificate: cert, | ||||
| 		privateKey:  privateKey, | ||||
| 	} | ||||
| 
 | ||||
| 	{ | ||||
| 		p := c.buildPrivateKeyPath(id, serial) | ||||
| 		err := c.storePrivateKey(privateKey, p) | ||||
| 		err := c.storePrivateKey(name, ki) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	{ | ||||
| 		p := c.buildCertificatePath(id, serial) | ||||
| 		err := c.storeCertificate(cert, p) | ||||
| 		err := c.storeCertificate(name, ki) | ||||
| 		if err != nil { | ||||
| 			// TODO: Delete private key?
 | ||||
| 			return err | ||||
|  | @ -493,15 +619,19 @@ func (c *VFSCAStore) StoreKeypair(id string, cert *pki.Certificate, privateKey * | |||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (c *VFSCAStore) AddCert(id string, cert *pki.Certificate) error { | ||||
| 	glog.Infof("Adding TLS certificate: %q", id) | ||||
| func (c *VFSCAStore) AddCert(name string, cert *pki.Certificate) error { | ||||
| 	glog.Infof("Adding TLS certificate: %q", name) | ||||
| 
 | ||||
| 	// We add with a timestamp of zero so this will never be the newest cert
 | ||||
| 	serial := pki.BuildPKISerial(0) | ||||
| 	serial := pki.BuildPKISerial(0).String() | ||||
| 
 | ||||
| 	p := c.buildCertificatePath(id, serial) | ||||
| 	p := c.buildCertificatePath(name, serial) | ||||
| 
 | ||||
| 	err := c.storeCertificate(cert, p) | ||||
| 	ki := &keysetItem{ | ||||
| 		id:          serial, | ||||
| 		certificate: cert, | ||||
| 	} | ||||
| 	err := c.storeCertificate(name, ki) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | @ -511,7 +641,21 @@ func (c *VFSCAStore) AddCert(id string, cert *pki.Certificate) error { | |||
| 	return err | ||||
| } | ||||
| 
 | ||||
| func (c *VFSCAStore) loadPrivateKeys(p vfs.Path) (*keyset, error) { | ||||
| func (c *VFSCAStore) loadPrivateKeys(p vfs.Path, useBundle bool) (*keyset, error) { | ||||
| 	// Attempt to load prebuilt bundle, which avoids having to list files, which is a permission that can be hard to
 | ||||
| 	// give on GCE / other clouds
 | ||||
| 	if useBundle { | ||||
| 		bundlePath := p.Join("keyset.yaml") | ||||
| 		bundle, err := c.loadKeysetBundle(bundlePath) | ||||
| 		if err != nil { | ||||
| 			glog.Warningf("unable to read bundle %q, falling back to directory-list method: %v", bundlePath, err) | ||||
| 		} else if bundle == nil { | ||||
| 			glog.V(2).Infof("no certificate bundle %q, falling back to directory-list method", bundlePath) | ||||
| 		} else { | ||||
| 			return bundle, nil | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	files, err := p.ReadDir() | ||||
| 	if err != nil { | ||||
| 		if os.IsNotExist(err) { | ||||
|  | @ -525,12 +669,17 @@ func (c *VFSCAStore) loadPrivateKeys(p vfs.Path) (*keyset, error) { | |||
| 	} | ||||
| 
 | ||||
| 	for _, f := range files { | ||||
| 		id := f.Base() | ||||
| 		if strings.HasSuffix(id, ".yaml") { | ||||
| 			// ignore bundle
 | ||||
| 			continue | ||||
| 		} | ||||
| 		id = strings.TrimSuffix(id, ".key") | ||||
| 
 | ||||
| 		privateKey, err := c.loadOnePrivateKey(f) | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("error loading private key %q: %v", f, err) | ||||
| 		} | ||||
| 		id := f.Base() | ||||
| 		id = strings.TrimSuffix(id, ".key") | ||||
| 		keys.items[id] = &keysetItem{ | ||||
| 			id:         id, | ||||
| 			privateKey: privateKey, | ||||
|  | @ -572,11 +721,10 @@ func (c *VFSCAStore) FindPrivateKey(id string) (*pki.PrivateKey, error) { | |||
| 	} else { | ||||
| 		var err error | ||||
| 		p := c.buildPrivateKeyPoolPath(id) | ||||
| 		keys, err = c.loadPrivateKeys(p) | ||||
| 		keys, err = c.loadPrivateKeys(p, true) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	var key *pki.PrivateKey | ||||
|  | @ -597,33 +745,147 @@ func (c *VFSCAStore) CreateKeypair(signer string, id string, template *x509.Cert | |||
| 	return cert, nil | ||||
| } | ||||
| 
 | ||||
| func (c *VFSCAStore) storePrivateKey(privateKey *pki.PrivateKey, p vfs.Path) error { | ||||
| 	var data bytes.Buffer | ||||
| 	_, err := privateKey.WriteTo(&data) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| func (c *VFSCAStore) storePrivateKey(name string, ki *keysetItem) error { | ||||
| 	if ki.privateKey == nil { | ||||
| 		return fmt.Errorf("privateKey not provided to storeCertificate") | ||||
| 	} | ||||
| 
 | ||||
| 	acl, err := acls.GetACL(p, c.cluster) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	// Write the bundle
 | ||||
| 	{ | ||||
| 		p := c.buildPrivateKeyPoolPath(name) | ||||
| 		ks, err := c.loadPrivateKeys(p, false) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		if ks == nil { | ||||
| 			ks = &keyset{} | ||||
| 		} | ||||
| 		if ks.items == nil { | ||||
| 			ks.items = make(map[string]*keysetItem) | ||||
| 		} | ||||
| 		ks.items[ki.id] = ki | ||||
| 
 | ||||
| 		if err := c.writeKeysetBundle(p, name, ks, true); err != nil { | ||||
| 			return fmt.Errorf("error writing bundle: %v", err) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Write the data
 | ||||
| 	{ | ||||
| 		var data bytes.Buffer | ||||
| 		if _, err := ki.privateKey.WriteTo(&data); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		p := c.buildPrivateKeyPath(name, ki.id) | ||||
| 		acl, err := acls.GetACL(p, c.cluster) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		return p.WriteFile(data.Bytes(), acl) | ||||
| 	} | ||||
| 	return p.WriteFile(data.Bytes(), acl) | ||||
| } | ||||
| 
 | ||||
| func (c *VFSCAStore) storeCertificate(cert *pki.Certificate, p vfs.Path) error { | ||||
| 	// TODO: replace storePrivateKey & storeCertificate with writeFile(io.WriterTo)?
 | ||||
| 	var data bytes.Buffer | ||||
| 	_, err := cert.WriteTo(&data) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| func (c *VFSCAStore) storeCertificate(name string, ki *keysetItem) error { | ||||
| 	if ki.certificate == nil { | ||||
| 		return fmt.Errorf("certificate not provided to storeCertificate") | ||||
| 	} | ||||
| 
 | ||||
| 	acl, err := acls.GetACL(p, c.cluster) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	// Write the bundle
 | ||||
| 	{ | ||||
| 		p := c.buildCertificatePoolPath(name) | ||||
| 		ks, err := c.loadCertificates(p, false) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		if ks == nil { | ||||
| 			ks = &keyset{} | ||||
| 		} | ||||
| 		if ks.items == nil { | ||||
| 			ks.items = make(map[string]*keysetItem) | ||||
| 		} | ||||
| 		ks.items[ki.id] = ki | ||||
| 
 | ||||
| 		if err := c.writeKeysetBundle(p, name, ks, false); err != nil { | ||||
| 			return fmt.Errorf("error writing bundle: %v", err) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Write the data
 | ||||
| 	{ | ||||
| 		var data bytes.Buffer | ||||
| 		if _, err := ki.certificate.WriteTo(&data); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		p := c.buildCertificatePath(name, ki.id) | ||||
| 		acl, err := acls.GetACL(p, c.cluster) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		return p.WriteFile(data.Bytes(), acl) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (c *VFSCAStore) deletePrivateKey(name string, id string) (bool, error) { | ||||
| 	// Update the bundle
 | ||||
| 	{ | ||||
| 		p := c.buildPrivateKeyPoolPath(name) | ||||
| 		ks, err := c.loadPrivateKeys(p, false) | ||||
| 		if err != nil { | ||||
| 			return false, err | ||||
| 		} | ||||
| 
 | ||||
| 		if ks == nil || ks.items[id] == nil { | ||||
| 			return false, nil | ||||
| 		} | ||||
| 		delete(ks.items, id) | ||||
| 
 | ||||
| 		if err := c.writeKeysetBundle(p, name, ks, true); err != nil { | ||||
| 			return false, fmt.Errorf("error writing bundle: %v", err) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Delete the file itself
 | ||||
| 	{ | ||||
| 
 | ||||
| 		p := c.buildPrivateKeyPath(name, id) | ||||
| 		if err := p.Remove(); err != nil { | ||||
| 			return false, err | ||||
| 		} | ||||
| 		return true, nil | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (c *VFSCAStore) deleteCertificate(name string, id string) (bool, error) { | ||||
| 	// Update the bundle
 | ||||
| 	{ | ||||
| 		p := c.buildPrivateKeyPoolPath(name) | ||||
| 		ks, err := c.loadCertificates(p, false) | ||||
| 		if err != nil { | ||||
| 			return false, err | ||||
| 		} | ||||
| 
 | ||||
| 		if ks == nil || ks.items[id] == nil { | ||||
| 			return false, nil | ||||
| 		} | ||||
| 		delete(ks.items, id) | ||||
| 
 | ||||
| 		if err := c.writeKeysetBundle(p, name, ks, false); err != nil { | ||||
| 			return false, fmt.Errorf("error writing bundle: %v", err) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Delete the file itself
 | ||||
| 	{ | ||||
| 		p := c.buildCertificatePath(name, id) | ||||
| 		if err := p.Remove(); err != nil { | ||||
| 			return false, err | ||||
| 		} | ||||
| 		return true, nil | ||||
| 	} | ||||
| 	return p.WriteFile(data.Bytes(), acl) | ||||
| } | ||||
| 
 | ||||
| func (c *VFSCAStore) buildSerial() *big.Int { | ||||
|  | @ -705,18 +967,24 @@ func (c *VFSCAStore) loadData(p vfs.Path) (*pki.PrivateKey, error) { | |||
| func (c *VFSCAStore) DeleteKeysetItem(item *kops.Keyset, id string) error { | ||||
| 	switch item.Spec.Type { | ||||
| 	case kops.SecretTypeKeypair: | ||||
| 		version, ok := big.NewInt(0).SetString(id, 10) | ||||
| 		_, ok := big.NewInt(0).SetString(id, 10) | ||||
| 		if !ok { | ||||
| 			return fmt.Errorf("keypair had non-integer version: %q", id) | ||||
| 		} | ||||
| 		p := c.buildCertificatePath(item.Name, version) | ||||
| 		if err := p.Remove(); err != nil { | ||||
| 		removed, err := c.deleteCertificate(item.Name, id) | ||||
| 		if err != nil { | ||||
| 			return fmt.Errorf("error deleting certificate: %v", err) | ||||
| 		} | ||||
| 		p = c.buildPrivateKeyPath(item.Name, version) | ||||
| 		if err := p.Remove(); err != nil { | ||||
| 		if !removed { | ||||
| 			glog.Warningf("certificate %s:%s was not found", item.Name, id) | ||||
| 		} | ||||
| 		removed, err = c.deletePrivateKey(item.Name, id) | ||||
| 		if err != nil { | ||||
| 			return fmt.Errorf("error deleting private key: %v", err) | ||||
| 		} | ||||
| 		if !removed { | ||||
| 			glog.Warningf("private key %s:%s was not found", item.Name, id) | ||||
| 		} | ||||
| 		return nil | ||||
| 
 | ||||
| 	default: | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue