Skip to content

Commit

Permalink
Merge pull request #27 from h0n9/develop
Browse files Browse the repository at this point in the history
Update version to v0.5
  • Loading branch information
h0n9 authored May 3, 2024
2 parents a8877bb + ff3b92a commit 5498b3b
Show file tree
Hide file tree
Showing 12 changed files with 482 additions and 206 deletions.
11 changes: 7 additions & 4 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ on:
env:
img-registry: ghcr.io/h0n9
img-repository: cloud-secrets-manager
img-tag: latest
img-tags: ghcr.io/h0n9/cloud-secrets-manager:tmp
img-push: "false"
img-platforms: linux/amd64
jobs:
build-push:
runs-on: ubuntu-22.04
Expand All @@ -33,18 +34,20 @@ jobs:
if: ${{ github.ref_name == 'develop' }}
shell: bash
run: |
echo "img-tag=dev-${GITHUB_SHA::6}" >> $GITHUB_ENV
echo "img-tags=${{ env.img-registry }}/${{ env.img-repository }}:dev-${GITHUB_SHA::6}" >> $GITHUB_ENV
echo "img-push=true" >> $GITHUB_ENV
- name: "Set env vars (tag)"
if: ${{ startsWith(github.ref_name, 'v') }}
shell: bash
run: |
echo "img-tag=${GITHUB_REF_NAME}" >> $GITHUB_ENV
echo "img-tags=${{ env.img-registry }}/${{ env.img-repository }}:${GITHUB_REF_NAME},${{ env.img-registry }}/${{ env.img-repository }}:latest" >> $GITHUB_ENV
echo "img-push=true" >> $GITHUB_ENV
echo "img-platforms=linux/amd64,linux/arm64" >> $GITHUB_ENV
- name: Build Docker image
uses: docker/build-push-action@v2
with:
platforms: ${{ env.img-platforms }}
push: ${{ env.img-push }}
tags: ${{ env.img-registry }}/${{ env.img-repository }}:${{ env.img-tag }}
tags: ${{ env.img-tags }}
cache-from: type=gha,scope=cloud-secrets-manager
cache-to: type=gha,mode=max,scope=cloud-secrets-manager
71 changes: 67 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,32 @@ to inject secrets strored on Cloud-based secrets managers into Kubernetes Pods,
functioning as [HashiCorp Vault's Agent Sidecar
Injector](https://www.vaultproject.io/docs/platform/k8s/injector).

## Cloud Providers

### Currently Supported
Also, it provides a convenient CLI tool with features like `list` and `edit` to
make secret management easier than using the Cloud Console. If you want to jump
into the CLI tool, please refer to the [CLI Tool](#cli-tool) section right away.

## Contents
- [Supported Cloud Providers](#cloud-providers)
- [Current](#current)
- [Planned](#planned)
- [Concept](#concept)
- [Constitution](#constitution)
- [Step-by-step](#step-by-step)
- [Installation](#installation)
- [Prerequisites](#prerequisites)
- [Using Helm chart](#using-helm-chart)
- [Usage](#usage)
- [Annotations](#annotations)
- [Providers](#providers)
- [CLI Tool](#cli-tool)

## Supported Cloud Providers

### Current
- AWS(Amazon Web Services): [Secrets Manager](https://aws.amazon.com/secrets-manager/)
- GCP(Google Cloud Platform): [Secret Manager](https://cloud.google.com/secret-manager) `(BETA)`

### TO-BE Supported
### Planned
- Azure: [Key Vault](https://azure.microsoft.com/services/key-vault/#getting-started)
- Hashicorp: [Vault](https://www.vaultproject.io)

Expand Down Expand Up @@ -106,3 +125,47 @@ following explanation.

- [AWS(Amazon Web Services)](docs/aws.md)
- [GCP(Google Cloud Platform)](docs/gcp.md)

### CLI Tool

#### Installation

As Cloud Secrets Manager is available as a Docker image, there is no need to
install the CLI tool. Just run the Docker container as follows:

```bash
$ dokcer pull ghcr.io/h0n9/cloud-secrets-manager:latest
```

You can change the tag to a specific version if you want like following:

```bash
$ dokcer pull ghcr.io/h0n9/cloud-secrets-manager:v0.5
```

#### List Secrets

```bash
$ docker run --rm -it ghcr.io/h0n9/cloud-secrets-manager:latest secrets list --provider aws --limit 3
dev/hello-world
dev/very-precious-secret
dev/another-secret
```
The `--limit` option is available to limit the number of secrets to be listed.

#### Edit Secret

```bash
$ docker run --rm -it ghcr.io/h0n9/cloud-secrets-manager:latest secrets edit --provider aws --secret-id dev/very-precious-secret
```

A text editor will be opened with the secret value. After editing, save and
close the editor to update the secret value. If you want to cancel the editing,
just close the editor without saving.

If you want to use a specific editor, set the `EDITOR` environment variable.

```bash
$ export EDITOR=nano
$ docker run --rm -it ghcr.io/h0n9/cloud-secrets-manager:latest secrets edit --provider aws --secret-id dev/very-precious-secret
```
4 changes: 3 additions & 1 deletion cli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/h0n9/cloud-secrets-manager/cli/cert"
"github.com/h0n9/cloud-secrets-manager/cli/controller"
"github.com/h0n9/cloud-secrets-manager/cli/injector"
cliSecrets "github.com/h0n9/cloud-secrets-manager/cli/secrets"
cliTemplate "github.com/h0n9/cloud-secrets-manager/cli/template"
)

Expand All @@ -23,9 +24,10 @@ func init() {
RootCmd.AddCommand(
controller.Cmd,
injector.Cmd,
cert.Cmd,
newLineCmd,
cliSecrets.Cmd,
cliTemplate.Cmd,
cert.Cmd,
newLineCmd,
VersionCmd,
)
Expand Down
147 changes: 147 additions & 0 deletions cli/secrets/edit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package secrets

import (
"context"
"crypto/sha1"
"fmt"
"os"
"os/exec"
"path"
"strings"

"github.com/spf13/cobra"
"sigs.k8s.io/yaml"

"github.com/h0n9/cloud-secrets-manager/provider"
"github.com/h0n9/cloud-secrets-manager/util"
)

var (
secretID string
)

var editCmd = &cobra.Command{
Use: "edit",
Short: "edit a secret",
RunE: func(cmd *cobra.Command, args []string) error {
// check secretID
if secretID == "" {
return fmt.Errorf("failed to read 'secret-id' flag")
}

// define variables
var (
err error
secretProvider provider.SecretProvider
)

// init ctx
ctx := context.Background()

// init secret provider
switch strings.ToLower(providerName) {
case "aws":
secretProvider, err = provider.NewAWS(ctx)
case "gcp":
secretProvider, err = provider.NewGCP(ctx)
default:
return fmt.Errorf("failed to figure out secret provider")
}
if err != nil {
return err
}
defer secretProvider.Close()

// get secret value
secretValue, err := secretProvider.GetSecretValue(secretID)
if err != nil {
return err
}

// convert json to yaml
data, err := yaml.JSONToYAML([]byte(secretValue))
if err != nil {
return err
}

// write data to tmp file
UserCacheDir, err := os.UserCacheDir()
if err != nil {
return err
}
hash := sha1.Sum([]byte(secretID))
tmpFilePath := path.Join(UserCacheDir, fmt.Sprintf("%x", hash))
err = os.WriteFile(tmpFilePath, data, 0644)
if err != nil {
return err
}
defer os.Remove(tmpFilePath)

// get initial stat of tmp file
initialStat, err := os.Stat(tmpFilePath)
if err != nil {
return err
}

// open tmp file with editor(e.g. vim)
editor := util.GetEnv("EDITOR", DefaultEditor)
execCmd := exec.Command(editor, tmpFilePath)
execCmd.Stdin = os.Stdin
execCmd.Stdout = os.Stdout
err = execCmd.Run()
if err != nil {
return err
}

// get updated stat of tmp file
updatedStat, err := os.Stat(tmpFilePath)
if err != nil {
return err
}

// check if tmp file is updated. if not, return nil
if initialStat.ModTime().Equal(updatedStat.ModTime()) &&
initialStat.Size() == updatedStat.Size() {
fmt.Println("found nothing to update")
return nil
}

// read tmp file
data, err = os.ReadFile(tmpFilePath)
if err != nil {
return err
}

// convert yaml to json
data, err = yaml.YAMLToJSON(data)
if err != nil {
return err
}

// update secret value
secretValue = string(data)

// set secret value to provider
err = secretProvider.SetSecretValue(secretID, secretValue)
if err != nil {
return err
}

return nil
},
}

func init() {
editCmd.Flags().StringVar(
&providerName,
"provider",
DefaultProviderName,
"cloud provider name",
)
editCmd.Flags().StringVar(
&secretID,
"secret-id",
"",
"secret id",
)
}
81 changes: 81 additions & 0 deletions cli/secrets/list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package secrets

import (
"context"
"fmt"
"strings"

"github.com/spf13/cobra"

"github.com/h0n9/cloud-secrets-manager/provider"
)

const (
DefaultListSecretsLimit = 10
)

var (
listSecretsLimit int
)

var listCmd = &cobra.Command{
Use: "list",
Short: "list secrets",
RunE: func(cmd *cobra.Command, args []string) error {
// define variables
var (
err error
secretProvider provider.SecretProvider
)

// check constraints
if listSecretsLimit <= 0 {
return fmt.Errorf("'--limit' flag value must be greater than 0")
}

// init ctx
ctx := context.Background()

// init secret provider
switch strings.ToLower(providerName) {
case "aws":
secretProvider, err = provider.NewAWS(ctx)
case "gcp":
secretProvider, err = provider.NewGCP(ctx)
default:
return fmt.Errorf("failed to figure out secret provider")
}
if err != nil {
return err
}
defer secretProvider.Close()

// list secrets
secrets, err := secretProvider.ListSecrets(listSecretsLimit)
if err != nil {
return err
}

// print secrets
for _, secret := range secrets {
fmt.Println(secret)
}

return nil
},
}

func init() {
listCmd.Flags().StringVar(
&providerName,
"provider",
DefaultProviderName,
"cloud provider name",
)
listCmd.Flags().IntVar(
&listSecretsLimit,
"limit",
DefaultListSecretsLimit,
"limit the number of secrets to list",
)
}
24 changes: 24 additions & 0 deletions cli/secrets/secrets.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package secrets

import (
"github.com/spf13/cobra"
)

const (
DefaultProviderName = "aws"
DefaultEditor = "vim"
)

var (
providerName string
)

var Cmd = &cobra.Command{
Use: "secrets",
Short: "CLI for managing secrets",
}

func init() {
Cmd.AddCommand(listCmd)
Cmd.AddCommand(editCmd)
}
Loading

0 comments on commit 5498b3b

Please sign in to comment.