mirror of
https://github.com/davidallendj/magellan.git
synced 2025-12-20 03:27:03 -07:00
refactor: added function to open secrets store by checking env var
This commit is contained in:
parent
48a53f6d5d
commit
a1276360fe
3 changed files with 229 additions and 0 deletions
212
pkg/secrets/example/main.go
Normal file
212
pkg/secrets/example/main.go
Normal file
|
|
@ -0,0 +1,212 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
// This example demonstrates the usage of the LocalSecretStore to store and retrieve secrets.
|
||||||
|
// It provides a command-line interface to generate a master key, store secrets, and retrieve them.
|
||||||
|
// The master key is assumed to be stored in the environment variable MASTER_KEY and while it can
|
||||||
|
// anything you want, we recommend a 32 bit key for AES-256 encryption. The master key is used
|
||||||
|
// as part of a Key Derivation Function (KDF) to generate a unique AES key for each secret.
|
||||||
|
// The algorithm of choice is HMAC-based Extract-and-Expand Key Derivation Function (HKDF).
|
||||||
|
// Each secret is separately encrypted using AES-GCM and stored in a JSON file.
|
||||||
|
// The JSON file is loaded into memory when the LocalSecretStore is created and saved back to the file
|
||||||
|
// when a secret is stored or removed.
|
||||||
|
//
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/OpenCHAMI/magellan/pkg/secrets"
|
||||||
|
)
|
||||||
|
|
||||||
|
func usage() {
|
||||||
|
fmt.Println("Usage:")
|
||||||
|
fmt.Println(" go run main.go generatekey")
|
||||||
|
fmt.Println(" - Generates a new 32-byte master key (in hex).")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println(" Export MASTER_KEY=<your master key> to use the same key in the next commands.")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println(" go run main.go store <secretID> <secretValue> [filename]")
|
||||||
|
fmt.Println(" - Stores the given string value under secretID.")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println(" go run main.go storebase64 <secretID> <base64String> [filename]")
|
||||||
|
fmt.Println(" - Decodes the base64-encoded string before storing.")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println(" go run main.go storejson <secretID> <jsonString> [filename]")
|
||||||
|
fmt.Println(" - Stores the provided JSON for the specified secretID.")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println(" go run main.go retrieve <secretID> [filename]")
|
||||||
|
fmt.Println(" - Retrieves and prints the secret value for the given secretID.")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println(" go run main.go list [filename]")
|
||||||
|
fmt.Println(" - Lists all the secret IDs and their values.")
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
|
||||||
|
// openStore tries to create or open the LocalSecretStore based on the environment
|
||||||
|
// variable MASTER_KEY. If not found, it prints an error.
|
||||||
|
func openStore(filename string) (*secrets.LocalSecretStore, error) {
|
||||||
|
masterKey := os.Getenv("MASTER_KEY")
|
||||||
|
if masterKey == "" {
|
||||||
|
return nil, fmt.Errorf("MASTER_KEY environment variable not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
store, err := secrets.NewLocalSecretStore(masterKey, filename, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot open secrets store: %v", err)
|
||||||
|
}
|
||||||
|
return store, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if len(os.Args) < 2 {
|
||||||
|
usage()
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := os.Args[1]
|
||||||
|
|
||||||
|
switch cmd {
|
||||||
|
case "generatekey":
|
||||||
|
key, err := secrets.GenerateMasterKey()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error generating master key: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
fmt.Printf("%s\n", key)
|
||||||
|
|
||||||
|
case "store":
|
||||||
|
if len(os.Args) < 4 {
|
||||||
|
fmt.Println("Not enough arguments. Usage: go run main.go store <secretID> <secretValue> [filename]")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
secretID := os.Args[2]
|
||||||
|
secretValue := os.Args[3]
|
||||||
|
filename := "mysecrets.json"
|
||||||
|
if len(os.Args) == 5 {
|
||||||
|
filename = os.Args[4]
|
||||||
|
}
|
||||||
|
|
||||||
|
store, err := openStore(filename)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := store.StoreSecretByID(secretID, secretValue); err != nil {
|
||||||
|
fmt.Printf("Error storing secret: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
fmt.Println("Secret stored successfully.")
|
||||||
|
|
||||||
|
case "storebase64":
|
||||||
|
if len(os.Args) < 4 {
|
||||||
|
fmt.Println("Not enough arguments. Usage: go run main.go storebase64 <secretID> <base64String> [filename]")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
secretID := os.Args[2]
|
||||||
|
base64Value := os.Args[3]
|
||||||
|
filename := "mysecrets.json"
|
||||||
|
if len(os.Args) == 5 {
|
||||||
|
filename = os.Args[4]
|
||||||
|
}
|
||||||
|
|
||||||
|
decoded, err := base64.StdEncoding.DecodeString(base64Value)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error decoding base64 data: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
store, err := openStore(filename)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := store.StoreSecretByID(secretID, string(decoded)); err != nil {
|
||||||
|
fmt.Printf("Error storing base64-decoded secret: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
fmt.Println("Base64-decoded secret stored successfully.")
|
||||||
|
|
||||||
|
case "storejson":
|
||||||
|
if len(os.Args) < 4 {
|
||||||
|
fmt.Println(`Not enough arguments. Usage: go run main.go storejson <secretID> '{"key":"value"}' [filename]`)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
secretID := os.Args[2]
|
||||||
|
jsonValue := os.Args[3]
|
||||||
|
filename := "mysecrets.json"
|
||||||
|
if len(os.Args) == 5 {
|
||||||
|
filename = os.Args[4]
|
||||||
|
}
|
||||||
|
|
||||||
|
store, err := openStore(filename)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := store.StoreSecretByID(secretID, jsonValue); err != nil {
|
||||||
|
fmt.Printf("Error storing JSON secret: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
fmt.Println("JSON secret stored successfully.")
|
||||||
|
|
||||||
|
case "retrieve":
|
||||||
|
if len(os.Args) < 3 {
|
||||||
|
fmt.Println("Not enough arguments. Usage: go run main.go retrieve <secretID> [filename]")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
secretID := os.Args[2]
|
||||||
|
filename := "mysecrets.json"
|
||||||
|
if len(os.Args) == 4 {
|
||||||
|
filename = os.Args[3]
|
||||||
|
}
|
||||||
|
|
||||||
|
store, err := openStore(filename)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
secretValue, err := store.GetSecretByID(secretID)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error retrieving secret: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
fmt.Printf("Secret for %s: %s\n", secretID, secretValue)
|
||||||
|
|
||||||
|
case "list":
|
||||||
|
if len(os.Args) < 2 {
|
||||||
|
fmt.Println("Not enough arguments. Usage: go run main.go list [filename]")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
filename := "mysecrets.json"
|
||||||
|
if len(os.Args) == 3 {
|
||||||
|
filename = os.Args[2]
|
||||||
|
}
|
||||||
|
|
||||||
|
store, err := openStore(filename)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
secrets, err := store.ListSecrets()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error listing secrets: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Secrets:")
|
||||||
|
for key, value := range secrets {
|
||||||
|
fmt.Printf("%s: %s\n", key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
usage()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -101,6 +101,21 @@ func (l *LocalSecretStore) ListSecrets() (map[string]string, error) {
|
||||||
return secretsCopy, nil
|
return secretsCopy, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// openStore tries to create or open the LocalSecretStore based on the environment
|
||||||
|
// variable MASTER_KEY. If not found, it prints an error.
|
||||||
|
func OpenStore(filename string) (SecretStore, error) {
|
||||||
|
masterKey := os.Getenv("MASTER_KEY")
|
||||||
|
if masterKey == "" {
|
||||||
|
return nil, fmt.Errorf("MASTER_KEY environment variable not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
store, err := NewLocalSecretStore(masterKey, filename, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot open secrets store: %v", err)
|
||||||
|
}
|
||||||
|
return store, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Saves secrets back to the JSON file
|
// Saves secrets back to the JSON file
|
||||||
func saveSecrets(jsonFile string, store map[string]string) error {
|
func saveSecrets(jsonFile string, store map[string]string) error {
|
||||||
file, err := os.OpenFile(jsonFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
|
file, err := os.OpenFile(jsonFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,11 @@ func NewStaticStore(username, password string) *StaticStore {
|
||||||
func (s *StaticStore) GetSecretByID(secretID string) (string, error) {
|
func (s *StaticStore) GetSecretByID(secretID string) (string, error) {
|
||||||
return fmt.Sprintf(`{"username":"%s","password":"%s"}`, s.Username, s.Password), nil
|
return fmt.Sprintf(`{"username":"%s","password":"%s"}`, s.Username, s.Password), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StaticStore) StoreSecretByID(secretID, secret string) error {
|
func (s *StaticStore) StoreSecretByID(secretID, secret string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StaticStore) ListSecrets() (map[string]string, error) {
|
func (s *StaticStore) ListSecrets() (map[string]string, error) {
|
||||||
return map[string]string{
|
return map[string]string{
|
||||||
"static_creds": fmt.Sprintf(`{"username":"%s","password":"%s"}`, s.Username, s.Password),
|
"static_creds": fmt.Sprintf(`{"username":"%s","password":"%s"}`, s.Username, s.Password),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue