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/apis/kops/registry"
|
||||||
"k8s.io/kops/pkg/client/simple"
|
"k8s.io/kops/pkg/client/simple"
|
||||||
"k8s.io/kops/pkg/kubeconfig"
|
"k8s.io/kops/pkg/kubeconfig"
|
||||||
|
"k8s.io/kops/pkg/pki"
|
||||||
"k8s.io/kops/upup/pkg/fi"
|
"k8s.io/kops/upup/pkg/fi"
|
||||||
"k8s.io/kops/upup/pkg/fi/fitasks"
|
"k8s.io/kops/upup/pkg/fi/fitasks"
|
||||||
"k8s.io/kops/upup/pkg/fi/k8sapi"
|
"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
|
id := fi.CertificateId_CA
|
||||||
caCert, caPrivateKey, err := keystore.FindKeypair(id)
|
caCert, caPrivateKey, err := keystore.FindKeypair(id)
|
||||||
if err != nil {
|
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)
|
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 {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import (
|
||||||
"k8s.io/kops/federation/targets/kubernetestarget"
|
"k8s.io/kops/federation/targets/kubernetestarget"
|
||||||
kopsapi "k8s.io/kops/pkg/apis/kops"
|
kopsapi "k8s.io/kops/pkg/apis/kops"
|
||||||
"k8s.io/kops/pkg/kubeconfig"
|
"k8s.io/kops/pkg/kubeconfig"
|
||||||
|
"k8s.io/kops/pkg/pki"
|
||||||
"k8s.io/kops/upup/pkg/fi"
|
"k8s.io/kops/upup/pkg/fi"
|
||||||
"k8s.io/kops/upup/pkg/fi/fitasks"
|
"k8s.io/kops/upup/pkg/fi/fitasks"
|
||||||
)
|
)
|
||||||
|
|
@ -275,7 +276,7 @@ func (o *FederationConfiguration) EnsureConfiguration(c *fi.Context) error {
|
||||||
return nil
|
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
|
k8s := c.Target.(*kubernetestarget.KubernetesTarget).KubernetesClient
|
||||||
|
|
||||||
_, err := mutateSecret(k8s, o.Namespace, o.KubeconfigSecretName, func(s *v1.Secret) (*v1.Secret, error) {
|
_, 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/resources
|
||||||
k8s.io/kops/pkg/model/vspheremodel
|
k8s.io/kops/pkg/model/vspheremodel
|
||||||
k8s.io/kops/pkg/openapi
|
k8s.io/kops/pkg/openapi
|
||||||
|
k8s.io/kops/pkg/pki
|
||||||
k8s.io/kops/pkg/pretty
|
k8s.io/kops/pkg/pretty
|
||||||
k8s.io/kops/pkg/resources
|
k8s.io/kops/pkg/resources
|
||||||
k8s.io/kops/pkg/resources/digitalocean
|
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 (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto"
|
|
||||||
crypto_rand "crypto/rand"
|
|
||||||
"crypto/rsa"
|
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"crypto/x509/pkix"
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/json"
|
|
||||||
"encoding/pem"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"math/big"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
|
"k8s.io/kops/pkg/pki"
|
||||||
"k8s.io/kops/util/pkg/vfs"
|
"k8s.io/kops/util/pkg/vfs"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const CertificateId_CA = "ca"
|
const CertificateId_CA = "ca"
|
||||||
|
|
||||||
type Certificate struct {
|
|
||||||
Subject pkix.Name
|
|
||||||
IsCA bool
|
|
||||||
|
|
||||||
Certificate *x509.Certificate
|
|
||||||
PublicKey crypto.PublicKey
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SecretTypeSSHPublicKey = "SSHPublicKey"
|
SecretTypeSSHPublicKey = "SSHPublicKey"
|
||||||
SecretTypeKeypair = "Keypair"
|
SecretTypeKeypair = "Keypair"
|
||||||
|
|
@ -62,76 +43,29 @@ type KeystoreItem struct {
|
||||||
Data []byte
|
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
|
// Keystore contains just the functions we need to issue keypairs, not to list / manage them
|
||||||
type Keystore interface {
|
type Keystore interface {
|
||||||
// FindKeypair finds a cert & private key, returning nil where either is not found
|
// 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)
|
// (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
|
// Store the keypair
|
||||||
StoreKeypair(id string, cert *Certificate, privateKey *PrivateKey) error
|
StoreKeypair(id string, cert *pki.Certificate, privateKey *pki.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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type CAStore interface {
|
type CAStore interface {
|
||||||
Keystore
|
Keystore
|
||||||
|
|
||||||
// Cert returns the primary specified certificate
|
// 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 returns all active certificates with the specified id
|
||||||
CertificatePool(name string) (*CertificatePool, error)
|
CertificatePool(name string) (*CertificatePool, error)
|
||||||
PrivateKey(name string) (*PrivateKey, error)
|
PrivateKey(name string) (*pki.PrivateKey, error)
|
||||||
|
|
||||||
FindCert(name string) (*Certificate, error)
|
FindCert(name string) (*pki.Certificate, error)
|
||||||
FindPrivateKey(name string) (*PrivateKey, error)
|
FindPrivateKey(name string) (*pki.PrivateKey, error)
|
||||||
|
|
||||||
// List will list all the items, but will not fetch the data
|
// List will list all the items, but will not fetch the data
|
||||||
List() ([]*KeystoreItem, error)
|
List() ([]*KeystoreItem, error)
|
||||||
|
|
@ -140,7 +74,7 @@ type CAStore interface {
|
||||||
VFSPath() vfs.Path
|
VFSPath() vfs.Path
|
||||||
|
|
||||||
// AddCert adds an alternative certificate to the pool (primarily useful for CAs)
|
// 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 adds an SSH public key
|
||||||
AddSSHPublicKey(name string, data []byte) error
|
AddSSHPublicKey(name string, data []byte) error
|
||||||
|
|
@ -152,268 +86,9 @@ type CAStore interface {
|
||||||
DeleteSecret(item *KeystoreItem) error
|
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 {
|
type CertificatePool struct {
|
||||||
Secondary []*Certificate
|
Secondary []*pki.Certificate
|
||||||
Primary *Certificate
|
Primary *pki.Certificate
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CertificatePool) AsString() (string, error) {
|
func (c *CertificatePool) AsString() (string, error) {
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
|
"k8s.io/kops/pkg/pki"
|
||||||
"k8s.io/kops/upup/pkg/fi"
|
"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
|
// if we change keys we often have to regenerate e.g. the service accounts
|
||||||
// TODO: Eventually rotate keys / don't always reuse?
|
// TODO: Eventually rotate keys / don't always reuse?
|
||||||
if privateKey == nil {
|
if privateKey == nil {
|
||||||
privateKey, err = fi.GeneratePrivateKey()
|
privateKey, err = pki.GeneratePrivateKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ package k8sapi
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"k8s.io/client-go/pkg/api/v1"
|
"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
|
// KeypairSecret is a wrapper around a k8s Secret object that holds a TLS keypair
|
||||||
|
|
@ -27,8 +27,8 @@ type KeypairSecret struct {
|
||||||
Namespace string
|
Namespace string
|
||||||
Name string
|
Name string
|
||||||
|
|
||||||
Certificate *fi.Certificate
|
Certificate *pki.Certificate
|
||||||
PrivateKey *fi.PrivateKey
|
PrivateKey *pki.PrivateKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseKeypairSecret parses the secret object, decoding the certificate & private-key, if present
|
// 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]
|
certData := secret.Data[v1.TLSCertKey]
|
||||||
if certData != nil {
|
if certData != nil {
|
||||||
cert, err := fi.LoadPEMCertificate(certData)
|
cert, err := pki.LoadPEMCertificate(certData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error parsing certificate in %s/%s: %q", k.Namespace, k.Name, err)
|
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]
|
keyData := secret.Data[v1.TLSPrivateKeyKey]
|
||||||
if keyData != nil {
|
if keyData != nil {
|
||||||
key, err := fi.ParsePEMPrivateKey(keyData)
|
key, err := pki.ParsePEMPrivateKey(keyData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error parsing key in %s/%s: %q", k.Namespace, k.Name, err)
|
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"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
"k8s.io/client-go/pkg/api/v1"
|
"k8s.io/client-go/pkg/api/v1"
|
||||||
|
"k8s.io/kops/pkg/pki"
|
||||||
"k8s.io/kops/upup/pkg/fi"
|
"k8s.io/kops/upup/pkg/fi"
|
||||||
"math/big"
|
"math/big"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -49,7 +50,7 @@ func NewKubernetesKeystore(client kubernetes.Interface, namespace string) fi.Key
|
||||||
return c
|
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)
|
glog.Infof("Issuing new certificate: %q", id)
|
||||||
|
|
||||||
template.SerialNumber = serial
|
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")
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -87,7 +88,7 @@ func (c *KubernetesKeystore) findSecret(id string) (*v1.Secret, error) {
|
||||||
return secret, nil
|
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)
|
secret, err := c.findSecret(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
|
@ -105,9 +106,9 @@ func (c *KubernetesKeystore) FindKeypair(id string) (*fi.Certificate, *fi.Privat
|
||||||
return keypair.Certificate, keypair.PrivateKey, nil
|
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()
|
t := time.Now().UnixNano()
|
||||||
serial := fi.BuildPKISerial(t)
|
serial := pki.BuildPKISerial(t)
|
||||||
|
|
||||||
cert, err := c.issueCert(id, serial, privateKey, template)
|
cert, err := c.issueCert(id, serial, privateKey, template)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -117,7 +118,7 @@ func (c *KubernetesKeystore) CreateKeypair(id string, template *x509.Certificate
|
||||||
return cert, nil
|
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{
|
keypair := &KeypairSecret{
|
||||||
Namespace: c.namespace,
|
Namespace: c.namespace,
|
||||||
Name: id,
|
Name: id,
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import (
|
||||||
api "k8s.io/kops/pkg/apis/kops"
|
api "k8s.io/kops/pkg/apis/kops"
|
||||||
"k8s.io/kops/pkg/apis/nodeup"
|
"k8s.io/kops/pkg/apis/nodeup"
|
||||||
"k8s.io/kops/pkg/flagbuilder"
|
"k8s.io/kops/pkg/flagbuilder"
|
||||||
|
"k8s.io/kops/pkg/pki"
|
||||||
"k8s.io/kops/upup/pkg/fi"
|
"k8s.io/kops/upup/pkg/fi"
|
||||||
"k8s.io/kops/upup/pkg/fi/secrets"
|
"k8s.io/kops/upup/pkg/fi/secrets"
|
||||||
"k8s.io/kops/util/pkg/vfs"
|
"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
|
// 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)
|
return t.keyStore.Cert(fi.CertificateId_CA)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrivateKey returns the specified private key
|
// 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)
|
return t.keyStore.PrivateKey(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Certificate returns the specified private key
|
// 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)
|
return t.keyStore.Cert(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ import (
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
|
|
||||||
|
"k8s.io/kops/pkg/pki"
|
||||||
"k8s.io/kops/util/pkg/vfs"
|
"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)
|
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 {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
t := time.Now().UnixNano()
|
t := time.Now().UnixNano()
|
||||||
serial := BuildPKISerial(t)
|
serial := pki.BuildPKISerial(t)
|
||||||
|
|
||||||
keyPath := c.buildPrivateKeyPath(CertificateId_CA, serial)
|
keyPath := c.buildPrivateKeyPath(CertificateId_CA, serial)
|
||||||
err = c.storePrivateKey(caPrivateKey, keyPath)
|
err = c.storePrivateKey(caPrivateKey, keyPath)
|
||||||
|
|
@ -186,11 +187,11 @@ func (c *VFSCAStore) buildPrivateKeyPath(id string, serial *big.Int) vfs.Path {
|
||||||
}
|
}
|
||||||
|
|
||||||
type certificates struct {
|
type certificates struct {
|
||||||
certificates map[string]*Certificate
|
certificates map[string]*pki.Certificate
|
||||||
primary string
|
primary string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *certificates) Primary() *Certificate {
|
func (p *certificates) Primary() *pki.Certificate {
|
||||||
if p.primary == "" {
|
if p.primary == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -207,7 +208,7 @@ func (c *VFSCAStore) loadCertificates(p vfs.Path) (*certificates, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
certs := &certificates{
|
certs := &certificates{
|
||||||
certificates: make(map[string]*Certificate),
|
certificates: make(map[string]*pki.Certificate),
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, f := range files {
|
for _, f := range files {
|
||||||
|
|
@ -241,7 +242,7 @@ func (c *VFSCAStore) loadCertificates(p vfs.Path) (*certificates, error) {
|
||||||
return certs, nil
|
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()
|
data, err := p.ReadFile()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
|
|
@ -249,7 +250,7 @@ func (c *VFSCAStore) loadOneCertificate(p vfs.Path) (*Certificate, error) {
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
cert, err := LoadPEMCertificate(data)
|
cert, err := pki.LoadPEMCertificate(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -259,12 +260,12 @@ func (c *VFSCAStore) loadOneCertificate(p vfs.Path) (*Certificate, error) {
|
||||||
return cert, nil
|
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)
|
cert, err := c.FindCert(id)
|
||||||
if err == nil && cert == nil {
|
if err == nil && cert == nil {
|
||||||
if c.DryRun {
|
if c.DryRun {
|
||||||
glog.Warningf("using empty certificate, because running with 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)
|
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)
|
cert, err := c.FindCert(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
|
@ -299,7 +300,7 @@ func (c *VFSCAStore) FindKeypair(id string) (*Certificate, *PrivateKey, error) {
|
||||||
return cert, key, nil
|
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 certs *certificates
|
||||||
|
|
||||||
var err error
|
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)
|
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 != "" {
|
if certs != nil && certs.primary != "" {
|
||||||
cert = certs.certificates[certs.primary]
|
cert = certs.certificates[certs.primary]
|
||||||
}
|
}
|
||||||
|
|
@ -404,7 +405,7 @@ func (c *VFSCAStore) List() ([]*KeystoreItem, error) {
|
||||||
return items, nil
|
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)
|
glog.Infof("Issuing new certificate: %q", id)
|
||||||
|
|
||||||
template.SerialNumber = serial
|
template.SerialNumber = serial
|
||||||
|
|
@ -417,7 +418,7 @@ func (c *VFSCAStore) IssueCert(id string, serial *big.Int, privateKey *PrivateKe
|
||||||
if caPrivateKeys == nil || caPrivateKeys.Primary() == nil {
|
if caPrivateKeys == nil || caPrivateKeys.Primary() == nil {
|
||||||
return nil, fmt.Errorf("ca.key was not found; cannot issue certificates")
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -432,7 +433,7 @@ func (c *VFSCAStore) IssueCert(id string, serial *big.Int, privateKey *PrivateKe
|
||||||
return c.loadOneCertificate(p)
|
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
|
serial := cert.Certificate.SerialNumber
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
@ -455,11 +456,11 @@ func (c *VFSCAStore) StoreKeypair(id string, cert *Certificate, privateKey *Priv
|
||||||
return nil
|
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)
|
glog.Infof("Adding TLS certificate: %q", id)
|
||||||
|
|
||||||
// We add with a timestamp of zero so this will never be the newest cert
|
// 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)
|
p := c.buildCertificatePath(id, serial)
|
||||||
|
|
||||||
|
|
@ -474,11 +475,11 @@ func (c *VFSCAStore) AddCert(id string, cert *Certificate) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
type privateKeys struct {
|
type privateKeys struct {
|
||||||
keys map[string]*PrivateKey
|
keys map[string]*pki.PrivateKey
|
||||||
primary string
|
primary string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *privateKeys) Primary() *PrivateKey {
|
func (p *privateKeys) Primary() *pki.PrivateKey {
|
||||||
if p.primary == "" {
|
if p.primary == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -495,7 +496,7 @@ func (c *VFSCAStore) loadPrivateKeys(p vfs.Path) (*privateKeys, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
keys := &privateKeys{
|
keys := &privateKeys{
|
||||||
keys: make(map[string]*PrivateKey),
|
keys: make(map[string]*pki.PrivateKey),
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, f := range files {
|
for _, f := range files {
|
||||||
|
|
@ -529,7 +530,7 @@ func (c *VFSCAStore) loadPrivateKeys(p vfs.Path) (*privateKeys, error) {
|
||||||
return keys, nil
|
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()
|
data, err := p.ReadFile()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
|
|
@ -537,25 +538,14 @@ func (c *VFSCAStore) loadOnePrivateKey(p vfs.Path) (*PrivateKey, error) {
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
k, err := ParsePEMPrivateKey(data)
|
k, err := pki.ParsePEMPrivateKey(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error parsing private key from %q: %v", p, err)
|
return nil, fmt.Errorf("error parsing private key from %q: %v", p, err)
|
||||||
}
|
}
|
||||||
return k, err
|
return k, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParsePEMPrivateKey(data []byte) (*PrivateKey, error) {
|
func (c *VFSCAStore) FindPrivateKey(id string) (*pki.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) {
|
|
||||||
var keys *privateKeys
|
var keys *privateKeys
|
||||||
if id == CertificateId_CA {
|
if id == CertificateId_CA {
|
||||||
_, caPrivateKeys, err := c.readCAKeypairs()
|
_, 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 != "" {
|
if keys != nil && keys.primary != "" {
|
||||||
key = keys.keys[keys.primary]
|
key = keys.keys[keys.primary]
|
||||||
}
|
}
|
||||||
return key, nil
|
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)
|
key, err := c.FindPrivateKey(id)
|
||||||
if err == nil && key == nil {
|
if err == nil && key == nil {
|
||||||
if c.DryRun {
|
if c.DryRun {
|
||||||
glog.Warningf("using empty certificate, because running with 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)
|
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()
|
serial := c.buildSerial()
|
||||||
|
|
||||||
cert, err := c.IssueCert(id, serial, privateKey, template)
|
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
|
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
|
var data bytes.Buffer
|
||||||
_, err := privateKey.WriteTo(&data)
|
_, err := privateKey.WriteTo(&data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -614,7 +604,7 @@ func (c *VFSCAStore) storePrivateKey(privateKey *PrivateKey, p vfs.Path) error {
|
||||||
return p.WriteFile(data.Bytes())
|
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)?
|
// TODO: replace storePrivateKey & storeCertificate with writeFile(io.WriterTo)?
|
||||||
var data bytes.Buffer
|
var data bytes.Buffer
|
||||||
_, err := cert.WriteTo(&data)
|
_, err := cert.WriteTo(&data)
|
||||||
|
|
@ -627,25 +617,7 @@ func (c *VFSCAStore) storeCertificate(cert *Certificate, p vfs.Path) error {
|
||||||
|
|
||||||
func (c *VFSCAStore) buildSerial() *big.Int {
|
func (c *VFSCAStore) buildSerial() *big.Int {
|
||||||
t := time.Now().UnixNano()
|
t := time.Now().UnixNano()
|
||||||
return BuildPKISerial(t)
|
return pki.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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatFingerprint(data []byte) string {
|
func formatFingerprint(data []byte) string {
|
||||||
|
|
@ -761,7 +733,7 @@ func (c *VFSCAStore) loadPath(p vfs.Path) ([]*KeystoreItem, error) {
|
||||||
return keystoreItems, nil
|
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()
|
data, err := p.ReadFile()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
|
|
@ -769,7 +741,7 @@ func (c *VFSCAStore) loadData(p vfs.Path) (*PrivateKey, error) {
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
k, err := ParsePEMPrivateKey(data)
|
k, err := pki.ParsePEMPrivateKey(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error parsing private key from %q: %v", p, err)
|
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"
|
||||||
"k8s.io/kops/pkg/apis/kops/registry"
|
"k8s.io/kops/pkg/apis/kops/registry"
|
||||||
"k8s.io/kops/pkg/client/simple"
|
"k8s.io/kops/pkg/client/simple"
|
||||||
|
"k8s.io/kops/pkg/pki"
|
||||||
"k8s.io/kops/pkg/resources"
|
"k8s.io/kops/pkg/resources"
|
||||||
"k8s.io/kops/upup/pkg/fi"
|
"k8s.io/kops/upup/pkg/fi"
|
||||||
"k8s.io/kops/upup/pkg/fi/cloudup"
|
"k8s.io/kops/upup/pkg/fi/cloudup"
|
||||||
|
|
@ -714,7 +715,7 @@ func (u *UserDataConfiguration) ParseBool(key string) *bool {
|
||||||
return fi.Bool(false)
|
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]
|
s := u.Settings[key]
|
||||||
if s == "" {
|
if s == "" {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
@ -724,7 +725,7 @@ func (u *UserDataConfiguration) ParseCert(key string) (*fi.Certificate, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error decoding base64 certificate %q: %v", key, err)
|
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 {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error parsing certificate %q: %v", key, err)
|
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
|
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]
|
s := u.Settings[key]
|
||||||
if s == "" {
|
if s == "" {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
@ -742,7 +743,7 @@ func (u *UserDataConfiguration) ParseKey(key string) (*fi.PrivateKey, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error decoding base64 private key %q: %v", key, err)
|
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 {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error parsing private key %q: %v", key, err)
|
return nil, fmt.Errorf("error parsing private key %q: %v", key, err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue