878d37a8 |
package admin
import (
"bytes"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"github.com/golang/glog"
"github.com/spf13/cobra"
|
83c702b4 |
kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" |
6267dded |
"github.com/openshift/origin/pkg/cmd/templates" |
878d37a8 |
)
const CreateKeyPairCommandName = "create-key-pair"
type CreateKeyPairOptions struct {
PublicKeyFile string
PrivateKeyFile string
Overwrite bool |
7b23556d |
Output io.Writer |
878d37a8 |
}
|
6267dded |
var createKeyPairLong = templates.LongDesc(`
Create an RSA key pair and generate PEM-encoded public/private key files |
878d37a8 |
|
6267dded |
Example: Creating service account signing and authenticating key files: |
878d37a8 |
|
6267dded |
CONFIG=openshift.local.config/master
%[1]s --public-key=$CONFIG/serviceaccounts.public.key --private-key=$CONFIG/serviceaccounts.private.key
`) |
878d37a8 |
func NewCommandCreateKeyPair(commandName string, fullName string, out io.Writer) *cobra.Command { |
7b23556d |
options := &CreateKeyPairOptions{Output: out} |
878d37a8 |
cmd := &cobra.Command{
Use: commandName,
Short: "Create a public/private key pair", |
5f3f5b85 |
Long: fmt.Sprintf(createKeyPairLong, fullName), |
878d37a8 |
Run: func(cmd *cobra.Command, args []string) {
if err := options.Validate(args); err != nil {
kcmdutil.CheckErr(kcmdutil.UsageError(cmd, err.Error()))
}
err := options.CreateKeyPair()
kcmdutil.CheckErr(err)
},
}
flags := cmd.Flags()
flags.StringVar(&options.PublicKeyFile, "public-key", "", "The public key file.")
flags.StringVar(&options.PrivateKeyFile, "private-key", "", "The private key file.")
flags.BoolVar(&options.Overwrite, "overwrite", false, "Overwrite existing key files if found. If false, either file existing will prevent creation.")
|
ea725ace |
// autocompletion hints
cmd.MarkFlagFilename("public-key")
cmd.MarkFlagFilename("private-key")
|
878d37a8 |
return cmd
}
func (o CreateKeyPairOptions) Validate(args []string) error {
if len(args) != 0 {
return errors.New("no arguments are supported")
}
if len(o.PublicKeyFile) == 0 {
return errors.New("--public-key must be provided")
}
if len(o.PrivateKeyFile) == 0 {
return errors.New("--private-key must be provided")
}
if o.PublicKeyFile == o.PrivateKeyFile {
return errors.New("--public-key and --private-key must be different")
}
return nil
}
func (o CreateKeyPairOptions) CreateKeyPair() error { |
7b23556d |
glog.V(4).Infof("Creating a key pair with: %#v", o) |
878d37a8 |
if !o.Overwrite {
if _, err := os.Stat(o.PrivateKeyFile); err == nil { |
7b23556d |
glog.V(3).Infof("Keeping existing private key file %s\n", o.PrivateKeyFile) |
878d37a8 |
return nil
}
if _, err := os.Stat(o.PublicKeyFile); err == nil { |
7b23556d |
glog.V(3).Infof("Keeping existing public key file %s\n", o.PublicKeyFile) |
878d37a8 |
return nil
}
}
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return err
}
if err := writePrivateKeyFile(o.PrivateKeyFile, privateKey); err != nil {
return err
}
if err := writePublicKeyFile(o.PublicKeyFile, &privateKey.PublicKey); err != nil {
return err
}
|
7b23556d |
fmt.Fprintf(o.Output, "Generated new key pair as %s and %s\n", o.PublicKeyFile, o.PrivateKeyFile) |
878d37a8 |
return nil
}
func writePublicKeyFile(path string, key *rsa.PublicKey) error {
// ensure parent dir
if err := os.MkdirAll(filepath.Dir(path), os.FileMode(0755)); err != nil {
return err
}
derBytes, err := x509.MarshalPKIXPublicKey(key)
if err != nil {
return err
}
b := bytes.Buffer{}
if err := pem.Encode(&b, &pem.Block{Type: "RSA PUBLIC KEY", Bytes: derBytes}); err != nil {
return err
}
return ioutil.WriteFile(path, b.Bytes(), os.FileMode(0600))
}
func writePrivateKeyFile(path string, key *rsa.PrivateKey) error {
// ensure parent dir
if err := os.MkdirAll(filepath.Dir(path), os.FileMode(0755)); err != nil {
return err
}
b := bytes.Buffer{}
err := pem.Encode(&b, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)})
if err != nil {
return err
}
return ioutil.WriteFile(path, b.Bytes(), os.FileMode(0600))
} |