implementation custom ca cert and key #2924

- implementing as new subcommand keypair to secret
- rename of LoadPEMCertificate to ParsePEMCertificate to have
  the same naming of parsing of certificate/private key bytes in
  the same package result is
    pki.ParsePEMPrivateKey(privateKeyBytes)
    pki.ParsePEMCertificate(certBytes)
This commit is contained in:
Alexander Brandstedt 2018-02-26 16:02:48 +01:00
parent b2c161111f
commit 62ab65e8e3
14 changed files with 302 additions and 11 deletions

View File

@ -10,6 +10,8 @@ go_library(
"create_secret.go",
"create_secret_dockerconfig.go",
"create_secret_encryptionconfig.go",
"create_secret_keypair.go",
"create_secret_keypair_ca.go",
"create_secret_sshpublickey.go",
"create_secret_tls.go",
"delete.go",
@ -73,6 +75,7 @@ go_library(
"//pkg/instancegroups:go_default_library",
"//pkg/kopscodecs:go_default_library",
"//pkg/kubeconfig:go_default_library",
"//pkg/pki:go_default_library",
"//pkg/pretty:go_default_library",
"//pkg/resources:go_default_library",
"//pkg/resources/ops:go_default_library",

View File

@ -56,6 +56,7 @@ func NewCmdCreateSecret(f *util.Factory, out io.Writer) *cobra.Command {
cmd.AddCommand(NewCmdCreateSecretPublicKey(f, out))
cmd.AddCommand(NewCmdCreateSecretDockerConfig(f, out))
cmd.AddCommand(NewCmdCreateSecretEncryptionConfig(f, out))
cmd.AddCommand(NewCmdCreateKeypairSecret(f, out))
return cmd
}

View File

@ -0,0 +1,54 @@
/*
Copyright 2018 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 main
import (
"io"
"github.com/spf13/cobra"
"k8s.io/kops/cmd/kops/util"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
)
var (
createSecretKeypairLong = templates.LongDesc(i18n.T(`
Create a secret keypair`))
createSecretKeypairExample = templates.Examples(i18n.T(`
Add a ca certificate and private key.
kops create secret keypair ca \
--cert ~/ca.pem --key ~/ca-key.pem \
--name k8s-cluster.example.com --state s3://example.com
`))
createSecretKeypairShort = i18n.T(`Create a secret keypair.`)
)
func NewCmdCreateKeypairSecret(f *util.Factory, out io.Writer) *cobra.Command {
cmd := &cobra.Command{
Use: "keypair",
Short: createSecretKeypairShort,
Long: createSecretKeypairLong,
Example: createSecretKeypairExample,
}
// create subcommands
cmd.AddCommand(NewCmdCreateSecretCaCert(f, out))
return cmd
}

View File

@ -0,0 +1,142 @@
/*
Copyright 2018 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 main
import (
"fmt"
"io"
"io/ioutil"
"os"
"github.com/golang/glog"
"github.com/spf13/cobra"
"k8s.io/kops/cmd/kops/util"
"k8s.io/kops/pkg/pki"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kops/upup/pkg/fi/utils"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
)
var (
createSecretCacertLong = templates.LongDesc(i18n.T(`
Add a ca certificate and private key.
`))
createSecretCacertExample = templates.Examples(i18n.T(`
Add a ca certificate and private key.
kops create secret keypair ca \
--cert ~/ca.pem --key ~/ca-key.pem \
--name k8s-cluster.example.com --state s3://example.com
`))
createSecretCacertShort = i18n.T(`Add a ca cert and key`)
)
type CreateSecretCaCertOptions struct {
ClusterName string
CaPrivateKeyPath string
CaCertPath string
}
// NewCmdCreateSecretCaCert returns create ca certificate command
func NewCmdCreateSecretCaCert(f *util.Factory, out io.Writer) *cobra.Command {
options := &CreateSecretCaCertOptions{}
cmd := &cobra.Command{
Use: "ca",
Short: createSecretCacertShort,
Long: createSecretCacertLong,
Example: createSecretCacertExample,
Run: func(cmd *cobra.Command, args []string) {
err := rootCommand.ProcessArgs(args)
if err != nil {
exitWithError(err)
}
options.ClusterName = rootCommand.ClusterName()
err = RunCreateSecretCaCert(f, os.Stdout, options)
if err != nil {
exitWithError(err)
}
},
}
cmd.Flags().StringVar(&options.CaCertPath, "cert", options.CaCertPath, "Path to ca cert")
cmd.Flags().StringVar(&options.CaPrivateKeyPath, "key", options.CaPrivateKeyPath, "Path to ca cert private key")
return cmd
}
// RunCreateSecretCaCert adds a custom ca certificate and private key
func RunCreateSecretCaCert(f *util.Factory, out io.Writer, options *CreateSecretCaCertOptions) error {
if options.CaCertPath == "" {
return fmt.Errorf("error cert provided")
}
if options.CaPrivateKeyPath == "" {
return fmt.Errorf("error no private key provided")
}
cluster, err := GetCluster(f, options.ClusterName)
if err != nil {
return fmt.Errorf("error getting cluster: %q: %v", options.ClusterName, err)
}
clientSet, err := f.Clientset()
if err != nil {
return fmt.Errorf("error getting clientset: %v", err)
}
keyStore, err := clientSet.KeyStore(cluster)
if err != nil {
return fmt.Errorf("error getting keystore: %v", err)
}
options.CaCertPath = utils.ExpandPath(options.CaCertPath)
options.CaPrivateKeyPath = utils.ExpandPath(options.CaPrivateKeyPath)
certBytes, err := ioutil.ReadFile(options.CaCertPath)
if err != nil {
return fmt.Errorf("error reading user provided cert %q: %v", options.CaCertPath, err)
}
privateKeyBytes, err := ioutil.ReadFile(options.CaPrivateKeyPath)
if err != nil {
return fmt.Errorf("error reading user provided private key %q: %v", options.CaPrivateKeyPath, err)
}
privateKey, err := pki.ParsePEMPrivateKey(privateKeyBytes)
if err != nil {
return fmt.Errorf("error loading private key %q: %v", privateKeyBytes, err)
}
cert, err := pki.ParsePEMCertificate(certBytes)
if err != nil {
return fmt.Errorf("error loading certificate %q: %v", options.CaCertPath, err)
}
err = keyStore.StoreKeypair(fi.CertificateId_CA, cert, privateKey)
if err != nil {
return fmt.Errorf("error storing user provided keys %q %q: %v", options.CaCertPath, options.CaPrivateKeyPath, err)
}
glog.Infof("using user provided cert: %v\n", options.CaCertPath)
glog.Infof("using user provided private key: %v\n", options.CaPrivateKeyPath)
return nil
}

View File

@ -43,5 +43,6 @@ Create a secret
* [kops create](kops_create.md) - Create a resource by command line, filename or stdin.
* [kops create secret dockerconfig](kops_create_secret_dockerconfig.md) - Create a docker config.
* [kops create secret encryptionconfig](kops_create_secret_encryptionconfig.md) - Create an encryption config.
* [kops create secret keypair](kops_create_secret_keypair.md) - Create a secret keypair.
* [kops create secret sshpublickey](kops_create_secret_sshpublickey.md) - Create a ssh public key.

View File

@ -0,0 +1,40 @@
<!--- This file is automatically generated by make gen-cli-docs; changes should be made in the go CLI command code (under cmd/kops) -->
## kops create secret keypair
Create a secret keypair.
### Synopsis
Create a secret keypair
### Examples
```
Add a ca certificate and private key.
kops create secret keypair ca \
--cert ~/ca.pem --key ~/ca-key.pem \
--name k8s-cluster.example.com --state s3://example.com
```
### Options inherited from parent commands
```
--alsologtostderr log to standard error as well as files
--config string config file (default is $HOME/.kops.yaml)
--log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0)
--log_dir string If non-empty, write log files in this directory
--logtostderr log to standard error instead of files (default false)
--name string Name of cluster
--state string Location of state storage
--stderrthreshold severity logs at or above this threshold go to stderr (default 2)
-v, --v Level log level for V logs
--vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging
```
### SEE ALSO
* [kops create secret](kops_create_secret.md) - Create a secret.
* [kops create secret keypair ca](kops_create_secret_keypair_ca.md) - Add a ca cert and key

View File

@ -0,0 +1,50 @@
<!--- This file is automatically generated by make gen-cli-docs; changes should be made in the go CLI command code (under cmd/kops) -->
## kops create secret keypair ca
Add a ca cert and key
### Synopsis
Add a ca certificate and private key.
```
kops create secret keypair ca
```
### Examples
```
Add a ca certificate and private key.
kops create secret keypair ca \
--cert ~/ca.pem --key ~/ca-key.pem \
--name k8s-cluster.example.com --state s3://example.com
```
### Options
```
--cert string Path to ca cert
--key string Path to ca cert private key
```
### Options inherited from parent commands
```
--alsologtostderr log to standard error as well as files
--config string config file (default is $HOME/.kops.yaml)
--log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0)
--log_dir string If non-empty, write log files in this directory
--logtostderr log to standard error instead of files (default false)
--name string Name of cluster
--state string Location of state storage
--stderrthreshold severity logs at or above this threshold go to stderr (default 2)
-v, --v Level log level for V logs
--vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging
```
### SEE ALSO
* [kops create secret keypair](kops_create_secret_keypair.md) - Create a secret keypair.

View File

@ -41,13 +41,13 @@ type Certificate struct {
func (c *Certificate) UnmarshalJSON(b []byte) error {
s := ""
if err := json.Unmarshal(b, &s); err == nil {
r, err := LoadPEMCertificate([]byte(s))
r, err := ParsePEMCertificate([]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)
r2, err2 := ParsePEMCertificate(d)
if err2 == nil {
glog.Warningf("used base64 decode of certificate")
r = r2
@ -75,7 +75,7 @@ func (c *Certificate) MarshalJSON() ([]byte, error) {
return json.Marshal(data.String())
}
func LoadPEMCertificate(pemData []byte) (*Certificate, error) {
func ParsePEMCertificate(pemData []byte) (*Certificate, error) {
cert, err := parsePEMCertificate(pemData)
if err != nil {
return nil, err

View File

@ -85,9 +85,9 @@ func TestGenerateCertificate(t *testing.T) {
func TestCertificateRoundTrip(t *testing.T) {
data := "-----BEGIN CERTIFICATE-----\nMIIC2DCCAcCgAwIBAgIRALJXAkVj964tq67wMSI8oJQwDQYJKoZIhvcNAQELBQAw\nFTETMBEGA1UEAxMKa3ViZXJuZXRlczAeFw0xNzEyMjcyMzUyNDBaFw0yNzEyMjcy\nMzUyNDBaMBUxEzARBgNVBAMTCmt1YmVybmV0ZXMwggEiMA0GCSqGSIb3DQEBAQUA\nA4IBDwAwggEKAoIBAQDgnCkSmtnmfxEgS3qNPaUCH5QOBGDH/inHbWCODLBCK9gd\nXEcBl7FVv8T2kFr1DYb0HVDtMI7tixRVFDLgkwNlW34xwWdZXB7GeoFgU1xWOQSY\nOACC8JgYTQ/139HBEvgq4sej67p+/s/SNcw34Kk7HIuFhlk1rRk5kMexKIlJBKP1\nYYUYetsJ/QpUOkqJ5HW4GoetE76YtHnORfYvnybviSMrh2wGGaN6r/s4ChOaIbZC\nAn8/YiPKGIDaZGpj6GXnmXARRX/TIdgSQkLwt0aTDBnPZ4XvtpI8aaL8DYJIqAzA\nNPH2b4/uNylat5jDo0b0G54agMi97+2AUrC9UUXpAgMBAAGjIzAhMA4GA1UdDwEB\n/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBVGR2r\nhzXzRMU5wriPQAJScszNORvoBpXfZoZ09FIupudFxBVU3d4hV9StKnQgPSGA5XQO\nHE97+BxJDuA/rB5oBUsMBjc7y1cde/T6hmi3rLoEYBSnSudCOXJE4G9/0f8byAJe\nrN8+No1r2VgZvZh6p74TEkXv/l3HBPWM7IdUV0HO9JDhSgOVF1fyQKJxRuLJR8jt\nO6mPH2UX0vMwVa4jvwtkddqk2OAdYQvH9rbDjjbzaiW0KnmdueRo92KHAN7BsDZy\nVpXHpqo1Kzg7D3fpaXCf5si7lqqrdJVXH4JC72zxsPehqgi8eIuqOBkiDWmRxAxh\n8yGeRx9AbknHh4Ia\n-----END CERTIFICATE-----\n"
cert, err := LoadPEMCertificate([]byte(data))
cert, err := ParsePEMCertificate([]byte(data))
if err != nil {
t.Fatalf("error from LoadPEMCertificate: %v", err)
t.Fatalf("error from ParsePEMCertificate: %v", err)
}
var b bytes.Buffer

View File

@ -145,7 +145,7 @@ func parseKeyset(o *kops.Keyset) (*keyset, error) {
id: key.Id,
}
if len(key.PublicMaterial) != 0 {
cert, err := pki.LoadPEMCertificate(key.PublicMaterial)
cert, err := pki.ParsePEMCertificate(key.PublicMaterial)
if err != nil {
glog.Warningf("key public material was %s", key.PublicMaterial)
return nil, fmt.Errorf("error loading certificate %s/%s: %v", name, key.Id, err)

View File

@ -40,7 +40,7 @@ func ParseKeypairSecret(secret *v1.Secret) (*KeypairSecret, error) {
certData := secret.Data[v1.TLSCertKey]
if certData != nil {
cert, err := pki.LoadPEMCertificate(certData)
cert, err := pki.ParsePEMCertificate(certData)
if err != nil {
return nil, fmt.Errorf("error parsing certificate in %s/%s: %q", k.Namespace, k.Name, err)
}

View File

@ -421,7 +421,7 @@ func (c *VFSCAStore) loadOneCertificate(p vfs.Path) (*pki.Certificate, error) {
}
return nil, err
}
cert, err := pki.LoadPEMCertificate(data)
cert, err := pki.ParsePEMCertificate(data)
if err != nil {
return nil, err
}

View File

@ -65,9 +65,9 @@ func TestVFSCAStoreRoundTrip(t *testing.T) {
}
certData := "-----BEGIN CERTIFICATE-----\nMIIC2DCCAcCgAwIBAgIRALJXAkVj964tq67wMSI8oJQwDQYJKoZIhvcNAQELBQAw\nFTETMBEGA1UEAxMKa3ViZXJuZXRlczAeFw0xNzEyMjcyMzUyNDBaFw0yNzEyMjcy\nMzUyNDBaMBUxEzARBgNVBAMTCmt1YmVybmV0ZXMwggEiMA0GCSqGSIb3DQEBAQUA\nA4IBDwAwggEKAoIBAQDgnCkSmtnmfxEgS3qNPaUCH5QOBGDH/inHbWCODLBCK9gd\nXEcBl7FVv8T2kFr1DYb0HVDtMI7tixRVFDLgkwNlW34xwWdZXB7GeoFgU1xWOQSY\nOACC8JgYTQ/139HBEvgq4sej67p+/s/SNcw34Kk7HIuFhlk1rRk5kMexKIlJBKP1\nYYUYetsJ/QpUOkqJ5HW4GoetE76YtHnORfYvnybviSMrh2wGGaN6r/s4ChOaIbZC\nAn8/YiPKGIDaZGpj6GXnmXARRX/TIdgSQkLwt0aTDBnPZ4XvtpI8aaL8DYJIqAzA\nNPH2b4/uNylat5jDo0b0G54agMi97+2AUrC9UUXpAgMBAAGjIzAhMA4GA1UdDwEB\n/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBVGR2r\nhzXzRMU5wriPQAJScszNORvoBpXfZoZ09FIupudFxBVU3d4hV9StKnQgPSGA5XQO\nHE97+BxJDuA/rB5oBUsMBjc7y1cde/T6hmi3rLoEYBSnSudCOXJE4G9/0f8byAJe\nrN8+No1r2VgZvZh6p74TEkXv/l3HBPWM7IdUV0HO9JDhSgOVF1fyQKJxRuLJR8jt\nO6mPH2UX0vMwVa4jvwtkddqk2OAdYQvH9rbDjjbzaiW0KnmdueRo92KHAN7BsDZy\nVpXHpqo1Kzg7D3fpaXCf5si7lqqrdJVXH4JC72zxsPehqgi8eIuqOBkiDWmRxAxh\n8yGeRx9AbknHh4Ia\n-----END CERTIFICATE-----\n"
cert, err := pki.LoadPEMCertificate([]byte(certData))
cert, err := pki.ParsePEMCertificate([]byte(certData))
if err != nil {
t.Fatalf("error from LoadPEMCertificate: %v", err)
t.Fatalf("error from ParsePEMCertificate: %v", err)
}
if err := s.StoreKeypair("ca", cert, privateKey); err != nil {

View File

@ -725,7 +725,7 @@ func (u *UserDataConfiguration) ParseCert(key string) (*pki.Certificate, error)
if err != nil {
return nil, fmt.Errorf("error decoding base64 certificate %q: %v", key, err)
}
cert, err := pki.LoadPEMCertificate(data)
cert, err := pki.ParsePEMCertificate(data)
if err != nil {
return nil, fmt.Errorf("error parsing certificate %q: %v", key, err)
}