Skip to content

Commit

Permalink
Add a command to create secrets
Browse files Browse the repository at this point in the history
  • Loading branch information
ojmhetar committed Jan 28, 2019
1 parent cf5daff commit 525217d
Show file tree
Hide file tree
Showing 3 changed files with 216 additions and 106 deletions.
129 changes: 23 additions & 106 deletions cmd/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ import (

corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
certutil "k8s.io/client-go/util/cert"

"github.com/platform9/cctl/common"
"github.com/platform9/cctl/pkg/util/clusterapi"
"github.com/platform9/cctl/pkg/util/secret"
"github.com/platform9/cctl/semverutil"

spconstants "github.com/platform9/ssh-provider/constants"
Expand All @@ -43,7 +43,6 @@ var clusterCmdCreate = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {

vip := cmd.Flag("vip").Value.String()

// Verify that both routerID and vip are not defaults if one is specified
if (routerID == common.RouterID) != (len(vip) == 0) {
log.Fatalf("Must specify both routerID and vip, or leave both empty for non-HA cluster.")
Expand Down Expand Up @@ -85,12 +84,29 @@ var clusterCmdCreate = &cobra.Command{
}
}
setClusterConfigDefaults(clusterConfig)
newAPIServerCASecret := createCASecret(common.DefaultAPIServerCASecretName, apiServerCACertFile, apiServerCAKeyFile)
newEtcdCASecret := createCASecret(common.DefaultEtcdCASecretName, etcdCACertFile, etcdCAKeyFile)
newFrontProxyCASecret := createCASecret(common.DefaultFrontProxyCASecretName, frontProxyCACertFile, frontProxyCAKeyFile)

newServiceAccountKeySecret := createServiceAccountKeySecret(saPrivateKeyFile, saPublicKeyFile)
newBootstrapTokenSecret := createBootstrapTokenSecret(common.DefaultBootstrapTokenSecretName)
newAPIServerCASecret, err := secret.CreateCASecret(common.DefaultAPIServerCASecretName, apiServerCACertFile, apiServerCAKeyFile)
if err != nil {
log.Fatalf("Unable to generate API Server CA cert pair: %v", err)
}
newEtcdCASecret, err := secret.CreateCASecret(common.DefaultEtcdCASecretName, etcdCACertFile, etcdCAKeyFile)
if err != nil {
log.Fatalf("Unable to generate etcd CA cert pair: %v", err)
}
newFrontProxyCASecret, err := secret.CreateCASecret(common.DefaultFrontProxyCASecretName, frontProxyCACertFile, frontProxyCAKeyFile)
if err != nil {
log.Fatalf("Unable to generate front proxy CA cert pair: %v", err)
}

newServiceAccountKeySecret, err := secret.CreateSAKeySecret(common.DefaultServiceAccountKeySecretName, saPrivateKeyFile, saPublicKeyFile)
if err != nil {
log.Fatalf("Unable to generate service account key pair: %v", err)
}
newBootstrapTokenSecret, err := secret.CreateBootstrapTokenSecret(common.DefaultBootstrapTokenSecretName)
if err != nil {
log.Fatalf("Unable to generate bootstrap token secret: %v", err)
}

newCluster, err := createCluster(common.DefaultClusterName, podsCIDR, servicesCIDR, vip, routerID, clusterConfig)
if err != nil {
log.Fatalf("Unable to create cluster: %v", err)
Expand Down Expand Up @@ -267,105 +283,6 @@ func createCluster(clusterName, podsCIDR, servicesCIDR, vip string, routerID int
return &newCluster, nil
}

func createServiceAccountKeySecret(saPrivateKeyFile, saPublicKeyFile string) *corev1.Secret {
sakSecret := corev1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "serviceaccount-key",
Namespace: common.DefaultNamespace,
CreationTimestamp: metav1.Now(),
},
Data: make(map[string][]byte),
}

var privateKeyBytes []byte
var publicKeyBytes []byte
if len(saPrivateKeyFile) != 0 && len(saPublicKeyFile) != 0 {
var err error
privateKeyBytes, err = ioutil.ReadFile(saPrivateKeyFile)
if err != nil {
log.Fatalf("Unable to read service account private key %q: %v", saPrivateKeyFile, err)
}
publicKeyBytes, err = ioutil.ReadFile(saPublicKeyFile)
if err != nil {
log.Fatalf("Unable to read service account public key %q: %v", saPublicKeyFile, err)
}
} else {
key, err := certutil.NewPrivateKey()
if err != nil {
log.Fatalf("Unable to create a service account private key: %v", err)
}
privateKeyBytes = certutil.EncodePrivateKeyPEM(key)
publicKeyBytes, err = certutil.EncodePublicKeyPEM(&key.PublicKey)
if err != nil {
log.Fatalf("Unable to encode service account public key to PEM format: %v", err)
}
}

sakSecret.Data["privatekey"] = privateKeyBytes
sakSecret.Data["publickey"] = publicKeyBytes

return &sakSecret
}

func createCASecret(secretName, certFilename, keyFilename string) *corev1.Secret {
caSecret := corev1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
Namespace: common.DefaultNamespace,
CreationTimestamp: metav1.Now(),
},
Data: make(map[string][]byte),
}

var certBytes []byte
var keyBytes []byte
if len(certFilename) != 0 && len(keyFilename) != 0 {
var err error
certBytes, err = ioutil.ReadFile(certFilename)
if err != nil {
log.Fatalf("Unable to read CA cert %q: %v", certFilename, err)
}
keyBytes, err = ioutil.ReadFile(keyFilename)
if err != nil {
log.Fatalf("Unable to read CA key %q: %v", keyFilename, err)
}
} else {
cert, key, err := common.NewCertificateAuthority()
if err != nil {
log.Fatalf("Unable to create CA: %v", err)
}
certBytes = certutil.EncodeCertPEM(cert)
keyBytes = certutil.EncodePrivateKeyPEM(key)
}
caSecret.Data["tls.crt"] = certBytes
caSecret.Data["tls.key"] = keyBytes
return &caSecret
}

func createBootstrapTokenSecret(name string) *corev1.Secret {
btSecret := corev1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: common.DefaultNamespace,
CreationTimestamp: metav1.Now(),
},
Data: make(map[string][]byte),
}
return &btSecret
}

var clusterCmdDelete = &cobra.Command{
Use: "cluster",
Short: "Deletes a node from a cluster",
Expand Down
71 changes: 71 additions & 0 deletions cmd/secret.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package cmd

import (
"fmt"

"github.com/platform9/cctl/common"
log "github.com/platform9/cctl/pkg/logrus"
"github.com/platform9/cctl/pkg/util/secret"
"github.com/spf13/cobra"
)

var secretCmdCreate = &cobra.Command{
Use: "secrets",
Short: "Create default secrets",
Run: func(cmd *cobra.Command, args []string) {
err := createSecretDefaults()
if err != nil {
log.Fatalf("Unable to create secrets: %v", err)
}
log.Println("Secrets created successfully.")
},
}

func createSecretDefaults() error {
newAPIServerCASecret, err := secret.CreateCASecretDefault(common.DefaultAPIServerCASecretName)
if err != nil {
return fmt.Errorf("unable to generate API server CA secret: %v", err)
}
newEtcdCASecret, err := secret.CreateCASecretDefault(common.DefaultEtcdCASecretName)
if err != nil {
return fmt.Errorf("unable to generate etcd CA secret: %v", err)
}
newFrontProxyCASecret, err := secret.CreateCASecretDefault(common.DefaultFrontProxyCASecretName)
if err != nil {
return fmt.Errorf("unable to generate front proxy CA secret: %v", err)
}

newServiceAccountKeySecret, err := secret.CreateSAKeySecretDefault(common.DefaultServiceAccountKeySecretName)
if err != nil {
return fmt.Errorf("unable to generate service account CA secret: %v", err)
}
newBootstrapTokenSecret, err := secret.CreateBootstrapTokenSecret(common.DefaultBootstrapTokenSecretName)
if err != nil {
return fmt.Errorf("unable to generate bootstrap token CA secret: %v", err)
}

if _, err := state.KubeClient.CoreV1().Secrets(common.DefaultNamespace).Create(newAPIServerCASecret); err != nil {
return fmt.Errorf("unable to create API server CA secret: %v", err)
}
if _, err := state.KubeClient.CoreV1().Secrets(common.DefaultNamespace).Create(newEtcdCASecret); err != nil {
return fmt.Errorf("unable to create etcd CA secret: %v", err)
}
if _, err := state.KubeClient.CoreV1().Secrets(common.DefaultNamespace).Create(newFrontProxyCASecret); err != nil {
return fmt.Errorf("unable to create front proxy CA secret: %v", err)
}
if _, err := state.KubeClient.CoreV1().Secrets(common.DefaultNamespace).Create(newServiceAccountKeySecret); err != nil {
return fmt.Errorf("unable to create service account secret: %v", err)
}
if _, err := state.KubeClient.CoreV1().Secrets(common.DefaultNamespace).Create(newBootstrapTokenSecret); err != nil {
return fmt.Errorf("unable to create bootstrap token secret: %v", err)
}
if err := state.PullFromAPIs(); err != nil {
return fmt.Errorf("unable to sync on-disk state: %v", err)
}

return nil
}

func init() {
createCmd.AddCommand(secretCmdCreate)
}
122 changes: 122 additions & 0 deletions pkg/util/secret/secret_util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package secret

import (
"fmt"
"io/ioutil"

"github.com/platform9/cctl/common"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
certutil "k8s.io/client-go/util/cert"
)

func CreateCASecretDefault(secretName string) (*corev1.Secret, error) {
return CreateCASecret(secretName, "", "")
}

func CreateSAKeySecretDefault(secretName string) (*corev1.Secret, error) {
return CreateSAKeySecret(secretName, "", "")
}

func CreateCASecret(secretName, certFilename, keyFilename string) (*corev1.Secret, error) {
caSecret := createSecret(secretName)

var certBytes []byte
var keyBytes []byte
if len(certFilename) != 0 && len(keyFilename) != 0 {
var err error
certBytes, err = ioutil.ReadFile(certFilename)
if err != nil {
return nil, fmt.Errorf("unable to read CA cert %q: %v", certFilename, err)
}
keyBytes, err = ioutil.ReadFile(keyFilename)
if err != nil {
return nil, fmt.Errorf("unable to read CA key %q: %v", keyFilename, err)
}
} else {
var err error
certBytes, keyBytes, err = generateCertPair()
if err != nil {
return nil, fmt.Errorf("unable to generate cert pair: %v", err)
}

}
caSecret.Data["tls.crt"] = certBytes
caSecret.Data["tls.key"] = keyBytes
return caSecret, nil
}

func CreateSAKeySecret(secretName, saPrivateKeyFile, saPublicKeyFile string) (*corev1.Secret, error) {
sakSecret := createSecret(secretName)

var privateKeyBytes []byte
var publicKeyBytes []byte
if len(saPrivateKeyFile) != 0 && len(saPublicKeyFile) != 0 {
var err error
privateKeyBytes, err = ioutil.ReadFile(saPrivateKeyFile)
if err != nil {
return nil, fmt.Errorf("unable to read service account private key %q: %v", saPrivateKeyFile, err)
}
publicKeyBytes, err = ioutil.ReadFile(saPublicKeyFile)
if err != nil {
return nil, fmt.Errorf("unable to read service account public key %q: %v", saPublicKeyFile, err)
}
} else {
var err error
privateKeyBytes, publicKeyBytes, err = generateKeyPair()
if err != nil {
return nil, fmt.Errorf("unable to generate key pair: %v", err)
}
}

sakSecret.Data["privatekey"] = privateKeyBytes
sakSecret.Data["publickey"] = publicKeyBytes

return sakSecret, nil
}

func CreateBootstrapTokenSecret(secretName string) (*corev1.Secret, error) {
btSecret := createSecret(secretName)
return btSecret, nil
}

func generateCertPair() ([]byte, []byte, error) {
var certBytes, keyBytes []byte
cert, key, err := common.NewCertificateAuthority()
if err != nil {
return nil, nil, fmt.Errorf("unable to create CA: %v", err)
}
certBytes = certutil.EncodeCertPEM(cert)
keyBytes = certutil.EncodePrivateKeyPEM(key)
return certBytes, keyBytes, nil
}

func generateKeyPair() ([]byte, []byte, error) {
var privateKeyBytes, publicKeyBytes []byte
key, err := certutil.NewPrivateKey()
if err != nil {
return nil, nil, fmt.Errorf("unable to create a service account private key: %v", err)
}
privateKeyBytes = certutil.EncodePrivateKeyPEM(key)
publicKeyBytes, err = certutil.EncodePublicKeyPEM(&key.PublicKey)
if err != nil {
return nil, nil, fmt.Errorf("unable to encode service account public key to PEM format: %v", err)
}
return privateKeyBytes, publicKeyBytes, nil
}

func createSecret(name string) *corev1.Secret {
btSecret := corev1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: common.DefaultNamespace,
CreationTimestamp: metav1.Now(),
},
Data: make(map[string][]byte),
}
return &btSecret
}

0 comments on commit 525217d

Please sign in to comment.