Skip to content

Commit

Permalink
Merge pull request #35 from h0n9/develop
Browse files Browse the repository at this point in the history
Update version to v0.6
  • Loading branch information
h0n9 authored Jun 15, 2024
2 parents 5498b3b + 3052f09 commit a97ccd6
Show file tree
Hide file tree
Showing 13 changed files with 210 additions and 98 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
name: ci
on:
workflow_dispatch:
push:
branches:
- main
Expand All @@ -9,11 +10,13 @@ on:
- v*
paths-ignore:
- ".github/**"
- "docs/**"
- "*.md"
env:
img-registry: ghcr.io/h0n9
img-repository: cloud-secrets-manager
img-tags: ghcr.io/h0n9/cloud-secrets-manager:tmp
img-push: "false"
img-push: "true"
img-platforms: linux/amd64
jobs:
build-push:
Expand All @@ -22,7 +25,6 @@ jobs:
- name: Checkout
uses: actions/checkout@v2
- name: Login to GitHub Container Registry
if: ${{ github.ref_name == 'develop' || startsWith(github.ref_name, 'v') }}
uses: docker/login-action@v2
with:
registry: ${{ env.img-registry }}
Expand All @@ -31,11 +33,9 @@ jobs:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: "Set env vars (develop)"
if: ${{ github.ref_name == 'develop' }}
shell: bash
run: |
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
Expand Down
56 changes: 41 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,14 @@ of other new charts.
The following annotatins are required to inject `cloud-secrets-injector` into
pods:

| **Key** | **Required** | **Description** | **Example** |
|----------------------------------------------------|--------------|---------------------------|----------------------------------------------------------|
| `cloud-secrets-manager.h0n9.postie.chat/provider` | true | Cloud Provider Name | `aws` |
| `cloud-secrets-manager.h0n9.postie.chat/secret-id` | true | Secret Name | `very-precious-secret` |
| `cloud-secrets-manager.h0n9.postie.chat/template` | true | Template for secret value | ```{{ range $k, $v := . }}{{ $k }}={{ $v }} {{ end }}``` |
| `cloud-secrets-manager.h0n9.postie.chat/output` | true | File path for output | `/secrets/env` |
| `cloud-secrets-manager.h0n9.postie.chat/injected` | false | Identifier for injection | `false` |
| **Key** | **Required** | **Description** | **Example** |
|--------------------------------------------------------|--------------|------------------------------------|----------------------------------------------------------|
| `cloud-secrets-manager.h0n9.postie.chat/provider` | true | Cloud Provider Name | `aws` |
| `cloud-secrets-manager.h0n9.postie.chat/secret-id` | true | Secret Name | `very-precious-secret` |
| `cloud-secrets-manager.h0n9.postie.chat/template` | true | Template for secret value | ```{{ range $k, $v := . }}{{ $k }}={{ $v }} {{ end }}``` |
| `cloud-secrets-manager.h0n9.postie.chat/output` | true | File path for output | `/secrets/env` |
| `cloud-secrets-manager.h0n9.postie.chat/decode-base64` | false | Decode base64-encoded secret value | `true` or `false` |
| `cloud-secrets-manager.h0n9.postie.chat/injected` | false | Identifier for injection | `false` |

#### Annotations for Multiple Secrets Injection

Expand Down Expand Up @@ -117,6 +118,29 @@ cloud-secrets-manager.h0n9.postie.chat/template-config-secrets: |
Just add `<secret-name>` at the end of each annotation key, like
`cloud-secrets-manager.h0n9.postie.chat/provider-<secret-name>`. That's it!

#### Annotation for Decoding Base64-encoded Secret Value

From the version `v0.6`, you can decode base64-encoded secret values by setting
the `cloud-secrets-manager.h0n9.postie.chat/decode-base64` annotation to `true`.

```yaml
cloud-secrets-manager.h0n9.postie.chat/provider-cert: aws
cloud-secrets-manager.h0n9.postie.chat/secret-id-cert: very-precious-secret
cloud-secrets-manager.h0n9.postie.chat/output-cert: /secrets/precious.cer
cloud-secrets-manager.h0n9.postie.chat/template-cert: |
{{ .base64-encoded-precious-cert }}
cloud-secrets-manager.h0n9.postie.chat/decode-base64-cert: "true"
cloud-secrets-manager.h0n9.postie.chat/provider-key: aws
cloud-secrets-manager.h0n9.postie.chat/secret-id-key: very-precious-secret
cloud-secrets-manager.h0n9.postie.chat/output-key: /secrets/precious.key
cloud-secrets-manager.h0n9.postie.chat/template-key: |
{{ .base64-encoded-precious-key }}
cloud-secrets-manager.h0n9.postie.chat/decode-base64-key: "true"
```

This feature is useful when you want to inject a base64-encoded secret value as
a file into a pod.

### Providers

Supported providers require the annotations mentioned above in common. However,
Expand All @@ -130,23 +154,25 @@ following explanation.

#### 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:
Cloud Secrets Manager can be installed via Homebrew:

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

You can change the tag to a specific version if you want like following:
That's it! You can now use the `cloud-secrets-manager` or `csm` commands.

> For `aws-vault` users, you can use the following command to execute the
`cloud-secrets-manager` command with the specified AWS profile:

```bash
$ dokcer pull ghcr.io/h0n9/cloud-secrets-manager:v0.5
$ aws-vault exec <profile> -- csm <command>
```

#### List Secrets

```bash
$ docker run --rm -it ghcr.io/h0n9/cloud-secrets-manager:latest secrets list --provider aws --limit 3
$ csm secrets list --provider aws --limit 3
dev/hello-world
dev/very-precious-secret
dev/another-secret
Expand All @@ -156,7 +182,7 @@ 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
$ csm secrets edit --provider aws --secret-id dev/very-precious-secret
```

A text editor will be opened with the secret value. After editing, save and
Expand All @@ -167,5 +193,5 @@ 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
$ csm secrets edit --provider aws --secret-id dev/very-precious-secret
```
6 changes: 0 additions & 6 deletions cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,6 @@ import (
"github.com/spf13/cobra"
)

const (
DefaultProviderName = "aws"
DefaultTemplateBase64 = "e3sgcmFuZ2UgJGssICR2IDo9IC4gfX1be3sgJGsgfX1dCnt7ICR2IH19Cgp7eyBlbmQgfX0K"
DefaultOutputFilename = "output"
)

var VersionCmd = &cobra.Command{
Use: "version",
Short: fmt.Sprintf("print '%s' version information", csm.Name),
Expand Down
38 changes: 25 additions & 13 deletions cli/injector/injector.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ import (

const (
DefaultProviderName = "aws"
DefaultSecretID = ""
DefaultTemplateBase64 = "e3sgcmFuZ2UgJGssICR2IDo9IC4gfX1be3sgJGsgfX1dCnt7ICR2IH19Cgp7eyBlbmQgfX0K"
DefaultOutputFilename = "output"
DefaultOutputFilename = ""
DefaultDecodeBase64 = false
)

var Cmd = &cobra.Command{
Expand All @@ -27,10 +29,11 @@ var Cmd = &cobra.Command{
}

var (
providerName string
secretID string
templateBase64 string
output string
providerName string
secretID string
templateBase64 string
outputFilename string
decodeBase64EncodedSecret bool
)

var runCmd = &cobra.Command{
Expand All @@ -45,15 +48,18 @@ var runCmd = &cobra.Command{

logger.Info().Msg("initialized context")

// get envs
// check required flags
if secretID == "" {
return fmt.Errorf("failed to read 'secret-id' flag")
}
if outputFilename == "" {
return fmt.Errorf("failed to read 'output' flag")
}

logger.Info().Msg("read environment variables")

// decode base64-encoded template to string
templateStr, err := util.DecodeBase64(templateBase64)
templateStr, err := util.DecodeBase64StrToStr(templateBase64)
if err != nil {
return err
}
Expand Down Expand Up @@ -92,12 +98,12 @@ var runCmd = &cobra.Command{

logger.Info().Msg("initialized secret handler")

err = secretHandler.Save(secretID, output)
err = secretHandler.Save(secretID, outputFilename, decodeBase64EncodedSecret)
if err != nil {
return err
}

logger.Info().Msg(fmt.Sprintf("saved secret id '%s' values to '%s'", secretID, output))
logger.Info().Msg(fmt.Sprintf("saved secret id '%s' values to '%s'", secretID, outputFilename))

return nil
},
Expand All @@ -107,7 +113,7 @@ func init() {
runCmd.Flags().StringVar(
&providerName,
"provider",
"aws",
DefaultProviderName,
"cloud provider name",
)
runCmd.Flags().StringVar(
Expand All @@ -119,14 +125,20 @@ func init() {
runCmd.Flags().StringVar(
&templateBase64,
"template",
"e3sgcmFuZ2UgJGssICR2IDo9IC4gfX1be3sgJGsgfX1dCnt7ICR2IH19Cgp7eyBlbmQgfX0K",
DefaultTemplateBase64,
"base64 encoded template string",
)
runCmd.Flags().StringVar(
&output,
&outputFilename,
"output",
"secret",
DefaultOutputFilename,
"output filename",
)
runCmd.Flags().BoolVar(
&decodeBase64EncodedSecret,
"decode-b64-secret",
DefaultDecodeBase64,
"decode base64-encoded secret",
)
Cmd.AddCommand(runCmd)
}
2 changes: 1 addition & 1 deletion cli/template/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ var decodeCmd = &cobra.Command{
if args[0] == "" {
return fmt.Errorf("failed to decode empty string")
}
template, err := util.DecodeBase64(args[0])
template, err := util.DecodeBase64StrToStr(args[0])
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion cli/template/encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ var encodeCmd = &cobra.Command{
if args[0] == "" {
return fmt.Errorf("failed to encode empty string")
}
fmt.Println(util.EncodeBase64(args[0]))
fmt.Println(util.EncodeBase64StrToStr(args[0]))
return nil
},
}
2 changes: 1 addition & 1 deletion cli/template/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ var testCmd = &cobra.Command{
if args[0] == "" {
return fmt.Errorf("failed to test empty string")
}
templateStr, err := util.DecodeBase64(args[0])
templateStr, err := util.DecodeBase64StrToStr(args[0])
if err != nil {
return err
}
Expand Down
32 changes: 30 additions & 2 deletions handler/handler.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package handler

import (
"bytes"
"encoding/json"
"os"
"text/template"

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

type SecretHandlerFunc func(string) (string, error)
Expand Down Expand Up @@ -34,17 +36,43 @@ func (handler *SecretHandler) Get(secretID string) (map[string]interface{}, erro
return m, nil
}

func (handler *SecretHandler) Save(secretID, path string) error {
func (handler *SecretHandler) Save(secretID, path string, decodeBase64EncodedSecret bool) error {
// get secret
m, err := handler.Get(secretID)
if err != nil {
return err
}

// create file
file, err := os.Create(path)
if err != nil {
return err
}
defer file.Close()

return handler.template.Execute(file, m)
// if secret is not base64 encoded, write it to file and return
if !decodeBase64EncodedSecret {
return handler.template.Execute(file, m)
}

// execute template
var buff bytes.Buffer
err = handler.template.Execute(&buff, m)
if err != nil {
return err
}

// decode base64 encoded secret
decodedSecret, err := util.DecodeBase64BytesToBytes(buff.Bytes())
if err != nil {
return err
}

// write decoded secret to file
_, err = file.Write(decodedSecret)
if err != nil {
return err
}

return nil
}
2 changes: 1 addition & 1 deletion manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package manager

const (
Name = "cloud-secrets-manager"
Version = "v0.5"
Version = "v0.6"
AnnotationPrefix = "cloud-secrets-manager.h0n9.postie.chat"
InjectorVolumeMountPath = "/tmp/cloud-secrets-injector/secrets"
)
19 changes: 16 additions & 3 deletions util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,31 @@ func GetEnv(key, fallback string) string {
return fallback
}

func EncodeBase64(input string) string {
func EncodeBase64StrToStr(input string) string {
return base64.RawStdEncoding.EncodeToString([]byte(input))
}

func DecodeBase64(input string) (string, error) {
output, err := base64.RawStdEncoding.DecodeString(input)
func DecodeBase64StrToStr(input string) (string, error) {
output, err := DecodeBase64StrToBytes(input)
if err != nil {
return "", err
}
return string(output), nil
}

func DecodeBase64StrToBytes(input string) ([]byte, error) {
return base64.RawStdEncoding.DecodeString(input)
}

func DecodeBase64BytesToBytes(input []byte) ([]byte, error) {
output := make([]byte, base64.StdEncoding.DecodedLen(len(input)))
n, err := base64.StdEncoding.Decode(output, input)
if err != nil {
return nil, err
}
return output[:n], nil
}

func ReadFileToBytes(filename string) ([]byte, error) {
data, err := ioutil.ReadFile(filename)
if err != nil {
Expand Down
Loading

0 comments on commit a97ccd6

Please sign in to comment.