refactor: updated description/example and added 'secrets-file' flag to cmd

This commit is contained in:
David Allen 2025-03-17 10:37:04 -06:00 committed by David Allen
parent f9059c50a1
commit 842e864384
Signed by: towk
GPG key ID: 0430CDBE22619155
4 changed files with 210 additions and 17 deletions

View file

@ -29,7 +29,11 @@ var CollectCmd = &cobra.Command{
"See the 'scan' command on how to perform a scan.\n\n" + "See the 'scan' command on how to perform a scan.\n\n" +
"Examples:\n" + "Examples:\n" +
" magellan collect --cache ./assets.db --output ./logs --timeout 30 --cacert cecert.pem\n" + " magellan collect --cache ./assets.db --output ./logs --timeout 30 --cacert cecert.pem\n" +
" magellan collect --host smd.example.com --port 27779 --username username --password password", " magellan collect --host smd.example.com --port 27779 --username $username --password $password\n\n" +
// example using `collect`
" export MASTER_KEY=$(magellan secrets generatekey)\n" +
" magellan secrets store $node_creds_json -f nodes.json" +
" magellan collect --host openchami.cluster --username $username --password $password \\\n",
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
// get probe states stored in db from scan // get probe states stored in db from scan
scannedResults, err := sqlite.GetScannedAssets(cachePath) scannedResults, err := sqlite.GetScannedAssets(cachePath)
@ -52,17 +56,13 @@ var CollectCmd = &cobra.Command{
} }
} }
if verbose { // set the minimum/maximum number of concurrent processes
log.Debug().Str("Access Token", accessToken)
}
//
if concurrency <= 0 { if concurrency <= 0 {
concurrency = mathutil.Clamp(len(scannedResults), 1, 10000) concurrency = mathutil.Clamp(len(scannedResults), 1, 10000)
} }
// Create a StaticSecretStore to hold the username and password
secrets := secrets.NewStaticStore(username, password) // set the collect parameters from CLI params
_, err = magellan.CollectInventory(&scannedResults, &magellan.CollectParams{ params := &magellan.CollectParams{
URI: host, URI: host,
Timeout: timeout, Timeout: timeout,
Concurrency: concurrency, Concurrency: concurrency,
@ -71,9 +71,26 @@ var CollectCmd = &cobra.Command{
OutputPath: outputPath, OutputPath: outputPath,
ForceUpdate: forceUpdate, ForceUpdate: forceUpdate,
AccessToken: accessToken, AccessToken: accessToken,
}, secrets) }
// show all of the 'collect' parameters being set from CLI if verbose
if verbose {
log.Debug().Any("params", params)
}
// load the secrets file to get node credentials by ID (i.e. the BMC node's URI)
store, err := secrets.OpenStore(params.SecretsFile)
if err != nil { if err != nil {
log.Error().Err(err).Msgf("failed to collect data") // Something went wrong with the store so try using
// Create a StaticSecretStore to hold the username and password
fmt.Println(err)
store = secrets.NewStaticStore(username, password)
} else {
}
_, err = magellan.CollectInventory(&scannedResults, params, store)
if err != nil {
log.Error().Err(err).Msg("failed to collect data")
} }
}, },
} }
@ -81,13 +98,14 @@ var CollectCmd = &cobra.Command{
func init() { func init() {
currentUser, _ = user.Current() currentUser, _ = user.Current()
CollectCmd.PersistentFlags().StringVar(&host, "host", "", "Set the URI to the SMD root endpoint") CollectCmd.PersistentFlags().StringVar(&host, "host", "", "Set the URI to the SMD root endpoint")
CollectCmd.PersistentFlags().StringVar(&username, "username", "", "Set the BMC user") CollectCmd.PersistentFlags().StringVar(&username, "username", "", "Set the master BMC username")
CollectCmd.PersistentFlags().StringVar(&password, "password", "", "Set the BMC password") CollectCmd.PersistentFlags().StringVar(&password, "password", "", "Set the master BMC password")
CollectCmd.PersistentFlags().StringVar(&scheme, "scheme", "https", "Set the scheme used to query") CollectCmd.PersistentFlags().StringVar(&secretsFile, "secrets-file", "", "Set path to the node secrets file")
CollectCmd.PersistentFlags().StringVar(&scheme, "scheme", "https", "Set the default scheme used to query when not included in URI")
CollectCmd.PersistentFlags().StringVar(&protocol, "protocol", "tcp", "Set the protocol used to query") CollectCmd.PersistentFlags().StringVar(&protocol, "protocol", "tcp", "Set the protocol used to query")
CollectCmd.PersistentFlags().StringVarP(&outputPath, "output", "o", fmt.Sprintf("/tmp/%smagellan/inventory/", currentUser.Username+"/"), "Set the path to store collection data") CollectCmd.PersistentFlags().StringVarP(&outputPath, "output", "o", fmt.Sprintf("/tmp/%smagellan/inventory/", currentUser.Username+"/"), "Set the path to store collection data")
CollectCmd.PersistentFlags().BoolVar(&forceUpdate, "force-update", false, "Set flag to force update data sent to SMD") CollectCmd.PersistentFlags().BoolVar(&forceUpdate, "force-update", false, "Set flag to force update data sent to SMD")
CollectCmd.PersistentFlags().StringVar(&cacertPath, "cacert", "", "Path to CA cert. (defaults to system CAs)") CollectCmd.PersistentFlags().StringVar(&cacertPath, "cacert", "", "Set the path to CA cert file. (defaults to system CAs when blank)")
// set flags to only be used together // set flags to only be used together
CollectCmd.MarkFlagsRequiredTogether("username", "password") CollectCmd.MarkFlagsRequiredTogether("username", "password")

View file

@ -18,8 +18,8 @@ import (
var CrawlCmd = &cobra.Command{ var CrawlCmd = &cobra.Command{
Use: "crawl [uri]", Use: "crawl [uri]",
Short: "Crawl a single BMC for inventory information", Short: "Crawl a single BMC for inventory information",
Long: "Crawl a single BMC for inventory information. This command does NOT store information\n" + Long: "Crawl a single BMC for inventory information with URI. This command does NOT scan subnets nor store scan information\n" +
"about the scan into cache after completion. To do so, use the 'collect' command instead\n\n" + "in cache after completion. To do so, use the 'collect' command instead\n\n" +
"Examples:\n" + "Examples:\n" +
" magellan crawl https://bmc.example.com\n" + " magellan crawl https://bmc.example.com\n" +
" magellan crawl https://bmc.example.com -i -u username -p password", " magellan crawl https://bmc.example.com -i -u username -p password",

View file

@ -38,6 +38,7 @@ var (
cacertPath string cacertPath string
username string username string
password string password string
secretsFile string
cachePath string cachePath string
outputPath string outputPath string
configPath string configPath string

174
cmd/secrets.go Normal file
View file

@ -0,0 +1,174 @@
package cmd
import (
"encoding/base64"
"fmt"
"os"
"github.com/OpenCHAMI/magellan/pkg/secrets"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var secretsCmd = &cobra.Command{
Use: "secrets",
Short: "Manage credentials for BMC nodes",
Long: "Manage credentials for BMC nodes to for querying information through redfish. This requires generating a key and setting the 'MASTER_KEY' environment variable for the secrets store.\n" +
"Examples:\n\n" +
" export MASTER_KEY=$(magellan secrets generatekey)\n" +
// store specific BMC node creds for `collect` and `crawl` in default secrets store (`--file/-f`` flag not set)
" magellan secrets store $bmc_host $bmc_creds" +
// retrieve creds from secrets store
" magellan secrets retrieve $bmc_host -f nodes.json" +
// list creds from specific secrets
" magellan secrets list -f nodes.json",
Run: func(cmd *cobra.Command, args []string) {
// show command help and exit
if len(args) < 1 {
cmd.Help()
os.Exit(0)
}
},
}
var secretsGenerateKeyCmd = &cobra.Command{
Use: "generatekey",
Short: "Generates a new 32-byte master key (in hex).",
Run: func(cmd *cobra.Command, args []string) {
key, err := secrets.GenerateMasterKey()
if err != nil {
fmt.Printf("Error generating master key: %v\n", err)
os.Exit(1)
}
fmt.Printf("%s\n", key)
},
}
var secretsStoreCmd = &cobra.Command{
Use: "store secretID secretValue",
Args: cobra.ExactArgs(2),
Short: "Stores the given string value under secretID.",
Run: func(cmd *cobra.Command, args []string) {
var (
secretID = args[0]
secretValue = args[1]
)
store, err := secrets.OpenStore(secretsFile)
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.")
},
}
var secretsStoreBase64Cmd = &cobra.Command{
Use: "storebase64 base64String",
Args: cobra.ExactArgs(1),
Short: "Decodes the base64-encoded string before storing.",
Run: func(cmd *cobra.Command, args []string) {
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 := secrets.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.")
},
}
var secretsRetrieveCmd = &cobra.Command{
Use: "retrieve secretID",
Run: func(cmd *cobra.Command, args []string) {
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]
store, err := secrets.OpenStore(secretsFile)
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)
},
}
var secretsListCmd = &cobra.Command{
Use: "list",
Short: "Lists all the secret IDs and their values.",
Run: func(cmd *cobra.Command, args []string) {
if len(args) < 2 {
fmt.Println("Not enough arguments. Usage: go run main.go list [filename]")
os.Exit(1)
}
store, err := secrets.OpenStore(secretsFile)
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)
}
},
}
func init() {
secretsCmd.Flags().StringVarP(&secretsFile, "file", "f", "nodes.json", "")
secretsCmd.AddCommand(secretsGenerateKeyCmd)
secretsCmd.AddCommand(secretsStoreCmd)
secretsCmd.AddCommand(secretsStoreBase64Cmd)
secretsCmd.AddCommand(secretsRetrieveCmd)
secretsCmd.AddCommand(secretsListCmd)
checkBindFlagError(viper.BindPFlags(secretsCmd.Flags()))
checkBindFlagError(viper.BindPFlags(secretsGenerateKeyCmd.Flags()))
checkBindFlagError(viper.BindPFlags(secretsStoreCmd.Flags()))
checkBindFlagError(viper.BindPFlags(secretsGenerateKeyCmd.Flags()))
checkBindFlagError(viper.BindPFlags(secretsGenerateKeyCmd.Flags()))
checkBindFlagError(viper.BindPFlags(secretsGenerateKeyCmd.Flags()))
}