diff --git a/cmd/kops/get_secrets.go b/cmd/kops/get_secrets.go new file mode 100644 index 0000000000..678782e120 --- /dev/null +++ b/cmd/kops/get_secrets.go @@ -0,0 +1,85 @@ +package main + +import ( + "fmt" + "os" + + "github.com/golang/glog" + "github.com/spf13/cobra" + "k8s.io/kops/upup/pkg/fi" +) + +type GetSecretsCommand struct { +} + +var getSecretsCommand GetSecretsCommand + +func init() { + cmd := &cobra.Command{ + Use: "secrets", + Aliases: []string{"secret"}, + Short: "get secrets", + Long: `List or get secrets.`, + Run: func(cmd *cobra.Command, args []string) { + err := getSecretsCommand.Run() + if err != nil { + glog.Exitf("%v", err) + } + }, + } + + getCmd.AddCommand(cmd) +} + +func (c *GetSecretsCommand) Run() error { + var items []*fi.KeystoreItem + { + caStore, err := rootCommand.KeyStore() + if err != nil { + return err + } + l, err := caStore.List() + if err != nil { + return fmt.Errorf("error listing CA store items %v", err) + } + + for _, i := range l { + items = append(items, i) + } + } + + { + secretStore, err := rootCommand.SecretStore() + if err != nil { + return err + } + l, err := secretStore.ListSecrets() + if err != nil { + return fmt.Errorf("error listing secrets %v", err) + } + + for _, id := range l { + info := &fi.KeystoreItem{ + Name: id, + Type: fi.SecretTypeSecret, + } + items = append(items, info) + } + } + + if len(items) == 0 { + return nil + } + + t := &Table{} + t.AddColumn("NAME", func(i *fi.KeystoreItem) string { + return i.Name + }) + t.AddColumn("ID", func(i *fi.KeystoreItem) string { + return i.Id + }) + t.AddColumn("TYPE", func(i *fi.KeystoreItem) string { + return i.Type + }) + return t.Render(items, os.Stdout, "TYPE", "NAME", "ID") +} diff --git a/cmd/kops/secrets_describe.go b/cmd/kops/secrets_describe.go index 9f2a85677d..bc74cee3ee 100644 --- a/cmd/kops/secrets_describe.go +++ b/cmd/kops/secrets_describe.go @@ -48,12 +48,18 @@ func (c *DescribeSecretsCommand) Run() error { if err != nil { return err } - ids, err := caStore.List() + items, err := caStore.List() if err != nil { return fmt.Errorf("error listing CA store items %v", err) } - for _, id := range ids { + for _, item := range items { + if item.Type != fi.SecretTypeKeypair { + continue + } + + id := item.Name + cert, err := caStore.FindCert(id) if err != nil { return fmt.Errorf("error retrieving cert %q: %v", id, err) diff --git a/cmd/kops/secrets_get.go b/cmd/kops/secrets_get.go index 9767794d8a..db99239fe2 100644 --- a/cmd/kops/secrets_get.go +++ b/cmd/kops/secrets_get.go @@ -1,20 +1,10 @@ package main import ( - "fmt" - - "bytes" "github.com/golang/glog" "github.com/spf13/cobra" - "os" - "text/tabwriter" ) -type GetSecretsCommand struct { -} - -var getSecretsCommand GetSecretsCommand - func init() { cmd := &cobra.Command{ Use: "get", @@ -30,73 +20,3 @@ func init() { secretsCmd.AddCommand(cmd) } - -type SecretInfo struct { - Id string - Type string -} - -func (c *GetSecretsCommand) Run() error { - var infos []*SecretInfo - { - caStore, err := rootCommand.KeyStore() - if err != nil { - return err - } - ids, err := caStore.List() - if err != nil { - return fmt.Errorf("error listing CA store items %v", err) - } - - for _, id := range ids { - info := &SecretInfo{ - Id: id, - Type: "keypair", - } - infos = append(infos, info) - } - } - - { - secretStore, err := rootCommand.SecretStore() - if err != nil { - return err - } - ids, err := secretStore.ListSecrets() - if err != nil { - return fmt.Errorf("error listing secrets %v", err) - } - - for _, id := range ids { - info := &SecretInfo{ - Id: id, - Type: "secret", - } - infos = append(infos, info) - } - } - - var b bytes.Buffer - w := new(tabwriter.Writer) - - // Format in tab-separated columns with a tab stop of 8. - w.Init(os.Stdout, 0, 8, 0, '\t', tabwriter.StripEscape) - for _, info := range infos { - b.WriteByte(tabwriter.Escape) - b.WriteString(info.Type) - b.WriteByte(tabwriter.Escape) - b.WriteByte('\t') - b.WriteByte(tabwriter.Escape) - b.WriteString(info.Id) - b.WriteByte(tabwriter.Escape) - b.WriteByte('\n') - - _, err := w.Write(b.Bytes()) - if err != nil { - return fmt.Errorf("error writing to output: %v", err) - } - b.Reset() - } - w.Flush() - return nil -} diff --git a/upup/pkg/fi/ca.go b/upup/pkg/fi/ca.go index 62ad40f4f0..b26d47f9b6 100644 --- a/upup/pkg/fi/ca.go +++ b/upup/pkg/fi/ca.go @@ -28,6 +28,12 @@ type Certificate struct { PublicKey crypto.PublicKey } +const ( + SecretTypeSSHPublicKey = "SSHPublicKey" + SecretTypeKeypair = "Keypair" + SecretTypeSecret = "Secret" +) + type KeystoreItem struct { Type string Name string @@ -74,29 +80,30 @@ func (c *Certificate) MarshalJSON() ([]byte, error) { type CAStore interface { // Cert returns the primary specified certificate - Cert(id string) (*Certificate, error) + Cert(name string) (*Certificate, error) // CertificatePool returns all active certificates with the specified id - CertificatePool(id string) (*CertificatePool, error) - PrivateKey(id string) (*PrivateKey, error) + CertificatePool(name string) (*CertificatePool, error) + PrivateKey(name string) (*PrivateKey, error) - FindCert(id string) (*Certificate, error) - FindPrivateKey(id string) (*PrivateKey, error) + FindCert(name string) (*Certificate, error) + FindPrivateKey(name string) (*PrivateKey, error) //IssueCert(id string, privateKey *PrivateKey, template *x509.Certificate) (*Certificate, error) //CreatePrivateKey(id string) (*PrivateKey, error) - CreateKeypair(id string, template *x509.Certificate) (*Certificate, *PrivateKey, error) + CreateKeypair(name string, template *x509.Certificate) (*Certificate, *PrivateKey, error) - List() ([]string, error) + // List will list all the items, but will not fetch the data + List() ([]*KeystoreItem, error) // VFSPath returns the path where the CAStore is stored VFSPath() vfs.Path // AddCert adds an alternative certificate to the pool (primarily useful for CAs) - AddCert(id string, cert *Certificate) error + AddCert(name string, cert *Certificate) error // AddSSHPublicKey adds an SSH public key - AddSSHPublicKey(id string, data []byte) error + AddSSHPublicKey(name string, data []byte) error // FindSSHPublicKeys retrieves the SSH public keys with the specific name FindSSHPublicKeys(name string) ([]*KeystoreItem, error) diff --git a/upup/pkg/fi/vfs_castore.go b/upup/pkg/fi/vfs_castore.go index a0c84fb7ee..2872b4ff8e 100644 --- a/upup/pkg/fi/vfs_castore.go +++ b/upup/pkg/fi/vfs_castore.go @@ -27,10 +27,6 @@ type VFSCAStore struct { cacheCaPrivateKeys *privateKeys } -const ( - SecretTypeSSHPublicKey = "SSHPublicKey" -) - var _ CAStore = &VFSCAStore{} func NewVFSCAStore(basedir vfs.Path) CAStore { @@ -322,20 +318,66 @@ func (c *VFSCAStore) FindCertificatePool(id string) (*CertificatePool, error) { return pool, nil } -func (c *VFSCAStore) List() ([]string, error) { - var ids []string +func (c *VFSCAStore) List() ([]*KeystoreItem, error) { + var items []*KeystoreItem - issuedDir := c.basedir.Join("issued") - files, err := issuedDir.ReadDir() - if err != nil { - return nil, fmt.Errorf("error reading directory %q: %v", issuedDir, err) + { + baseDir := c.basedir.Join("issued") + files, err := baseDir.ReadTree() + if err != nil { + return nil, fmt.Errorf("error reading directory %q: %v", baseDir, err) + } + + for _, f := range files { + relativePath, err := vfs.RelativePath(baseDir, f) + if err != nil { + return nil, err + } + + tokens := strings.Split(relativePath, "/") + if len(tokens) != 2 { + glog.V(2).Infof("ignoring unexpected file in keystore: %q", f) + continue + } + + item := &KeystoreItem{ + Name: tokens[0], + Id: strings.TrimSuffix(tokens[1], ".crt"), + Type: SecretTypeKeypair, + } + items = append(items, item) + } } - for _, f := range files { - name := f.Base() - ids = append(ids, name) + { + baseDir := c.basedir.Join("ssh", "public") + files, err := baseDir.ReadTree() + if err != nil { + return nil, fmt.Errorf("error reading directory %q: %v", baseDir, err) + } + + for _, f := range files { + relativePath, err := vfs.RelativePath(baseDir, f) + if err != nil { + return nil, err + } + + tokens := strings.Split(relativePath, "/") + if len(tokens) != 2 { + glog.V(2).Infof("ignoring unexpected file in keystore: %q", f) + continue + } + + item := &KeystoreItem{ + Name: tokens[0], + Id: tokens[1], + Type: SecretTypeSSHPublicKey, + } + items = append(items, item) + } } - return ids, nil + + return items, nil } func (c *VFSCAStore) IssueCert(id string, serial *big.Int, privateKey *PrivateKey, template *x509.Certificate) (*Certificate, error) {