Skip to content

Commit 8f9bb98

Browse files
committed
feat(stores): Added stores list and stores get --id $store_id functions that output JSON to stdout.
fix(cli): Refactored CLI to put `rot` in its own command sub tree
1 parent 478d85f commit 8f9bb98

File tree

3 files changed

+113
-66
lines changed

3 files changed

+113
-66
lines changed

cmd/root.go

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,35 @@ package cmd
77
import (
88
"os"
99

10+
"github.com/Keyfactor/keyfactor-go-client/api"
1011
"github.com/spf13/cobra"
12+
"log"
1113
)
1214

15+
func initClient() (*api.Client, error) {
16+
var clientAuth api.AuthConfig
17+
clientAuth.Username = os.Getenv("KEYFACTOR_USERNAME")
18+
log.Printf("[DEBUG] Username: %s", clientAuth.Username)
19+
clientAuth.Password = os.Getenv("KEYFACTOR_PASSWORD")
20+
log.Printf("[DEBUG] Password: %s", clientAuth.Password)
21+
clientAuth.Domain = os.Getenv("KEYFACTOR_DOMAIN")
22+
log.Printf("[DEBUG] Domain: %s", clientAuth.Domain)
23+
clientAuth.Hostname = os.Getenv("KEYFACTOR_HOSTNAME")
24+
log.Printf("[DEBUG] Hostname: %s", clientAuth.Hostname)
25+
26+
c, err := api.NewKeyfactorClient(&clientAuth)
27+
28+
if err != nil {
29+
log.Fatalf("Error creating Keyfactor client: %s", err)
30+
}
31+
return c, err
32+
}
33+
1334
// rootCmd represents the base command when called without any subcommands
1435
var rootCmd = &cobra.Command{
1536
Use: "kfutil",
16-
Short: "A brief description of your application",
17-
Long: `A longer description that spans multiple lines and likely contains
18-
examples and usage of using your application. For example:
19-
20-
Cobra is a CLI library for Go that empowers applications.
21-
This application is a tool to generate the needed files
22-
to quickly create a Cobra application.`,
37+
Short: "Keyfactor CLI utilities",
38+
Long: `A CLI wrapper around the Keyfactor Platform API.`,
2339
// Uncomment the following line if your bare application
2440
// has an action associated with it:
2541
// Run: func(cmd *cobra.Command, args []string) { },

cmd/rot.go

Lines changed: 42 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,25 @@ type RotCert struct {
3838
type RotAction struct {
3939
StoreId string
4040
StoreType string
41+
StorePath string
4142
Thumbprint string
4243
CertId int
4344
Add bool
4445
Remove bool
4546
}
4647

48+
var rotCmd = &cobra.Command{
49+
Use: "rot",
50+
Short: "Root of trust utility",
51+
Long: `Root of trust allows you to manage your trusted roots using Keyfactor certificate stores.`,
52+
//Run: func(cmd *cobra.Command, args []string) {
53+
// fmt.Println("stores called")
54+
//},
55+
}
56+
4757
// rotAuditCmd represents the rot command
4858
var rotAuditCmd = &cobra.Command{
49-
Use: "rot-audit",
59+
Use: "audit",
5060
Short: "Root Of Trust Audit",
5161
Long: `Root Of Trust Audit: Will read and parse inputs to generate a report of certs that need to be added or removed from the "root of trust" stores.`,
5262
Run: func(cmd *cobra.Command, args []string) {
@@ -70,15 +80,15 @@ var rotAuditCmd = &cobra.Command{
7080
if entry[0] == "StoreId" {
7181
continue // Skip header
7282
}
73-
apiResp, err := kfClient.GetCertificateStoreByID(entry[0])
83+
_, err := kfClient.GetCertificateStoreByID(entry[0])
7484
if err != nil {
7585
//log.Fatalf("Error getting cert store: %s", err)
7686
log.Printf("[ERROR] Error getting cert store: %s", err)
7787
lookupFailures = append(lookupFailures, strings.Join(entry, ","))
7888
continue
7989
}
8090

81-
log.Printf("[DEBUG] Store: %s", apiResp)
91+
//log.Printf("[DEBUG] Store: %s", apiResp)
8292
inventory, invErr := kfClient.GetCertStoreInventory(entry[0])
8393
if invErr != nil {
8494
log.Fatal("[ERROR] Error getting cert store inventory: %s", invErr)
@@ -94,8 +104,7 @@ var rotAuditCmd = &cobra.Command{
94104
}
95105

96106
}
97-
storesJson, _ := json.Marshal(stores)
98-
fmt.Println(string(storesJson))
107+
//storesJson, _ := json.Marshal(stores)
99108

100109
// Read in the add addCerts CSV
101110
var certsToAdd = make(map[string]string)
@@ -105,8 +114,8 @@ var rotAuditCmd = &cobra.Command{
105114
// log.Fatalf("Error reading addCerts file: %s", err)
106115
//}
107116
addCertsJson, _ := json.Marshal(certsToAdd)
108-
fmt.Printf("[DEBUG] add certs JSON: %s", string(addCertsJson))
109-
fmt.Println("add rot called")
117+
log.Printf("[DEBUG] add certs JSON: %s", string(addCertsJson))
118+
log.Println("[DEBUG] Add ROT called")
110119
} else {
111120
log.Printf("[DEBUG] No addCerts file specified")
112121
log.Printf("[DEBUG] No addCerts = %s", certsToAdd)
@@ -131,7 +140,7 @@ var rotAuditCmd = &cobra.Command{
131140
}
132141

133142
var rotReconcileCmd = &cobra.Command{
134-
Use: "rot-reconcile",
143+
Use: "reconcile",
135144
Short: "Root Of Trust",
136145
Long: `Root Of Trust: Will parse a CSV and attempt to enroll a cert or set of certs into a list of cert stores.`,
137146
Run: func(cmd *cobra.Command, args []string) {
@@ -166,7 +175,7 @@ var rotReconcileCmd = &cobra.Command{
166175
continue
167176
}
168177

169-
log.Printf("[DEBUG] Store: %s", apiResp)
178+
//log.Printf("[DEBUG] Store: %s", apiResp)
170179
inventory, invErr := kfClient.GetCertStoreInventory(entry[0])
171180
if invErr != nil {
172181
log.Fatal("[ERROR] Error getting cert store inventory: %s", invErr)
@@ -190,37 +199,23 @@ var rotReconcileCmd = &cobra.Command{
190199
}
191200

192201
}
193-
storesJson, _ := json.Marshal(stores)
194-
fmt.Println(string(storesJson))
195202

196203
// Read in the add addCerts CSV
197204
var certsToAdd = make(map[string]string)
198205
if addRootsFile != "" {
199206
certsToAdd, _ = readCertsFile(addRootsFile, kfClient)
200-
//if err != nil {
201-
// log.Fatalf("Error reading addCerts file: %s", err)
202-
//}
203-
addCertsJson, _ := json.Marshal(certsToAdd)
204-
fmt.Printf("[DEBUG] add certs JSON: %s", string(addCertsJson))
205-
fmt.Println("add rot called")
207+
log.Printf("[DEBUG] ROT add certs called")
206208
} else {
207209
log.Printf("[DEBUG] No addCerts file specified")
208-
log.Printf("[DEBUG] No addCerts = %s", certsToAdd)
209210
}
210211

211212
// Read in the remove removeCerts CSV
212213
var certsToRemove = make(map[string]string)
213214
if removeRootsFile != "" {
214215
certsToRemove, _ = readCertsFile(removeRootsFile, kfClient)
215-
//if err != nil {
216-
// log.Fatalf("Error reading removeCerts file: %s", err)
217-
//}
218-
removeCertsJson, _ := json.Marshal(certsToRemove)
219-
fmt.Println(string(removeCertsJson))
220-
fmt.Println("remove rot called")
216+
log.Printf("[DEBUG] ROT remove certs called")
221217
} else {
222218
log.Printf("[DEBUG] No removeCerts file specified")
223-
log.Printf("[DEBUG] No removeCerts = %s", certsToRemove)
224219
}
225220
_, actions, err := generateAuditReport(certsToAdd, certsToRemove, stores, kfClient)
226221
if err != nil {
@@ -231,12 +226,18 @@ var rotReconcileCmd = &cobra.Command{
231226
}
232227

233228
func reconcileRoots(actions map[string]RotAction, kfClient *api.Client, dryRun bool) {
229+
log.Printf("[DEBUG] Reconciling roots")
230+
if len(actions) == 0 {
231+
log.Printf("[INFO] No actions to take, roots are up-to-date.")
232+
return
233+
}
234234
for thumbprint, action := range actions {
235235
if action.Add {
236-
log.Printf("[INFO] Adding cert %s to store %s", thumbprint, action.StoreId)
236+
log.Printf("[INFO] Adding cert %s to store %s(%s)", thumbprint, action.StoreId, action.StorePath)
237237
if !dryRun {
238238
cStore := api.CertificateStore{
239239
CertificateStoreId: action.StoreId,
240+
Overwrite: true,
240241
}
241242
var stores []api.CertificateStore
242243
stores = append(stores, cStore)
@@ -252,10 +253,12 @@ func reconcileRoots(actions map[string]RotAction, kfClient *api.Client, dryRun b
252253
if err != nil {
253254
log.Fatalf("[ERROR] Error adding cert to store: %s", err)
254255
}
256+
} else {
257+
log.Printf("[INFO] DRY RUN: Would have added cert %s from store %s", thumbprint, action.StoreId)
255258
}
256259
} else if action.Remove {
257-
log.Printf("[INFO] Removing cert from store %s", action.StoreId)
258260
if !dryRun {
261+
log.Printf("[INFO] Removing cert from store %s", action.StoreId)
259262
cStore := api.CertificateStore{
260263
CertificateStoreId: action.StoreId,
261264
}
@@ -274,7 +277,10 @@ func reconcileRoots(actions map[string]RotAction, kfClient *api.Client, dryRun b
274277
if err != nil {
275278
log.Fatalf("[ERROR] Error removing cert from store: %s", err)
276279
}
280+
} else {
281+
log.Printf("[INFO] DRY RUN: Would have removed cert %s from store %s", thumbprint, action.StoreId)
277282
}
283+
278284
}
279285
}
280286
}
@@ -336,6 +342,7 @@ func generateAuditReport(addCerts map[string]string, removeCerts map[string]stri
336342
CertId: certId,
337343
StoreId: store.Id,
338344
StoreType: store.Type,
345+
StorePath: store.Path,
339346
Add: true,
340347
Remove: false,
341348
}
@@ -367,12 +374,12 @@ func generateAuditReport(addCerts map[string]string, removeCerts map[string]stri
367374
csvWriter.Flush()
368375
csvFile.Close()
369376

370-
log.Printf("[DEBUG] data: %s", data)
377+
//log.Printf("[DEBUG] data: %s", data)
371378
return data, actions, nil
372379
}
373380

374381
var rotGenStoreTemplateCmd = &cobra.Command{
375-
Use: "rot-generate-template",
382+
Use: "generate-template",
376383
Short: "For generating Root Of Trust template(s)",
377384
Long: `Root Of Trust: Will parse a CSV and attempt to enroll a cert or set of certs into a list of cert stores.`,
378385
Run: func(cmd *cobra.Command, args []string) {
@@ -452,34 +459,18 @@ func isRootStore(st *api.GetStoreByIDResp, inv *api.CertStoreInventory, minCerts
452459
return true
453460
}
454461

455-
func initClient() (*api.Client, error) {
456-
var clientAuth api.AuthConfig
457-
clientAuth.Username = os.Getenv("KEYFACTOR_USERNAME")
458-
log.Printf("[DEBUG] Username: %s", clientAuth.Username)
459-
clientAuth.Password = os.Getenv("KEYFACTOR_PASSWORD")
460-
log.Printf("[DEBUG] Password: %s", clientAuth.Password)
461-
clientAuth.Domain = os.Getenv("KEYFACTOR_DOMAIN")
462-
log.Printf("[DEBUG] Domain: %s", clientAuth.Domain)
463-
clientAuth.Hostname = os.Getenv("KEYFACTOR_HOSTNAME")
464-
log.Printf("[DEBUG] Hostname: %s", clientAuth.Hostname)
465-
466-
c, err := api.NewKeyfactorClient(&clientAuth)
467-
468-
if err != nil {
469-
log.Fatalf("Error creating Keyfactor client: %s", err)
470-
}
471-
return c, err
472-
}
473-
474462
func init() {
463+
log.SetFlags(log.LstdFlags | log.Lshortfile)
464+
log.SetOutput(os.Stdout)
475465
var stores string
476466
var addCerts string
477467
var removeCerts string
478468
var minCertsInStore int
479469
var maxPrivateKeys int
480470
var maxLeaves int
481471

482-
storesCmd.AddCommand(rotAuditCmd)
472+
storesCmd.AddCommand(rotCmd)
473+
rotCmd.AddCommand(rotAuditCmd)
483474
rotAuditCmd.Flags().StringVarP(&stores, "stores", "s", "", "CSV file containing cert stores to enroll into")
484475
rotAuditCmd.MarkFlagRequired("stores")
485476
rotAuditCmd.Flags().StringVarP(&addCerts, "add-certs", "a", "", "CSV file containing cert(s) to enroll into the defined cert stores")
@@ -490,7 +481,7 @@ func init() {
490481
rotAuditCmd.Flags().BoolP("dry-run", "d", false, "Dry run mode")
491482
rotAuditCmd.MarkFlagRequired("certs")
492483

493-
storesCmd.AddCommand(rotReconcileCmd)
484+
rotCmd.AddCommand(rotReconcileCmd)
494485
rotReconcileCmd.Flags().StringVarP(&stores, "stores", "s", "", "CSV file containing cert stores to enroll into")
495486
rotReconcileCmd.MarkFlagRequired("stores")
496487
rotReconcileCmd.Flags().StringVarP(&addCerts, "add-certs", "a", "", "CSV file containing cert(s) to enroll into the defined cert stores")
@@ -501,7 +492,7 @@ func init() {
501492
rotReconcileCmd.Flags().BoolP("dry-run", "d", false, "Dry run mode")
502493
rotReconcileCmd.MarkFlagRequired("certs")
503494

504-
storesCmd.AddCommand(rotGenStoreTemplateCmd)
495+
rotCmd.AddCommand(rotGenStoreTemplateCmd)
505496
rotGenStoreTemplateCmd.Flags().String("outpath", "", "Output file to write the template to")
506497
rotGenStoreTemplateCmd.Flags().String("format", "csv", "The type of template to generate. Only `csv` is supported at this time.")
507498
rotGenStoreTemplateCmd.Flags().String("type", "stores", "The type of template to generate. Only `certs|stores` are supported at this time.")

cmd/stores.go

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,68 @@ Copyright © 2022 NAME HERE <EMAIL ADDRESS>
55
package cmd
66

77
import (
8+
"encoding/json"
89
"fmt"
9-
1010
"github.com/spf13/cobra"
11+
"io/ioutil"
12+
"log"
1113
)
1214

1315
// storesCmd represents the stores command
1416
var storesCmd = &cobra.Command{
1517
Use: "stores",
16-
Short: "A brief description of your command",
17-
Long: `A longer description that spans multiple lines and likely contains examples
18-
and usage of using your command. For example:
18+
Short: "Keyfactor certificate stores APIs and utilities.",
19+
Long: `A collections of APIs and utilities for interacting with Keyfactor certificate stores.`,
20+
//Run: func(cmd *cobra.Command, args []string) {
21+
// fmt.Println("stores called")
22+
//},
23+
}
24+
25+
var storesListCmd = &cobra.Command{
26+
Use: "list",
27+
Short: "List certificate stores.",
28+
Long: `List certificate stores.`,
29+
Run: func(cmd *cobra.Command, args []string) {
30+
log.SetOutput(ioutil.Discard)
31+
kfClient, _ := initClient()
32+
stores, err := kfClient.ListCertificateStores()
33+
if err != nil {
34+
log.Printf("Error: %s", err)
35+
}
36+
output, jErr := json.Marshal(stores)
37+
if jErr != nil {
38+
log.Printf("Error: %s", jErr)
39+
}
40+
fmt.Printf("%s", output)
41+
},
42+
}
1943

20-
Cobra is a CLI library for Go that empowers applications.
21-
This application is a tool to generate the needed files
22-
to quickly create a Cobra application.`,
44+
var storesGetCmd = &cobra.Command{
45+
Use: "get",
46+
Short: "Get a certificate store by ID.",
47+
Long: `Get a certificate store by ID.`,
2348
Run: func(cmd *cobra.Command, args []string) {
24-
fmt.Println("stores called")
49+
log.SetOutput(ioutil.Discard) //todo: remove this and set it global
50+
storeId, _ := cmd.Flags().GetString("id")
51+
kfClient, _ := initClient()
52+
stores, err := kfClient.GetCertificateStoreByID(storeId)
53+
if err != nil {
54+
log.Printf("Error: %s", err)
55+
}
56+
output, jErr := json.Marshal(stores)
57+
if jErr != nil {
58+
log.Printf("Error: %s", jErr)
59+
}
60+
fmt.Printf("%s", output)
2561
},
2662
}
2763

2864
func init() {
65+
var storeId string
2966
rootCmd.AddCommand(storesCmd)
67+
storesCmd.AddCommand(storesListCmd)
68+
storesCmd.AddCommand(storesGetCmd)
69+
storesGetCmd.Flags().StringVarP(&storeId, "id", "i", "", "Id of the certificate store to get.")
3070

3171
// Here you will define your flags and configuration settings.
3272

0 commit comments

Comments
 (0)