Skip to content

Commit

Permalink
setting envar export as default and adding quotes; updating secret pu…
Browse files Browse the repository at this point in the history
…t command with interactive inputs; adding sample operatory deploy yaml and sample vault yaml to public site; updating readme files
  • Loading branch information
shibme committed Feb 27, 2024
1 parent bbf7636 commit 0a49bd0
Show file tree
Hide file tree
Showing 9 changed files with 351 additions and 40 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:

jobs:

slv:
release:
runs-on: ubuntu-latest
steps:
- name: Setting SLV Version
Expand Down
77 changes: 72 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,79 @@
Secure Local Vault - SLV (a.k.a Secrets Launch Vehicle 🔐🚀) is a tool to manage secrets locally in a secure manner. It is designed to be used by developers to manage secrets along with their code so that they can be shared with other developers and services in a secure manner.

SLV is designed based on the following **key principles**
- Anyone can add or update secrets, however will not be allowed to read them unless they have access to the vault
- An environment should have a single key that will give access to all necessary secrets irrespective of the number of vaults shared with it
- Anyone can add or update secrets, however will not be able to read them unless they have access to the vault
- An environment should have a single identity that will give access to all necessary secrets from any vault shared with it

## How to install
SLV can be installed using brew using the following command
## Installation
Download the latest SLV binary from the [releases](https://github.com/savesecrets/slv/releases/latest) page and add it to your path.

SLV can also be installed with brew using the following command
```zsh
brew install savesecrets/tap/slv
```
Alternatively, you can download the SLV binary from the [releases](https://github.com/savesecrets/slv/releases/latest) page and add it to your path.

## Usage

#### Create a new profile
```sh
$ slv profile new -n amagi

Created profile: amagi
```

#### Create a new environment
```sh
$ slv env new -n alice -e alice@example.com --add

ID (Public Key): SLV_EPK_AEAUKAELRTIL2YIXNP7NYTYQMHUX77BWK2LXSKXN4GHSUECDNEJ7XFECLE
Name: alice
Email: alice@example.com
Tags: []

Env Data: SLV_EDS_AF4JYNGKIFVYGMAYQDQ774U5MUDRSBDSTK5G7UZFBPMYYW5ECRETKSBAKFISVFOS75PKJ5HY6I7FPEHHSN3S3MY3KAUPSX4DSI2QSJQVJOIP7KUCY522DBJEUJLPLT3XLZUUFUT7CZZV2MRNLY77HMWC5RO6AF6RD6MHDBAIQQERMKAY55NAWELAGDHD766NLZGJRPD5NHD3BP3BKXN3J26FZ3V4GK6TF5AA7RYI4Q6K5LVTOPVINTQNHVIIBWZ5AAAP775I7Q3QS

Secret Key: SLV_ESK_AEAEKAHBIONE3QIIWFXFRNJPE6A6AYL527QW4OF4HWWFDOE5E4XR5LO2WI
```

#### Create a vault
- To create a vault and share it with the environment `alice`, use the following command
```sh
$ slv vault new -v test.slv -s alice

Created vault: test.slv
```
- To create a K8s compatible vault, use the following command
```sh
$ slv vault new -v test.slv.yaml -s alice --k8s production

Created vault: test.slv.yaml
```

#### Add secrets to the vault
```sh
$ slv secret put -v test.slv -n db_password -s "super_secret_pwd"

Added secret: db_password to vault: test.slv
```

#### Get secrets from the vault
Set the environment variable `SLV_ENV_SECRET_KEY` to the secret key generated in the previous step
```sh
$ export SLV_ENV_SECRET_KEY=SLV_ESK_AEAEKAHBIONE3QIIWFXFRNJPE6A6AYL527QW4OF4HWWFDOE5E4XR5LO2WI
$ slv secret get -v test.slv -n db_password

super_secret_pwd
```

#### Share the vault with other environments
Ensure that the current environment has access to the vault in order to share it with other environments
```sh
$ slv vault share -v test.slv -s bob

Shared vault: test.slv
```
Once shared, the other environments can access the vault using their respective secret keys

## Integrations
Some of the integrations that SLV supports currently are:
- [Kubernetes Operator](/operator/README.md)
9 changes: 9 additions & 0 deletions cli/internal/commands/commons.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,19 @@ package commands
import (
"fmt"
"os"
"syscall"

"github.com/fatih/color"
"golang.org/x/term"
)

func getHiddenInputFromUser(prompt string) ([]byte, error) {
fmt.Print(prompt)
input, err := term.ReadPassword(int(syscall.Stdin))
fmt.Println()
return input, err
}

func exitOnError(err error) {
fmt.Fprintln(os.Stderr, color.RedString(err.Error()))
erroredExit()
Expand Down
38 changes: 27 additions & 11 deletions cli/internal/commands/secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,20 +50,35 @@ func secretPutCommand() *cobra.Command {
Run: func(cmd *cobra.Command, args []string) {
vaultFile := cmd.Flag(vaultFileFlag.name).Value.String()
name := cmd.Flag(secretNameFlag.name).Value.String()
secret := cmd.Flag(secretValueFlag.name).Value.String()
secretStr := cmd.Flag(secretValueFlag.name).Value.String()
vault, err := getVault(vaultFile)
if err != nil {
exitOnError(err)
}
forceUpdate, _ := cmd.Flags().GetBool(secretForceUpdateFlag.name)
if !forceUpdate && vault.SecretExists(name) {
exitOnErrorWithMessage("secret already exists. please use the --" + secretForceUpdateFlag.name + " flag to overwrite it.")
fmt.Print("Secret already exists. Do you wish to overwrite it? (y/n): ")
var confirmation string
fmt.Scanln(&confirmation)
if confirmation != "y" {
fmt.Println(color.YellowString("Operation aborted"))
safeExit()
}
}
var secret []byte
if secretStr == "" {
secret, err = getHiddenInputFromUser("Enter the secret value for " + name + ": ")
if err != nil {
exitOnError(err)
}
} else {
secret = []byte(secretStr)
}
err = vault.PutSecret(name, []byte(secret))
err = vault.PutSecret(name, secret)
if err != nil {
exitOnError(err)
}
fmt.Println("Added secret: ", color.GreenString(name), " to vault: ", color.GreenString(vaultFile))
fmt.Println("Updated secret: ", color.GreenString(name), " to vault: ", color.GreenString(vaultFile))
safeExit()
},
}
Expand All @@ -73,7 +88,6 @@ func secretPutCommand() *cobra.Command {
secretPutCmd.Flags().Bool(secretForceUpdateFlag.name, false, secretForceUpdateFlag.usage)
secretPutCmd.MarkFlagRequired(vaultFileFlag.name)
secretPutCmd.MarkFlagRequired(secretNameFlag.name)
secretPutCmd.MarkFlagRequired(secretValueFlag.name)
return secretPutCmd
}

Expand Down Expand Up @@ -156,11 +170,11 @@ func secretExportCommand() *cobra.Command {
secretOutputMap[name] = string(secret)
}
}
listFormat := cmd.Flag(secretListFormatFlag.name).Value.String()
if listFormat == "" {
listFormat = "table"
exportFormat := cmd.Flag(secretListFormatFlag.name).Value.String()
if exportFormat == "" {
exportFormat = "env"
}
switch listFormat {
switch exportFormat {
case "table":
tw := tabwriter.NewWriter(os.Stdout, 0, 8, 2, ' ', 0)
for key, value := range secretOutputMap {
Expand All @@ -181,10 +195,12 @@ func secretExportCommand() *cobra.Command {
fmt.Println(string(yamlData))
case "envars", "envar", "env":
for key, value := range secretOutputMap {
fmt.Printf("%s=%s\n", key, value)
value = strings.ReplaceAll(value, "\\", "\\\\")
value = strings.ReplaceAll(value, "\"", "\\\"")
fmt.Printf("%s=\"%s\"\n", key, value)
}
default:
exitOnErrorWithMessage("invalid format: " + listFormat)
exitOnErrorWithMessage("invalid format: " + exportFormat)
}
safeExit()
},
Expand Down
161 changes: 161 additions & 0 deletions docs/operator/samples/deploy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.14.0
name: slvs.slv.savesecrets.org
spec:
group: slv.savesecrets.org
names:
kind: SLV
listKind: SLVList
plural: slvs
singular: slv
scope: Namespaced
versions:
- name: v1
schema:
openAPIV3Schema:
description: SLV is the Schema for the slvs API
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
spec:
description: SLVSpec defines the desired state of SLV
properties:
slvConfig:
properties:
hashLength:
format: int32
type: integer
publicKey:
type: string
wrappedKeys:
items:
type: string
type: array
required:
- publicKey
- wrappedKeys
type: object
slvSecrets:
additionalProperties:
type: string
type: object
required:
- slvConfig
- slvSecrets
type: object
status:
description: SLVStatus defines the observed state of SLV
properties:
error:
type: string
type: object
type: object
served: true
storage: true
subresources:
status: {}

---
apiVersion: v1
kind: Namespace
metadata:
name: slv

---
apiVersion: v1
kind: ServiceAccount
metadata:
name: slv-operator
namespace: slv
automountServiceAccountToken: true

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: slv-operator-clusterrole
rules:

- apiGroups: ["slv.savesecrets.org"]
resources: ["slvs"] # plural of SLV CRD
verbs:
- "watch"
- "get"
- "list"

- apiGroups: [""]
resources: ["secrets"]
verbs:
- "create"
- "list"
- "update"
- "delete" # Delete the secret when corresponding SLV CR is deleted
- "watch" # Watching secrets annotated by SLV being modified and reverse sync for reverting to original state.

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: slv-operator-rolebinding
subjects:
- kind: ServiceAccount
name: slv-operator
namespace: slv
roleRef:
kind: ClusterRole
name: slv-operator-clusterrole
apiGroup: rbac.authorization.k8s.io

---
apiVersion: apps/v1
kind: Deployment
metadata:
name: slv-operator
namespace: slv
labels:
app: slv-operator
spec:
replicas: 1
selector:
matchLabels:
app: slv-operator
template:
metadata:
labels:
app: slv-operator
spec:
serviceAccountName: slv-operator
containers:
- name: slv-operator
image: ghcr.io/savesecrets/slv/operator:latest # Use a specific version tag corresponding to the version of SLV used with the CR
resources:
limits:
cpu: "1" # 1 CPU should be fairly enough for SLV Controller
memory: "1Gi" # 1Gi is the minimum memory requirement for SLV Controller
env:
- name: SLV_ENV_SECRET_BINDING
value: "SLV_ESB_ENVSECRETBINDINGSTRINGGOESHERE" # Ensure the appropriate KMS role is attached to the K8s Service Account
- name: SLV_ENV_SECRET_KEY
valueFrom: # SLV Environment Secret Key taken from K8s secret
secretKeyRef:
name: slv # Name of K8 Secret
key: secretkey # Key within K8 Secret
21 changes: 21 additions & 0 deletions docs/operator/samples/pets.slv.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
apiVersion: slv.savesecrets.org/v1
kind: SLV
metadata:
name: pets
spec:
slvSecrets:
supercat: SLV_VSS_AFLGLVMLEEACIAIBKYAL7QS4URIE3VNM4BDC7U5ULCUFXI7VSUGYU623JRBOINO2FTPACXAATPB5MNWWE2E3ALMLGUOKBC6N2EXPPWWKPORH3U3QVTQEUDCXUUOISVUI5I5ESRNYTLHDTUFF57TLBG7NTKOG5WZFLQARNLXSEJWQSKEP4G75PPKK2A4TNPCK7IRYU3U67ERFMW2LN6LSRB6Q
cat1: SLV_VSS_AFLGLVMLEEACIAIBKYAL7QS4URIE3VNM4BDC7U5ULCUFXI7VSUGYU623JRBOINO2FTPACXAA3UTBQQ36X6IHCLCMOUTSECWG7LBVIRT73NNWCHANMPYPFFQQPJBHDRU7ONADRGY3ZCYVXUNNMH5JWO3DYMPODMDBLUA57ZCEVTSF4HN3V2W4QSMN5VPI7NULFIPQ62XZGFOKGKO4FQISKHGJ
cat2: SLV_VSS_AFLGLVMLEEACIAIBKYAL7QS4URIE3VNM4BDC7U5ULCUFXI7VSUGYU623JRBOINO2FTPACXAAJ54ZG3CM64U6HMZDWHDN4Q7A7JKHSUXMFJQ2Q72GB6DIOUFIFEFB4A3H3SAPZ7KU3RAUOJY7C7ILB4U2RVLJSHTNFMAXBIYH42VLREDWGGGDS632FJAKHDRIT6HQEBEBVZXJPOALRFZBOGO4VGSR4
dog1: SLV_VSS_AFLGLVMLEEACIAIBKYAL7QS4URIE3VNM4BDC7U5ULCUFXI7VSUGYU623JRBOINO2FTPACXAAZERB5D7EH43DHEDL73MPWLPDGDZXNLY6I6LZZCDKWMMRDGMV346Q23NUFCEFMFZ7ZKFOCGMRSGD7BIA7GRFJ2CFGW4AVKCAFVLYH55K4TI565TTVUKOD7KLJ3RID3TXEABVTKNNH7IFLLUKI
dog2: SLV_VSS_AFLGLVMLEEACIAIBKYAL7QS4URIE3VNM4BDC7U5ULCUFXI7VSUGYU623JRBOINO2FTPACXAA6EKSCXWMKU5EJBT76L5JUEUHY5Z2AZJSXU5GVW5TWKGTCAVFZJL6RDO5SH3Y6PYGDVTLXUIPRZGA75LFFAK6JTINYAAS5C2LH6WRZJP4BX4H63SCOVFGGIKO32CYPOZKWCDSSCZYSB6YV532N4ZQ
dog3: SLV_VSS_AFLGLVMLEEACIAIBKYAL7QS4URIE3VNM4BDC7U5ULCUFXI7VSUGYU623JRBOINO2FTPACXAAX5PDJLYMJJFS5WSM7MUSGOUFZHPWVVGQYRFN2XAME2SJ2N4X2BPYHJLX5MPHIM4BI6VQCL54RYSJX4SIOWHEWRTXVMAYY6DZP4LB2V6Y2EQX2E7TEHH7JJZUQRUENNMVTIVIXVFES7V3HWA
dog4: SLV_VSS_AFLGLVMLEEACIAIBKYAL7QS4URIE3VNM4BDC7U5ULCUFXI7VSUGYU623JRBOINO2FTPACXAA5KKTTNTGJVDAYCB53MPDIM2TTVFOZ277FM2FDBN2RFMSCABLNNTH7Q4UMWZXSCUELAHKUGP4C4ZOTUVMXCYW4ZH7EUA5VOK7A3AB4CPVICRJDNTJ2MIYWDZ2TH4NG2AKUO4YYMUZ3HCDKJPK
dog5: SLV_VSS_AFLGLVMLEEACIAIBKYAL7QS4URIE3VNM4BDC7U5ULCUFXI7VSUGYU623JRBOINO2FTPACXAAZRAGCZI4RMMW2QIGXJ7AOY4LGOXLCES6Q2WO4JUYY5HEEACB5BDRK6O6GN3CREVF4522Z4ALK4UJXFV3EP44QG7XU4A5HBKEKFAB7R4GALRPNQ6362W4X5MXDE2AU6KPVOX3AOPP3EJ3VF4J3U
dog6: SLV_VSS_AFLGLVMLEEACIAIBKYAL7QS4URIE3VNM4BDC7U5ULCUFXI7VSUGYU623JRBOINO2FTPACXAAVVR5FSDZ5TS2UAFORSNEMXSBEJ4WHRXYVP7YOGWSBOVGH7TO4ZGKZ6G6TA6BNK66VNWIGJK25622POY5TUT7P7KZJAA5PMREQVNU66WRGKDLOD2PWSTFQEAAEQVVWJO3L2YVUXLOTOE6KXAZOFDA
dog7: SLV_VSS_AFLGLVMLEEACIAIBKYAL7QS4URIE3VNM4BDC7U5ULCUFXI7VSUGYU623JRBOINO2FTPACXAA6ZS2LSPURVVTZGLAIQX6KUF2HJ7OAC36XIGVJUSPFWQ5NWJFRZIY4QLLDF467B67ISEUNMTPHTMMDA2L5WZR2NDHLIAVTXNA765F5Z7AJXRPBJXCRGPUGM3U5QVLNZDUG2L24Q7ZUBT4Z3Q
dog8: SLV_VSS_AFLGLVMLEEACIAIBKYAL7QS4URIE3VNM4BDC7U5ULCUFXI7VSUGYU623JRBOINO2FTPACXAASXY3S325JRWOGC2LW2JTTZABWFOWHOT5WSY74ZJATOWT7IPY2JISZEGMNN7R7UGPAQCHT5KRVNT6MFENBBJB3DTC7UA55W5LSYSLBNF57YC2YYJZDQ3JJA2LJEF7OZJF2EEZO2LQ5J6OPBA
slvConfig:
publicKey: SLV_VPK_AEAVMAF7YJOKIUCN2WWOARRP2O2FRKC3UP2ZKDMKPNNUYQXEGXNCZXQBLQ
wrappedKeys:
- SLV_EWK_AFCWLVMKRUACIAIBIUAIXDGQXVQRO2763RHRAYPJP76DMVUXPEVO3YMPFIIEG2IT7OKIEWIA2QG6EVXOHHKNZVUG73LXSQ5OD2XW3QEXKN5FYWLVMT67E2RHN5NKCEQ2EY4CRN3M5LGVPTAWMEIE37NT7Y5QH6AKMMA6NNASASUMJ3KNEPHS5BOQ43ROZGLDFVWC53HOUI3H6L32D5VOTLZWDT6N62QBYU6AH6IRBNKSUV6TSFEU2ZE7VVXDZXQ2APYURJHRFOYM4
Loading

0 comments on commit 0a49bd0

Please sign in to comment.