pkg/cmd/server/admin/create_keypair.go
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))
 }