Skip to content

Commit

Permalink
list k8s secrets
Browse files Browse the repository at this point in the history
  • Loading branch information
pr8kerl committed Aug 10, 2019
1 parent 4db22b2 commit dd36139
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 32 deletions.
40 changes: 21 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,42 +1,44 @@
# kubectl-ssm-secret

A kubectl plugin to allow import/export of kubernetes secrets key/value pairs to/from AWS SSM Parameter Store under a common path.
A kubectl plugin to allow import/export of kubernetes secrets to/from AWS SSM Parameter Store path.

The plugin is opinionated. It will look for parameters under a single path. It will not recursively search more than one level under a given path.
Useful if you are reprovisioning clusters or namespaces and need to provision the same secrets over and over.
Or perhaps useful to backup/restore your LetsEncrypt or other certificates.

Import example.
## examples

Given a couple of parameters stored in param store under the path `/foo`, these can easily be imported into kubernetes into a single secret.

If an AWS parameter at path `/foo/bar` contains a secret value, and the parameter `/foo/passwd` contains a secure password, we can view the keys and vaules in parameter store using the list subcommand:
If an AWS parameter at path `/foo/bar` contains a secret value, and the parameter `/foo/passwd` contains a secure password, we can view the keys and values in parameter store using the `kubectl ssm-secret list` subcommand:

```
% kubectl ssm-secret list /foo
bar: foobar
passwd: SuperSecretSquirrelPassword
% kubectl ssm-secret list --ssm-path /foo
ssm:/foo/bar: foobar
ssm:/foo/passwd: SuperSecretSquirrelPassword
```

These params can then be imported with the following import command:
```
% kubectl ssm-secret import test-secret --ssm-path /foo
% kubectl ssm-secret import foo --ssm-path /foo
imported secret: test-secret
```

And we can then check the secret using the beaut `view-secret` kubectl plugin:
And we can then view the contents of the kubernetes secret using list subcommand:
```
% kubectl ssm-secret list foo
k8s:default/foo/bar: foobar
k8s:default/foo/passwd: SuperSecretSquirrelPassword
```
% kubectl view-secret test-secret
Multiple sub keys found. Specify another argument, one of:
-> bar
-> passwd

% kubectl view-secret test-secret bar
foobar%
Finally we can export a secret from kubernetes into a parameter store path:

% kubectl view-secret test-secret passwd
SuperSecretSquirrelPassword%
```

% kubectl ssm-secret export foo --ssm-path /bar
created parameter: /bar/bar, version: 1
created parameter: /bar/passwd, version: 1
exported secret: foo
```

## Install

Expand All @@ -56,15 +58,15 @@ Requires docker and docker-compose installed locally.

```
% git clone [email protected]:pr8kerl/kubectl-ssm-secret.git
% cd kubectl-ssm-secret !11252
% cd kubectl-ssm-secret
% GOOS=darwin docker-compose run --rm make
```

## Use

* Authenticate to AWS
* Authenticate to your kubernetes cluster
* Use the `import` subcommand to create a kubernetes secret from key/valus stored under a parameter store path
* Use the `import` subcommand to create a kubernetes secret from key/values stored under a parameter store path
* Use the `export` subcommand to copy from a kubernetes secret to a parameter store path
* Use the `--overwrite` flag to overwrite an existing kubernetes secret or existing parameter store keys.
* Use the `--tls` flag with the import subcommand to create a kubernetes tls secret instead of the default opaque type
Expand Down
40 changes: 32 additions & 8 deletions pkg/cmd/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,51 @@ var listCmd = &cobra.Command{
Short: "list ssm parameters by path ",
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("no ssm param store path provided")
}
return cli.List(args)
},
}

func (c *CommandOptions) List(args []string) error {
for _, key := range args {
secrets, err := c.ssm.GetSecrets(key)
c.SetNamespace()
err := c.ListSsmSecrets()
if err != nil {
return err
}
err = c.ListK8sSecrets(args)
if err != nil {
return err
}
return nil
}

func (c *CommandOptions) ListSsmSecrets() error {
if len(c.ssmPath) > 0 {
secrets, err := c.ssm.GetSecrets(c.ssmPath)
if err != nil {
return err
}

if len(secrets) == 0 {
return fmt.Errorf(fmt.Sprintf("no parameters found at path: %s", key))
return fmt.Errorf(fmt.Sprintf("no parameters found at path: %s", c.ssmPath))
}
for k, v := range secrets {
fmt.Printf("%s: %s\n", k, v)
fmt.Printf("ssm:%s/%s: %s\n", c.ssmPath, k, v)
}
}
return nil
}

func (c *CommandOptions) ListK8sSecrets(args []string) error {
for _, key := range args {
secrets, err := c.k8s.GetSecret(key)
if err != nil {
return err
}
if len(secrets) == 0 {
return fmt.Errorf(fmt.Sprintf("no secret data found in secret: %s", key))
}
for k, v := range secrets {
fmt.Printf("k8s:%s/%s/%s: %s\n", c.namespace, key, k, v)
}
}
return nil
}
12 changes: 8 additions & 4 deletions pkg/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ import (
var (
commandExample = `
# view the parameter store keys and values located in parameter store path /param/path/foo
%[1]s list /param/path/foo
%[1]s list --ssm-path /param/path/foo
# view the kubernetes secret called foo
%[1]s list foo
# import to a kubernetes secret called foo from key/values stored at parameter store path /param/path/foo
%[1]s import foo --ssm-path /param/path/foo
Expand Down Expand Up @@ -56,6 +59,7 @@ func NewCommandOptions() *CommandOptions {
fmt.Printf("error: cannot init k8s client: %s\n", err)
os.Exit(1)
}
ns := kclient.GetNamespace()
return &CommandOptions{
toSsm: false,
ssmPath: "",
Expand All @@ -64,7 +68,7 @@ func NewCommandOptions() *CommandOptions {
overwrite: false,
encode: false,
tls: false,
namespace: "",
namespace: ns,
}
}

Expand All @@ -78,17 +82,17 @@ func init() {
rootCmd.AddCommand(listCmd)
rootCmd.AddCommand(importCmd)
rootCmd.AddCommand(exportCmd)
rootCmd.PersistentFlags().StringVarP(&cli.namespace, "namespace", "n", cli.namespace, "kubernetes namespace")
listCmd.Flags().StringVarP(&cli.ssmPath, "ssm-path", "s", cli.ssmPath, "ssm parameter store path to list parameters from")
importCmd.Flags().StringVarP(&cli.ssmPath, "ssm-path", "s", cli.ssmPath, "ssm parameter store path to read data from")
importCmd.MarkFlagRequired("ssm-path")
importCmd.Flags().BoolVarP(&cli.overwrite, "overwrite", "o", cli.overwrite, "if k8s secret exists, overwite its values with those from param store")
importCmd.Flags().BoolVarP(&cli.encode, "decode", "d", cli.encode, "treat store values in param store as gzipped, base64 encoded strings")
importCmd.Flags().BoolVarP(&cli.tls, "tls", "t", cli.tls, "import ssm param store values to k8s tls secret")
importCmd.Flags().StringVarP(&cli.namespace, "namespace", "n", cli.namespace, "kubernetes namespace")
exportCmd.Flags().StringVarP(&cli.ssmPath, "ssm-path", "s", cli.ssmPath, "ssm parameter store path to write data to")
exportCmd.MarkFlagRequired("ssm-path")
exportCmd.Flags().BoolVarP(&cli.overwrite, "overwrite", "o", cli.overwrite, "if parameter store key exists, overwite its values with those from k8s secret")
exportCmd.Flags().BoolVarP(&cli.encode, "encode", "e", cli.encode, "gzip, base64 encode values in parameter store")
exportCmd.Flags().StringVarP(&cli.namespace, "namespace", "n", cli.namespace, "kubernetes namespace")
}

var rootCmd = &cobra.Command{
Expand Down
5 changes: 4 additions & 1 deletion pkg/k8s/k8s.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,13 @@ func NewK8sConfig() (*K8sConfig, error) {
func (c *K8sClient) SetNamespace(ns string) {
if len(ns) > 0 {
c.namespace = ns
fmt.Printf("namespace set to: %s\n", c.namespace)
}
}

func (c *K8sClient) GetNamespace() string {
return c.namespace
}

func (c *K8sClient) CreateSecret(secretname string, secrets map[string]string, tls bool) error {

if len(secrets) == 0 {
Expand Down

0 comments on commit dd36139

Please sign in to comment.