mirror of https://github.com/kubernetes/kops.git
Merge pull request #3288 from justinsb/refactor_pki
Automatic merge from submit-queue Refactor PKI classes into their own package
This commit is contained in:
commit
327235a22c
|
|
@ -36,6 +36,7 @@ import (
|
|||
"k8s.io/kops/pkg/apis/kops/registry"
|
||||
"k8s.io/kops/pkg/client/simple"
|
||||
"k8s.io/kops/pkg/kubeconfig"
|
||||
"k8s.io/kops/pkg/pki"
|
||||
"k8s.io/kops/upup/pkg/fi"
|
||||
"k8s.io/kops/upup/pkg/fi/fitasks"
|
||||
"k8s.io/kops/upup/pkg/fi/k8sapi"
|
||||
|
|
@ -398,7 +399,7 @@ func (o *ApplyFederationOperation) ensureFederationNamespace(k8s federation_clie
|
|||
})
|
||||
}
|
||||
|
||||
func EnsureCASecret(keystore fi.Keystore) (*fi.Certificate, *fi.PrivateKey, error) {
|
||||
func EnsureCASecret(keystore fi.Keystore) (*pki.Certificate, *pki.PrivateKey, error) {
|
||||
id := fi.CertificateId_CA
|
||||
caCert, caPrivateKey, err := keystore.FindKeypair(id)
|
||||
if err != nil {
|
||||
|
|
@ -411,9 +412,9 @@ func EnsureCASecret(keystore fi.Keystore) (*fi.Certificate, *fi.PrivateKey, erro
|
|||
return nil, nil, fmt.Errorf("error generating RSA private key: %v", err)
|
||||
}
|
||||
|
||||
caPrivateKey = &fi.PrivateKey{Key: caRsaKey}
|
||||
caPrivateKey = &pki.PrivateKey{Key: caRsaKey}
|
||||
|
||||
caCert, err = fi.SignNewCertificate(caPrivateKey, template, nil, nil)
|
||||
caCert, err = pki.SignNewCertificate(caPrivateKey, template, nil, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import (
|
|||
"k8s.io/kops/federation/targets/kubernetestarget"
|
||||
kopsapi "k8s.io/kops/pkg/apis/kops"
|
||||
"k8s.io/kops/pkg/kubeconfig"
|
||||
"k8s.io/kops/pkg/pki"
|
||||
"k8s.io/kops/upup/pkg/fi"
|
||||
"k8s.io/kops/upup/pkg/fi/fitasks"
|
||||
)
|
||||
|
|
@ -275,7 +276,7 @@ func (o *FederationConfiguration) EnsureConfiguration(c *fi.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (o *FederationConfiguration) ensureSecretKubeconfig(c *fi.Context, caCert *fi.Certificate, user kubeconfig.KubectlUser) error {
|
||||
func (o *FederationConfiguration) ensureSecretKubeconfig(c *fi.Context, caCert *pki.Certificate, user kubeconfig.KubectlUser) error {
|
||||
k8s := c.Target.(*kubernetestarget.KubernetesTarget).KubernetesClient
|
||||
|
||||
_, err := mutateSecret(k8s, o.Namespace, o.KubeconfigSecretName, func(s *v1.Secret) (*v1.Secret, error) {
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ k8s.io/kops/pkg/model/iam
|
|||
k8s.io/kops/pkg/model/resources
|
||||
k8s.io/kops/pkg/model/vspheremodel
|
||||
k8s.io/kops/pkg/openapi
|
||||
k8s.io/kops/pkg/pki
|
||||
k8s.io/kops/pkg/pretty
|
||||
k8s.io/kops/pkg/resources
|
||||
k8s.io/kops/pkg/resources/digitalocean
|
||||
|
|
|
|||
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
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 pki
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"github.com/golang/glog"
|
||||
"io"
|
||||
)
|
||||
|
||||
type Certificate struct {
|
||||
Subject pkix.Name
|
||||
IsCA bool
|
||||
|
||||
Certificate *x509.Certificate
|
||||
PublicKey crypto.PublicKey
|
||||
}
|
||||
|
||||
func (c *Certificate) UnmarshalJSON(b []byte) error {
|
||||
s := ""
|
||||
if err := json.Unmarshal(b, &s); err == nil {
|
||||
r, err := LoadPEMCertificate([]byte(s))
|
||||
if err != nil {
|
||||
// Alternative form: Check if base64 encoded
|
||||
// TODO: Do we need this? I think we need this only on nodeup, but maybe we could just not base64-it?
|
||||
d, err2 := base64.StdEncoding.DecodeString(s)
|
||||
if err2 == nil {
|
||||
r2, err2 := LoadPEMCertificate(d)
|
||||
if err2 == nil {
|
||||
glog.Warningf("used base64 decode of certificate")
|
||||
r = r2
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
glog.Infof("Invalid certificate data: %q", string(b))
|
||||
return fmt.Errorf("error parsing certificate: %v", err)
|
||||
}
|
||||
}
|
||||
*c = *r
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown format for Certificate: %q", string(b))
|
||||
}
|
||||
|
||||
func (c *Certificate) MarshalJSON() ([]byte, error) {
|
||||
var data bytes.Buffer
|
||||
_, err := c.WriteTo(&data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error writing SSL certificate: %v", err)
|
||||
}
|
||||
return json.Marshal(data.String())
|
||||
}
|
||||
|
||||
func LoadPEMCertificate(pemData []byte) (*Certificate, error) {
|
||||
cert, err := parsePEMCertificate(pemData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c := &Certificate{
|
||||
Subject: cert.Subject,
|
||||
Certificate: cert,
|
||||
PublicKey: cert.PublicKey,
|
||||
IsCA: cert.IsCA,
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
var _ io.WriterTo = &Certificate{}
|
||||
|
||||
func parsePEMCertificate(pemData []byte) (*x509.Certificate, error) {
|
||||
for {
|
||||
block, rest := pem.Decode(pemData)
|
||||
if block == nil {
|
||||
return nil, fmt.Errorf("could not parse certificate")
|
||||
}
|
||||
|
||||
if block.Type == "CERTIFICATE" {
|
||||
glog.V(8).Infof("Parsing pem block: %q", block.Type)
|
||||
return x509.ParseCertificate(block.Bytes)
|
||||
} else {
|
||||
glog.Infof("Ignoring unexpected PEM block: %q", block.Type)
|
||||
}
|
||||
|
||||
pemData = rest
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Certificate) AsString() (string, error) {
|
||||
// Nicer behaviour because this is called from templates
|
||||
if c == nil {
|
||||
return "", fmt.Errorf("AsString called on nil Certificate")
|
||||
}
|
||||
|
||||
var data bytes.Buffer
|
||||
_, err := c.WriteTo(&data)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error writing SSL certificate: %v", err)
|
||||
}
|
||||
return data.String(), nil
|
||||
}
|
||||
|
||||
func (c *Certificate) AsBytes() ([]byte, error) {
|
||||
// Nicer behaviour because this is called from templates
|
||||
if c == nil {
|
||||
return nil, fmt.Errorf("AsBytes called on nil Certificate")
|
||||
}
|
||||
|
||||
var data bytes.Buffer
|
||||
_, err := c.WriteTo(&data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error writing SSL certificate: %v", err)
|
||||
}
|
||||
return data.Bytes(), nil
|
||||
}
|
||||
|
||||
func (c *Certificate) WriteTo(w io.Writer) (int64, error) {
|
||||
// For the dry-run case
|
||||
if c.Certificate == nil {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
var b bytes.Buffer
|
||||
err := pem.Encode(&b, &pem.Block{Type: "CERTIFICATE", Bytes: c.Certificate.Raw})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return b.WriteTo(w)
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
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 pki
|
||||
|
||||
import (
|
||||
crypto_rand "crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"github.com/golang/glog"
|
||||
"math/big"
|
||||
"time"
|
||||
)
|
||||
|
||||
// BuildPKISerial produces a serial number for certs that is vanishingly unlikely to collide
|
||||
// The timestamp should be provided as an input (time.Now().UnixNano()), and then we combine
|
||||
// that with a 32 bit random crypto-rand integer.
|
||||
// We also know that a bigger value was created later (modulo clock skew)
|
||||
func BuildPKISerial(timestamp int64) *big.Int {
|
||||
randomLimit := new(big.Int).Lsh(big.NewInt(1), 32)
|
||||
randomComponent, err := crypto_rand.Int(crypto_rand.Reader, randomLimit)
|
||||
if err != nil {
|
||||
glog.Fatalf("error generating random number: %v", err)
|
||||
}
|
||||
|
||||
serial := big.NewInt(timestamp)
|
||||
serial.Lsh(serial, 32)
|
||||
serial.Or(serial, randomComponent)
|
||||
|
||||
return serial
|
||||
}
|
||||
|
||||
func SignNewCertificate(privateKey *PrivateKey, template *x509.Certificate, signer *x509.Certificate, signerPrivateKey *PrivateKey) (*Certificate, error) {
|
||||
if template.PublicKey == nil {
|
||||
rsaPrivateKey, ok := privateKey.Key.(*rsa.PrivateKey)
|
||||
if ok {
|
||||
template.PublicKey = rsaPrivateKey.Public()
|
||||
}
|
||||
}
|
||||
|
||||
if template.PublicKey == nil {
|
||||
return nil, fmt.Errorf("PublicKey not set, and cannot be determined from %T", privateKey)
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
if template.NotBefore.IsZero() {
|
||||
template.NotBefore = now.Add(time.Hour * -48)
|
||||
}
|
||||
|
||||
if template.NotAfter.IsZero() {
|
||||
template.NotAfter = now.Add(time.Hour * 10 * 365 * 24)
|
||||
}
|
||||
|
||||
if template.SerialNumber == nil {
|
||||
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
|
||||
serialNumber, err := crypto_rand.Int(crypto_rand.Reader, serialNumberLimit)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error generating certificate serial number: %s", err)
|
||||
}
|
||||
template.SerialNumber = serialNumber
|
||||
}
|
||||
var parent *x509.Certificate
|
||||
if signer != nil {
|
||||
parent = signer
|
||||
} else {
|
||||
parent = template
|
||||
signerPrivateKey = privateKey
|
||||
}
|
||||
|
||||
if template.KeyUsage == 0 {
|
||||
template.KeyUsage = x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment
|
||||
}
|
||||
|
||||
if template.ExtKeyUsage == nil {
|
||||
template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}
|
||||
}
|
||||
//c.SignatureAlgorithm = do we want to overrride?
|
||||
|
||||
certificateData, err := x509.CreateCertificate(crypto_rand.Reader, template, parent, template.PublicKey, signerPrivateKey.Key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating certificate: %v", err)
|
||||
}
|
||||
|
||||
c := &Certificate{}
|
||||
c.PublicKey = template.PublicKey
|
||||
|
||||
cert, err := x509.ParseCertificate(certificateData)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing certificate: %v", err)
|
||||
}
|
||||
c.Certificate = cert
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
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 pki
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
crypto_rand "crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"github.com/golang/glog"
|
||||
"io"
|
||||
)
|
||||
|
||||
func ParsePEMPrivateKey(data []byte) (*PrivateKey, error) {
|
||||
k, err := parsePEMPrivateKey(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if k == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return &PrivateKey{Key: k}, nil
|
||||
}
|
||||
|
||||
func GeneratePrivateKey() (*PrivateKey, error) {
|
||||
rsaKey, err := rsa.GenerateKey(crypto_rand.Reader, 2048)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error generating RSA private key: %v", err)
|
||||
}
|
||||
|
||||
privateKey := &PrivateKey{Key: rsaKey}
|
||||
return privateKey, nil
|
||||
}
|
||||
|
||||
type PrivateKey struct {
|
||||
Key crypto.PrivateKey
|
||||
}
|
||||
|
||||
func (k *PrivateKey) AsString() (string, error) {
|
||||
// Nicer behaviour because this is called from templates
|
||||
if k == nil {
|
||||
return "", fmt.Errorf("AsString called on nil private key")
|
||||
}
|
||||
|
||||
var data bytes.Buffer
|
||||
_, err := k.WriteTo(&data)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error writing SSL private key: %v", err)
|
||||
}
|
||||
return data.String(), nil
|
||||
}
|
||||
|
||||
func (k *PrivateKey) AsBytes() ([]byte, error) {
|
||||
// Nicer behaviour because this is called from templates
|
||||
if k == nil {
|
||||
return nil, fmt.Errorf("AsBytes called on nil private key")
|
||||
}
|
||||
|
||||
var data bytes.Buffer
|
||||
_, err := k.WriteTo(&data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error writing SSL PrivateKey: %v", err)
|
||||
}
|
||||
return data.Bytes(), nil
|
||||
}
|
||||
|
||||
func (k *PrivateKey) UnmarshalJSON(b []byte) (err error) {
|
||||
s := ""
|
||||
if err := json.Unmarshal(b, &s); err == nil {
|
||||
r, err := parsePEMPrivateKey([]byte(s))
|
||||
if err != nil {
|
||||
// Alternative form: Check if base64 encoded
|
||||
// TODO: Do we need this? I think we need this only on nodeup, but maybe we could just not base64-it?
|
||||
d, err2 := base64.StdEncoding.DecodeString(s)
|
||||
if err2 == nil {
|
||||
r2, err2 := parsePEMPrivateKey(d)
|
||||
if err2 == nil {
|
||||
glog.Warningf("used base64 decode of PrivateKey")
|
||||
r = r2
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing private key: %v", err)
|
||||
}
|
||||
}
|
||||
k.Key = r
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("unknown format for private key: %q", string(b))
|
||||
}
|
||||
|
||||
func (k *PrivateKey) MarshalJSON() ([]byte, error) {
|
||||
var data bytes.Buffer
|
||||
_, err := k.WriteTo(&data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error writing SSL private key: %v", err)
|
||||
}
|
||||
return json.Marshal(data.String())
|
||||
}
|
||||
|
||||
var _ io.WriterTo = &PrivateKey{}
|
||||
|
||||
func (k *PrivateKey) WriteTo(w io.Writer) (int64, error) {
|
||||
if k.Key == nil {
|
||||
// For the dry-run case
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
var data bytes.Buffer
|
||||
var err error
|
||||
|
||||
switch pk := k.Key.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
err = pem.Encode(w, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(pk)})
|
||||
default:
|
||||
return 0, fmt.Errorf("unknown private key type: %T", k.Key)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("error writing SSL private key: %v", err)
|
||||
}
|
||||
|
||||
return data.WriteTo(w)
|
||||
}
|
||||
|
||||
func parsePEMPrivateKey(pemData []byte) (crypto.PrivateKey, error) {
|
||||
for {
|
||||
block, rest := pem.Decode(pemData)
|
||||
if block == nil {
|
||||
return nil, fmt.Errorf("could not parse private key")
|
||||
}
|
||||
|
||||
if block.Type == "RSA PRIVATE KEY" {
|
||||
glog.V(8).Infof("Parsing pem block: %q", block.Type)
|
||||
return x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||
} else if block.Type == "PRIVATE KEY" {
|
||||
glog.V(8).Infof("Parsing pem block: %q", block.Type)
|
||||
k, err := x509.ParsePKCS8PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return k.(crypto.PrivateKey), nil
|
||||
} else {
|
||||
glog.Infof("Ignoring unexpected PEM block: %q", block.Type)
|
||||
}
|
||||
|
||||
pemData = rest
|
||||
}
|
||||
}
|
||||
|
|
@ -18,34 +18,15 @@ package fi
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
crypto_rand "crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"k8s.io/kops/pkg/pki"
|
||||
"k8s.io/kops/util/pkg/vfs"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
const CertificateId_CA = "ca"
|
||||
|
||||
type Certificate struct {
|
||||
Subject pkix.Name
|
||||
IsCA bool
|
||||
|
||||
Certificate *x509.Certificate
|
||||
PublicKey crypto.PublicKey
|
||||
}
|
||||
|
||||
const (
|
||||
SecretTypeSSHPublicKey = "SSHPublicKey"
|
||||
SecretTypeKeypair = "Keypair"
|
||||
|
|
@ -62,76 +43,29 @@ type KeystoreItem struct {
|
|||
Data []byte
|
||||
}
|
||||
|
||||
func (c *Certificate) UnmarshalJSON(b []byte) error {
|
||||
s := ""
|
||||
if err := json.Unmarshal(b, &s); err == nil {
|
||||
r, err := LoadPEMCertificate([]byte(s))
|
||||
if err != nil {
|
||||
// Alternative form: Check if base64 encoded
|
||||
// TODO: Do we need this? I think we need this only on nodeup, but maybe we could just not base64-it?
|
||||
d, err2 := base64.StdEncoding.DecodeString(s)
|
||||
if err2 == nil {
|
||||
r2, err2 := LoadPEMCertificate(d)
|
||||
if err2 == nil {
|
||||
glog.Warningf("used base64 decode of certificate")
|
||||
r = r2
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
glog.Infof("Invalid certificate data: %q", string(b))
|
||||
return fmt.Errorf("error parsing certificate: %v", err)
|
||||
}
|
||||
}
|
||||
*c = *r
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown format for Certificate: %q", string(b))
|
||||
}
|
||||
|
||||
func (c *Certificate) MarshalJSON() ([]byte, error) {
|
||||
var data bytes.Buffer
|
||||
_, err := c.WriteTo(&data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error writing SSL certificate: %v", err)
|
||||
}
|
||||
return json.Marshal(data.String())
|
||||
}
|
||||
|
||||
// Keystore contains just the functions we need to issue keypairs, not to list / manage them
|
||||
type Keystore interface {
|
||||
// FindKeypair finds a cert & private key, returning nil where either is not found
|
||||
// (if the certificate is found but not keypair, that is not an error: only the cert will be returned)
|
||||
FindKeypair(name string) (*Certificate, *PrivateKey, error)
|
||||
FindKeypair(name string) (*pki.Certificate, *pki.PrivateKey, error)
|
||||
|
||||
CreateKeypair(name string, template *x509.Certificate, privateKey *PrivateKey) (*Certificate, error)
|
||||
CreateKeypair(name string, template *x509.Certificate, privateKey *pki.PrivateKey) (*pki.Certificate, error)
|
||||
|
||||
// Store the keypair
|
||||
StoreKeypair(id string, cert *Certificate, privateKey *PrivateKey) error
|
||||
}
|
||||
|
||||
func GeneratePrivateKey() (*PrivateKey, error) {
|
||||
rsaKey, err := rsa.GenerateKey(crypto_rand.Reader, 2048)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error generating RSA private key: %v", err)
|
||||
}
|
||||
|
||||
privateKey := &PrivateKey{Key: rsaKey}
|
||||
return privateKey, nil
|
||||
StoreKeypair(id string, cert *pki.Certificate, privateKey *pki.PrivateKey) error
|
||||
}
|
||||
|
||||
type CAStore interface {
|
||||
Keystore
|
||||
|
||||
// Cert returns the primary specified certificate
|
||||
Cert(name string) (*Certificate, error)
|
||||
Cert(name string) (*pki.Certificate, error)
|
||||
// CertificatePool returns all active certificates with the specified id
|
||||
CertificatePool(name string) (*CertificatePool, error)
|
||||
PrivateKey(name string) (*PrivateKey, error)
|
||||
PrivateKey(name string) (*pki.PrivateKey, error)
|
||||
|
||||
FindCert(name string) (*Certificate, error)
|
||||
FindPrivateKey(name string) (*PrivateKey, error)
|
||||
FindCert(name string) (*pki.Certificate, error)
|
||||
FindPrivateKey(name string) (*pki.PrivateKey, error)
|
||||
|
||||
// List will list all the items, but will not fetch the data
|
||||
List() ([]*KeystoreItem, error)
|
||||
|
|
@ -140,7 +74,7 @@ type CAStore interface {
|
|||
VFSPath() vfs.Path
|
||||
|
||||
// AddCert adds an alternative certificate to the pool (primarily useful for CAs)
|
||||
AddCert(name string, cert *Certificate) error
|
||||
AddCert(name string, cert *pki.Certificate) error
|
||||
|
||||
// AddSSHPublicKey adds an SSH public key
|
||||
AddSSHPublicKey(name string, data []byte) error
|
||||
|
|
@ -152,268 +86,9 @@ type CAStore interface {
|
|||
DeleteSecret(item *KeystoreItem) error
|
||||
}
|
||||
|
||||
func (c *Certificate) AsString() (string, error) {
|
||||
// Nicer behaviour because this is called from templates
|
||||
if c == nil {
|
||||
return "", fmt.Errorf("AsString called on nil Certificate")
|
||||
}
|
||||
|
||||
var data bytes.Buffer
|
||||
_, err := c.WriteTo(&data)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error writing SSL certificate: %v", err)
|
||||
}
|
||||
return data.String(), nil
|
||||
}
|
||||
|
||||
func (c *Certificate) AsBytes() ([]byte, error) {
|
||||
// Nicer behaviour because this is called from templates
|
||||
if c == nil {
|
||||
return nil, fmt.Errorf("AsBytes called on nil Certificate")
|
||||
}
|
||||
|
||||
var data bytes.Buffer
|
||||
_, err := c.WriteTo(&data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error writing SSL certificate: %v", err)
|
||||
}
|
||||
return data.Bytes(), nil
|
||||
}
|
||||
|
||||
type PrivateKey struct {
|
||||
Key crypto.PrivateKey
|
||||
}
|
||||
|
||||
func (k *PrivateKey) AsString() (string, error) {
|
||||
// Nicer behaviour because this is called from templates
|
||||
if k == nil {
|
||||
return "", fmt.Errorf("AsString called on nil private key")
|
||||
}
|
||||
|
||||
var data bytes.Buffer
|
||||
_, err := k.WriteTo(&data)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error writing SSL private key: %v", err)
|
||||
}
|
||||
return data.String(), nil
|
||||
}
|
||||
|
||||
func (k *PrivateKey) AsBytes() ([]byte, error) {
|
||||
// Nicer behaviour because this is called from templates
|
||||
if k == nil {
|
||||
return nil, fmt.Errorf("AsBytes called on nil private key")
|
||||
}
|
||||
|
||||
var data bytes.Buffer
|
||||
_, err := k.WriteTo(&data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error writing SSL PrivateKey: %v", err)
|
||||
}
|
||||
return data.Bytes(), nil
|
||||
}
|
||||
|
||||
func (k *PrivateKey) UnmarshalJSON(b []byte) (err error) {
|
||||
s := ""
|
||||
if err := json.Unmarshal(b, &s); err == nil {
|
||||
r, err := parsePEMPrivateKey([]byte(s))
|
||||
if err != nil {
|
||||
// Alternative form: Check if base64 encoded
|
||||
// TODO: Do we need this? I think we need this only on nodeup, but maybe we could just not base64-it?
|
||||
d, err2 := base64.StdEncoding.DecodeString(s)
|
||||
if err2 == nil {
|
||||
r2, err2 := parsePEMPrivateKey(d)
|
||||
if err2 == nil {
|
||||
glog.Warningf("used base64 decode of PrivateKey")
|
||||
r = r2
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing private key: %v", err)
|
||||
}
|
||||
}
|
||||
k.Key = r
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("unknown format for private key: %q", string(b))
|
||||
}
|
||||
|
||||
func (k *PrivateKey) MarshalJSON() ([]byte, error) {
|
||||
var data bytes.Buffer
|
||||
_, err := k.WriteTo(&data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error writing SSL private key: %v", err)
|
||||
}
|
||||
return json.Marshal(data.String())
|
||||
}
|
||||
|
||||
var _ io.WriterTo = &PrivateKey{}
|
||||
|
||||
func (k *PrivateKey) WriteTo(w io.Writer) (int64, error) {
|
||||
if k.Key == nil {
|
||||
// For the dry-run case
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
var data bytes.Buffer
|
||||
var err error
|
||||
|
||||
switch pk := k.Key.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
err = pem.Encode(w, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(pk)})
|
||||
default:
|
||||
return 0, fmt.Errorf("unknown private key type: %T", k.Key)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("error writing SSL private key: %v", err)
|
||||
}
|
||||
|
||||
return data.WriteTo(w)
|
||||
}
|
||||
|
||||
func LoadPEMCertificate(pemData []byte) (*Certificate, error) {
|
||||
cert, err := parsePEMCertificate(pemData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c := &Certificate{
|
||||
Subject: cert.Subject,
|
||||
Certificate: cert,
|
||||
PublicKey: cert.PublicKey,
|
||||
IsCA: cert.IsCA,
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func SignNewCertificate(privateKey *PrivateKey, template *x509.Certificate, signer *x509.Certificate, signerPrivateKey *PrivateKey) (*Certificate, error) {
|
||||
if template.PublicKey == nil {
|
||||
rsaPrivateKey, ok := privateKey.Key.(*rsa.PrivateKey)
|
||||
if ok {
|
||||
template.PublicKey = rsaPrivateKey.Public()
|
||||
}
|
||||
}
|
||||
|
||||
if template.PublicKey == nil {
|
||||
return nil, fmt.Errorf("PublicKey not set, and cannot be determined from %T", privateKey)
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
if template.NotBefore.IsZero() {
|
||||
template.NotBefore = now.Add(time.Hour * -48)
|
||||
}
|
||||
|
||||
if template.NotAfter.IsZero() {
|
||||
template.NotAfter = now.Add(time.Hour * 10 * 365 * 24)
|
||||
}
|
||||
|
||||
if template.SerialNumber == nil {
|
||||
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
|
||||
serialNumber, err := crypto_rand.Int(crypto_rand.Reader, serialNumberLimit)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error generating certificate serial number: %s", err)
|
||||
}
|
||||
template.SerialNumber = serialNumber
|
||||
}
|
||||
var parent *x509.Certificate
|
||||
if signer != nil {
|
||||
parent = signer
|
||||
} else {
|
||||
parent = template
|
||||
signerPrivateKey = privateKey
|
||||
}
|
||||
|
||||
if template.KeyUsage == 0 {
|
||||
template.KeyUsage = x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment
|
||||
}
|
||||
|
||||
if template.ExtKeyUsage == nil {
|
||||
template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}
|
||||
}
|
||||
//c.SignatureAlgorithm = do we want to overrride?
|
||||
|
||||
certificateData, err := x509.CreateCertificate(crypto_rand.Reader, template, parent, template.PublicKey, signerPrivateKey.Key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating certificate: %v", err)
|
||||
}
|
||||
|
||||
c := &Certificate{}
|
||||
c.PublicKey = template.PublicKey
|
||||
|
||||
cert, err := x509.ParseCertificate(certificateData)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing certificate: %v", err)
|
||||
}
|
||||
c.Certificate = cert
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
var _ io.WriterTo = &Certificate{}
|
||||
|
||||
func (c *Certificate) WriteTo(w io.Writer) (int64, error) {
|
||||
// For the dry-run case
|
||||
if c.Certificate == nil {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
var b bytes.Buffer
|
||||
err := pem.Encode(&b, &pem.Block{Type: "CERTIFICATE", Bytes: c.Certificate.Raw})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return b.WriteTo(w)
|
||||
}
|
||||
|
||||
func parsePEMCertificate(pemData []byte) (*x509.Certificate, error) {
|
||||
for {
|
||||
block, rest := pem.Decode(pemData)
|
||||
if block == nil {
|
||||
return nil, fmt.Errorf("could not parse certificate")
|
||||
}
|
||||
|
||||
if block.Type == "CERTIFICATE" {
|
||||
glog.V(8).Infof("Parsing pem block: %q", block.Type)
|
||||
return x509.ParseCertificate(block.Bytes)
|
||||
} else {
|
||||
glog.Infof("Ignoring unexpected PEM block: %q", block.Type)
|
||||
}
|
||||
|
||||
pemData = rest
|
||||
}
|
||||
}
|
||||
|
||||
func parsePEMPrivateKey(pemData []byte) (crypto.PrivateKey, error) {
|
||||
for {
|
||||
block, rest := pem.Decode(pemData)
|
||||
if block == nil {
|
||||
return nil, fmt.Errorf("could not parse private key")
|
||||
}
|
||||
|
||||
if block.Type == "RSA PRIVATE KEY" {
|
||||
glog.V(8).Infof("Parsing pem block: %q", block.Type)
|
||||
return x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||
} else if block.Type == "PRIVATE KEY" {
|
||||
glog.V(8).Infof("Parsing pem block: %q", block.Type)
|
||||
k, err := x509.ParsePKCS8PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return k.(crypto.PrivateKey), nil
|
||||
} else {
|
||||
glog.Infof("Ignoring unexpected PEM block: %q", block.Type)
|
||||
}
|
||||
|
||||
pemData = rest
|
||||
}
|
||||
}
|
||||
|
||||
type CertificatePool struct {
|
||||
Secondary []*Certificate
|
||||
Primary *Certificate
|
||||
Secondary []*pki.Certificate
|
||||
Primary *pki.Certificate
|
||||
}
|
||||
|
||||
func (c *CertificatePool) AsString() (string, error) {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/kops/pkg/pki"
|
||||
"k8s.io/kops/upup/pkg/fi"
|
||||
)
|
||||
|
||||
|
|
@ -177,7 +178,7 @@ func (_ *Keypair) Render(c *fi.Context, a, e, changes *Keypair) error {
|
|||
// if we change keys we often have to regenerate e.g. the service accounts
|
||||
// TODO: Eventually rotate keys / don't always reuse?
|
||||
if privateKey == nil {
|
||||
privateKey, err = fi.GeneratePrivateKey()
|
||||
privateKey, err = pki.GeneratePrivateKey()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ package k8sapi
|
|||
import (
|
||||
"fmt"
|
||||
"k8s.io/client-go/pkg/api/v1"
|
||||
"k8s.io/kops/upup/pkg/fi"
|
||||
"k8s.io/kops/pkg/pki"
|
||||
)
|
||||
|
||||
// KeypairSecret is a wrapper around a k8s Secret object that holds a TLS keypair
|
||||
|
|
@ -27,8 +27,8 @@ type KeypairSecret struct {
|
|||
Namespace string
|
||||
Name string
|
||||
|
||||
Certificate *fi.Certificate
|
||||
PrivateKey *fi.PrivateKey
|
||||
Certificate *pki.Certificate
|
||||
PrivateKey *pki.PrivateKey
|
||||
}
|
||||
|
||||
// ParseKeypairSecret parses the secret object, decoding the certificate & private-key, if present
|
||||
|
|
@ -39,7 +39,7 @@ func ParseKeypairSecret(secret *v1.Secret) (*KeypairSecret, error) {
|
|||
|
||||
certData := secret.Data[v1.TLSCertKey]
|
||||
if certData != nil {
|
||||
cert, err := fi.LoadPEMCertificate(certData)
|
||||
cert, err := pki.LoadPEMCertificate(certData)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing certificate in %s/%s: %q", k.Namespace, k.Name, err)
|
||||
}
|
||||
|
|
@ -47,7 +47,7 @@ func ParseKeypairSecret(secret *v1.Secret) (*KeypairSecret, error) {
|
|||
}
|
||||
keyData := secret.Data[v1.TLSPrivateKeyKey]
|
||||
if keyData != nil {
|
||||
key, err := fi.ParsePEMPrivateKey(keyData)
|
||||
key, err := pki.ParsePEMPrivateKey(keyData)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing key in %s/%s: %q", k.Namespace, k.Name, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import (
|
|||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/pkg/api/v1"
|
||||
"k8s.io/kops/pkg/pki"
|
||||
"k8s.io/kops/upup/pkg/fi"
|
||||
"math/big"
|
||||
"time"
|
||||
|
|
@ -49,7 +50,7 @@ func NewKubernetesKeystore(client kubernetes.Interface, namespace string) fi.Key
|
|||
return c
|
||||
}
|
||||
|
||||
func (c *KubernetesKeystore) issueCert(id string, serial *big.Int, privateKey *fi.PrivateKey, template *x509.Certificate) (*fi.Certificate, error) {
|
||||
func (c *KubernetesKeystore) issueCert(id string, serial *big.Int, privateKey *pki.PrivateKey, template *x509.Certificate) (*pki.Certificate, error) {
|
||||
glog.Infof("Issuing new certificate: %q", id)
|
||||
|
||||
template.SerialNumber = serial
|
||||
|
|
@ -63,7 +64,7 @@ func (c *KubernetesKeystore) issueCert(id string, serial *big.Int, privateKey *f
|
|||
return nil, fmt.Errorf("CA keypair was not found; cannot issue certificates")
|
||||
}
|
||||
|
||||
cert, err := fi.SignNewCertificate(privateKey, template, caCert.Certificate, caKey)
|
||||
cert, err := pki.SignNewCertificate(privateKey, template, caCert.Certificate, caKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -87,7 +88,7 @@ func (c *KubernetesKeystore) findSecret(id string) (*v1.Secret, error) {
|
|||
return secret, nil
|
||||
}
|
||||
|
||||
func (c *KubernetesKeystore) FindKeypair(id string) (*fi.Certificate, *fi.PrivateKey, error) {
|
||||
func (c *KubernetesKeystore) FindKeypair(id string) (*pki.Certificate, *pki.PrivateKey, error) {
|
||||
secret, err := c.findSecret(id)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
|
@ -105,9 +106,9 @@ func (c *KubernetesKeystore) FindKeypair(id string) (*fi.Certificate, *fi.Privat
|
|||
return keypair.Certificate, keypair.PrivateKey, nil
|
||||
}
|
||||
|
||||
func (c *KubernetesKeystore) CreateKeypair(id string, template *x509.Certificate, privateKey *fi.PrivateKey) (*fi.Certificate, error) {
|
||||
func (c *KubernetesKeystore) CreateKeypair(id string, template *x509.Certificate, privateKey *pki.PrivateKey) (*pki.Certificate, error) {
|
||||
t := time.Now().UnixNano()
|
||||
serial := fi.BuildPKISerial(t)
|
||||
serial := pki.BuildPKISerial(t)
|
||||
|
||||
cert, err := c.issueCert(id, serial, privateKey, template)
|
||||
if err != nil {
|
||||
|
|
@ -117,7 +118,7 @@ func (c *KubernetesKeystore) CreateKeypair(id string, template *x509.Certificate
|
|||
return cert, nil
|
||||
}
|
||||
|
||||
func (c *KubernetesKeystore) StoreKeypair(id string, cert *fi.Certificate, privateKey *fi.PrivateKey) error {
|
||||
func (c *KubernetesKeystore) StoreKeypair(id string, cert *pki.Certificate, privateKey *pki.PrivateKey) error {
|
||||
keypair := &KeypairSecret{
|
||||
Namespace: c.namespace,
|
||||
Name: id,
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import (
|
|||
api "k8s.io/kops/pkg/apis/kops"
|
||||
"k8s.io/kops/pkg/apis/nodeup"
|
||||
"k8s.io/kops/pkg/flagbuilder"
|
||||
"k8s.io/kops/pkg/pki"
|
||||
"k8s.io/kops/upup/pkg/fi"
|
||||
"k8s.io/kops/upup/pkg/fi/secrets"
|
||||
"k8s.io/kops/util/pkg/vfs"
|
||||
|
|
@ -122,17 +123,17 @@ func (t *templateFunctions) populate(dest template.FuncMap) {
|
|||
}
|
||||
|
||||
// CACertificate returns the primary CA certificate for the cluster
|
||||
func (t *templateFunctions) CACertificate() (*fi.Certificate, error) {
|
||||
func (t *templateFunctions) CACertificate() (*pki.Certificate, error) {
|
||||
return t.keyStore.Cert(fi.CertificateId_CA)
|
||||
}
|
||||
|
||||
// PrivateKey returns the specified private key
|
||||
func (t *templateFunctions) PrivateKey(id string) (*fi.PrivateKey, error) {
|
||||
func (t *templateFunctions) PrivateKey(id string) (*pki.PrivateKey, error) {
|
||||
return t.keyStore.PrivateKey(id)
|
||||
}
|
||||
|
||||
// Certificate returns the specified private key
|
||||
func (t *templateFunctions) Certificate(id string) (*fi.Certificate, error) {
|
||||
func (t *templateFunctions) Certificate(id string) (*pki.Certificate, error) {
|
||||
return t.keyStore.Cert(id)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import (
|
|||
"github.com/golang/glog"
|
||||
"golang.org/x/crypto/ssh"
|
||||
|
||||
"k8s.io/kops/pkg/pki"
|
||||
"k8s.io/kops/util/pkg/vfs"
|
||||
)
|
||||
|
||||
|
|
@ -125,15 +126,15 @@ func (c *VFSCAStore) generateCACertificate() (*certificates, *privateKeys, error
|
|||
return nil, nil, fmt.Errorf("error generating RSA private key: %v", err)
|
||||
}
|
||||
|
||||
caPrivateKey := &PrivateKey{Key: caRsaKey}
|
||||
caPrivateKey := &pki.PrivateKey{Key: caRsaKey}
|
||||
|
||||
caCertificate, err := SignNewCertificate(caPrivateKey, template, nil, nil)
|
||||
caCertificate, err := pki.SignNewCertificate(caPrivateKey, template, nil, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
t := time.Now().UnixNano()
|
||||
serial := BuildPKISerial(t)
|
||||
serial := pki.BuildPKISerial(t)
|
||||
|
||||
keyPath := c.buildPrivateKeyPath(CertificateId_CA, serial)
|
||||
err = c.storePrivateKey(caPrivateKey, keyPath)
|
||||
|
|
@ -186,11 +187,11 @@ func (c *VFSCAStore) buildPrivateKeyPath(id string, serial *big.Int) vfs.Path {
|
|||
}
|
||||
|
||||
type certificates struct {
|
||||
certificates map[string]*Certificate
|
||||
certificates map[string]*pki.Certificate
|
||||
primary string
|
||||
}
|
||||
|
||||
func (p *certificates) Primary() *Certificate {
|
||||
func (p *certificates) Primary() *pki.Certificate {
|
||||
if p.primary == "" {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -207,7 +208,7 @@ func (c *VFSCAStore) loadCertificates(p vfs.Path) (*certificates, error) {
|
|||
}
|
||||
|
||||
certs := &certificates{
|
||||
certificates: make(map[string]*Certificate),
|
||||
certificates: make(map[string]*pki.Certificate),
|
||||
}
|
||||
|
||||
for _, f := range files {
|
||||
|
|
@ -241,7 +242,7 @@ func (c *VFSCAStore) loadCertificates(p vfs.Path) (*certificates, error) {
|
|||
return certs, nil
|
||||
}
|
||||
|
||||
func (c *VFSCAStore) loadOneCertificate(p vfs.Path) (*Certificate, error) {
|
||||
func (c *VFSCAStore) loadOneCertificate(p vfs.Path) (*pki.Certificate, error) {
|
||||
data, err := p.ReadFile()
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
|
|
@ -249,7 +250,7 @@ func (c *VFSCAStore) loadOneCertificate(p vfs.Path) (*Certificate, error) {
|
|||
}
|
||||
return nil, err
|
||||
}
|
||||
cert, err := LoadPEMCertificate(data)
|
||||
cert, err := pki.LoadPEMCertificate(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -259,12 +260,12 @@ func (c *VFSCAStore) loadOneCertificate(p vfs.Path) (*Certificate, error) {
|
|||
return cert, nil
|
||||
}
|
||||
|
||||
func (c *VFSCAStore) Cert(id string) (*Certificate, error) {
|
||||
func (c *VFSCAStore) Cert(id string) (*pki.Certificate, error) {
|
||||
cert, err := c.FindCert(id)
|
||||
if err == nil && cert == nil {
|
||||
if c.DryRun {
|
||||
glog.Warningf("using empty certificate, because running with DryRun")
|
||||
return &Certificate{}, err
|
||||
return &pki.Certificate{}, err
|
||||
}
|
||||
return nil, fmt.Errorf("cannot find certificate %q", id)
|
||||
}
|
||||
|
|
@ -285,7 +286,7 @@ func (c *VFSCAStore) CertificatePool(id string) (*CertificatePool, error) {
|
|||
|
||||
}
|
||||
|
||||
func (c *VFSCAStore) FindKeypair(id string) (*Certificate, *PrivateKey, error) {
|
||||
func (c *VFSCAStore) FindKeypair(id string) (*pki.Certificate, *pki.PrivateKey, error) {
|
||||
cert, err := c.FindCert(id)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
|
@ -299,7 +300,7 @@ func (c *VFSCAStore) FindKeypair(id string) (*Certificate, *PrivateKey, error) {
|
|||
return cert, key, nil
|
||||
}
|
||||
|
||||
func (c *VFSCAStore) FindCert(id string) (*Certificate, error) {
|
||||
func (c *VFSCAStore) FindCert(id string) (*pki.Certificate, error) {
|
||||
var certs *certificates
|
||||
|
||||
var err error
|
||||
|
|
@ -309,7 +310,7 @@ func (c *VFSCAStore) FindCert(id string) (*Certificate, error) {
|
|||
return nil, fmt.Errorf("error in 'FindCert' attempting to load cert %q: %v", id, err)
|
||||
}
|
||||
|
||||
var cert *Certificate
|
||||
var cert *pki.Certificate
|
||||
if certs != nil && certs.primary != "" {
|
||||
cert = certs.certificates[certs.primary]
|
||||
}
|
||||
|
|
@ -404,7 +405,7 @@ func (c *VFSCAStore) List() ([]*KeystoreItem, error) {
|
|||
return items, nil
|
||||
}
|
||||
|
||||
func (c *VFSCAStore) IssueCert(id string, serial *big.Int, privateKey *PrivateKey, template *x509.Certificate) (*Certificate, error) {
|
||||
func (c *VFSCAStore) IssueCert(id string, serial *big.Int, privateKey *pki.PrivateKey, template *x509.Certificate) (*pki.Certificate, error) {
|
||||
glog.Infof("Issuing new certificate: %q", id)
|
||||
|
||||
template.SerialNumber = serial
|
||||
|
|
@ -417,7 +418,7 @@ func (c *VFSCAStore) IssueCert(id string, serial *big.Int, privateKey *PrivateKe
|
|||
if caPrivateKeys == nil || caPrivateKeys.Primary() == nil {
|
||||
return nil, fmt.Errorf("ca.key was not found; cannot issue certificates")
|
||||
}
|
||||
cert, err := SignNewCertificate(privateKey, template, caCertificates.Primary().Certificate, caPrivateKeys.Primary())
|
||||
cert, err := pki.SignNewCertificate(privateKey, template, caCertificates.Primary().Certificate, caPrivateKeys.Primary())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -432,7 +433,7 @@ func (c *VFSCAStore) IssueCert(id string, serial *big.Int, privateKey *PrivateKe
|
|||
return c.loadOneCertificate(p)
|
||||
}
|
||||
|
||||
func (c *VFSCAStore) StoreKeypair(id string, cert *Certificate, privateKey *PrivateKey) error {
|
||||
func (c *VFSCAStore) StoreKeypair(id string, cert *pki.Certificate, privateKey *pki.PrivateKey) error {
|
||||
serial := cert.Certificate.SerialNumber
|
||||
|
||||
{
|
||||
|
|
@ -455,11 +456,11 @@ func (c *VFSCAStore) StoreKeypair(id string, cert *Certificate, privateKey *Priv
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *VFSCAStore) AddCert(id string, cert *Certificate) error {
|
||||
func (c *VFSCAStore) AddCert(id string, cert *pki.Certificate) error {
|
||||
glog.Infof("Adding TLS certificate: %q", id)
|
||||
|
||||
// We add with a timestamp of zero so this will never be the newest cert
|
||||
serial := BuildPKISerial(0)
|
||||
serial := pki.BuildPKISerial(0)
|
||||
|
||||
p := c.buildCertificatePath(id, serial)
|
||||
|
||||
|
|
@ -474,11 +475,11 @@ func (c *VFSCAStore) AddCert(id string, cert *Certificate) error {
|
|||
}
|
||||
|
||||
type privateKeys struct {
|
||||
keys map[string]*PrivateKey
|
||||
keys map[string]*pki.PrivateKey
|
||||
primary string
|
||||
}
|
||||
|
||||
func (p *privateKeys) Primary() *PrivateKey {
|
||||
func (p *privateKeys) Primary() *pki.PrivateKey {
|
||||
if p.primary == "" {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -495,7 +496,7 @@ func (c *VFSCAStore) loadPrivateKeys(p vfs.Path) (*privateKeys, error) {
|
|||
}
|
||||
|
||||
keys := &privateKeys{
|
||||
keys: make(map[string]*PrivateKey),
|
||||
keys: make(map[string]*pki.PrivateKey),
|
||||
}
|
||||
|
||||
for _, f := range files {
|
||||
|
|
@ -529,7 +530,7 @@ func (c *VFSCAStore) loadPrivateKeys(p vfs.Path) (*privateKeys, error) {
|
|||
return keys, nil
|
||||
}
|
||||
|
||||
func (c *VFSCAStore) loadOnePrivateKey(p vfs.Path) (*PrivateKey, error) {
|
||||
func (c *VFSCAStore) loadOnePrivateKey(p vfs.Path) (*pki.PrivateKey, error) {
|
||||
data, err := p.ReadFile()
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
|
|
@ -537,25 +538,14 @@ func (c *VFSCAStore) loadOnePrivateKey(p vfs.Path) (*PrivateKey, error) {
|
|||
}
|
||||
return nil, err
|
||||
}
|
||||
k, err := ParsePEMPrivateKey(data)
|
||||
k, err := pki.ParsePEMPrivateKey(data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing private key from %q: %v", p, err)
|
||||
}
|
||||
return k, err
|
||||
}
|
||||
|
||||
func ParsePEMPrivateKey(data []byte) (*PrivateKey, error) {
|
||||
k, err := parsePEMPrivateKey(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if k == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return &PrivateKey{Key: k}, nil
|
||||
}
|
||||
|
||||
func (c *VFSCAStore) FindPrivateKey(id string) (*PrivateKey, error) {
|
||||
func (c *VFSCAStore) FindPrivateKey(id string) (*pki.PrivateKey, error) {
|
||||
var keys *privateKeys
|
||||
if id == CertificateId_CA {
|
||||
_, caPrivateKeys, err := c.readCAKeypairs()
|
||||
|
|
@ -573,19 +563,19 @@ func (c *VFSCAStore) FindPrivateKey(id string) (*PrivateKey, error) {
|
|||
|
||||
}
|
||||
|
||||
var key *PrivateKey
|
||||
var key *pki.PrivateKey
|
||||
if keys != nil && keys.primary != "" {
|
||||
key = keys.keys[keys.primary]
|
||||
}
|
||||
return key, nil
|
||||
}
|
||||
|
||||
func (c *VFSCAStore) PrivateKey(id string) (*PrivateKey, error) {
|
||||
func (c *VFSCAStore) PrivateKey(id string) (*pki.PrivateKey, error) {
|
||||
key, err := c.FindPrivateKey(id)
|
||||
if err == nil && key == nil {
|
||||
if c.DryRun {
|
||||
glog.Warningf("using empty certificate, because running with DryRun")
|
||||
return &PrivateKey{}, err
|
||||
return &pki.PrivateKey{}, err
|
||||
}
|
||||
return nil, fmt.Errorf("cannot find SSL key %q", id)
|
||||
}
|
||||
|
|
@ -593,7 +583,7 @@ func (c *VFSCAStore) PrivateKey(id string) (*PrivateKey, error) {
|
|||
|
||||
}
|
||||
|
||||
func (c *VFSCAStore) CreateKeypair(id string, template *x509.Certificate, privateKey *PrivateKey) (*Certificate, error) {
|
||||
func (c *VFSCAStore) CreateKeypair(id string, template *x509.Certificate, privateKey *pki.PrivateKey) (*pki.Certificate, error) {
|
||||
serial := c.buildSerial()
|
||||
|
||||
cert, err := c.IssueCert(id, serial, privateKey, template)
|
||||
|
|
@ -604,7 +594,7 @@ func (c *VFSCAStore) CreateKeypair(id string, template *x509.Certificate, privat
|
|||
return cert, nil
|
||||
}
|
||||
|
||||
func (c *VFSCAStore) storePrivateKey(privateKey *PrivateKey, p vfs.Path) error {
|
||||
func (c *VFSCAStore) storePrivateKey(privateKey *pki.PrivateKey, p vfs.Path) error {
|
||||
var data bytes.Buffer
|
||||
_, err := privateKey.WriteTo(&data)
|
||||
if err != nil {
|
||||
|
|
@ -614,7 +604,7 @@ func (c *VFSCAStore) storePrivateKey(privateKey *PrivateKey, p vfs.Path) error {
|
|||
return p.WriteFile(data.Bytes())
|
||||
}
|
||||
|
||||
func (c *VFSCAStore) storeCertificate(cert *Certificate, p vfs.Path) error {
|
||||
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)
|
||||
|
|
@ -627,25 +617,7 @@ func (c *VFSCAStore) storeCertificate(cert *Certificate, p vfs.Path) error {
|
|||
|
||||
func (c *VFSCAStore) buildSerial() *big.Int {
|
||||
t := time.Now().UnixNano()
|
||||
return BuildPKISerial(t)
|
||||
}
|
||||
|
||||
// BuildPKISerial produces a serial number for certs that is vanishingly unlikely to collide
|
||||
// The timestamp should be provided as an input (time.Now().UnixNano()), and then we combine
|
||||
// that with a 32 bit random crypto-rand integer.
|
||||
// We also know that a bigger value was created later (modulo clock skew)
|
||||
func BuildPKISerial(timestamp int64) *big.Int {
|
||||
randomLimit := new(big.Int).Lsh(big.NewInt(1), 32)
|
||||
randomComponent, err := crypto_rand.Int(crypto_rand.Reader, randomLimit)
|
||||
if err != nil {
|
||||
glog.Fatalf("error generating random number: %v", err)
|
||||
}
|
||||
|
||||
serial := big.NewInt(timestamp)
|
||||
serial.Lsh(serial, 32)
|
||||
serial.Or(serial, randomComponent)
|
||||
|
||||
return serial
|
||||
return pki.BuildPKISerial(t)
|
||||
}
|
||||
|
||||
func formatFingerprint(data []byte) string {
|
||||
|
|
@ -761,7 +733,7 @@ func (c *VFSCAStore) loadPath(p vfs.Path) ([]*KeystoreItem, error) {
|
|||
return keystoreItems, nil
|
||||
}
|
||||
|
||||
func (c *VFSCAStore) loadData(p vfs.Path) (*PrivateKey, error) {
|
||||
func (c *VFSCAStore) loadData(p vfs.Path) (*pki.PrivateKey, error) {
|
||||
data, err := p.ReadFile()
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
|
|
@ -769,7 +741,7 @@ func (c *VFSCAStore) loadData(p vfs.Path) (*PrivateKey, error) {
|
|||
}
|
||||
return nil, err
|
||||
}
|
||||
k, err := ParsePEMPrivateKey(data)
|
||||
k, err := pki.ParsePEMPrivateKey(data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing private key from %q: %v", p, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import (
|
|||
"k8s.io/kops/pkg/apis/kops"
|
||||
"k8s.io/kops/pkg/apis/kops/registry"
|
||||
"k8s.io/kops/pkg/client/simple"
|
||||
"k8s.io/kops/pkg/pki"
|
||||
"k8s.io/kops/pkg/resources"
|
||||
"k8s.io/kops/upup/pkg/fi"
|
||||
"k8s.io/kops/upup/pkg/fi/cloudup"
|
||||
|
|
@ -714,7 +715,7 @@ func (u *UserDataConfiguration) ParseBool(key string) *bool {
|
|||
return fi.Bool(false)
|
||||
}
|
||||
|
||||
func (u *UserDataConfiguration) ParseCert(key string) (*fi.Certificate, error) {
|
||||
func (u *UserDataConfiguration) ParseCert(key string) (*pki.Certificate, error) {
|
||||
s := u.Settings[key]
|
||||
if s == "" {
|
||||
return nil, nil
|
||||
|
|
@ -724,7 +725,7 @@ func (u *UserDataConfiguration) ParseCert(key string) (*fi.Certificate, error) {
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("error decoding base64 certificate %q: %v", key, err)
|
||||
}
|
||||
cert, err := fi.LoadPEMCertificate(data)
|
||||
cert, err := pki.LoadPEMCertificate(data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing certificate %q: %v", key, err)
|
||||
}
|
||||
|
|
@ -732,7 +733,7 @@ func (u *UserDataConfiguration) ParseCert(key string) (*fi.Certificate, error) {
|
|||
return cert, nil
|
||||
}
|
||||
|
||||
func (u *UserDataConfiguration) ParseKey(key string) (*fi.PrivateKey, error) {
|
||||
func (u *UserDataConfiguration) ParseKey(key string) (*pki.PrivateKey, error) {
|
||||
s := u.Settings[key]
|
||||
if s == "" {
|
||||
return nil, nil
|
||||
|
|
@ -742,7 +743,7 @@ func (u *UserDataConfiguration) ParseKey(key string) (*fi.PrivateKey, error) {
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("error decoding base64 private key %q: %v", key, err)
|
||||
}
|
||||
k, err := fi.ParsePEMPrivateKey(data)
|
||||
k, err := pki.ParsePEMPrivateKey(data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing private key %q: %v", key, err)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue