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
|
||||
}
|
||||
|
||||
// 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
|
||||
func saveSecrets(jsonFile string, store map[string]string) error {
|
||||
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) {
|
||||
return fmt.Sprintf(`{"username":"%s","password":"%s"}`, s.Username, s.Password), nil
|
||||
}
|
||||
|
||||
func (s *StaticStore) StoreSecretByID(secretID, secret string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *StaticStore) ListSecrets() (map[string]string, error) {
|
||||
return map[string]string{
|
||||
"static_creds": fmt.Sprintf(`{"username":"%s","password":"%s"}`, s.Username, s.Password),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue