From c6cab03f5ed59594fb1def75d9a88b1497ac9c69 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Thu, 19 Sep 2024 11:18:50 -0700 Subject: [PATCH 01/19] fix(pkg): Bump package version to v1.5.1 Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- CHANGELOG.md | 6 ++++++ pkg/version/version.go | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6243e17..fea864b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# v1.5.1 + +## Fixes + +- fix(pkg): Bump module version to `v1.5.1` to fix an issue with the `1.5.0` release. + # v1.5.0 ## Features diff --git a/pkg/version/version.go b/pkg/version/version.go index 354b351..f105ad9 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -14,4 +14,4 @@ package version -const VERSION = "1.4.0" +const VERSION = "1.5.1" From e68267df1edfdca6c8107585785049a02ddee1d7 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Wed, 23 Oct 2024 09:03:12 -0700 Subject: [PATCH 02/19] WIP Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- cmd/certificates.go | 11 +- cmd/containers.go | 4 +- cmd/export.go | 41 +- cmd/import.go | 130 +- cmd/inventory.go | 322 ++++- cmd/login.go | 337 ++--- cmd/root.go | 544 +++++--- cmd/rot.go | 2593 +++++++++++++++++++---------------- cmd/storeTypes.go | 2 +- cmd/storeTypes_get.go | 46 +- cmd/storesBulkOperations.go | 152 +- go.mod | 16 +- go.sum | 38 +- pkg/version/version.go | 2 +- 14 files changed, 2540 insertions(+), 1698 deletions(-) diff --git a/cmd/certificates.go b/cmd/certificates.go index 0384474..447b5d7 100644 --- a/cmd/certificates.go +++ b/cmd/certificates.go @@ -15,9 +15,10 @@ package cmd import ( "fmt" - "github.com/Keyfactor/keyfactor-go-client/v2/api" "log" + "github.com/Keyfactor/keyfactor-go-client/v3/api" + "github.com/spf13/cobra" ) @@ -61,5 +62,11 @@ func certToString(response *api.GetCertificateResponse) string { if len(sansString) > 0 { sansString = sansString[:len(sansString)-1] } - return fmt.Sprintf("DN=(%s),SANs=(%s),TP=(%s),ID=(%d)", response.IssuedDN, sansString, response.Thumbprint, response.Id) + return fmt.Sprintf( + "DN=(%s),SANs=(%s),TP=(%s),ID=(%d)", + response.IssuedDN, + sansString, + response.Thumbprint, + response.Id, + ) } diff --git a/cmd/containers.go b/cmd/containers.go index 2b29dfe..fe8698f 100644 --- a/cmd/containers.go +++ b/cmd/containers.go @@ -60,9 +60,7 @@ var containersGetCmd = &cobra.Command{ return debugErr } - // Authenticate - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) - kfClient, _ := initClient(configFile, profile, providerType, providerProfile, noPrompt, authConfig, false) + kfClient, _ := initClient(configFile, profile, providerType, providerProfile, noPrompt, false) agents, aErr := kfClient.GetStoreContainer(id) if aErr != nil { diff --git a/cmd/export.go b/cmd/export.go index 07d0431..909589b 100644 --- a/cmd/export.go +++ b/cmd/export.go @@ -18,12 +18,13 @@ import ( "context" "encoding/json" "fmt" + "os" + "strconv" + "github.com/Keyfactor/keyfactor-go-client-sdk/api/keyfactor" - "github.com/Keyfactor/keyfactor-go-client/v2/api" + "github.com/Keyfactor/keyfactor-go-client/v3/api" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - "os" - "strconv" ) var exportPath string @@ -137,7 +138,17 @@ var exportCmd = &cobra.Command{ } log.Debug().Msgf("%s: createAuthConfigFromParams", DebugFuncCall) - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) + //authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) + authConfig := createAuthConfigFromParams( + kfcHostName, + kfcUsername, + kfcPassword, + kfcDomain, + kfcAPIPath, + kfcClientId, + kfcClientSecret, + kfcTokenUrl, + ) if authConfig == nil { log.Error().Msg("auth config is nil, invalid client configuration") @@ -371,8 +382,10 @@ func getIssuedAlerts(kfClient *keyfactor.APIClient) []keyfactor.KeyfactorApiMode func getDeniedAlerts(kfClient *keyfactor.APIClient) []keyfactor.KeyfactorApiModelsAlertsDeniedDeniedAlertCreationRequest { alerts, _, reqErr := kfClient.DeniedAlertApi.DeniedAlertGetDeniedAlerts( - context.Background()).XKeyfactorRequestedWith( - XKeyfactorRequestedWith).XKeyfactorApiVersion(XKeyfactorApiVersion).Execute() + context.Background(), + ).XKeyfactorRequestedWith( + XKeyfactorRequestedWith, + ).XKeyfactorApiVersion(XKeyfactorApiVersion).Execute() if reqErr != nil { fmt.Printf("%s Error! Unable to get denied cert alerts %s%s\n", ColorRed, reqErr, ColorWhite) } @@ -575,7 +588,13 @@ func init() { exportCmd.Flags().Lookup("collections").NoOptDefVal = "true" exportCmd.Flags().BoolVarP(&fMetadata, "metadata", "m", false, "export metadata to JSON file") exportCmd.Flags().Lookup("metadata").NoOptDefVal = "true" - exportCmd.Flags().BoolVarP(&fExpirationAlerts, "expiration-alerts", "e", false, "export expiration cert alerts to JSON file") + exportCmd.Flags().BoolVarP( + &fExpirationAlerts, + "expiration-alerts", + "e", + false, + "export expiration cert alerts to JSON file", + ) exportCmd.Flags().Lookup("expiration-alerts").NoOptDefVal = "true" exportCmd.Flags().BoolVarP(&fIssuedAlerts, "issued-alerts", "i", false, "export issued cert alerts to JSON file") exportCmd.Flags().Lookup("issued-alerts").NoOptDefVal = "true" @@ -585,7 +604,13 @@ func init() { exportCmd.Flags().Lookup("pending-alerts").NoOptDefVal = "true" exportCmd.Flags().BoolVarP(&fNetworks, "networks", "n", false, "export SSL networks to JSON file") exportCmd.Flags().Lookup("networks").NoOptDefVal = "true" - exportCmd.Flags().BoolVarP(&fWorkflowDefinitions, "workflow-definitions", "w", false, "export workflow definitions to JSON file") + exportCmd.Flags().BoolVarP( + &fWorkflowDefinitions, + "workflow-definitions", + "w", + false, + "export workflow definitions to JSON file", + ) exportCmd.Flags().Lookup("workflow-definitions").NoOptDefVal = "true" exportCmd.Flags().BoolVarP(&fReports, "reports", "r", false, "export reports to JSON file") exportCmd.Flags().Lookup("reports").NoOptDefVal = "true" diff --git a/cmd/import.go b/cmd/import.go index 5004a2e..0432306 100644 --- a/cmd/import.go +++ b/cmd/import.go @@ -18,12 +18,13 @@ import ( "context" "encoding/json" "fmt" + "io" + "os" + "github.com/Keyfactor/keyfactor-go-client-sdk/api/keyfactor" - "github.com/Keyfactor/keyfactor-go-client/v2/api" + "github.com/Keyfactor/keyfactor-go-client/v3/api" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - "io" - "os" ) type Body struct { @@ -194,7 +195,10 @@ var importCmd = &cobra.Command{ }, } -func importCollections(collections []keyfactor.KeyfactorApiModelsCertificateCollectionsCertificateCollectionCreateRequest, kfClient *keyfactor.APIClient) { +func importCollections( + collections []keyfactor.KeyfactorApiModelsCertificateCollectionsCertificateCollectionCreateRequest, + kfClient *keyfactor.APIClient, +) { for _, collection := range collections { _, httpResp, reqErr := kfClient.CertificateCollectionApi. CertificateCollectionCreateCollection(context.Background()). @@ -209,7 +213,13 @@ func importCollections(collections []keyfactor.KeyfactorApiModelsCertificateColl log.Error().Err(jmErr).Send() } if reqErr != nil { - fmt.Printf("%s Error! Unable to create collection %s - %s%s\n", ColorRed, string(name), parseError(httpResp.Body), ColorWhite) + fmt.Printf( + "%s Error! Unable to create collection %s - %s%s\n", + ColorRed, + string(name), + parseError(httpResp.Body), + ColorWhite, + ) } else { n, jnErr := json.Marshal(collection.Name) if jnErr != nil { @@ -222,7 +232,10 @@ func importCollections(collections []keyfactor.KeyfactorApiModelsCertificateColl } } -func importMetadataFields(metadataFields []keyfactor.KeyfactorApiModelsMetadataFieldMetadataFieldCreateRequest, kfClient *keyfactor.APIClient) { +func importMetadataFields( + metadataFields []keyfactor.KeyfactorApiModelsMetadataFieldMetadataFieldCreateRequest, + kfClient *keyfactor.APIClient, +) { for _, metadata := range metadataFields { _, httpResp, reqErr := kfClient.MetadataFieldApi.MetadataFieldCreateMetadataField(context.Background()). XKeyfactorRequestedWith(XKeyfactorRequestedWith). @@ -238,7 +251,13 @@ func importMetadataFields(metadataFields []keyfactor.KeyfactorApiModelsMetadataF log.Error().Err(jmErr).Send() } log.Error().Err(reqErr).Send() - fmt.Printf("%s Error! Unable to create metadata field type %s - %s%s\n", ColorRed, string(n), parseError(httpResp.Body), ColorWhite) + fmt.Printf( + "%s Error! Unable to create metadata field type %s - %s%s\n", + ColorRed, + string(n), + parseError(httpResp.Body), + ColorWhite, + ) } else { log.Info().Msgf("Added %s to metadata field types.", string(n)) fmt.Println("Added", string(n), "to metadata field types.") @@ -246,36 +265,63 @@ func importMetadataFields(metadataFields []keyfactor.KeyfactorApiModelsMetadataF } } -func importIssuedCertAlerts(alerts []keyfactor.KeyfactorApiModelsAlertsIssuedIssuedAlertCreationRequest, kfClient *keyfactor.APIClient) { +func importIssuedCertAlerts( + alerts []keyfactor.KeyfactorApiModelsAlertsIssuedIssuedAlertCreationRequest, + kfClient *keyfactor.APIClient, +) { for _, alert := range alerts { _, httpResp, reqErr := kfClient.IssuedAlertApi.IssuedAlertAddIssuedAlert(context.Background()).XKeyfactorRequestedWith(XKeyfactorRequestedWith).Req(alert).XKeyfactorApiVersion(XKeyfactorApiVersion).Execute() name, _ := json.Marshal(alert.DisplayName) if reqErr != nil { - fmt.Printf("%s Error! Unable to create issued cert alert %s - %s%s\n", ColorRed, string(name), parseError(httpResp.Body), ColorWhite) + fmt.Printf( + "%s Error! Unable to create issued cert alert %s - %s%s\n", + ColorRed, + string(name), + parseError(httpResp.Body), + ColorWhite, + ) } else { fmt.Println("Added", string(name), "to issued cert alerts.") } } } -func importDeniedCertAlerts(alerts []keyfactor.KeyfactorApiModelsAlertsDeniedDeniedAlertCreationRequest, kfClient *keyfactor.APIClient) { +func importDeniedCertAlerts( + alerts []keyfactor.KeyfactorApiModelsAlertsDeniedDeniedAlertCreationRequest, + kfClient *keyfactor.APIClient, +) { for _, alert := range alerts { _, httpResp, reqErr := kfClient.DeniedAlertApi.DeniedAlertAddDeniedAlert(context.Background()).XKeyfactorRequestedWith(XKeyfactorRequestedWith).Req(alert).XKeyfactorApiVersion(XKeyfactorApiVersion).Execute() name, _ := json.Marshal(alert.DisplayName) if reqErr != nil { - fmt.Printf("%s Error! Unable to create denied cert alert %s - %s%s\n", ColorRed, string(name), parseError(httpResp.Body), ColorWhite) + fmt.Printf( + "%s Error! Unable to create denied cert alert %s - %s%s\n", + ColorRed, + string(name), + parseError(httpResp.Body), + ColorWhite, + ) } else { fmt.Println("Added", string(name), "to denied cert alerts.") } } } -func importPendingCertAlerts(alerts []keyfactor.KeyfactorApiModelsAlertsPendingPendingAlertCreationRequest, kfClient *keyfactor.APIClient) { +func importPendingCertAlerts( + alerts []keyfactor.KeyfactorApiModelsAlertsPendingPendingAlertCreationRequest, + kfClient *keyfactor.APIClient, +) { for _, alert := range alerts { _, httpResp, reqErr := kfClient.PendingAlertApi.PendingAlertAddPendingAlert(context.Background()).XKeyfactorRequestedWith(XKeyfactorRequestedWith).Req(alert).XKeyfactorApiVersion(XKeyfactorApiVersion).Execute() name, _ := json.Marshal(alert.DisplayName) if reqErr != nil { - fmt.Printf("%s Error! Unable to create pending cert alert %s - %s%s\n", ColorRed, string(name), parseError(httpResp.Body), ColorWhite) + fmt.Printf( + "%s Error! Unable to create pending cert alert %s - %s%s\n", + ColorRed, + string(name), + parseError(httpResp.Body), + ColorWhite, + ) } else { fmt.Println("Added", string(name), "to pending cert alerts.") } @@ -287,7 +333,13 @@ func importNetworks(networks []keyfactor.KeyfactorApiModelsSslCreateNetworkReque _, httpResp, reqErr := kfClient.SslApi.SslCreateNetwork(context.Background()).XKeyfactorRequestedWith(XKeyfactorRequestedWith).Network(network).XKeyfactorApiVersion(XKeyfactorApiVersion).Execute() name, _ := json.Marshal(network.Name) if reqErr != nil { - fmt.Printf("%s Error! Unable to create SSL network %s - %s%s\n", ColorRed, string(name), parseError(httpResp.Body), ColorWhite) + fmt.Printf( + "%s Error! Unable to create SSL network %s - %s%s\n", + ColorRed, + string(name), + parseError(httpResp.Body), + ColorWhite, + ) } else { fmt.Println("Added", string(name), "to SSL networks.") } @@ -295,7 +347,10 @@ func importNetworks(networks []keyfactor.KeyfactorApiModelsSslCreateNetworkReque } // identify matching templates between instances by name, then return the template Id of the matching template in the import instance -func findMatchingTemplates(exportedWorkflowDef exportKeyfactorAPIModelsWorkflowsDefinitionCreateRequest, kfClient *keyfactor.APIClient) *string { +func findMatchingTemplates( + exportedWorkflowDef exportKeyfactorAPIModelsWorkflowsDefinitionCreateRequest, + kfClient *keyfactor.APIClient, +) *string { importInstanceTemplates, _, _ := kfClient.TemplateApi.TemplateGetTemplates(context.Background()).XKeyfactorRequestedWith(XKeyfactorRequestedWith).XKeyfactorApiVersion(XKeyfactorApiVersion).Execute() for _, template := range importInstanceTemplates { importInstTempNameJson, _ := json.Marshal(template.TemplateName) @@ -309,7 +364,10 @@ func findMatchingTemplates(exportedWorkflowDef exportKeyfactorAPIModelsWorkflows return nil } -func importWorkflowDefinitions(workflowDefs []exportKeyfactorAPIModelsWorkflowsDefinitionCreateRequest, kfClient *keyfactor.APIClient) { +func importWorkflowDefinitions( + workflowDefs []exportKeyfactorAPIModelsWorkflowsDefinitionCreateRequest, + kfClient *keyfactor.APIClient, +) { for _, workflowDef := range workflowDefs { wJson, _ := json.Marshal(workflowDef) var workflowDefReq keyfactor.KeyfactorApiModelsWorkflowsDefinitionCreateRequest @@ -338,7 +396,13 @@ func importWorkflowDefinitions(workflowDefs []exportKeyfactorAPIModelsWorkflowsD } if reqErr != nil { - fmt.Printf("%s Error! Unable to create workflow definition %s - %s%s\n", ColorRed, string(name), parseError(httpResp.Body), ColorWhite) + fmt.Printf( + "%s Error! Unable to create workflow definition %s - %s%s\n", + ColorRed, + string(name), + parseError(httpResp.Body), + ColorWhite, + ) log.Error().Err(reqErr).Send() } else { fmt.Println("Added", string(name), "to workflow definitions.") @@ -401,7 +465,13 @@ func importBuiltInReports(reports []exportModelsReport, kfClient *keyfactor.APIC return } if reqErr != nil { - fmt.Printf("%s Error! Unable to update built-in report %s - %s%s\n", ColorRed, string(name), parseError(httpResp.Body), ColorWhite) + fmt.Printf( + "%s Error! Unable to update built-in report %s - %s%s\n", + ColorRed, + string(name), + parseError(httpResp.Body), + ColorWhite, + ) log.Error().Err(reqErr).Send() } else { fmt.Println("Updated", string(name), "in built-in reports.") @@ -416,7 +486,13 @@ func importCustomReports(reports []keyfactor.ModelsCustomReportCreationRequest, _, httpResp, reqErr := kfClient.ReportsApi.ReportsCreateCustomReport(context.Background()).XKeyfactorRequestedWith(XKeyfactorRequestedWith).Request(report).XKeyfactorApiVersion(XKeyfactorApiVersion).Execute() name, _ := json.Marshal(report.DisplayName) if reqErr != nil { - fmt.Printf("%s Error! Unable to create custom report %s - %s%s\n", ColorRed, string(name), parseError(httpResp.Body), ColorWhite) + fmt.Printf( + "%s Error! Unable to create custom report %s - %s%s\n", + ColorRed, + string(name), + parseError(httpResp.Body), + ColorWhite, + ) } else { fmt.Println("Added", string(name), "to custom reports.") } @@ -428,7 +504,13 @@ func importSecurityRoles(roles []api.CreateSecurityRoleArg, kfClient *api.Client _, reqErr := kfClient.CreateSecurityRole(&role) name, _ := json.Marshal(role.Name) if reqErr != nil { - fmt.Printf("%s Error! Unable to create security role %s - %s%s\n", ColorRed, string(name), reqErr, ColorWhite) + fmt.Printf( + "%s Error! Unable to create security role %s - %s%s\n", + ColorRed, + string(name), + reqErr, + ColorWhite, + ) } else { fmt.Println("Added", string(name), "to security roles.") } @@ -456,7 +538,13 @@ func init() { importCmd.Flags().Lookup("pending-alerts").NoOptDefVal = "true" importCmd.Flags().BoolVarP(&fNetworks, "networks", "n", false, "import SSL networks to JSON file") importCmd.Flags().Lookup("networks").NoOptDefVal = "true" - importCmd.Flags().BoolVarP(&fWorkflowDefinitions, "workflow-definitions", "w", false, "import workflow definitions to JSON file") + importCmd.Flags().BoolVarP( + &fWorkflowDefinitions, + "workflow-definitions", + "w", + false, + "import workflow definitions to JSON file", + ) importCmd.Flags().Lookup("workflow-definitions").NoOptDefVal = "true" importCmd.Flags().BoolVarP(&fReports, "reports", "r", false, "import reports to JSON file") importCmd.Flags().Lookup("reports").NoOptDefVal = "true" diff --git a/cmd/inventory.go b/cmd/inventory.go index 0b004ec..92ab084 100644 --- a/cmd/inventory.go +++ b/cmd/inventory.go @@ -17,9 +17,10 @@ package cmd import ( "encoding/json" "fmt" - "github.com/Keyfactor/keyfactor-go-client/v2/api" - "github.com/spf13/cobra" "log" + + "github.com/Keyfactor/keyfactor-go-client/v3/api" + "github.com/spf13/cobra" ) // inventoryCmd represents the inventory command @@ -133,7 +134,11 @@ var inventoryClearCmd = &cobra.Command{ } if !force { - fmt.Printf("This will clear the inventory of ALL certificates in the store %s:%s. Are you sure you sure?! Press 'y' to continue? (y/n) ", store.ClientMachine, store.StorePath) + fmt.Printf( + "This will clear the inventory of ALL certificates in the store %s:%s. Are you sure you sure?! Press 'y' to continue? (y/n) ", + store.ClientMachine, + store.StorePath, + ) var answer string fmt.Scanln(&answer) if answer != "y" { @@ -145,7 +150,8 @@ var inventoryClearCmd = &cobra.Command{ for _, inv := range *sInvs { certs := inv.Certificates for _, cert := range certs { - st := api.CertificateStore{ //TODO: This conversion is a bit weird to have to do. Should be able to pass the store directly. + st := api.CertificateStore{ + //TODO: This conversion is a bit weird to have to do. Should be able to pass the store directly. CertificateStoreId: store.Id, Alias: cert.Thumbprint, Overwrite: true, @@ -163,12 +169,23 @@ var inventoryClearCmd = &cobra.Command{ if !dryRun { _, err := kfClient.RemoveCertificateFromStores(&removeReq) if err != nil { - fmt.Printf("Error removing certificate %s(%d) from store %s: %s\n", cert.IssuedDN, cert.Id, st.CertificateStoreId, err) + fmt.Printf( + "Error removing certificate %s(%d) from store %s: %s\n", + cert.IssuedDN, + cert.Id, + st.CertificateStoreId, + err, + ) log.Printf("[ERROR] %s", err) continue } } else { - fmt.Printf("Dry run: Would have removed certificate %s(%d) from store %s\n", cert.IssuedDN, cert.Id, st.CertificateStoreId) + fmt.Printf( + "Dry run: Would have removed certificate %s(%d) from store %s\n", + cert.IssuedDN, + cert.Id, + st.CertificateStoreId, + ) } } @@ -264,9 +281,11 @@ attempt to add all the certificate(s) meeting the specified criteria to all stor var filteredCerts []api.GetCertificateResponse for _, cn := range subjects { - cert, err := kfClient.ListCertificates(map[string]string{ - "subject": cn, - }) + cert, err := kfClient.ListCertificates( + map[string]string{ + "subject": cn, + }, + ) if err != nil { fmt.Printf("Unable to find certificate with subject: %s\n", cn) continue @@ -274,9 +293,11 @@ attempt to add all the certificate(s) meeting the specified criteria to all stor filteredCerts = append(filteredCerts, cert...) } for _, thumbprint := range thumbprints { - cert, err := kfClient.ListCertificates(map[string]string{ - "thumbprint": thumbprint, - }) + cert, err := kfClient.ListCertificates( + map[string]string{ + "thumbprint": thumbprint, + }, + ) if err != nil { fmt.Printf("Unable to find certificate with thumbprint: %s\n", thumbprint) continue @@ -284,9 +305,11 @@ attempt to add all the certificate(s) meeting the specified criteria to all stor filteredCerts = append(filteredCerts, cert...) } for _, certID := range certIDs { - cert, err := kfClient.ListCertificates(map[string]string{ - "id": certID, - }) + cert, err := kfClient.ListCertificates( + map[string]string{ + "id": certID, + }, + ) if err != nil { fmt.Printf("Unable to find certificate with ID: %s\n", certID) continue @@ -323,7 +346,8 @@ attempt to add all the certificate(s) meeting the specified criteria to all stor Immediate: boolToPointer(true), } for _, cert := range filteredCerts { - st := api.CertificateStore{ //TODO: This conversion is weird. Should be able to use the store directly. + st := api.CertificateStore{ + //TODO: This conversion is weird. Should be able to use the store directly. CertificateStoreId: store.Id, Alias: cert.Thumbprint, Overwrite: true, @@ -340,7 +364,13 @@ attempt to add all the certificate(s) meeting the specified criteria to all stor } if !dryRun { if !force { - fmt.Printf("This will add the certificate %s(%d) to certificate store %s%s's inventory. Are you sure you shouldPass to continue? (y/n) ", cert.IssuedCN, cert.Id, store.ClientMachine, store.StorePath) + fmt.Printf( + "This will add the certificate %s(%d) to certificate store %s%s's inventory. Are you sure you shouldPass to continue? (y/n) ", + cert.IssuedCN, + cert.Id, + store.ClientMachine, + store.StorePath, + ) var answer string fmt.Scanln(&answer) if answer != "y" { @@ -350,12 +380,23 @@ attempt to add all the certificate(s) meeting the specified criteria to all stor } _, err := kfClient.AddCertificateToStores(&addReq) if err != nil { - fmt.Printf("Error adding certificate %s(%d) to store %s: %s\n", cert.IssuedCN, cert.Id, st.CertificateStoreId, err) + fmt.Printf( + "Error adding certificate %s(%d) to store %s: %s\n", + cert.IssuedCN, + cert.Id, + st.CertificateStoreId, + err, + ) log.Printf("[ERROR] %s", err) continue } } else { - fmt.Printf("Dry run: Would have added certificate %s(%d) from store %s", cert.IssuedDN, cert.Id, st.CertificateStoreId) + fmt.Printf( + "Dry run: Would have added certificate %s(%d) from store %s", + cert.IssuedDN, + cert.Id, + st.CertificateStoreId, + ) } } @@ -430,9 +471,11 @@ var inventoryRemoveCmd = &cobra.Command{ var filteredCerts []api.GetCertificateResponse for _, cn := range subjects { - cert, err := kfClient.ListCertificates(map[string]string{ - "subject": cn, - }) + cert, err := kfClient.ListCertificates( + map[string]string{ + "subject": cn, + }, + ) if err != nil { fmt.Printf("Unable to find certificate with subject: %s\n", cn) continue @@ -440,9 +483,11 @@ var inventoryRemoveCmd = &cobra.Command{ filteredCerts = append(filteredCerts, cert...) } for _, thumbprint := range thumbprints { - cert, err := kfClient.ListCertificates(map[string]string{ - "thumbprint": thumbprint, - }) + cert, err := kfClient.ListCertificates( + map[string]string{ + "thumbprint": thumbprint, + }, + ) if err != nil { fmt.Printf("Unable to find certificate with thumbprint: %s\n", thumbprint) continue @@ -450,9 +495,11 @@ var inventoryRemoveCmd = &cobra.Command{ filteredCerts = append(filteredCerts, cert...) } for _, certID := range certIDs { - cert, err := kfClient.ListCertificates(map[string]string{ - "id": certID, - }) + cert, err := kfClient.ListCertificates( + map[string]string{ + "id": certID, + }, + ) if err != nil { fmt.Printf("Unable to find certificate with ID: %s\n", certID) continue @@ -490,7 +537,8 @@ var inventoryRemoveCmd = &cobra.Command{ Immediate: boolToPointer(true), } for _, cert := range filteredCerts { - st := api.CertificateStore{ //TODO: This conversion is weird. Should be able to use the store directly. + st := api.CertificateStore{ + //TODO: This conversion is weird. Should be able to use the store directly. CertificateStoreId: store.Id, Alias: cert.Thumbprint, Overwrite: true, @@ -507,7 +555,12 @@ var inventoryRemoveCmd = &cobra.Command{ } if !dryRun { if !force { - fmt.Printf("This will remove the certificate %s from certificate store %s%s's inventory. Are you sure you shouldPass to continue? (y/n) ", certToString(&cert), store.ClientMachine, store.StorePath) + fmt.Printf( + "This will remove the certificate %s from certificate store %s%s's inventory. Are you sure you shouldPass to continue? (y/n) ", + certToString(&cert), + store.ClientMachine, + store.StorePath, + ) var answer string fmt.Scanln(&answer) if answer != "y" { @@ -517,12 +570,21 @@ var inventoryRemoveCmd = &cobra.Command{ } _, err := kfClient.RemoveCertificateFromStores(&removeReq) if err != nil { - fmt.Printf("Error removing certificate %s to store %s: %s\n", certToString(&cert), st.CertificateStoreId, err) + fmt.Printf( + "Error removing certificate %s to store %s: %s\n", + certToString(&cert), + st.CertificateStoreId, + err, + ) log.Printf("[ERROR] %s", err) continue } } else { - fmt.Printf("Dry run: Would have removed certificate %s from store %s\n", certToString(&cert), st.CertificateStoreId) + fmt.Printf( + "Dry run: Would have removed certificate %s from store %s\n", + certToString(&cert), + st.CertificateStoreId, + ) } } @@ -669,42 +731,182 @@ func init() { storesCmd.AddCommand(inventoryCmd) inventoryCmd.AddCommand(inventoryClearCmd) - inventoryClearCmd.Flags().StringSliceVar(&ids, "sid", []string{}, "The Keyfactor Command ID of the certificate store(s) remove all inventory from.") - inventoryClearCmd.Flags().StringSliceVar(&clients, "client", []string{}, "Remove all inventory from store(s) of specific client machine(s).") - inventoryClearCmd.Flags().StringSliceVar(&types, "store-type", []string{}, "Remove all inventory from store(s) of specific store type(s).") - inventoryClearCmd.Flags().StringSliceVar(&containers, "container", []string{}, "Remove all inventory from store(s) of specific container type(s).") + inventoryClearCmd.Flags().StringSliceVar( + &ids, + "sid", + []string{}, + "The Keyfactor Command ID of the certificate store(s) remove all inventory from.", + ) + inventoryClearCmd.Flags().StringSliceVar( + &clients, + "client", + []string{}, + "Remove all inventory from store(s) of specific client machine(s).", + ) + inventoryClearCmd.Flags().StringSliceVar( + &types, + "store-type", + []string{}, + "Remove all inventory from store(s) of specific store type(s).", + ) + inventoryClearCmd.Flags().StringSliceVar( + &containers, + "container", + []string{}, + "Remove all inventory from store(s) of specific container type(s).", + ) inventoryClearCmd.Flags().BoolVar(&all, "all", false, "Remove all inventory from all certificate stores.") - inventoryClearCmd.Flags().BoolVar(&force, "force", false, "Force removal of inventory without prompting for confirmation.") - inventoryClearCmd.Flags().BoolVar(&dryRun, "dry-run", false, "Do not remove inventory, only show what would be removed.") + inventoryClearCmd.Flags().BoolVar( + &force, + "force", + false, + "Force removal of inventory without prompting for confirmation.", + ) + inventoryClearCmd.Flags().BoolVar( + &dryRun, + "dry-run", + false, + "Do not remove inventory, only show what would be removed.", + ) inventoryCmd.AddCommand(inventoryAddCmd) - inventoryAddCmd.Flags().StringSliceVar(&ids, "sid", []string{}, "The Keyfactor Command ID of the certificate store(s) to add inventory to.") - inventoryAddCmd.Flags().StringSliceVar(&clients, "client", []string{}, "Add a certificate to all stores of specific client machine(s).") - inventoryAddCmd.Flags().StringSliceVar(&types, "store-type", []string{}, "Add a certificate to all stores of specific store type(s).") - inventoryAddCmd.Flags().StringSliceVar(&containers, "container", []string{}, "Add a certificate to all stores of specific container type(s).") - inventoryAddCmd.Flags().StringSliceVar(&thumbprints, "thumbprint", []string{}, "The thumbprint of the certificate(s) to add to the store(s).") - inventoryAddCmd.Flags().StringSliceVar(&cIDs, "cid", []string{}, "The Keyfactor command certificate ID(s) of the certificate to add to the store(s).") - inventoryAddCmd.Flags().StringSliceVar(&subjectNames, "cn", []string{}, "Subject name(s) of the certificate(s) to add to the store(s).") + inventoryAddCmd.Flags().StringSliceVar( + &ids, + "sid", + []string{}, + "The Keyfactor Command ID of the certificate store(s) to add inventory to.", + ) + inventoryAddCmd.Flags().StringSliceVar( + &clients, + "client", + []string{}, + "Add a certificate to all stores of specific client machine(s).", + ) + inventoryAddCmd.Flags().StringSliceVar( + &types, + "store-type", + []string{}, + "Add a certificate to all stores of specific store type(s).", + ) + inventoryAddCmd.Flags().StringSliceVar( + &containers, + "container", + []string{}, + "Add a certificate to all stores of specific container type(s).", + ) + inventoryAddCmd.Flags().StringSliceVar( + &thumbprints, + "thumbprint", + []string{}, + "The thumbprint of the certificate(s) to add to the store(s).", + ) + inventoryAddCmd.Flags().StringSliceVar( + &cIDs, + "cid", + []string{}, + "The Keyfactor command certificate ID(s) of the certificate to add to the store(s).", + ) + inventoryAddCmd.Flags().StringSliceVar( + &subjectNames, + "cn", + []string{}, + "Subject name(s) of the certificate(s) to add to the store(s).", + ) inventoryAddCmd.Flags().BoolVar(&all, "all-stores", false, "Add the certificate(s) to all certificate stores.") - inventoryAddCmd.Flags().BoolVar(&force, "force", false, "Force addition of inventory without prompting for confirmation.") + inventoryAddCmd.Flags().BoolVar( + &force, + "force", + false, + "Force addition of inventory without prompting for confirmation.", + ) inventoryAddCmd.Flags().BoolVar(&dryRun, "dry-run", false, "Do not add inventory, only show what would be added.") inventoryCmd.AddCommand(inventoryRemoveCmd) - inventoryRemoveCmd.Flags().StringSliceVar(&ids, "sid", []string{}, "The Keyfactor Command ID of the certificate store(s) to remove inventory from.") - inventoryRemoveCmd.Flags().StringSliceVar(&clients, "client", []string{}, "Remove certificate(s) from all stores of specific client machine(s).") - inventoryRemoveCmd.Flags().StringSliceVar(&types, "store-type", []string{}, "Remove certificate(s) from all stores of specific store type(s).") - inventoryRemoveCmd.Flags().StringSliceVar(&containers, "container", []string{}, "Remove certificate(s) from all stores of specific container type(s).") - inventoryRemoveCmd.Flags().StringSliceVar(&thumbprints, "thumbprint", []string{}, "The thumbprint of the certificate(s) to remove from the store(s).") - inventoryRemoveCmd.Flags().StringSliceVar(&cIDs, "cid", []string{}, "The Keyfactor command certificate ID(s) of the certificate to remove from the store(s).") - inventoryRemoveCmd.Flags().StringSliceVar(&subjectNames, "cn", []string{}, "Subject name(s) of the certificate(s) to remove from the store(s).") - inventoryRemoveCmd.Flags().BoolVar(&all, "all-stores", false, "Remove the certificate(s) from all certificate stores.") - inventoryRemoveCmd.Flags().BoolVar(&force, "force", false, "Force removal of inventory without prompting for confirmation.") - inventoryRemoveCmd.Flags().BoolVar(&dryRun, "dry-run", false, "Do not remove inventory, only show what would be removed.") + inventoryRemoveCmd.Flags().StringSliceVar( + &ids, + "sid", + []string{}, + "The Keyfactor Command ID of the certificate store(s) to remove inventory from.", + ) + inventoryRemoveCmd.Flags().StringSliceVar( + &clients, + "client", + []string{}, + "Remove certificate(s) from all stores of specific client machine(s).", + ) + inventoryRemoveCmd.Flags().StringSliceVar( + &types, + "store-type", + []string{}, + "Remove certificate(s) from all stores of specific store type(s).", + ) + inventoryRemoveCmd.Flags().StringSliceVar( + &containers, + "container", + []string{}, + "Remove certificate(s) from all stores of specific container type(s).", + ) + inventoryRemoveCmd.Flags().StringSliceVar( + &thumbprints, + "thumbprint", + []string{}, + "The thumbprint of the certificate(s) to remove from the store(s).", + ) + inventoryRemoveCmd.Flags().StringSliceVar( + &cIDs, + "cid", + []string{}, + "The Keyfactor command certificate ID(s) of the certificate to remove from the store(s).", + ) + inventoryRemoveCmd.Flags().StringSliceVar( + &subjectNames, + "cn", + []string{}, + "Subject name(s) of the certificate(s) to remove from the store(s).", + ) + inventoryRemoveCmd.Flags().BoolVar( + &all, + "all-stores", + false, + "Remove the certificate(s) from all certificate stores.", + ) + inventoryRemoveCmd.Flags().BoolVar( + &force, + "force", + false, + "Force removal of inventory without prompting for confirmation.", + ) + inventoryRemoveCmd.Flags().BoolVar( + &dryRun, + "dry-run", + false, + "Do not remove inventory, only show what would be removed.", + ) inventoryCmd.AddCommand(inventoryShowCmd) - inventoryShowCmd.Flags().StringSliceVar(&ids, "sid", []string{}, "The Keyfactor Command ID of the certificate store(s) to retrieve inventory from.") - inventoryShowCmd.Flags().StringSliceVar(&clients, "client", []string{}, "Show certificate inventories for stores of specific client machine(s).") - inventoryShowCmd.Flags().StringSliceVar(&types, "store-type", []string{}, "Show certificate inventories for stores of specific store type(s).") - inventoryShowCmd.Flags().StringSliceVar(&containers, "container", []string{}, "Show certificate inventories for stores of specific container type(s).") + inventoryShowCmd.Flags().StringSliceVar( + &ids, + "sid", + []string{}, + "The Keyfactor Command ID of the certificate store(s) to retrieve inventory from.", + ) + inventoryShowCmd.Flags().StringSliceVar( + &clients, + "client", + []string{}, + "Show certificate inventories for stores of specific client machine(s).", + ) + inventoryShowCmd.Flags().StringSliceVar( + &types, + "store-type", + []string{}, + "Show certificate inventories for stores of specific store type(s).", + ) + inventoryShowCmd.Flags().StringSliceVar( + &containers, + "container", + []string{}, + "Show certificate inventories for stores of specific container type(s).", + ) } diff --git a/cmd/login.go b/cmd/login.go index 527c786..3814906 100644 --- a/cmd/login.go +++ b/cmd/login.go @@ -17,16 +17,17 @@ package cmd import ( "encoding/json" "fmt" - "github.com/Keyfactor/keyfactor-go-client-sdk/api/keyfactor" - "github.com/Keyfactor/keyfactor-go-client/v2/api" - "github.com/google/go-cmp/cmp" - "github.com/rs/zerolog/log" - "github.com/spf13/cobra" - "golang.org/x/crypto/ssh/terminal" "os" "path" "strings" "syscall" + + "github.com/Keyfactor/keyfactor-auth-client-go/auth_config" + "github.com/Keyfactor/keyfactor-go-client/v3/api" + "github.com/google/go-cmp/cmp" + "github.com/rs/zerolog/log" + "github.com/spf13/cobra" + "golang.org/x/crypto/ssh/terminal" ) var loginCmd = &cobra.Command{ @@ -84,7 +85,11 @@ WARNING: The 'username'' and 'password' will be stored in the config file in pla if noPrompt { log.Info().Msg("Using environment variables for configuration data.") // First try to auth with environment variables - authConfig, authEnvErr = authEnvVars(configFile, profile, true) // always save config file is login is called + authConfig, authEnvErr = authEnvVars( + configFile, + profile, + true, + ) // always save config file is login is called if authEnvErr != nil { for _, err := range authEnvErr { log.Error().Err(err) @@ -94,7 +99,13 @@ WARNING: The 'username'' and 'password' will be stored in the config file in pla if !validConfigFileEntry(authConfig, profile) { // Attempt to auth with config file log.Info().Msgf("Attempting to authenticate via config '%s' profile.", profile) - authConfig, authEnvErr = authConfigFile(configFile, profile, "", noPrompt, true) // always save config file is login is called + authConfig, authEnvErr = authConfigFile( + configFile, + profile, + "", + noPrompt, + true, + ) // always save config file is login is called if authEnvErr != nil { // Print out the error messages for _, err := range authEnvErr { @@ -125,7 +136,17 @@ WARNING: The 'username'' and 'password' will be stored in the config file in pla Str("domain", existingAuth.Domain). Str("apiPath", existingAuth.APIPath). Msg("call: authInteractive()") - authConfig, authErr = authInteractive(existingAuth.Hostname, existingAuth.Username, existingAuth.Password, existingAuth.Domain, existingAuth.APIPath, profile, !noPrompt, true, configFile) + authConfig, authErr = authInteractive( + existingAuth.Hostname, + existingAuth.Username, + existingAuth.Password, + existingAuth.Domain, + existingAuth.APIPath, + profile, + !noPrompt, + true, + configFile, + ) log.Debug().Msg("authInteractive() returned") if authErr != nil { log.Error().Err(authErr) @@ -143,7 +164,13 @@ WARNING: The 'username'' and 'password' will be stored in the config file in pla Str("profile", profile). Bool("noPrompt", noPrompt). Msg("call: authConfigFile()") - authConfig, authConfigFileErrs = authConfigFile(configFile, profile, "", noPrompt, true) // always save config file is login is called + authConfig, authConfigFileErrs = authConfigFile( + configFile, + profile, + "", + noPrompt, + true, + ) // always save config file is login is called log.Debug().Msg("authConfigFile() returned") if authConfigFileErrs != nil { // Print out the error messages @@ -157,7 +184,17 @@ WARNING: The 'username'' and 'password' will be stored in the config file in pla //Attempt to auth with user interactive login log.Info().Msg("Attempting to authenticate via user interactive login.") authEntry := authConfig.Servers[profile] - authConfig, authErr = authInteractive(authEntry.Hostname, authEntry.Username, authEntry.Password, authEntry.Domain, authEntry.APIPath, profile, false, true, configFile) + authConfig, authErr = authInteractive( + authEntry.Hostname, + authEntry.Username, + authEntry.Password, + authEntry.Domain, + authEntry.APIPath, + profile, + false, + true, + configFile, + ) if authErr != nil { //log.Println(authErr) log.Error().Err(authErr) @@ -208,7 +245,10 @@ func validConfigFileEntry(configFile ConfigurationFile, profile string) bool { if configFile.Servers[profile].Hostname == "" || configFile.Servers[profile].Username == "" || configFile.Servers[profile].Password == "" { return false } - if configFile.Servers[profile].Domain == "" && (!strings.Contains(configFile.Servers[profile].Username, "@") || !strings.Contains(configFile.Servers[profile].Username, "\\")) { + if configFile.Servers[profile].Domain == "" && (!strings.Contains( + configFile.Servers[profile].Username, + "@", + ) || !strings.Contains(configFile.Servers[profile].Username, "\\")) { return false } return true @@ -223,7 +263,14 @@ func getDomainFromUsername(username string) string { return "" } -func createConfigFile(hostname string, username string, password string, domain string, apiPath string, profileName string) ConfigurationFile { +func createConfigFile( + hostname string, + username string, + password string, + domain string, + apiPath string, + profileName string, +) ConfigurationFile { output := ConfigurationFile{ Servers: map[string]ConfigurationFileEntry{ profileName: { @@ -238,28 +285,6 @@ func createConfigFile(hostname string, username string, password string, domain return output } -func createAuthConfig(hostname string, username string, password string, domain string, apiPath string) api.AuthConfig { - output := api.AuthConfig{ - Hostname: hostname, - Username: username, - Password: password, - Domain: domain, - APIPath: apiPath, - } - return output -} - -func createAuthConfigFromConfigFile(configFileEntry ConfigurationFileEntry) api.AuthConfig { - output := api.AuthConfig{ - Hostname: configFileEntry.Hostname, - Username: configFileEntry.Username, - Password: configFileEntry.Password, - Domain: configFileEntry.Domain, - APIPath: configFileEntry.APIPath, - } - return output -} - func promptForInteractiveParameter(parameterName string, defaultValue string) string { var input string fmt.Printf("Enter %s [%s]: \n", parameterName, defaultValue) @@ -329,7 +354,17 @@ func saveConfigFile(configFile ConfigurationFile, configPath string, profileName return loadedConfig, nil } -func authInteractive(hostname string, username string, password string, domain string, apiPath string, profileName string, forcePrompt bool, saveConfig bool, configPath string) (ConfigurationFile, error) { +func authInteractive( + hostname string, + username string, + password string, + domain string, + apiPath string, + profileName string, + forcePrompt bool, + saveConfig bool, + configPath string, +) (ConfigurationFile, error) { if hostname == "" || forcePrompt { hostname = promptForInteractiveParameter("Keyfactor Command kfcHostName", hostname) } @@ -397,7 +432,12 @@ func prepHomeDir() (string, error) { return userHomeDir, hErr } -func loadConfigFileData(profileName string, configPath string, noPrompt bool, configurationFile ConfigurationFile) (string, string, string, string, string) { +func loadConfigFileData( + profileName string, + configPath string, + noPrompt bool, + configurationFile ConfigurationFile, +) (string, string, string, string, string) { log.Debug().Str("profileName", profileName). Str("configPath", configPath). Bool("noPrompt", noPrompt). @@ -500,12 +540,15 @@ func loadConfigFileData(profileName string, configPath string, noPrompt bool, co func authViaProvider() (*api.Client, error) { var clientAuth api.AuthConfig - var commandConfig ConfigurationFile + var commandConfig auth_config.Config if providerType != "" { log.Info().Str("providerType", providerType).Msg("attempting to auth via auth provider") var providerConfig AuthProvider if providerProfile == "" { - log.Info().Str("providerProfile", providerProfile).Msg("auth provider profile not set, defaulting to 'default'") + log.Info().Str( + "providerProfile", + providerProfile, + ).Msg("auth provider profile not set, defaulting to 'default'") providerProfile = "default" } @@ -565,22 +608,29 @@ func authViaProvider() (*api.Client, error) { } log.Trace().Interface("pvConfig", pvConfig).Send() - commandConfig = pvConfig - clientAuth.Username = commandConfig.Servers[providerProfile].Username - clientAuth.Password = commandConfig.Servers[providerProfile].Password - clientAuth.Domain = commandConfig.Servers[providerProfile].Domain - clientAuth.Hostname = commandConfig.Servers[providerProfile].Hostname - clientAuth.APIPath = commandConfig.Servers[providerProfile].APIPath - - log.Debug().Str("clientAuth.Username", clientAuth.Username). - Str("clientAuth.Password", hashSecretValue(clientAuth.Password)). - Str("clientAuth.Domain", clientAuth.Domain). - Str("clientAuth.Hostname", clientAuth.Hostname). - Str("clientAuth.APIPath", clientAuth.APIPath). + //commandConfig = pvConfig //TODO: Handle this ab#55467 + clientConfig := clientAuth.GetServerConfig() + clientConfig.Username = commandConfig.Servers[providerProfile].Username + clientConfig.Password = commandConfig.Servers[providerProfile].Password + clientConfig.Domain = commandConfig.Servers[providerProfile].Domain + clientConfig.Host = commandConfig.Servers[providerProfile].Host + clientConfig.ClientID = commandConfig.Servers[providerProfile].ClientID + clientConfig.ClientSecret = commandConfig.Servers[providerProfile].ClientSecret + clientConfig.OAuthTokenUrl = commandConfig.Servers[providerProfile].OAuthTokenUrl + clientConfig.APIPath = commandConfig.Servers[providerProfile].APIPath + + log.Debug(). + Str("clientAuth.Username", clientConfig.Username). + Str("clientAuth.Password", hashSecretValue(clientConfig.Password)). + Str("clientAuth.Domain", clientConfig.Domain). + Str("clientAuth.ClientID", clientConfig.ClientID). + Str("clientAuth.ClientSecret", hashSecretValue(clientConfig.ClientSecret)). + Str("clientAuth.Hostname", clientConfig.Host). + Str("clientAuth.APIPath", clientConfig.APIPath). Msg("Client authentication params") log.Debug().Msg("call: api.NewKeyfactorClient()") - c, err := api.NewKeyfactorClient(&clientAuth) + c, err := api.NewKeyfactorClient(clientConfig, nil) log.Debug().Msg("complete: api.NewKeyfactorClient()") if err != nil { @@ -598,100 +648,6 @@ func authViaProvider() (*api.Client, error) { return nil, fmt.Errorf("unable to auth via provider, providerType is empty") } -func authViaProviderGenClient() (*keyfactor.APIClient, error) { - var commandConfig ConfigurationFile - if providerType != "" { - log.Info().Str("providerType", providerType).Msg("attempting to auth via auth provider") - var providerConfig AuthProvider - if providerProfile == "" { - log.Info().Str("providerProfile", providerProfile).Msg("auth provider profile not set, defaulting to 'default'") - providerProfile = "default" - } - - providerConfig = AuthProvider{ - Type: providerType, - Profile: providerProfile, - Parameters: nil, - } - - if configFile == "" { - homeDir, hdErr := os.UserHomeDir() - if hdErr != nil { - homeDir, hdErr = os.Getwd() - if hdErr != nil { - homeDir = "." // Default to current directory - } - } - configFile = path.Join(homeDir, ".keyfactor", DefaultConfigFileName) - } - - // Load config file - log.Debug().Str("configFile", configFile).Msg("configFile is set, loading config file") - log.Debug().Msg("calling loadConfigurationFile()") - configurationFile, cErr := loadConfigurationFile(configFile, true) - log.Debug().Msg("loadConfigurationFile() returned") - if cErr != nil { - log.Error().Err(cErr).Msg("unable to load provider config file") - return nil, cErr - } - // look for profile in config file - log.Debug().Str("profile", profile). - Str("providerProfile", providerProfile). - Msg("checking if providerProfile exists in config file") - - providerConfigEntry, providerProfileExists := configurationFile.Servers[providerProfile] - if !providerProfileExists { - log.Error().Str("providerProfile", providerProfile).Msg("providerProfile does not exist in config file") - return nil, fmt.Errorf("providerProfile '%s' does not exist in config file", providerProfile) - } - params := providerConfigEntry.AuthProvider.Parameters - if params == nil { - log.Error().Msg("providerProfile parameters are empty") - return nil, fmt.Errorf("providerProfile '%s' parameters are empty", providerProfile) - } - providerConfig.Parameters = params - - log.Debug().Str("providerConfig.Type", providerConfig.Type). - Msg("call: authViaProviderParams()") - pvConfig, pErr := authViaProviderParams(&providerConfig) - log.Debug().Msg("returned: authViaProviderParams()") - if pErr != nil { - log.Error().Err(pErr). - Str("providerConfig.Type", providerConfig.Type). - Str("providerConfig.Profile", providerConfig.Profile). - Msg("unable to auth via provider") - return nil, pErr - } - log.Trace().Interface("pvConfig", pvConfig).Send() - - commandConfig = pvConfig - sdkClientConfig := make(map[string]string) - sdkClientConfig["host"] = commandConfig.Servers[providerProfile].Hostname - sdkClientConfig["username"] = commandConfig.Servers[providerProfile].Username - sdkClientConfig["password"] = commandConfig.Servers[providerProfile].Password - sdkClientConfig["domain"] = commandConfig.Servers[providerProfile].Domain - sdkClientConfig["apiPath"] = commandConfig.Servers[providerProfile].APIPath - - log.Debug().Str("clientAuth.Username", sdkClientConfig["username"]). - Str("clientAuth.Password", hashSecretValue(sdkClientConfig["password"])). - Str("clientAuth.Domain", sdkClientConfig["domain"]). - Str("clientAuth.Hostname", sdkClientConfig["host"]). - Str("clientAuth.APIPath", sdkClientConfig["apiPath"]). - Msg("Client authentication params") - - log.Debug().Msg("call: api.NewKeyfactorClient()") - configuration := keyfactor.NewConfiguration(sdkClientConfig) - c := keyfactor.NewAPIClient(configuration) - log.Debug().Msg("complete: api.NewKeyfactorClient()") - log.Info().Msg("Keyfactor Command client created") - log.Debug().Str("flagAuthProvider", providerType). - Str("providerProfile", providerProfile). - Msg("returning from provider auth") - return c, nil - } - return nil, fmt.Errorf("unable to auth via provider, providerType is empty") -} - func authViaProviderParams(providerConfig *AuthProvider) (ConfigurationFile, error) { pt := providerConfig.Type @@ -702,7 +658,11 @@ func authViaProviderParams(providerConfig *AuthProvider) (ConfigurationFile, err // Check if auth provider is valid if !validAuthProvider(pt) { - return ConfigurationFile{}, fmt.Errorf("invalid auth provider type '%s'. Valid auth providers are: %v", pt, ValidAuthProviders) + return ConfigurationFile{}, fmt.Errorf( + "invalid auth provider type '%s'. Valid auth providers are: %v", + pt, + ValidAuthProviders, + ) } // Check if provider type matches requested provider type @@ -734,7 +694,11 @@ func authViaProviderParams(providerConfig *AuthProvider) (ConfigurationFile, err log.Error().Msg("invalid auth provider type") break } - return ConfigurationFile{}, fmt.Errorf("invalid auth provider type '%s'. Valid auth providers are: %v", pt, ValidAuthProviders) + return ConfigurationFile{}, fmt.Errorf( + "invalid auth provider type '%s'. Valid auth providers are: %v", + pt, + ValidAuthProviders, + ) } func validAuthProvider(providerType string) bool { @@ -752,7 +716,13 @@ func validAuthProvider(providerType string) bool { return false } -func authConfigFile(configPath string, profileName string, authProviderProfile string, noPrompt bool, saveConfig bool) (ConfigurationFile, []error) { +func authConfigFile( + configPath string, + profileName string, + authProviderProfile string, + noPrompt bool, + saveConfig bool, +) (ConfigurationFile, []error) { var configurationFile ConfigurationFile var ( hostName string @@ -793,7 +763,12 @@ func authConfigFile(configPath string, profileName string, authProviderProfile s } log.Debug().Msg("calling loadConfigFileData()") - hostName, userName, password, domain, apiPath = loadConfigFileData(profileName, configPath, noPrompt, configurationFile) + hostName, userName, password, domain, apiPath = loadConfigFileData( + profileName, + configPath, + noPrompt, + configurationFile, + ) log.Debug().Msg("loadConfigFileData() returned") log.Debug().Str("hostName", hostName). @@ -832,7 +807,10 @@ func authConfigFile(configPath string, profileName string, authProviderProfile s func authEnvProvider(authProvider *AuthProvider, configProfile string) (ConfigurationFile, []error) { //log.Println(fmt.Sprintf("[INFO] authenticating with auth provider '%s' params from environment variables", authProvider.Type)) - log.Info().Str("authProvider.Type", authProvider.Type).Msg("authenticating with auth provider params from environment variables") + log.Info().Str( + "authProvider.Type", + authProvider.Type, + ).Msg("authenticating with auth provider params from environment variables") if configProfile == "" { log.Debug().Msg("configProfile is empty, setting to default") @@ -918,7 +896,12 @@ func authEnvProvider(authProvider *AuthProvider, configProfile string) (Configur } else { //log.Println(fmt.Sprintf("[DEBUG] profile '%s' not found in authProviderParams file", configProfile)) log.Debug().Str("configProfile", configProfile).Msg("profile not found in authProviderParams file") - return ConfigurationFile{}, []error{fmt.Errorf("profile '%s' not found in authProviderParams file", configProfile)} + return ConfigurationFile{}, []error{ + fmt.Errorf( + "profile '%s' not found in authProviderParams file", + configProfile, + ), + } } } else { //check if provider params is an AuthProvider @@ -956,7 +939,10 @@ func authEnvProvider(authProvider *AuthProvider, configProfile string) (Configur authProvider.Parameters = providerParams } //log.Println("[INFO] Attempting to fetch kfutil creds from auth provider ", authProvider) - log.Info().Str("authProvider", fmt.Sprintf("%+v", authProvider)).Msg("Attempting to fetch kfutil creds from auth provider") + log.Info().Str( + "authProvider", + fmt.Sprintf("%+v", authProvider), + ).Msg("Attempting to fetch kfutil creds from auth provider") configFile, authErr := authViaProviderParams(authProvider) if authErr != nil { //log.Println("[ERROR] Unable to authenticate via provider: ", authErr) @@ -1011,16 +997,28 @@ func authEnvVars(configPath string, profileName string, saveConfig bool) (Config var outputErr []error if !hostSet { - outputErr = append(outputErr, fmt.Errorf("KEYFACTOR_HOSTNAME environment variable not set. Please set the KEYFACTOR_HOSTNAME environment variable")) + outputErr = append( + outputErr, + fmt.Errorf("KEYFACTOR_HOSTNAME environment variable not set. Please set the KEYFACTOR_HOSTNAME environment variable"), + ) } if !userSet { - outputErr = append(outputErr, fmt.Errorf("KEYFACTOR_USERNAME environment variable not set. Please set the KEYFACTOR_USERNAME environment variable")) + outputErr = append( + outputErr, + fmt.Errorf("KEYFACTOR_USERNAME environment variable not set. Please set the KEYFACTOR_USERNAME environment variable"), + ) } if !passSet { - outputErr = append(outputErr, fmt.Errorf("KEYFACTOR_PASSWORD environment variable not set. Please set the KEYFACTOR_PASSWORD environment variable")) + outputErr = append( + outputErr, + fmt.Errorf("KEYFACTOR_PASSWORD environment variable not set. Please set the KEYFACTOR_PASSWORD environment variable"), + ) } if !domainSet { - outputErr = append(outputErr, fmt.Errorf("KEYFACTOR_DOMAIN environment variable not set. Please set the KEYFACTOR_DOMAIN environment variable")) + outputErr = append( + outputErr, + fmt.Errorf("KEYFACTOR_DOMAIN environment variable not set. Please set the KEYFACTOR_DOMAIN environment variable"), + ) } if !apiPathSet { apiPath = DefaultAPIPath @@ -1182,7 +1180,10 @@ func loadConfigurationFile(filePath string, silent bool) (ConfigurationFile, err sjErr := json.Unmarshal(f, &singleEntry) if sjErr != nil { //log.Println(fmt.Sprintf("[DEBUG] config file '%s' is a not single entry, will attempt to parse as v1 config file", filePath)) - log.Debug().Str("filePath", filePath).Msg("config file is not a single entry, will attempt to parse as v1 config file") + log.Debug().Str( + "filePath", + filePath, + ).Msg("config file is not a single entry, will attempt to parse as v1 config file") } else if (singleEntry != ConfigurationFileEntry{}) { // if we successfully unmarshalled a single entry, add it to the map as the default entry //log.Println(fmt.Sprintf("[DEBUG] config file '%s' is a single entry, adding to map", filePath)) @@ -1203,13 +1204,17 @@ func loadConfigurationFile(filePath string, silent bool) (ConfigurationFile, err return data, nil } -func createAuthConfigFromParams(hostname string, username string, password string, domain string, apiPath string) *api.AuthConfig { - output := api.AuthConfig{ - Hostname: hostname, - Username: username, - Password: password, - Domain: domain, - APIPath: apiPath, - } +func createAuthConfigFromParams( + hostname string, + username string, + password string, + domain string, + apiPath string, + clientId string, + clientSecret string, + tokenUrl string, +) *api.AuthConfig { + + serverConfig := auth_config.Server{} return &output } diff --git a/cmd/root.go b/cmd/root.go index a356d55..0c3b8d9 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -15,14 +15,18 @@ package cmd import ( + "context" _ "embed" "fmt" "io" stdlog "log" "os" + "strings" + "github.com/Keyfactor/keyfactor-auth-client-go/auth_config" + "github.com/Keyfactor/keyfactor-auth-client-go/auth_providers" "github.com/Keyfactor/keyfactor-go-client-sdk/api/keyfactor" - "github.com/Keyfactor/keyfactor-go-client/v2/api" + "github.com/Keyfactor/keyfactor-go-client/v3/api" "github.com/rs/zerolog/log" "github.com/spf13/cobra" "github.com/spf13/cobra/doc" @@ -35,17 +39,20 @@ var ( providerType string providerProfile string //providerConfig string - noPrompt bool - expEnabled bool - debugFlag bool - kfcUsername string - kfcHostName string - kfcPassword string - kfcDomain string - kfcAPIPath string - logInsecure bool - outputFormat string - offline bool + noPrompt bool + expEnabled bool + debugFlag bool + kfcUsername string + kfcHostName string + kfcPassword string + kfcDomain string + kfcClientId string + kfcClientSecret string + kfcTokenUrl string + kfcAPIPath string + logInsecure bool + outputFormat string + offline bool ) func hashSecretValue(secretValue string) string { @@ -66,155 +73,201 @@ func hashSecretValue(secretValue string) string { return string(hashedPassword) } -func initClient( - flagConfigFile string, - flagProfile string, - flagAuthProviderType string, - flagAuthProviderProfile string, - noPrompt bool, - authConfig *api.AuthConfig, - saveConfig bool, -) (*api.Client, error) { - log.Debug().Msg("Enter initClient()") - var clientAuth api.AuthConfig - var commandConfig ConfigurationFile +func getServerConfigFromFile(configFile string, profile string) (*auth_config.Server, error) { + var commandConfig *auth_config.Config + var serverConfig auth_config.Server - if providerType != "" { - return authViaProvider() + log.Debug(). + Str("configFile", configFile). + Str("profile", profile). + Msg("configFile or profile is not empty attempting to authenticate via config file") + if profile == "" { + profile = "default" } - - log.Debug().Msg("call: authEnvVars()") - commandConfig, _ = authEnvVars(flagConfigFile, flagProfile, saveConfig) - - // check if commandConfig is empty - if commandConfig.Servers == nil || len(commandConfig.Servers) == 0 { - log.Debug().Msg("commandConfig is empty") - if flagConfigFile != "" || !validConfigFileEntry(commandConfig, flagProfile) { - log.Debug(). - Str("flagConfigFile", flagConfigFile). - Str("flagProfile", flagProfile). - Bool("noPrompt", noPrompt). - Bool("saveConfig", saveConfig). - Msg("call: authConfigFile()") - commandConfig, _ = authConfigFile(flagConfigFile, flagProfile, "", noPrompt, saveConfig) - log.Debug().Msg("complete: authConfigFile()") - } + if configFile == "" { + homeDir, _ := os.UserHomeDir() + configFile = fmt.Sprintf("%s/%s", homeDir, auth_providers.DefaultConfigFilePath) + } + var cfgReadErr error + if strings.HasSuffix(configFile, ".yaml") || strings.HasSuffix(configFile, ".yml") { + log.Debug().Msg("call: auth_config.ReadConfigFromYAML()") + //commandConfig, cfgReadErr = auth_config.ReadConfigFromYAML(configFile) + commandConfig, cfgReadErr = auth_config.ReadConfigFromJSON(configFile) } else { - log.Debug().Msg("commandConfig is not empty and is valid") - authProviderProfile, _ := os.LookupEnv("KUTIL_AUTH_PROVIDER_PROFILE") - log.Debug().Str("authProviderProfile", authProviderProfile).Send() - if authProviderProfile != "" { - flagProfile = authProviderProfile - } else if flagAuthProviderProfile != "" { - flagProfile = flagAuthProviderProfile - } + log.Debug().Msg("call: auth_config.ReadConfigFromJSON()") + commandConfig, cfgReadErr = auth_config.ReadConfigFromJSON(configFile) } - log.Debug().Str("flagProfile", flagProfile).Send() - if flagProfile == "" { - flagProfile = "default" + if cfgReadErr != nil { + log.Error().Err(cfgReadErr).Msg("unable to read config file") + return nil, fmt.Errorf("unable to read config file: %s", cfgReadErr) } - //Params from authConfig take precedence over everything else - if authConfig != nil { - // replace commandConfig with authConfig params that aren't null or empty - log.Debug().Str("flagProfile", flagProfile).Msg("Loading profile from authConfig") - configEntry := commandConfig.Servers[flagProfile] - if authConfig.Hostname != "" { - log.Debug().Str("authConfig.Hostname", authConfig.Hostname). - Str("configEntry.Hostname", configEntry.Hostname). - Str("flagProfile", flagProfile). - Msg("Config file profile file hostname is set") - configEntry.Hostname = authConfig.Hostname - } - if authConfig.Username != "" { - log.Debug().Str("authConfig.Username", authConfig.Username). - Str("configEntry.Username", configEntry.Username). - Str("flagProfile", flagProfile). - Msg("Config file profile file username is set") - configEntry.Username = authConfig.Username - } - if authConfig.Password != "" { - log.Debug().Str("authConfig.Password", hashSecretValue(authConfig.Password)). - Str("configEntry.Password", hashSecretValue(configEntry.Password)). - Str("flagProfile", flagProfile). - Msg("Config file profile file password is set") - configEntry.Password = authConfig.Password - } - if authConfig.Domain != "" { - log.Debug().Str("authConfig.Domain", authConfig.Domain). - Str("configEntry.Domain", configEntry.Domain). - Str("flagProfile", flagProfile). - Msg("Config file profile file domain is set") - configEntry.Domain = authConfig.Domain - } else if authConfig.Username != "" { - log.Debug().Str("authConfig.Username", authConfig.Username). - Str("configEntry.Username", configEntry.Username). - Str("flagProfile", flagProfile). - Msg("Attempting to get domain from username") - tDomain := getDomainFromUsername(authConfig.Username) - if tDomain != "" { - log.Debug().Str("configEntry.Domain", tDomain). - Msg("domain set from username") - configEntry.Domain = tDomain - } + // check if the profile exists in the config file + var ok bool + if serverConfig, ok = commandConfig.Servers[profile]; !ok { + log.Error().Str("profile", profile).Msg("invalid profile") + return nil, fmt.Errorf("invalid profile: %s", profile) + } + + log.Debug().Msg("return: getServerConfigFromFile()") + return &serverConfig, nil +} + +func getServerConfigFromEnv() (*auth_config.Server, error) { + log.Debug().Msg("Enter getServerConfigFromEnv()") + + oAuthNoParamsConfig := &auth_providers.CommandConfigOauth{} + basicAuthNoParamsConfig := &auth_providers.CommandAuthConfigBasic{} + + bErr := basicAuthNoParamsConfig.Authenticate() + if bErr == nil { + log.Debug().Msg("return: getServerConfigFromEnv()") + return basicAuthNoParamsConfig.GetServerConfig(), nil + } + + oErr := oAuthNoParamsConfig.Authenticate() + if oErr == nil { + log.Debug().Msg("return: getServerConfigFromEnv()") + return oAuthNoParamsConfig.GetServerConfig(), nil + } + + log.Error().Msg("unable to authenticate with provided credentials") + if bErr != nil { + return nil, bErr + } + return nil, oErr + +} + +func authViaConfigFile(cfgFile string, cfgProfile string) (*api.Client, error) { + var ( + c *api.Client + cErr error + ) + log.Debug().Msg("call: getServerConfigFromFile()") + conf, err := getServerConfigFromFile(cfgFile, cfgProfile) + log.Debug().Msg("complete: getServerConfigFromFile()") + if err != nil { + log.Error(). + Err(err). + Msg("unable to get server config from file") + return nil, err + } + if conf != nil { + log.Debug().Msg("call: api.NewKeyfactorClient()") + c, cErr = api.NewKeyfactorClient(conf, nil) + log.Debug().Msg("complete: api.NewKeyfactorClient()") + if cErr != nil { + log.Error(). + Err(cErr). + Msg("unable to create Keyfactor client") + return nil, cErr } - if authConfig.APIPath != "" && configEntry.APIPath == "" { - log.Debug().Str("authConfig.APIPath", authConfig.APIPath). - Str("configEntry.APIPath", configEntry.APIPath). - Str("flagProfile", flagProfile). - Msg("Config file profile file APIPath is set") - configEntry.APIPath = authConfig.APIPath + log.Debug().Msg("call: c.AuthClient.Authenticate()") + authErr := c.AuthClient.Authenticate() + log.Debug().Msg("complete: c.AuthClient.Authenticate()") + if authErr == nil { + return c, nil } - log.Debug().Str("flagProfile", flagProfile).Msg("Setting configEntry") - commandConfig.Servers[flagProfile] = configEntry + } + log.Error().Msg("unable to authenticate via config file") + return nil, fmt.Errorf("unable to authenticate via config file '%s' using profile '%s'", cfgFile, cfgProfile) +} - if !validConfigFileEntry(commandConfig, flagProfile) { - if !noPrompt { - // Auth user interactively - authConfigEntry := commandConfig.Servers[flagProfile] - commandConfig, _ = authInteractive( - authConfigEntry.Hostname, - authConfigEntry.Username, - authConfigEntry.Password, - authConfigEntry.Domain, - authConfigEntry.APIPath, - flagProfile, - false, - false, - flagConfigFile, - ) - } else { - //log.Fatalf("[ERROR] auth config profile: %s", flagProfile) - log.Error().Str("flagProfile", flagProfile).Msg("invalid auth config profile") - return nil, fmt.Errorf("invalid auth config profile: %s", flagProfile) +func authViaEnvVars() (*api.Client, error) { + var ( + c *api.Client + cErr error + ) + log.Debug().Msg("enter: authViaEnvVars()") + log.Debug().Msg("call: getServerConfigFromEnv()") + conf, err := getServerConfigFromEnv() + log.Debug().Msg("complete: getServerConfigFromEnv()") + if err != nil { + log.Error().Err(err).Msg("unable to authenticate via environment variables") + log.Debug().Msg("return: authViaEnvVars()") + return nil, err + } + if conf != nil { + log.Debug().Msg("call: api.NewKeyfactorClient()") + c, cErr = api.NewKeyfactorClient(conf, nil) + log.Debug().Msg("complete: api.NewKeyfactorClient()") + if cErr != nil { + log.Error().Err(cErr).Msg("unable to create Keyfactor client") + log.Debug().Msg("return: authViaEnvVars()") + return nil, cErr } + log.Debug().Msg("call: c.AuthClient.Authenticate()") + authErr := c.AuthClient.Authenticate() + log.Debug().Msg("complete: c.AuthClient.Authenticate()") + if authErr != nil { + log.Error().Err(authErr).Msg("unable to authenticate via environment variables") + return nil, authErr + } + log.Debug().Msg("return: authViaEnvVars()") + return c, nil } + log.Error().Msg("unable to authenticate via environment variables") + log.Debug().Msg("return: authViaEnvVars()") + return nil, fmt.Errorf("unable to authenticate via environment variables") +} - clientAuth.Username = commandConfig.Servers[flagProfile].Username - clientAuth.Password = commandConfig.Servers[flagProfile].Password - clientAuth.Domain = commandConfig.Servers[flagProfile].Domain - clientAuth.Hostname = commandConfig.Servers[flagProfile].Hostname - clientAuth.APIPath = commandConfig.Servers[flagProfile].APIPath - - log.Debug().Str("clientAuth.Username", clientAuth.Username). - Str("clientAuth.Password", hashSecretValue(clientAuth.Password)). - Str("clientAuth.Domain", clientAuth.Domain). - Str("clientAuth.Hostname", clientAuth.Hostname). - Str("clientAuth.APIPath", clientAuth.APIPath). - Msg("Client authentication params") +func initClient(saveConfig bool) (*api.Client, error) { + log.Debug(). + Str("configFile", configFile). + Str("profile", profile). + Str("providerType", providerType). + Str("providerProfile", providerProfile). + Bool("noPrompt", noPrompt). + Bool("saveConfig", saveConfig). + Str("hostname", kfcHostName). + Str("username", kfcUsername). + Str("password", hashSecretValue(kfcPassword)). + Str("domain", kfcDomain). + Str("clientId", kfcClientId). + Str("clientSecret", hashSecretValue(kfcClientSecret)). + Str("apiPath", kfcAPIPath). + Str("providerType", providerType). + Str("providerProfile", providerProfile). + Msg("enter: initClient()") + var ( + authenticated bool + c *api.Client + cErr error + ) - log.Debug().Msg("call: api.NewKeyfactorClient()") - c, err := api.NewKeyfactorClient(&clientAuth) - log.Debug().Msg("complete: api.NewKeyfactorClient()") + if providerType != "" { + log.Debug(). + Str("providerType", providerType). + Msg("call: authViaProvider()") + return authViaProvider() + } + log.Debug(). + Msg("providerType is empty attempting to authenticate via params") + + if configFile != "" || profile != "" { + c, cErr = authViaConfigFile(configFile, profile) + if cErr == nil { + log.Info(). + Str("configFile", configFile). + Str("profile", profile). + Msgf("Authenticated via config file %s using profile %s", configFile, profile) + authenticated = true + } + } - if err != nil { - //fmt.Printf("Error connecting to Keyfactor: %s\n", err) - outputError(err, true, "text") - //log.Fatalf("[ERROR] creating Keyfactor client: %s", err) - return nil, fmt.Errorf("unable to create Keyfactor Command client: %s", err) + if !authenticated { + log.Debug().Msg("call: authViaEnvVars()") + c, cErr = authViaEnvVars() + log.Debug().Msg("returned: authViaEnvVars()") + if cErr == nil { + log.Info().Msg("Authenticated via environment variables") + authenticated = true + } } + log.Info().Msg("Keyfactor Command client created") return c, nil } @@ -223,85 +276,162 @@ func initGenClient( flagConfig string, flagProfile string, noPrompt bool, - authConfig *api.AuthConfig, + authConfig *auth_config.Config, saveConfig bool, ) (*keyfactor.APIClient, error) { - var commandConfig ConfigurationFile - - if providerType != "" { - return authViaProviderGenClient() - } - commandConfig, _ = authEnvVars(flagConfig, "", saveConfig) + baseConfig := auth_providers.CommandAuthConfig{} + baseConfig.WithCommandHostName(kfcHostName). + WithCommandAPIPath(kfcAPIPath). + WithConfigProfile(flagProfile). + WithConfigFile(flagConfig) - if flagConfig != "" || !validConfigFileEntry(commandConfig, flagProfile) { - commandConfig, _ = authConfigFile(flagConfig, flagProfile, "", noPrompt, saveConfig) + oClient := auth_providers.CommandConfigOauth{ + CommandAuthConfig: baseConfig, } - if flagProfile == "" { - flagProfile = "default" + bClient := auth_providers.CommandAuthConfigBasic{ + CommandAuthConfig: baseConfig, } - //Params from authConfig take precedence over everything else - if authConfig != nil { - // replace commandConfig with authConfig params that aren't null or empty - configEntry := commandConfig.Servers[flagProfile] - if authConfig.Hostname != "" { - configEntry.Hostname = authConfig.Hostname - } - if authConfig.Username != "" { - configEntry.Username = authConfig.Username - } - if authConfig.Password != "" { - configEntry.Password = authConfig.Password - } - if authConfig.Domain != "" { - configEntry.Domain = authConfig.Domain - } else if authConfig.Username != "" { - tDomain := getDomainFromUsername(authConfig.Username) - if tDomain != "" { - configEntry.Domain = tDomain - } - } - if authConfig.APIPath != "" { - configEntry.APIPath = authConfig.APIPath + serverConfig := auth_config.Server{} + if authConfig == nil { + var bErr error + var oErr error + if kfcUsername != "" && kfcPassword != "" { + bErr = bClient.WithUsername(kfcUsername). + WithPassword(kfcPassword). + WithDomain(kfcDomain). + Authenticate() + } else if kfcClientId != "" && kfcClientSecret != "" && kfcTokenUrl != "" { + oErr = oClient.WithClientId(kfcClientId). + WithClientSecret(kfcClientSecret). + WithTokenUrl(kfcTokenUrl). + Authenticate() + } else { + // Try both? + bErr = bClient.WithUsername(kfcUsername). + WithPassword(kfcPassword). + WithDomain(kfcDomain). + Authenticate() + oErr = oClient.WithClientId(kfcClientId). + WithClientSecret(kfcClientSecret). + WithTokenUrl(kfcTokenUrl). + Authenticate() } - commandConfig.Servers[flagProfile] = configEntry - } - if !validConfigFileEntry(commandConfig, flagProfile) { - if !noPrompt { - // Auth user interactively - authConfigEntry := commandConfig.Servers[flagProfile] - commandConfig, _ = authInteractive( - authConfigEntry.Hostname, - authConfigEntry.Username, - authConfigEntry.Password, - authConfigEntry.Domain, - authConfigEntry.APIPath, - flagProfile, - false, - false, - flagConfig, - ) + if bErr != nil && oErr != nil { + log.Error().Msg("Unable to authenticate with provided credentials") + //combine errors + return nil, fmt.Errorf("unable to authenticate with provided credentials: %s, %s", bErr, oErr) + } else if bErr == nil { + serverConfig.Username = bClient.Username + serverConfig.Password = bClient.Password + serverConfig.Domain = bClient.Domain + serverConfig.Host = bClient.CommandHostName + serverConfig.APIPath = bClient.CommandAPIPath } else { - //log.Fatalf("[ERROR] auth config profile: %s", flagProfile) - log.Error().Str("flagProfile", flagProfile).Msg("invalid auth config profile") - return nil, fmt.Errorf("auth config profile: %s", flagProfile) + serverConfig.ClientID = oClient.ClientID + serverConfig.ClientSecret = oClient.ClientSecret + serverConfig.Host = bClient.CommandHostName + serverConfig.APIPath = bClient.CommandAPIPath } } - sdkClientConfig := make(map[string]string) - sdkClientConfig["host"] = commandConfig.Servers[flagProfile].Hostname - sdkClientConfig["username"] = commandConfig.Servers[flagProfile].Username - sdkClientConfig["password"] = commandConfig.Servers[flagProfile].Password - sdkClientConfig["domain"] = commandConfig.Servers[flagProfile].Domain - - configuration := keyfactor.NewConfiguration(sdkClientConfig) - c := keyfactor.NewAPIClient(configuration) - return c, nil + apiClient := keyfactor.NewAPIClient(&serverConfig) + resp, r, err := apiClient.StatusApi.StatusGetEndpoints(context.Background()).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `StatusApi.StatusGetEndpoints``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `StatusGetEndpoints`: []string + fmt.Fprintf(os.Stdout, "Response from `StatusApi.StatusGetEndpoints`: %v\n", resp) + return apiClient, nil } +//func initGenClientV1( +// flagConfig string, +// flagProfile string, +// noPrompt bool, +// authConfig *api.AuthConfig, +// saveConfig bool, +//) (*keyfactor.APIClient, error) { +// var commandConfig ConfigurationFile +// +// if providerType != "" { +// return authViaProviderGenClient() +// } +// +// commandConfig, _ = authEnvVars(flagConfig, "", saveConfig) +// +// if flagConfig != "" || !validConfigFileEntry(commandConfig, flagProfile) { +// commandConfig, _ = authConfigFile(flagConfig, flagProfile, "", noPrompt, saveConfig) +// } +// +// if flagProfile == "" { +// flagProfile = "default" +// } +// +// //Params from authConfig take precedence over everything else +// if authConfig != nil { +// // replace commandConfig with authConfig params that aren't null or empty +// configEntry := commandConfig.Servers[flagProfile] +// if authConfig.Hostname != "" { +// configEntry.Hostname = authConfig.Hostname +// } +// if authConfig.Username != "" { +// configEntry.Username = authConfig.Username +// } +// if authConfig.Password != "" { +// configEntry.Password = authConfig.Password +// } +// if authConfig.Domain != "" { +// configEntry.Domain = authConfig.Domain +// } else if authConfig.Username != "" { +// tDomain := getDomainFromUsername(authConfig.Username) +// if tDomain != "" { +// configEntry.Domain = tDomain +// } +// } +// if authConfig.APIPath != "" { +// configEntry.APIPath = authConfig.APIPath +// } +// commandConfig.Servers[flagProfile] = configEntry +// } +// +// if !validConfigFileEntry(commandConfig, flagProfile) { +// if !noPrompt { +// // Auth user interactively +// authConfigEntry := commandConfig.Servers[flagProfile] +// commandConfig, _ = authInteractive( +// authConfigEntry.Hostname, +// authConfigEntry.Username, +// authConfigEntry.Password, +// authConfigEntry.Domain, +// authConfigEntry.APIPath, +// flagProfile, +// false, +// false, +// flagConfig, +// ) +// } else { +// //log.Fatalf("[ERROR] auth config profile: %s", flagProfile) +// log.Error().Str("flagProfile", flagProfile).Msg("invalid auth config profile") +// return nil, fmt.Errorf("auth config profile: %s", flagProfile) +// } +// } +// +// sdkClientConfig := make(map[string]string) +// sdkClientConfig["host"] = commandConfig.Servers[flagProfile].Hostname +// sdkClientConfig["username"] = commandConfig.Servers[flagProfile].Username +// sdkClientConfig["password"] = commandConfig.Servers[flagProfile].Password +// sdkClientConfig["domain"] = commandConfig.Servers[flagProfile].Domain +// +// configuration := keyfactor.NewConfiguration(sdkClientConfig) +// c := keyfactor.NewAPIClient(configuration) +// return c, nil +//} + var makeDocsCmd = &cobra.Command{ Use: "makedocs", Short: "Generate markdown documentation for kfutil", diff --git a/cmd/rot.go b/cmd/rot.go index 897e65f..6a2bfa2 100644 --- a/cmd/rot.go +++ b/cmd/rot.go @@ -14,1193 +14,1406 @@ package cmd -import ( - "bufio" - "encoding/csv" - "encoding/json" - "errors" - "fmt" - "github.com/Keyfactor/keyfactor-go-client/v2/api" - "github.com/spf13/cobra" - "log" - "os" - "strconv" - "strings" -) - -type templateType string -type StoreCSVEntry struct { - ID string `json:"id"` - Type string `json:"type"` - Machine string `json:"address"` - Path string `json:"path"` - Thumbprints map[string]bool `json:"thumbprints,omitempty"` - Serials map[string]bool `json:"serials,omitempty"` - Ids map[int]bool `json:"ids,omitempty"` -} -type ROTCert struct { - ID int `json:"id,omitempty"` - ThumbPrint string `json:"thumbprint,omitempty"` - CN string `json:"cn,omitempty"` - Locations []api.CertificateLocations `json:"locations,omitempty"` -} -type ROTAction struct { - StoreID string `json:"store_id,omitempty"` - StoreType string `json:"store_type,omitempty"` - StorePath string `json:"store_path,omitempty"` - Thumbprint string `json:"thumbprint,omitempty"` - CertID int `json:"cert_id,omitempty" mapstructure:"CertID,omitempty"` - AddCert bool `json:"add,omitempty" mapstructure:"AddCert,omitempty"` - RemoveCert bool `json:"remove,omitempty" mapstructure:"RemoveCert,omitempty"` -} - -const ( - tTypeCerts templateType = "certs" - reconcileDefaultFileName string = "rot_audit.csv" -) - -var ( - AuditHeader = []string{"Thumbprint", "CertID", "SubjectName", "Issuer", "StoreID", "StoreType", "Machine", "Path", "AddCert", "RemoveCert", "Deployed", "AuditDate"} - ReconciledAuditHeader = []string{"Thumbprint", "CertID", "SubjectName", "Issuer", "StoreID", "StoreType", "Machine", "Path", "AddCert", "RemoveCert", "Deployed", "ReconciledDate"} - StoreHeader = []string{"StoreID", "StoreType", "StoreMachine", "StorePath", "ContainerId", "ContainerName", "LastQueriedDate"} - CertHeader = []string{"Thumbprint", "SubjectName", "Issuer", "CertID", "Locations", "LastQueriedDate"} -) - -// String is used both by fmt.Print and by Cobra in help text -func (e *templateType) String() string { - return string(*e) -} - -// Set must have pointer receiver, so it doesn't change the value of a copy -func (e *templateType) Set(v string) error { - switch v { - case "certs", "stores", "actions": - *e = templateType(v) - return nil - default: - return errors.New(`must be one of "certs", "stores", or "actions"`) - } -} - -// Type is only used in help text -func (e *templateType) Type() string { - return "string" -} - -func templateTypeCompletion(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - return []string{ - "certs\tGenerates template CSV for certificate input to be used w/ `--add-certs` or `--remove-certs`", - "stores\tGenerates template CSV for certificate input to be used w/ `--stores`", - "actions\tGenerates template CSV for certificate input to be used w/ `--actions`", - }, cobra.ShellCompDirectiveDefault -} - -func generateAuditReport(addCerts map[string]string, removeCerts map[string]string, stores map[string]StoreCSVEntry, outpath string, kfClient *api.Client) ([][]string, map[string][]ROTAction, error) { - log.Println("[DEBUG] generateAuditReport called") - var ( - data [][]string - ) - - data = append(data, AuditHeader) - var csvFile *os.File - var fErr error - if outpath == "" { - csvFile, fErr = os.Create(reconcileDefaultFileName) - outpath = reconcileDefaultFileName - } else { - csvFile, fErr = os.Create(outpath) - } - - if fErr != nil { - fmt.Printf("%s", fErr) - log.Fatalf("[ERROR] creating audit file: %s", fErr) - } - csvWriter := csv.NewWriter(csvFile) - cErr := csvWriter.Write(AuditHeader) - if cErr != nil { - fmt.Printf("%s", cErr) - log.Fatalf("[ERROR] writing audit header: %s", cErr) - } - actions := make(map[string][]ROTAction) - - for _, cert := range addCerts { - certLookupReq := api.GetCertificateContextArgs{ - IncludeMetadata: boolToPointer(true), - IncludeLocations: boolToPointer(true), - CollectionId: nil, - Thumbprint: cert, - Id: 0, - } - certLookup, err := kfClient.GetCertificateContext(&certLookupReq) - if err != nil { - fmt.Printf("[ERROR] looking up certificate %s: %s\n", cert, err) - log.Printf("[ERROR] looking up cert: %s\n%v", cert, err) - continue - } - certID := certLookup.Id - certIDStr := strconv.Itoa(certID) - for _, store := range stores { - if _, ok := store.Thumbprints[cert]; ok { - // Cert is already in the store do nothing - row := []string{cert, certIDStr, certLookup.IssuedDN, certLookup.IssuerDN, store.ID, store.Type, store.Machine, store.Path, "false", "false", "true", getCurrentTime("")} - data = append(data, row) - wErr := csvWriter.Write(row) - if wErr != nil { - fmt.Printf("[ERROR] writing audit file row: %s\n", wErr) - log.Printf("[ERROR] writing audit row: %s", wErr) - } - } else { - // Cert is not deployed to this store and will need to be added - row := []string{cert, certIDStr, certLookup.IssuedDN, certLookup.IssuerDN, store.ID, store.Type, store.Machine, store.Path, "true", "false", "false", getCurrentTime("")} - data = append(data, row) - wErr := csvWriter.Write(row) - if wErr != nil { - fmt.Printf("[ERROR] writing audit file row: %s\n", wErr) - log.Printf("[ERROR] writing audit row: %s", wErr) - } - actions[cert] = append(actions[cert], ROTAction{ - Thumbprint: cert, - CertID: certID, - StoreID: store.ID, - StoreType: store.Type, - StorePath: store.Path, - AddCert: true, - RemoveCert: false, - }) - } - } - } - for _, cert := range removeCerts { - certLookupReq := api.GetCertificateContextArgs{ - IncludeMetadata: boolToPointer(true), - IncludeLocations: boolToPointer(true), - CollectionId: nil, - Thumbprint: cert, - Id: 0, - } - certLookup, err := kfClient.GetCertificateContext(&certLookupReq) - if err != nil { - log.Printf("[ERROR] looking up cert: %s", err) - continue - } - certID := certLookup.Id - certIDStr := strconv.Itoa(certID) - for _, store := range stores { - if _, ok := store.Thumbprints[cert]; ok { - // Cert is deployed to this store and will need to be removed - row := []string{cert, certIDStr, certLookup.IssuedDN, certLookup.IssuerDN, store.ID, store.Type, store.Machine, store.Path, "false", "true", "true", getCurrentTime("")} - data = append(data, row) - wErr := csvWriter.Write(row) - if wErr != nil { - fmt.Printf("%s", wErr) - log.Printf("[ERROR] writing row to CSV: %s", wErr) - } - actions[cert] = append(actions[cert], ROTAction{ - Thumbprint: cert, - CertID: certID, - StoreID: store.ID, - StoreType: store.Type, - StorePath: store.Path, - AddCert: false, - RemoveCert: true, - }) - } else { - // Cert is not deployed to this store do nothing - row := []string{cert, certIDStr, certLookup.IssuedDN, certLookup.IssuerDN, store.ID, store.Type, store.Machine, store.Path, "false", "false", "false", getCurrentTime("")} - data = append(data, row) - wErr := csvWriter.Write(row) - if wErr != nil { - fmt.Printf("%s", wErr) - log.Printf("[ERROR] writing row to CSV: %s", wErr) - } - } - } - } - csvWriter.Flush() - ioErr := csvFile.Close() - if ioErr != nil { - fmt.Println(ioErr) - log.Printf("[ERROR] closing audit file: %s", ioErr) - } - fmt.Printf("Audit report written to %s\n", outpath) - return data, actions, nil -} - -func reconcileRoots(actions map[string][]ROTAction, kfClient *api.Client, reportFile string, dryRun bool) error { - log.Printf("[DEBUG] Reconciling roots") - if len(actions) == 0 { - log.Printf("[INFO] No actions to take, roots are up-to-date.") - return nil - } - rFileName := fmt.Sprintf("%s_reconciled.csv", strings.Split(reportFile, ".csv")[0]) - csvFile, fErr := os.Create(rFileName) - if fErr != nil { - fmt.Printf("[ERROR] creating reconciled report file: %s", fErr) - } - csvWriter := csv.NewWriter(csvFile) - cErr := csvWriter.Write(ReconciledAuditHeader) - if cErr != nil { - fmt.Printf("%s", cErr) - log.Fatalf("[ERROR] writing audit header: %s", cErr) - } - for thumbprint, action := range actions { - - for _, a := range action { - if a.AddCert { - log.Printf("[INFO] Adding cert %s to store %s(%s)", thumbprint, a.StoreID, a.StorePath) - if !dryRun { - cStore := api.CertificateStore{ - CertificateStoreId: a.StoreID, - Overwrite: true, - } - var stores []api.CertificateStore - stores = append(stores, cStore) - schedule := &api.InventorySchedule{ - Immediate: boolToPointer(true), - } - addReq := api.AddCertificateToStore{ - CertificateId: a.CertID, - CertificateStores: &stores, - InventorySchedule: schedule, - } - log.Printf("[DEBUG] Adding cert %s to store %s", thumbprint, a.StoreID) - log.Printf("[TRACE] Add request: %+v", addReq) - addReqJSON, _ := json.Marshal(addReq) - log.Printf("[TRACE] Add request JSON: %s", addReqJSON) - _, err := kfClient.AddCertificateToStores(&addReq) - if err != nil { - fmt.Printf("[ERROR] adding cert %s (%d) to store %s (%s): %s\n", a.Thumbprint, a.CertID, a.StoreID, a.StorePath, err) - continue - } - } else { - log.Printf("[INFO] DRY RUN: Would have added cert %s from store %s", thumbprint, a.StoreID) - } - } else if a.RemoveCert { - if !dryRun { - log.Printf("[INFO] Removing cert from store %s", a.StoreID) - cStore := api.CertificateStore{ - CertificateStoreId: a.StoreID, - Alias: a.Thumbprint, - } - var stores []api.CertificateStore - stores = append(stores, cStore) - schedule := &api.InventorySchedule{ - Immediate: boolToPointer(true), - } - removeReq := api.RemoveCertificateFromStore{ - CertificateId: a.CertID, - CertificateStores: &stores, - InventorySchedule: schedule, - } - _, err := kfClient.RemoveCertificateFromStores(&removeReq) - if err != nil { - fmt.Printf("[ERROR] removing cert %s (ID: %d) from store %s (%s): %s\n", a.Thumbprint, a.CertID, a.StoreID, a.StorePath, err) - } - } else { - fmt.Printf("DRY RUN: Would have removed cert %s from store %s\n", thumbprint, a.StoreID) - log.Printf("[INFO] DRY RUN: Would have removed cert %s from store %s", thumbprint, a.StoreID) - } - } - } - } - return nil -} - -func readCertsFile(certsFilePath string, kfclient *api.Client) (map[string]string, error) { - // Read in the cert CSV - csvFile, _ := os.Open(certsFilePath) - reader := csv.NewReader(bufio.NewReader(csvFile)) - certEntries, _ := reader.ReadAll() - var certs = make(map[string]string) - for _, entry := range certEntries { - switch entry[0] { - case "CertID", "thumbprint", "id", "CertId", "Thumbprint": - continue // Skip header - } - certs[entry[0]] = entry[0] - } - return certs, nil -} - -func isRootStore(st *api.GetCertificateStoreResponse, invs *[]api.CertStoreInventoryV1, minCerts int, maxKeys int, maxLeaf int) bool { - leafCount := 0 - keyCount := 0 - certCount := 0 - for _, inv := range *invs { - log.Printf("[DEBUG] inv: %v", inv) - certCount += len(inv.Certificates) - - for _, cert := range inv.Certificates { - if cert.IssuedDN != cert.IssuerDN { - leafCount++ - } - if inv.Parameters["PrivateKeyEntry"] == "Yes" { - keyCount++ - } - } - } - if certCount < minCerts && minCerts >= 0 { - log.Printf("[DEBUG] Store %s has %d certs, less than the required count of %d", st.Id, certCount, minCerts) - return false - } - if leafCount > maxLeaf && maxLeaf >= 0 { - log.Printf("[DEBUG] Store %s has too many leaf certs", st.Id) - return false - } - - if keyCount > maxKeys && maxKeys >= 0 { - log.Printf("[DEBUG] Store %s has too many keys", st.Id) - return false - } - - return true -} - -var ( - rotCmd = &cobra.Command{ - Use: "rot", - Short: "Root of trust utility", - Long: `Root of trust allows you to manage your trusted roots using Keyfactor certificate stores. -For example if you wish to add a list of "root" certs to a list of certificate stores you would simply generate and fill -out the template CSV file. These template files can be generated with the following commands: -kfutil stores rot generate-template --type certs -kfutil stores rot generate-template --type stores -Once those files are filled out you can use the following command to add the certs to the stores: -kfutil stores rot audit --certs-file --stores-file -Will generate a CSV report file 'rot_audit.csv' of what actions will be taken. If those actions are correct you can run -the following command to actually perform the actions: -kfutil stores rot reconcile --certs-file --stores-file -OR if you want to use the audit report file generated you can run this command: -kfutil stores rot reconcile --import-csv -`, - } - rotAuditCmd = &cobra.Command{ - Use: "audit", - Aliases: nil, - SuggestFor: nil, - Short: "Audit generates a CSV report of what actions will be taken based on input CSV files.", - 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.`, - Example: "", - ValidArgs: nil, - ValidArgsFunction: nil, - Args: nil, - ArgAliases: nil, - BashCompletionFunction: "", - Deprecated: "", - Annotations: nil, - Version: "", - PersistentPreRun: nil, - PersistentPreRunE: nil, - PreRun: nil, - PreRunE: nil, - Run: func(cmd *cobra.Command, args []string) { - // Global flags - debugFlag, _ := cmd.Flags().GetBool("debugFlag") - configFile, _ := cmd.Flags().GetString("config") - noPrompt, _ := cmd.Flags().GetBool("no-prompt") - profile, _ := cmd.Flags().GetString("profile") - - kfcUsername, _ := cmd.Flags().GetString("kfcUsername") - kfcPassword, _ := cmd.Flags().GetString("kfcPassword") - kfcDomain, _ := cmd.Flags().GetString("kfcDomain") - - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) - - debugModeEnabled := checkDebug(debugFlag) - log.Println("Debug mode enabled: ", debugModeEnabled) - var lookupFailures []string - kfClient, _ := initClient(configFile, profile, "", "", noPrompt, authConfig, false) - storesFile, _ := cmd.Flags().GetString("stores") - addRootsFile, _ := cmd.Flags().GetString("add-certs") - removeRootsFile, _ := cmd.Flags().GetString("remove-certs") - minCerts, _ := cmd.Flags().GetInt("min-certs") - maxLeaves, _ := cmd.Flags().GetInt("max-leaf-certs") - maxKeys, _ := cmd.Flags().GetInt("max-keys") - dryRun, _ := cmd.Flags().GetBool("dry-run") - outpath, _ := cmd.Flags().GetString("outpath") - // Read in the stores CSV - log.Printf("[DEBUG] storesFile: %s", storesFile) - log.Printf("[DEBUG] addRootsFile: %s", addRootsFile) - log.Printf("[DEBUG] removeRootsFile: %s", removeRootsFile) - log.Printf("[DEBUG] dryRun: %t", dryRun) - // Read in the stores CSV - csvFile, _ := os.Open(storesFile) - reader := csv.NewReader(bufio.NewReader(csvFile)) - storeEntries, _ := reader.ReadAll() - var stores = make(map[string]StoreCSVEntry) - validHeader := false - for _, entry := range storeEntries { - if strings.EqualFold(strings.Join(entry, ","), strings.Join(StoreHeader, ",")) { - validHeader = true - continue // Skip header - } - if !validHeader { - fmt.Printf("[ERROR] Invalid header in stores file. Expected: %s", strings.Join(StoreHeader, ",")) - log.Fatalf("[ERROR] Stores CSV file is missing a valid header") - } - apiResp, err := kfClient.GetCertificateStoreByID(entry[0]) - if err != nil { - log.Printf("[ERROR] getting cert store: %s", err) - _ = append(lookupFailures, strings.Join(entry, ",")) - continue - } - - inventory, invErr := kfClient.GetCertStoreInventoryV1(entry[0]) - if invErr != nil { - log.Printf("[ERROR] getting cert store inventory for: %s\n%s", entry[0], invErr) - } - - if !isRootStore(apiResp, inventory, minCerts, maxLeaves, maxKeys) { - fmt.Printf("Store %s is not a root store, skipping.\n", entry[0]) - log.Printf("[WARN] Store %s is not a root store", apiResp.Id) - continue - } else { - log.Printf("[INFO] Store %s is a root store", apiResp.Id) - } - - stores[entry[0]] = StoreCSVEntry{ - ID: entry[0], - Type: entry[1], - Machine: entry[2], - Path: entry[3], - Thumbprints: make(map[string]bool), - Serials: make(map[string]bool), - Ids: make(map[int]bool), - } - for _, cert := range *inventory { - thumb := cert.Thumbprints - for t, v := range thumb { - stores[entry[0]].Thumbprints[t] = v - } - for t, v := range cert.Serials { - stores[entry[0]].Serials[t] = v - } - for t, v := range cert.Ids { - stores[entry[0]].Ids[t] = v - } - } - - } - - // Read in the add addCerts CSV - var certsToAdd = make(map[string]string) - if addRootsFile != "" { - var rcfErr error - certsToAdd, rcfErr = readCertsFile(addRootsFile, kfClient) - if rcfErr != nil { - fmt.Printf("[ERROR] reading certs file %s: %s", addRootsFile, rcfErr) - log.Fatalf("[ERROR] reading addCerts file: %s", rcfErr) - } - addCertsJSON, _ := json.Marshal(certsToAdd) - log.Printf("[DEBUG] add certs JSON: %s", string(addCertsJSON)) - log.Println("[DEBUG] AddCert ROT called") - } else { - log.Printf("[DEBUG] No addCerts file specified") - log.Printf("[DEBUG] No addCerts = %s", certsToAdd) - } - - // Read in the remove removeCerts CSV - var certsToRemove = make(map[string]string) - if removeRootsFile != "" { - var rcfErr error - certsToRemove, rcfErr = readCertsFile(removeRootsFile, kfClient) - if rcfErr != nil { - fmt.Printf("[ERROR] reading removeCerts file %s: %s", removeRootsFile, rcfErr) - log.Fatalf("[ERROR] reading removeCerts file: %s", rcfErr) - } - removeCertsJSON, _ := json.Marshal(certsToRemove) - log.Printf("[DEBUG] remove certs JSON: %s", string(removeCertsJSON)) - } else { - log.Printf("[DEBUG] No removeCerts file specified") - log.Printf("[DEBUG] No removeCerts = %s", certsToRemove) - } - _, _, gErr := generateAuditReport(certsToAdd, certsToRemove, stores, outpath, kfClient) - if gErr != nil { - log.Fatalf("[ERROR] generating audit report: %s", gErr) - } - }, - RunE: nil, - PostRun: nil, - PostRunE: nil, - PersistentPostRun: nil, - PersistentPostRunE: nil, - FParseErrWhitelist: cobra.FParseErrWhitelist{}, - CompletionOptions: cobra.CompletionOptions{}, - TraverseChildren: false, - Hidden: false, - SilenceErrors: false, - SilenceUsage: false, - DisableFlagParsing: false, - DisableAutoGenTag: false, - DisableFlagsInUseLine: false, - DisableSuggestions: false, - SuggestionsMinimumDistance: 0, - } - rotReconcileCmd = &cobra.Command{ - Use: "reconcile", - Aliases: nil, - SuggestFor: nil, - Short: "Reconcile either takes in or will generate an audit report and then add/remove certs as needed.", - Long: `Root of Trust (rot): Will parse either a combination of CSV files that define certs to -add and/or certs to remove with a CSV of certificate stores or an audit CSV file. If an audit CSV file is provided, the -add and remove actions defined in the audit file will be immediately executed. If a combination of CSV files are provided, -the utility will first generate an audit report and then execute the add/remove actions defined in the audit report.`, - Example: "", - ValidArgs: nil, - ValidArgsFunction: nil, - Args: nil, - ArgAliases: nil, - BashCompletionFunction: "", - Deprecated: "", - Annotations: nil, - Version: "", - PersistentPreRun: nil, - PersistentPreRunE: nil, - PreRun: nil, - PreRunE: nil, - Run: func(cmd *cobra.Command, args []string) { - // Global flags - debugFlag, _ := cmd.Flags().GetBool("debugFlag") - configFile, _ := cmd.Flags().GetString("config") - noPrompt, _ := cmd.Flags().GetBool("no-prompt") - profile, _ := cmd.Flags().GetString("profile") - - kfcUsername, _ := cmd.Flags().GetString("kfcUsername") - kfcPassword, _ := cmd.Flags().GetString("kfcPassword") - kfcDomain, _ := cmd.Flags().GetString("kfcDomain") - - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) - - debugModeEnabled := checkDebug(debugFlag) - - log.Println("Debug mode enabled: ", debugModeEnabled) - - var lookupFailures []string - kfClient, _ := initClient(configFile, profile, "", "", noPrompt, authConfig, false) - storesFile, _ := cmd.Flags().GetString("stores") - addRootsFile, _ := cmd.Flags().GetString("add-certs") - isCSV, _ := cmd.Flags().GetBool("import-csv") - reportFile, _ := cmd.Flags().GetString("input-file") - removeRootsFile, _ := cmd.Flags().GetString("remove-certs") - minCerts, _ := cmd.Flags().GetInt("min-certs") - maxLeaves, _ := cmd.Flags().GetInt("max-leaf-certs") - maxKeys, _ := cmd.Flags().GetInt("max-keys") - dryRun, _ := cmd.Flags().GetBool("dry-run") - outpath, _ := cmd.Flags().GetString("outpath") - - log.Printf("[DEBUG] configFile: %s", configFile) - log.Printf("[DEBUG] storesFile: %s", storesFile) - log.Printf("[DEBUG] addRootsFile: %s", addRootsFile) - log.Printf("[DEBUG] removeRootsFile: %s", removeRootsFile) - log.Printf("[DEBUG] dryRun: %t", dryRun) - - // Parse existing audit report - if isCSV && reportFile != "" { - log.Printf("[DEBUG] isCSV: %t", isCSV) - log.Printf("[DEBUG] reportFile: %s", reportFile) - // Read in the CSV - csvFile, err := os.Open(reportFile) - if err != nil { - fmt.Printf("[ERROR] opening file: %s", err) - log.Fatalf("[ERROR] opening CSV file: %s", err) - } - validHeader := false - - aCSV := csv.NewReader(csvFile) - aCSV.FieldsPerRecord = -1 - inFile, cErr := aCSV.ReadAll() - if cErr != nil { - fmt.Printf("[ERROR] reading CSV file: %s", cErr) - log.Fatalf("[ERROR] reading CSV file: %s", cErr) - } - actions := make(map[string][]ROTAction) - fieldMap := make(map[int]string) - for i, field := range AuditHeader { - fieldMap[i] = field - } - for ri, row := range inFile { - if strings.EqualFold(strings.Join(row, ","), strings.Join(AuditHeader, ",")) { - validHeader = true - continue // Skip header - } - if !validHeader { - fmt.Printf("[ERROR] Invalid header in stores file. Expected: %s", strings.Join(AuditHeader, ",")) - log.Fatalf("[ERROR] Stores CSV file is missing a valid header") - } - action := make(map[string]interface{}) - - for i, field := range row { - fieldInt, iErr := strconv.Atoi(field) - if iErr != nil { - log.Printf("[DEBUG] Field %s is not an int", field) - action[fieldMap[i]] = field - } else { - action[fieldMap[i]] = fieldInt - } - - } - - addCertStr, aOk := action["AddCert"].(string) - if !aOk { - addCertStr = "" - } - addCert, acErr := strconv.ParseBool(addCertStr) - if acErr != nil { - addCert = false - } - - removeCertStr, rOk := action["RemoveCert"].(string) - if !rOk { - removeCertStr = "" - } - removeCert, rcErr := strconv.ParseBool(removeCertStr) - if rcErr != nil { - removeCert = false - } - - sType, sOk := action["StoreType"].(string) - if !sOk { - sType = "" - } - - sPath, pOk := action["Path"].(string) - if !pOk { - sPath = "" - } - - tp, tpOk := action["Thumbprint"].(string) - if !tpOk { - tp = "" - } - cid, cidOk := action["CertID"].(int) - if !cidOk { - cid = -1 - } - - if !tpOk && !cidOk { - fmt.Printf("[ERROR] Missing Thumbprint or CertID for row %d in report file %s", ri, reportFile) - log.Printf("[ERROR] Invalid action: %v", action) - continue - } - - sId, sIdOk := action["StoreID"].(string) - if !sIdOk { - fmt.Printf("[ERROR] Missing StoreID for row %d in report file %s", ri, reportFile) - log.Printf("[ERROR] Invalid action: %v", action) - continue - } - if cid == -1 && tp != "" { - certLookupReq := api.GetCertificateContextArgs{ - IncludeMetadata: boolToPointer(true), - IncludeLocations: boolToPointer(true), - CollectionId: nil, - Thumbprint: tp, - Id: 0, - } - certLookup, err := kfClient.GetCertificateContext(&certLookupReq) - if err != nil { - fmt.Printf("[ERROR] looking up certificate %s: %s\n", tp, err) - log.Printf("[ERROR] looking up cert: %s\n%v", tp, err) - continue - } - cid = certLookup.Id - } - - a := ROTAction{ - StoreID: sId, - StoreType: sType, - StorePath: sPath, - Thumbprint: tp, - CertID: cid, - AddCert: addCert, - RemoveCert: removeCert, - } - - actions[a.Thumbprint] = append(actions[a.Thumbprint], a) - } - if len(actions) == 0 { - fmt.Println("No reconciliation actions to take, root stores are up-to-date. Exiting.") - return - } - rErr := reconcileRoots(actions, kfClient, reportFile, dryRun) - if rErr != nil { - fmt.Printf("[ERROR] reconciling roots: %s", rErr) - log.Fatalf("[ERROR] reconciling roots: %s", rErr) - } - defer csvFile.Close() - - orchsURL := fmt.Sprintf("https://%s/Keyfactor/Portal/AgentJobStatus/Index", kfClient.Hostname) - - fmt.Println(fmt.Sprintf("Reconciliation completed. Check orchestrator jobs for details. %s", orchsURL)) - } else { - // Read in the stores CSV - csvFile, _ := os.Open(storesFile) - reader := csv.NewReader(bufio.NewReader(csvFile)) - storeEntries, _ := reader.ReadAll() - var stores = make(map[string]StoreCSVEntry) - for i, entry := range storeEntries { - if entry[0] == "StoreID" || entry[0] == "StoreId" || i == 0 { - continue // Skip header - } - apiResp, err := kfClient.GetCertificateStoreByID(entry[0]) - if err != nil { - log.Printf("[ERROR] getting cert store: %s", err) - lookupFailures = append(lookupFailures, entry[0]) - continue - } - inventory, invErr := kfClient.GetCertStoreInventoryV1(entry[0]) - if invErr != nil { - log.Fatalf("[ERROR] getting cert store inventory: %s", invErr) - } - - if !isRootStore(apiResp, inventory, minCerts, maxLeaves, maxKeys) { - log.Printf("[WARN] Store %s is not a root store", apiResp.Id) - continue - } else { - log.Printf("[INFO] Store %s is a root store", apiResp.Id) - } - - stores[entry[0]] = StoreCSVEntry{ - ID: entry[0], - Type: entry[1], - Machine: entry[2], - Path: entry[3], - Thumbprints: make(map[string]bool), - Serials: make(map[string]bool), - Ids: make(map[int]bool), - } - for _, cert := range *inventory { - thumb := cert.Thumbprints - for t, v := range thumb { - stores[entry[0]].Thumbprints[t] = v - } - for t, v := range cert.Serials { - stores[entry[0]].Serials[t] = v - } - for t, v := range cert.Ids { - stores[entry[0]].Ids[t] = v - } - } - - } - if len(lookupFailures) > 0 { - fmt.Printf("[ERROR] the following stores were not found: %s", strings.Join(lookupFailures, ",")) - log.Fatalf("[ERROR] the following stores were not found: %s", strings.Join(lookupFailures, ",")) - } - if len(stores) == 0 { - fmt.Println("[ERROR] no root stores found. Exiting.") - log.Fatalf("[ERROR] No root stores found. Exiting.") - } - // Read in the add addCerts CSV - var certsToAdd = make(map[string]string) - if addRootsFile != "" { - certsToAdd, _ = readCertsFile(addRootsFile, kfClient) - log.Printf("[DEBUG] ROT add certs called") - } else { - log.Printf("[INFO] No addCerts file specified") - } - - // Read in the remove removeCerts CSV - var certsToRemove = make(map[string]string) - if removeRootsFile != "" { - certsToRemove, _ = readCertsFile(removeRootsFile, kfClient) - log.Printf("[DEBUG] ROT remove certs called") - } else { - log.Printf("[DEBUG] No removeCerts file specified") - } - _, actions, err := generateAuditReport(certsToAdd, certsToRemove, stores, outpath, kfClient) - if err != nil { - log.Fatalf("[ERROR] generating audit report: %s", err) - } - if len(actions) == 0 { - fmt.Println("No reconciliation actions to take, root stores are up-to-date. Exiting.") - return - } - rErr := reconcileRoots(actions, kfClient, reportFile, dryRun) - if rErr != nil { - fmt.Printf("[ERROR] reconciling roots: %s", rErr) - log.Fatalf("[ERROR] reconciling roots: %s", rErr) - } - if lookupFailures != nil { - fmt.Printf("The following stores could not be found: %s", strings.Join(lookupFailures, ",")) - } - orchsURL := fmt.Sprintf("https://%s/Keyfactor/Portal/AgentJobStatus/Index", kfClient.Hostname) - - fmt.Println(fmt.Sprintf("Reconciliation completed. Check orchestrator jobs for details. %s", orchsURL)) - } - - }, - RunE: nil, - PostRun: nil, - PostRunE: nil, - PersistentPostRun: nil, - PersistentPostRunE: nil, - FParseErrWhitelist: cobra.FParseErrWhitelist{}, - CompletionOptions: cobra.CompletionOptions{}, - TraverseChildren: false, - Hidden: false, - SilenceErrors: false, - SilenceUsage: false, - DisableFlagParsing: false, - DisableAutoGenTag: false, - DisableFlagsInUseLine: false, - DisableSuggestions: false, - SuggestionsMinimumDistance: 0, - } - rotGenStoreTemplateCmd = &cobra.Command{ - Use: "generate-template", - Aliases: nil, - SuggestFor: nil, - Short: "For generating Root Of Trust template(s)", - Long: `Root Of Trust: Will parse a CSV and attempt to deploy a cert or set of certs into a list of cert stores.`, - Example: "", - ValidArgs: nil, - ValidArgsFunction: nil, - Args: nil, - ArgAliases: nil, - BashCompletionFunction: "", - Deprecated: "", - Annotations: nil, - Version: "", - PersistentPreRun: nil, - PersistentPreRunE: nil, - PreRun: nil, - PreRunE: nil, - Run: func(cmd *cobra.Command, args []string) { - // Global flags - debugFlag, _ := cmd.Flags().GetBool("debugFlag") - configFile, _ := cmd.Flags().GetString("config") - noPrompt, _ := cmd.Flags().GetBool("no-prompt") - profile, _ := cmd.Flags().GetString("profile") - - kfcUsername, _ := cmd.Flags().GetString("kfcUsername") - kfcPassword, _ := cmd.Flags().GetString("kfcPassword") - kfcDomain, _ := cmd.Flags().GetString("kfcDomain") - - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) - - debugModeEnabled := checkDebug(debugFlag) - log.Println("Debug mode enabled: ", debugModeEnabled) - - templateType, _ := cmd.Flags().GetString("type") - format, _ := cmd.Flags().GetString("format") - outPath, _ := cmd.Flags().GetString("outpath") - storeType, _ := cmd.Flags().GetStringSlice("store-type") - containerName, _ := cmd.Flags().GetStringSlice("container-name") - collection, _ := cmd.Flags().GetStringSlice("collection") - subjectName, _ := cmd.Flags().GetStringSlice("cn") - stID := -1 - var storeData []api.GetCertificateStoreResponse - var csvStoreData [][]string - var csvCertData [][]string - var rowLookup = make(map[string]bool) - kfClient, cErr := initClient(configFile, profile, "", "", noPrompt, authConfig, false) - if len(storeType) != 0 { - for _, s := range storeType { - if cErr != nil { - log.Fatalf("[ERROR] creating client: %s", cErr) - } - var sType *api.CertificateStoreType - var stErr error - if s == "all" { - sType = &api.CertificateStoreType{ - Name: "", - ShortName: "", - Capability: "", - StoreType: 0, - ImportType: 0, - LocalStore: false, - SupportedOperations: nil, - Properties: nil, - EntryParameters: nil, - PasswordOptions: nil, - StorePathType: "", - StorePathValue: "", - PrivateKeyAllowed: "", - JobProperties: nil, - ServerRequired: false, - PowerShell: false, - BlueprintAllowed: false, - CustomAliasAllowed: "", - ServerRegistration: 0, - InventoryEndpoint: "", - InventoryJobType: "", - ManagementJobType: "", - DiscoveryJobType: "", - EnrollmentJobType: "", - } - } else { - // check if s is an int - sInt, err := strconv.Atoi(s) - if err == nil { - sType, stErr = kfClient.GetCertificateStoreTypeById(sInt) - } else { - sType, stErr = kfClient.GetCertificateStoreTypeByName(s) - } - if stErr != nil { - fmt.Printf("[ERROR] getting store type '%s'. %s\n", s, stErr) - continue - } - stID = sType.StoreType // This is the template type ID - } - - if stID >= 0 || s == "all" { - log.Printf("[DEBUG] Store type ID: %d\n", stID) - params := make(map[string]interface{}) - stores, sErr := kfClient.ListCertificateStores(¶ms) - if sErr != nil { - fmt.Printf("[ERROR] getting certificate stores of type '%s': %s\n", s, sErr) - log.Fatalf("[ERROR] getting certificate stores of type '%s': %s", s, sErr) - } - for _, store := range *stores { - if store.CertStoreType == stID || s == "all" { - storeData = append(storeData, store) - if !rowLookup[store.Id] { - lineData := []string{ - //"StoreID", "StoreType", "StoreMachine", "StorePath", "ContainerId" - store.Id, fmt.Sprintf("%s", sType.ShortName), store.ClientMachine, store.StorePath, fmt.Sprintf("%d", store.ContainerId), store.ContainerName, getCurrentTime(""), - } - csvStoreData = append(csvStoreData, lineData) - rowLookup[store.Id] = true - } - } - } - } - } - fmt.Println("Done") - } - if len(containerName) != 0 { - for _, c := range containerName { - - if cErr != nil { - log.Fatalf("[ERROR] creating client: %s", cErr) - } - cStoresResp, scErr := kfClient.GetCertificateStoreByContainerID(c) - if scErr != nil { - fmt.Printf("[ERROR] getting store container: %s\n", scErr) - } - if cStoresResp != nil { - for _, store := range *cStoresResp { - sType, stErr := kfClient.GetCertificateStoreType(store.CertStoreType) - if stErr != nil { - fmt.Printf("[ERROR] getting store type: %s\n", stErr) - continue - } - storeData = append(storeData, store) - if !rowLookup[store.Id] { - lineData := []string{ - // "StoreID", "StoreType", "StoreMachine", "StorePath", "ContainerId" - store.Id, sType.ShortName, store.ClientMachine, store.StorePath, fmt.Sprintf("%d", store.ContainerId), store.ContainerName, getCurrentTime(""), - } - csvStoreData = append(csvStoreData, lineData) - rowLookup[store.Id] = true - } - } - - } - } - } - if len(collection) != 0 { - for _, c := range collection { - if cErr != nil { - fmt.Println("[ERROR] connecting to Keyfactor. Please check your configuration and try again.") - log.Fatalf("[ERROR] creating client: %s", cErr) - } - q := make(map[string]string) - q["collection"] = c - certsResp, scErr := kfClient.ListCertificates(q) - if scErr != nil { - fmt.Printf("No certificates found in collection: %s\n", scErr) - } - if certsResp != nil { - for _, cert := range certsResp { - if !rowLookup[cert.Thumbprint] { - lineData := []string{ - // "Thumbprint", "SubjectName", "Issuer", "CertID", "Locations", "LastQueriedDate" - cert.Thumbprint, cert.IssuedCN, cert.IssuerDN, fmt.Sprintf("%d", cert.Id), fmt.Sprintf("%v", cert.Locations), getCurrentTime(""), - } - csvCertData = append(csvCertData, lineData) - rowLookup[cert.Thumbprint] = true - } - } - - } - } - } - if len(subjectName) != 0 { - for _, s := range subjectName { - if cErr != nil { - fmt.Println("[ERROR] connecting to Keyfactor. Please check your configuration and try again.") - log.Fatalf("[ERROR] creating client: %s", cErr) - } - q := make(map[string]string) - q["subject"] = s - certsResp, scErr := kfClient.ListCertificates(q) - if scErr != nil { - fmt.Printf("No certificates found with CN: %s\n", scErr) - } - if certsResp != nil { - for _, cert := range certsResp { - if !rowLookup[cert.Thumbprint] { - locationsFormatted := "" - for _, loc := range cert.Locations { - locationsFormatted += fmt.Sprintf("%s:%s\n", loc.StoreMachine, loc.StorePath) - } - lineData := []string{ - // "Thumbprint", "SubjectName", "Issuer", "CertID", "Locations", "LastQueriedDate" - cert.Thumbprint, cert.IssuedCN, cert.IssuerDN, fmt.Sprintf("%d", cert.Id), locationsFormatted, getCurrentTime(""), - } - csvCertData = append(csvCertData, lineData) - rowLookup[cert.Thumbprint] = true - } - } - - } - } - } - // Create CSV template file - - var filePath string - if outPath != "" { - filePath = outPath - } else { - filePath = fmt.Sprintf("%s_template.%s", templateType, format) - } - file, err := os.Create(filePath) - if err != nil { - fmt.Printf("[ERROR] creating file: %s", err) - log.Fatal("Cannot create file", err) - } - - switch format { - case "csv": - writer := csv.NewWriter(file) - var data [][]string - switch templateType { - case "stores": - data = append(data, StoreHeader) - if len(csvStoreData) != 0 { - data = append(data, csvStoreData...) - } - case "certs": - data = append(data, CertHeader) - if len(csvCertData) != 0 { - data = append(data, csvCertData...) - } - case "actions": - data = append(data, AuditHeader) - } - csvErr := writer.WriteAll(data) - if csvErr != nil { - fmt.Println(csvErr) - } - defer file.Close() - - case "json": - writer := bufio.NewWriter(file) - _, err := writer.WriteString("StoreID,StoreType,StoreMachine,StorePath") - if err != nil { - log.Fatal("Cannot write to file", err) - } - } - fmt.Printf("Template file created at %s.\n", filePath) - }, - RunE: nil, - PostRun: nil, - PostRunE: nil, - PersistentPostRun: nil, - PersistentPostRunE: nil, - FParseErrWhitelist: cobra.FParseErrWhitelist{}, - CompletionOptions: cobra.CompletionOptions{}, - TraverseChildren: false, - Hidden: false, - SilenceErrors: false, - SilenceUsage: false, - DisableFlagParsing: false, - DisableAutoGenTag: false, - DisableFlagsInUseLine: false, - DisableSuggestions: false, - SuggestionsMinimumDistance: 0, - } -) - -func init() { - log.SetFlags(log.LstdFlags | log.Lshortfile) - log.SetOutput(os.Stdout) - var ( - stores string - addCerts string - removeCerts string - minCertsInStore int - maxPrivateKeys int - maxLeaves int - tType = tTypeCerts - outPath string - outputFormat string - inputFile string - storeTypes []string - containerNames []string - collections []string - subjectNames []string - ) - - storesCmd.AddCommand(rotCmd) - - // Root of trust `audit` command - rotCmd.AddCommand(rotAuditCmd) - rotAuditCmd.Flags().StringVarP(&stores, "stores", "s", "", "CSV file containing cert stores to enroll into") - rotAuditCmd.Flags().StringVarP(&addCerts, "add-certs", "a", "", - "CSV file containing cert(s) to enroll into the defined cert stores") - rotAuditCmd.Flags().StringVarP(&removeCerts, "remove-certs", "r", "", - "CSV file containing cert(s) to remove from the defined cert stores") - rotAuditCmd.Flags().IntVarP(&minCertsInStore, "min-certs", "m", -1, - "The minimum number of certs that should be in a store to be considered a 'root' store. If set to `-1` then all stores will be considered.") - rotAuditCmd.Flags().IntVarP(&maxPrivateKeys, "max-keys", "k", -1, - "The max number of private keys that should be in a store to be considered a 'root' store. If set to `-1` then all stores will be considered.") - rotAuditCmd.Flags().IntVarP(&maxLeaves, "max-leaf-certs", "l", -1, - "The max number of non-root-certs that should be in a store to be considered a 'root' store. If set to `-1` then all stores will be considered.") - rotAuditCmd.Flags().BoolP("dry-run", "d", false, "Dry run mode") - rotAuditCmd.Flags().StringVarP(&outPath, "outpath", "o", "", - "Path to write the audit report file to. If not specified, the file will be written to the current directory.") - - // Root of trust `reconcile` command - rotCmd.AddCommand(rotReconcileCmd) - rotReconcileCmd.Flags().StringVarP(&stores, "stores", "s", "", "CSV file containing cert stores to enroll into") - rotReconcileCmd.Flags().StringVarP(&addCerts, "add-certs", "a", "", - "CSV file containing cert(s) to enroll into the defined cert stores") - rotReconcileCmd.Flags().StringVarP(&removeCerts, "remove-certs", "r", "", - "CSV file containing cert(s) to remove from the defined cert stores") - rotReconcileCmd.Flags().IntVarP(&minCertsInStore, "min-certs", "m", -1, - "The minimum number of certs that should be in a store to be considered a 'root' store. If set to `-1` then all stores will be considered.") - rotReconcileCmd.Flags().IntVarP(&maxPrivateKeys, "max-keys", "k", -1, - "The max number of private keys that should be in a store to be considered a 'root' store. If set to `-1` then all stores will be considered.") - rotReconcileCmd.Flags().IntVarP(&maxLeaves, "max-leaf-certs", "l", -1, - "The max number of non-root-certs that should be in a store to be considered a 'root' store. If set to `-1` then all stores will be considered.") - rotReconcileCmd.Flags().BoolP("dry-run", "d", false, "Dry run mode") - rotReconcileCmd.Flags().BoolP("import-csv", "v", false, "Import an audit report file in CSV format.") - rotReconcileCmd.Flags().StringVarP(&inputFile, "input-file", "i", reconcileDefaultFileName, - "Path to a file generated by 'stores rot audit' command.") - rotReconcileCmd.Flags().StringVarP(&outPath, "outpath", "o", "", - "Path to write the audit report file to. If not specified, the file will be written to the current directory.") - //rotReconcileCmd.MarkFlagsRequiredTogether("add-certs", "stores") - //rotReconcileCmd.MarkFlagsRequiredTogether("remove-certs", "stores") - rotReconcileCmd.MarkFlagsMutuallyExclusive("add-certs", "import-csv") - rotReconcileCmd.MarkFlagsMutuallyExclusive("remove-certs", "import-csv") - rotReconcileCmd.MarkFlagsMutuallyExclusive("stores", "import-csv") - - // Root of trust `generate` command - rotCmd.AddCommand(rotGenStoreTemplateCmd) - rotGenStoreTemplateCmd.Flags().StringVarP(&outPath, "outpath", "o", "", - "Path to write the template file to. If not specified, the file will be written to the current directory.") - rotGenStoreTemplateCmd.Flags().StringVarP(&outputFormat, "format", "f", "csv", - "The type of template to generate. Only `csv` is supported at this time.") - rotGenStoreTemplateCmd.Flags().Var(&tType, "type", - `The type of template to generate. Only "certs|stores|actions" are supported at this time.`) - rotGenStoreTemplateCmd.Flags().StringSliceVar(&storeTypes, "store-type", []string{}, "Multi value flag. Attempt to pre-populate the stores template with the certificate stores matching specified store types. If not specified, the template will be empty.") - rotGenStoreTemplateCmd.Flags().StringSliceVar(&containerNames, "container-name", []string{}, "Multi value flag. Attempt to pre-populate the stores template with the certificate stores matching specified container types. If not specified, the template will be empty.") - rotGenStoreTemplateCmd.Flags().StringSliceVar(&subjectNames, "cn", []string{}, "Subject name(s) to pre-populate the 'certs' template with. If not specified, the template will be empty. Does not work with SANs.") - rotGenStoreTemplateCmd.Flags().StringSliceVar(&collections, "collection", []string{}, "Certificate collection name(s) to pre-populate the stores template with. If not specified, the template will be empty.") - - rotGenStoreTemplateCmd.RegisterFlagCompletionFunc("type", templateTypeCompletion) - rotGenStoreTemplateCmd.MarkFlagRequired("type") -} +//import ( +// "bufio" +// "encoding/csv" +// "encoding/json" +// "errors" +// "fmt" +// "log" +// "os" +// "strconv" +// "strings" +// +// "github.com/Keyfactor/keyfactor-go-client/v3/api" +// "github.com/spf13/cobra" +//) +// +//type templateType string +//type StoreCSVEntry struct { +// ID string `json:"id"` +// Type string `json:"type"` +// Machine string `json:"address"` +// Path string `json:"path"` +// Thumbprints map[string]bool `json:"thumbprints,omitempty"` +// Serials map[string]bool `json:"serials,omitempty"` +// Ids map[int]bool `json:"ids,omitempty"` +//} +//type ROTCert struct { +// ID int `json:"id,omitempty"` +// ThumbPrint string `json:"thumbprint,omitempty"` +// CN string `json:"cn,omitempty"` +// Locations []api.CertificateLocations `json:"locations,omitempty"` +//} +//type ROTAction struct { +// StoreID string `json:"store_id,omitempty"` +// StoreType string `json:"store_type,omitempty"` +// StorePath string `json:"store_path,omitempty"` +// Thumbprint string `json:"thumbprint,omitempty"` +// CertID int `json:"cert_id,omitempty" mapstructure:"CertID,omitempty"` +// AddCert bool `json:"add,omitempty" mapstructure:"AddCert,omitempty"` +// RemoveCert bool `json:"remove,omitempty" mapstructure:"RemoveCert,omitempty"` +//} +// +//const ( +// tTypeCerts templateType = "certs" +// reconcileDefaultFileName string = "rot_audit.csv" +//) +// +//var ( +// AuditHeader = []string{ +// "Thumbprint", +// "CertID", +// "SubjectName", +// "Issuer", +// "StoreID", +// "StoreType", +// "Machine", +// "Path", +// "AddCert", +// "RemoveCert", +// "Deployed", +// "AuditDate", +// } +// ReconciledAuditHeader = []string{ +// "Thumbprint", +// "CertID", +// "SubjectName", +// "Issuer", +// "StoreID", +// "StoreType", +// "Machine", +// "Path", +// "AddCert", +// "RemoveCert", +// "Deployed", +// "ReconciledDate", +// } +// StoreHeader = []string{ +// "StoreID", +// "StoreType", +// "StoreMachine", +// "StorePath", +// "ContainerId", +// "ContainerName", +// "LastQueriedDate", +// } +// CertHeader = []string{"Thumbprint", "SubjectName", "Issuer", "CertID", "Locations", "LastQueriedDate"} +//) +// +//// String is used both by fmt.Print and by Cobra in help text +//func (e *templateType) String() string { +// return string(*e) +//} +// +//// Set must have pointer receiver, so it doesn't change the value of a copy +//func (e *templateType) Set(v string) error { +// switch v { +// case "certs", "stores", "actions": +// *e = templateType(v) +// return nil +// default: +// return errors.New(`must be one of "certs", "stores", or "actions"`) +// } +//} +// +//// Type is only used in help text +//func (e *templateType) Type() string { +// return "string" +//} +// +//func templateTypeCompletion(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { +// return []string{ +// "certs\tGenerates template CSV for certificate input to be used w/ `--add-certs` or `--remove-certs`", +// "stores\tGenerates template CSV for certificate input to be used w/ `--stores`", +// "actions\tGenerates template CSV for certificate input to be used w/ `--actions`", +// }, cobra.ShellCompDirectiveDefault +//} +// +//func generateAuditReport( +// addCerts map[string]string, +// removeCerts map[string]string, +// stores map[string]StoreCSVEntry, +// outpath string, +// kfClient *api.Client, +//) ([][]string, map[string][]ROTAction, error) { +// log.Println("[DEBUG] generateAuditReport called") +// var ( +// data [][]string +// ) +// +// data = append(data, AuditHeader) +// var csvFile *os.File +// var fErr error +// if outpath == "" { +// csvFile, fErr = os.Create(reconcileDefaultFileName) +// outpath = reconcileDefaultFileName +// } else { +// csvFile, fErr = os.Create(outpath) +// } +// +// if fErr != nil { +// fmt.Printf("%s", fErr) +// log.Fatalf("[ERROR] creating audit file: %s", fErr) +// } +// csvWriter := csv.NewWriter(csvFile) +// cErr := csvWriter.Write(AuditHeader) +// if cErr != nil { +// fmt.Printf("%s", cErr) +// log.Fatalf("[ERROR] writing audit header: %s", cErr) +// } +// actions := make(map[string][]ROTAction) +// +// for _, cert := range addCerts { +// certLookupReq := api.GetCertificateContextArgs{ +// IncludeMetadata: boolToPointer(true), +// IncludeLocations: boolToPointer(true), +// CollectionId: nil, +// Thumbprint: cert, +// Id: 0, +// } +// certLookup, err := kfClient.GetCertificateContext(&certLookupReq) +// if err != nil { +// fmt.Printf("[ERROR] looking up certificate %s: %s\n", cert, err) +// log.Printf("[ERROR] looking up cert: %s\n%v", cert, err) +// continue +// } +// certID := certLookup.Id +// certIDStr := strconv.Itoa(certID) +// for _, store := range stores { +// if _, ok := store.Thumbprints[cert]; ok { +// // Cert is already in the store do nothing +// row := []string{ +// cert, +// certIDStr, +// certLookup.IssuedDN, +// certLookup.IssuerDN, +// store.ID, +// store.Type, +// store.Machine, +// store.Path, +// "false", +// "false", +// "true", +// getCurrentTime(""), +// } +// data = append(data, row) +// wErr := csvWriter.Write(row) +// if wErr != nil { +// fmt.Printf("[ERROR] writing audit file row: %s\n", wErr) +// log.Printf("[ERROR] writing audit row: %s", wErr) +// } +// } else { +// // Cert is not deployed to this store and will need to be added +// row := []string{ +// cert, +// certIDStr, +// certLookup.IssuedDN, +// certLookup.IssuerDN, +// store.ID, +// store.Type, +// store.Machine, +// store.Path, +// "true", +// "false", +// "false", +// getCurrentTime(""), +// } +// data = append(data, row) +// wErr := csvWriter.Write(row) +// if wErr != nil { +// fmt.Printf("[ERROR] writing audit file row: %s\n", wErr) +// log.Printf("[ERROR] writing audit row: %s", wErr) +// } +// actions[cert] = append( +// actions[cert], ROTAction{ +// Thumbprint: cert, +// CertID: certID, +// StoreID: store.ID, +// StoreType: store.Type, +// StorePath: store.Path, +// AddCert: true, +// RemoveCert: false, +// }, +// ) +// } +// } +// } +// for _, cert := range removeCerts { +// certLookupReq := api.GetCertificateContextArgs{ +// IncludeMetadata: boolToPointer(true), +// IncludeLocations: boolToPointer(true), +// CollectionId: nil, +// Thumbprint: cert, +// Id: 0, +// } +// certLookup, err := kfClient.GetCertificateContext(&certLookupReq) +// if err != nil { +// log.Printf("[ERROR] looking up cert: %s", err) +// continue +// } +// certID := certLookup.Id +// certIDStr := strconv.Itoa(certID) +// for _, store := range stores { +// if _, ok := store.Thumbprints[cert]; ok { +// // Cert is deployed to this store and will need to be removed +// row := []string{ +// cert, +// certIDStr, +// certLookup.IssuedDN, +// certLookup.IssuerDN, +// store.ID, +// store.Type, +// store.Machine, +// store.Path, +// "false", +// "true", +// "true", +// getCurrentTime(""), +// } +// data = append(data, row) +// wErr := csvWriter.Write(row) +// if wErr != nil { +// fmt.Printf("%s", wErr) +// log.Printf("[ERROR] writing row to CSV: %s", wErr) +// } +// actions[cert] = append( +// actions[cert], ROTAction{ +// Thumbprint: cert, +// CertID: certID, +// StoreID: store.ID, +// StoreType: store.Type, +// StorePath: store.Path, +// AddCert: false, +// RemoveCert: true, +// }, +// ) +// } else { +// // Cert is not deployed to this store do nothing +// row := []string{ +// cert, +// certIDStr, +// certLookup.IssuedDN, +// certLookup.IssuerDN, +// store.ID, +// store.Type, +// store.Machine, +// store.Path, +// "false", +// "false", +// "false", +// getCurrentTime(""), +// } +// data = append(data, row) +// wErr := csvWriter.Write(row) +// if wErr != nil { +// fmt.Printf("%s", wErr) +// log.Printf("[ERROR] writing row to CSV: %s", wErr) +// } +// } +// } +// } +// csvWriter.Flush() +// ioErr := csvFile.Close() +// if ioErr != nil { +// fmt.Println(ioErr) +// log.Printf("[ERROR] closing audit file: %s", ioErr) +// } +// fmt.Printf("Audit report written to %s\n", outpath) +// return data, actions, nil +//} +// +//func reconcileRoots(actions map[string][]ROTAction, kfClient *api.Client, reportFile string, dryRun bool) error { +// log.Printf("[DEBUG] Reconciling roots") +// if len(actions) == 0 { +// log.Printf("[INFO] No actions to take, roots are up-to-date.") +// return nil +// } +// rFileName := fmt.Sprintf("%s_reconciled.csv", strings.Split(reportFile, ".csv")[0]) +// csvFile, fErr := os.Create(rFileName) +// if fErr != nil { +// fmt.Printf("[ERROR] creating reconciled report file: %s", fErr) +// } +// csvWriter := csv.NewWriter(csvFile) +// cErr := csvWriter.Write(ReconciledAuditHeader) +// if cErr != nil { +// fmt.Printf("%s", cErr) +// log.Fatalf("[ERROR] writing audit header: %s", cErr) +// } +// for thumbprint, action := range actions { +// +// for _, a := range action { +// if a.AddCert { +// log.Printf("[INFO] Adding cert %s to store %s(%s)", thumbprint, a.StoreID, a.StorePath) +// if !dryRun { +// cStore := api.CertificateStore{ +// CertificateStoreId: a.StoreID, +// Overwrite: true, +// } +// var stores []api.CertificateStore +// stores = append(stores, cStore) +// schedule := &api.InventorySchedule{ +// Immediate: boolToPointer(true), +// } +// addReq := api.AddCertificateToStore{ +// CertificateId: a.CertID, +// CertificateStores: &stores, +// InventorySchedule: schedule, +// } +// log.Printf("[DEBUG] Adding cert %s to store %s", thumbprint, a.StoreID) +// log.Printf("[TRACE] Add request: %+v", addReq) +// addReqJSON, _ := json.Marshal(addReq) +// log.Printf("[TRACE] Add request JSON: %s", addReqJSON) +// _, err := kfClient.AddCertificateToStores(&addReq) +// if err != nil { +// fmt.Printf( +// "[ERROR] adding cert %s (%d) to store %s (%s): %s\n", +// a.Thumbprint, +// a.CertID, +// a.StoreID, +// a.StorePath, +// err, +// ) +// continue +// } +// } else { +// log.Printf("[INFO] DRY RUN: Would have added cert %s from store %s", thumbprint, a.StoreID) +// } +// } else if a.RemoveCert { +// if !dryRun { +// log.Printf("[INFO] Removing cert from store %s", a.StoreID) +// cStore := api.CertificateStore{ +// CertificateStoreId: a.StoreID, +// Alias: a.Thumbprint, +// } +// var stores []api.CertificateStore +// stores = append(stores, cStore) +// schedule := &api.InventorySchedule{ +// Immediate: boolToPointer(true), +// } +// removeReq := api.RemoveCertificateFromStore{ +// CertificateId: a.CertID, +// CertificateStores: &stores, +// InventorySchedule: schedule, +// } +// _, err := kfClient.RemoveCertificateFromStores(&removeReq) +// if err != nil { +// fmt.Printf( +// "[ERROR] removing cert %s (ID: %d) from store %s (%s): %s\n", +// a.Thumbprint, +// a.CertID, +// a.StoreID, +// a.StorePath, +// err, +// ) +// } +// } else { +// fmt.Printf("DRY RUN: Would have removed cert %s from store %s\n", thumbprint, a.StoreID) +// log.Printf("[INFO] DRY RUN: Would have removed cert %s from store %s", thumbprint, a.StoreID) +// } +// } +// } +// } +// return nil +//} +// +//func readCertsFile(certsFilePath string, kfclient *api.Client) (map[string]string, error) { +// // Read in the cert CSV +// csvFile, _ := os.Open(certsFilePath) +// reader := csv.NewReader(bufio.NewReader(csvFile)) +// certEntries, _ := reader.ReadAll() +// var certs = make(map[string]string) +// for _, entry := range certEntries { +// switch entry[0] { +// case "CertID", "thumbprint", "id", "CertId", "Thumbprint": +// continue // Skip header +// } +// certs[entry[0]] = entry[0] +// } +// return certs, nil +//} +// +//func isRootStore( +// st *api.GetCertificateStoreResponse, +// invs *[]api.CertStoreInventoryV1, +// minCerts int, +// maxKeys int, +// maxLeaf int, +//) bool { +// leafCount := 0 +// keyCount := 0 +// certCount := 0 +// for _, inv := range *invs { +// log.Printf("[DEBUG] inv: %v", inv) +// certCount += len(inv.Certificates) +// +// for _, cert := range inv.Certificates { +// if cert.IssuedDN != cert.IssuerDN { +// leafCount++ +// } +// if inv.Parameters["PrivateKeyEntry"] == "Yes" { +// keyCount++ +// } +// } +// } +// if certCount < minCerts && minCerts >= 0 { +// log.Printf("[DEBUG] Store %s has %d certs, less than the required count of %d", st.Id, certCount, minCerts) +// return false +// } +// if leafCount > maxLeaf && maxLeaf >= 0 { +// log.Printf("[DEBUG] Store %s has too many leaf certs", st.Id) +// return false +// } +// +// if keyCount > maxKeys && maxKeys >= 0 { +// log.Printf("[DEBUG] Store %s has too many keys", st.Id) +// return false +// } +// +// return true +//} +// +//var ( +// rotCmd = &cobra.Command{ +// Use: "rot", +// Short: "Root of trust utility", +// Long: `Root of trust allows you to manage your trusted roots using Keyfactor certificate stores. +//For example if you wish to add a list of "root" certs to a list of certificate stores you would simply generate and fill +//out the template CSV file. These template files can be generated with the following commands: +//kfutil stores rot generate-template --type certs +//kfutil stores rot generate-template --type stores +//Once those files are filled out you can use the following command to add the certs to the stores: +//kfutil stores rot audit --certs-file --stores-file +//Will generate a CSV report file 'rot_audit.csv' of what actions will be taken. If those actions are correct you can run +//the following command to actually perform the actions: +//kfutil stores rot reconcile --certs-file --stores-file +//OR if you want to use the audit report file generated you can run this command: +//kfutil stores rot reconcile --import-csv +//`, +// } +// rotAuditCmd = &cobra.Command{ +// Use: "audit", +// Aliases: nil, +// SuggestFor: nil, +// Short: "Audit generates a CSV report of what actions will be taken based on input CSV files.", +// 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.`, +// Example: "", +// ValidArgs: nil, +// ValidArgsFunction: nil, +// Args: nil, +// ArgAliases: nil, +// BashCompletionFunction: "", +// Deprecated: "", +// Annotations: nil, +// Version: "", +// PersistentPreRun: nil, +// PersistentPreRunE: nil, +// PreRun: nil, +// PreRunE: nil, +// Run: func(cmd *cobra.Command, args []string) { +// // Global flags +// debugFlag, _ := cmd.Flags().GetBool("debugFlag") +// configFile, _ := cmd.Flags().GetString("config") +// noPrompt, _ := cmd.Flags().GetBool("no-prompt") +// profile, _ := cmd.Flags().GetString("profile") +// +// kfcUsername, _ := cmd.Flags().GetString("kfcUsername") +// kfcPassword, _ := cmd.Flags().GetString("kfcPassword") +// kfcDomain, _ := cmd.Flags().GetString("kfcDomain") +// +// authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) +// +// debugModeEnabled := checkDebug(debugFlag) +// log.Println("Debug mode enabled: ", debugModeEnabled) +// var lookupFailures []string +// kfClient, _ := initClient(configFile, profile, "", "", noPrompt, authConfig, false) +// storesFile, _ := cmd.Flags().GetString("stores") +// addRootsFile, _ := cmd.Flags().GetString("add-certs") +// removeRootsFile, _ := cmd.Flags().GetString("remove-certs") +// minCerts, _ := cmd.Flags().GetInt("min-certs") +// maxLeaves, _ := cmd.Flags().GetInt("max-leaf-certs") +// maxKeys, _ := cmd.Flags().GetInt("max-keys") +// dryRun, _ := cmd.Flags().GetBool("dry-run") +// outpath, _ := cmd.Flags().GetString("outpath") +// // Read in the stores CSV +// log.Printf("[DEBUG] storesFile: %s", storesFile) +// log.Printf("[DEBUG] addRootsFile: %s", addRootsFile) +// log.Printf("[DEBUG] removeRootsFile: %s", removeRootsFile) +// log.Printf("[DEBUG] dryRun: %t", dryRun) +// // Read in the stores CSV +// csvFile, _ := os.Open(storesFile) +// reader := csv.NewReader(bufio.NewReader(csvFile)) +// storeEntries, _ := reader.ReadAll() +// var stores = make(map[string]StoreCSVEntry) +// validHeader := false +// for _, entry := range storeEntries { +// if strings.EqualFold(strings.Join(entry, ","), strings.Join(StoreHeader, ",")) { +// validHeader = true +// continue // Skip header +// } +// if !validHeader { +// fmt.Printf("[ERROR] Invalid header in stores file. Expected: %s", strings.Join(StoreHeader, ",")) +// log.Fatalf("[ERROR] Stores CSV file is missing a valid header") +// } +// apiResp, err := kfClient.GetCertificateStoreByID(entry[0]) +// if err != nil { +// log.Printf("[ERROR] getting cert store: %s", err) +// _ = append(lookupFailures, strings.Join(entry, ",")) +// continue +// } +// +// //inventory, invErr := kfClient.GetCertStoreInventoryV1(entry[0]) +// //if invErr != nil { +// // log.Printf("[ERROR] getting cert store inventory for: %s\n%s", entry[0], invErr) +// //} +// var inventory []api.CertStoreInventoryV1 //TODO: Update this to use SDK inventory +// +// if !isRootStore(apiResp, &inventory, minCerts, maxLeaves, maxKeys) { +// fmt.Printf("Store %s is not a root store, skipping.\n", entry[0]) +// log.Printf("[WARN] Store %s is not a root store", apiResp.Id) +// continue +// } else { +// log.Printf("[INFO] Store %s is a root store", apiResp.Id) +// } +// +// stores[entry[0]] = StoreCSVEntry{ +// ID: entry[0], +// Type: entry[1], +// Machine: entry[2], +// Path: entry[3], +// Thumbprints: make(map[string]bool), +// Serials: make(map[string]bool), +// Ids: make(map[int]bool), +// } +// for _, cert := range inventory { +// thumb := cert.Thumbprints +// for t, v := range thumb { +// stores[entry[0]].Thumbprints[t] = v +// } +// for t, v := range cert.Serials { +// stores[entry[0]].Serials[t] = v +// } +// for t, v := range cert.Ids { +// stores[entry[0]].Ids[t] = v +// } +// } +// +// } +// +// // Read in the add addCerts CSV +// var certsToAdd = make(map[string]string) +// if addRootsFile != "" { +// var rcfErr error +// certsToAdd, rcfErr = readCertsFile(addRootsFile, kfClient) +// if rcfErr != nil { +// fmt.Printf("[ERROR] reading certs file %s: %s", addRootsFile, rcfErr) +// log.Fatalf("[ERROR] reading addCerts file: %s", rcfErr) +// } +// addCertsJSON, _ := json.Marshal(certsToAdd) +// log.Printf("[DEBUG] add certs JSON: %s", string(addCertsJSON)) +// log.Println("[DEBUG] AddCert ROT called") +// } else { +// log.Printf("[DEBUG] No addCerts file specified") +// log.Printf("[DEBUG] No addCerts = %s", certsToAdd) +// } +// +// // Read in the remove removeCerts CSV +// var certsToRemove = make(map[string]string) +// if removeRootsFile != "" { +// var rcfErr error +// certsToRemove, rcfErr = readCertsFile(removeRootsFile, kfClient) +// if rcfErr != nil { +// fmt.Printf("[ERROR] reading removeCerts file %s: %s", removeRootsFile, rcfErr) +// log.Fatalf("[ERROR] reading removeCerts file: %s", rcfErr) +// } +// removeCertsJSON, _ := json.Marshal(certsToRemove) +// log.Printf("[DEBUG] remove certs JSON: %s", string(removeCertsJSON)) +// } else { +// log.Printf("[DEBUG] No removeCerts file specified") +// log.Printf("[DEBUG] No removeCerts = %s", certsToRemove) +// } +// _, _, gErr := generateAuditReport(certsToAdd, certsToRemove, stores, outpath, kfClient) +// if gErr != nil { +// log.Fatalf("[ERROR] generating audit report: %s", gErr) +// } +// }, +// RunE: nil, +// PostRun: nil, +// PostRunE: nil, +// PersistentPostRun: nil, +// PersistentPostRunE: nil, +// FParseErrWhitelist: cobra.FParseErrWhitelist{}, +// CompletionOptions: cobra.CompletionOptions{}, +// TraverseChildren: false, +// Hidden: false, +// SilenceErrors: false, +// SilenceUsage: false, +// DisableFlagParsing: false, +// DisableAutoGenTag: false, +// DisableFlagsInUseLine: false, +// DisableSuggestions: false, +// SuggestionsMinimumDistance: 0, +// } +// rotReconcileCmd = &cobra.Command{ +// Use: "reconcile", +// Aliases: nil, +// SuggestFor: nil, +// Short: "Reconcile either takes in or will generate an audit report and then add/remove certs as needed.", +// Long: `Root of Trust (rot): Will parse either a combination of CSV files that define certs to +//add and/or certs to remove with a CSV of certificate stores or an audit CSV file. If an audit CSV file is provided, the +//add and remove actions defined in the audit file will be immediately executed. If a combination of CSV files are provided, +//the utility will first generate an audit report and then execute the add/remove actions defined in the audit report.`, +// Example: "", +// ValidArgs: nil, +// ValidArgsFunction: nil, +// Args: nil, +// ArgAliases: nil, +// BashCompletionFunction: "", +// Deprecated: "", +// Annotations: nil, +// Version: "", +// PersistentPreRun: nil, +// PersistentPreRunE: nil, +// PreRun: nil, +// PreRunE: nil, +// Run: func(cmd *cobra.Command, args []string) { +// // Global flags +// debugFlag, _ := cmd.Flags().GetBool("debugFlag") +// configFile, _ := cmd.Flags().GetString("config") +// noPrompt, _ := cmd.Flags().GetBool("no-prompt") +// profile, _ := cmd.Flags().GetString("profile") +// +// kfcUsername, _ := cmd.Flags().GetString("kfcUsername") +// kfcPassword, _ := cmd.Flags().GetString("kfcPassword") +// kfcDomain, _ := cmd.Flags().GetString("kfcDomain") +// +// authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) +// +// debugModeEnabled := checkDebug(debugFlag) +// +// log.Println("Debug mode enabled: ", debugModeEnabled) +// +// var lookupFailures []string +// kfClient, _ := initClient(configFile, profile, "", "", noPrompt, authConfig, false) +// storesFile, _ := cmd.Flags().GetString("stores") +// addRootsFile, _ := cmd.Flags().GetString("add-certs") +// isCSV, _ := cmd.Flags().GetBool("import-csv") +// reportFile, _ := cmd.Flags().GetString("input-file") +// removeRootsFile, _ := cmd.Flags().GetString("remove-certs") +// minCerts, _ := cmd.Flags().GetInt("min-certs") +// maxLeaves, _ := cmd.Flags().GetInt("max-leaf-certs") +// maxKeys, _ := cmd.Flags().GetInt("max-keys") +// dryRun, _ := cmd.Flags().GetBool("dry-run") +// outpath, _ := cmd.Flags().GetString("outpath") +// +// log.Printf("[DEBUG] configFile: %s", configFile) +// log.Printf("[DEBUG] storesFile: %s", storesFile) +// log.Printf("[DEBUG] addRootsFile: %s", addRootsFile) +// log.Printf("[DEBUG] removeRootsFile: %s", removeRootsFile) +// log.Printf("[DEBUG] dryRun: %t", dryRun) +// +// // Parse existing audit report +// if isCSV && reportFile != "" { +// log.Printf("[DEBUG] isCSV: %t", isCSV) +// log.Printf("[DEBUG] reportFile: %s", reportFile) +// // Read in the CSV +// csvFile, err := os.Open(reportFile) +// if err != nil { +// fmt.Printf("[ERROR] opening file: %s", err) +// log.Fatalf("[ERROR] opening CSV file: %s", err) +// } +// validHeader := false +// +// aCSV := csv.NewReader(csvFile) +// aCSV.FieldsPerRecord = -1 +// inFile, cErr := aCSV.ReadAll() +// if cErr != nil { +// fmt.Printf("[ERROR] reading CSV file: %s", cErr) +// log.Fatalf("[ERROR] reading CSV file: %s", cErr) +// } +// actions := make(map[string][]ROTAction) +// fieldMap := make(map[int]string) +// for i, field := range AuditHeader { +// fieldMap[i] = field +// } +// for ri, row := range inFile { +// if strings.EqualFold(strings.Join(row, ","), strings.Join(AuditHeader, ",")) { +// validHeader = true +// continue // Skip header +// } +// if !validHeader { +// fmt.Printf( +// "[ERROR] Invalid header in stores file. Expected: %s", +// strings.Join(AuditHeader, ","), +// ) +// log.Fatalf("[ERROR] Stores CSV file is missing a valid header") +// } +// action := make(map[string]interface{}) +// +// for i, field := range row { +// fieldInt, iErr := strconv.Atoi(field) +// if iErr != nil { +// log.Printf("[DEBUG] Field %s is not an int", field) +// action[fieldMap[i]] = field +// } else { +// action[fieldMap[i]] = fieldInt +// } +// +// } +// +// addCertStr, aOk := action["AddCert"].(string) +// if !aOk { +// addCertStr = "" +// } +// addCert, acErr := strconv.ParseBool(addCertStr) +// if acErr != nil { +// addCert = false +// } +// +// removeCertStr, rOk := action["RemoveCert"].(string) +// if !rOk { +// removeCertStr = "" +// } +// removeCert, rcErr := strconv.ParseBool(removeCertStr) +// if rcErr != nil { +// removeCert = false +// } +// +// sType, sOk := action["StoreType"].(string) +// if !sOk { +// sType = "" +// } +// +// sPath, pOk := action["Path"].(string) +// if !pOk { +// sPath = "" +// } +// +// tp, tpOk := action["Thumbprint"].(string) +// if !tpOk { +// tp = "" +// } +// cid, cidOk := action["CertID"].(int) +// if !cidOk { +// cid = -1 +// } +// +// if !tpOk && !cidOk { +// fmt.Printf("[ERROR] Missing Thumbprint or CertID for row %d in report file %s", ri, reportFile) +// log.Printf("[ERROR] Invalid action: %v", action) +// continue +// } +// +// sId, sIdOk := action["StoreID"].(string) +// if !sIdOk { +// fmt.Printf("[ERROR] Missing StoreID for row %d in report file %s", ri, reportFile) +// log.Printf("[ERROR] Invalid action: %v", action) +// continue +// } +// if cid == -1 && tp != "" { +// certLookupReq := api.GetCertificateContextArgs{ +// IncludeMetadata: boolToPointer(true), +// IncludeLocations: boolToPointer(true), +// CollectionId: nil, +// Thumbprint: tp, +// Id: 0, +// } +// certLookup, err := kfClient.GetCertificateContext(&certLookupReq) +// if err != nil { +// fmt.Printf("[ERROR] looking up certificate %s: %s\n", tp, err) +// log.Printf("[ERROR] looking up cert: %s\n%v", tp, err) +// continue +// } +// cid = certLookup.Id +// } +// +// a := ROTAction{ +// StoreID: sId, +// StoreType: sType, +// StorePath: sPath, +// Thumbprint: tp, +// CertID: cid, +// AddCert: addCert, +// RemoveCert: removeCert, +// } +// +// actions[a.Thumbprint] = append(actions[a.Thumbprint], a) +// } +// if len(actions) == 0 { +// fmt.Println("No reconciliation actions to take, root stores are up-to-date. Exiting.") +// return +// } +// rErr := reconcileRoots(actions, kfClient, reportFile, dryRun) +// if rErr != nil { +// fmt.Printf("[ERROR] reconciling roots: %s", rErr) +// log.Fatalf("[ERROR] reconciling roots: %s", rErr) +// } +// defer csvFile.Close() +// +// orchsURL := fmt.Sprintf("https://%s/Keyfactor/Portal/AgentJobStatus/Index", kfClient.Hostname) +// +// fmt.Println(fmt.Sprintf("Reconciliation completed. Check orchestrator jobs for details. %s", orchsURL)) +// } else { +// // Read in the stores CSV +// csvFile, _ := os.Open(storesFile) +// reader := csv.NewReader(bufio.NewReader(csvFile)) +// storeEntries, _ := reader.ReadAll() +// var stores = make(map[string]StoreCSVEntry) +// for i, entry := range storeEntries { +// if entry[0] == "StoreID" || entry[0] == "StoreId" || i == 0 { +// continue // Skip header +// } +// apiResp, err := kfClient.GetCertificateStoreByID(entry[0]) +// if err != nil { +// log.Printf("[ERROR] getting cert store: %s", err) +// lookupFailures = append(lookupFailures, entry[0]) +// continue +// } +// inventory, invErr := kfClient.GetCertStoreInventoryV1(entry[0]) +// if invErr != nil { +// log.Fatalf("[ERROR] getting cert store inventory: %s", invErr) +// } +// +// if !isRootStore(apiResp, inventory, minCerts, maxLeaves, maxKeys) { +// log.Printf("[WARN] Store %s is not a root store", apiResp.Id) +// continue +// } else { +// log.Printf("[INFO] Store %s is a root store", apiResp.Id) +// } +// +// stores[entry[0]] = StoreCSVEntry{ +// ID: entry[0], +// Type: entry[1], +// Machine: entry[2], +// Path: entry[3], +// Thumbprints: make(map[string]bool), +// Serials: make(map[string]bool), +// Ids: make(map[int]bool), +// } +// for _, cert := range *inventory { +// thumb := cert.Thumbprints +// for t, v := range thumb { +// stores[entry[0]].Thumbprints[t] = v +// } +// for t, v := range cert.Serials { +// stores[entry[0]].Serials[t] = v +// } +// for t, v := range cert.Ids { +// stores[entry[0]].Ids[t] = v +// } +// } +// +// } +// if len(lookupFailures) > 0 { +// fmt.Printf("[ERROR] the following stores were not found: %s", strings.Join(lookupFailures, ",")) +// log.Fatalf("[ERROR] the following stores were not found: %s", strings.Join(lookupFailures, ",")) +// } +// if len(stores) == 0 { +// fmt.Println("[ERROR] no root stores found. Exiting.") +// log.Fatalf("[ERROR] No root stores found. Exiting.") +// } +// // Read in the add addCerts CSV +// var certsToAdd = make(map[string]string) +// if addRootsFile != "" { +// certsToAdd, _ = readCertsFile(addRootsFile, kfClient) +// log.Printf("[DEBUG] ROT add certs called") +// } else { +// log.Printf("[INFO] No addCerts file specified") +// } +// +// // Read in the remove removeCerts CSV +// var certsToRemove = make(map[string]string) +// if removeRootsFile != "" { +// certsToRemove, _ = readCertsFile(removeRootsFile, kfClient) +// log.Printf("[DEBUG] ROT remove certs called") +// } else { +// log.Printf("[DEBUG] No removeCerts file specified") +// } +// _, actions, err := generateAuditReport(certsToAdd, certsToRemove, stores, outpath, kfClient) +// if err != nil { +// log.Fatalf("[ERROR] generating audit report: %s", err) +// } +// if len(actions) == 0 { +// fmt.Println("No reconciliation actions to take, root stores are up-to-date. Exiting.") +// return +// } +// rErr := reconcileRoots(actions, kfClient, reportFile, dryRun) +// if rErr != nil { +// fmt.Printf("[ERROR] reconciling roots: %s", rErr) +// log.Fatalf("[ERROR] reconciling roots: %s", rErr) +// } +// if lookupFailures != nil { +// fmt.Printf("The following stores could not be found: %s", strings.Join(lookupFailures, ",")) +// } +// orchsURL := fmt.Sprintf("https://%s/Keyfactor/Portal/AgentJobStatus/Index", kfClient.Hostname) +// +// fmt.Println(fmt.Sprintf("Reconciliation completed. Check orchestrator jobs for details. %s", orchsURL)) +// } +// +// }, +// RunE: nil, +// PostRun: nil, +// PostRunE: nil, +// PersistentPostRun: nil, +// PersistentPostRunE: nil, +// FParseErrWhitelist: cobra.FParseErrWhitelist{}, +// CompletionOptions: cobra.CompletionOptions{}, +// TraverseChildren: false, +// Hidden: false, +// SilenceErrors: false, +// SilenceUsage: false, +// DisableFlagParsing: false, +// DisableAutoGenTag: false, +// DisableFlagsInUseLine: false, +// DisableSuggestions: false, +// SuggestionsMinimumDistance: 0, +// } +// rotGenStoreTemplateCmd = &cobra.Command{ +// Use: "generate-template", +// Aliases: nil, +// SuggestFor: nil, +// Short: "For generating Root Of Trust template(s)", +// Long: `Root Of Trust: Will parse a CSV and attempt to deploy a cert or set of certs into a list of cert stores.`, +// Example: "", +// ValidArgs: nil, +// ValidArgsFunction: nil, +// Args: nil, +// ArgAliases: nil, +// BashCompletionFunction: "", +// Deprecated: "", +// Annotations: nil, +// Version: "", +// PersistentPreRun: nil, +// PersistentPreRunE: nil, +// PreRun: nil, +// PreRunE: nil, +// Run: func(cmd *cobra.Command, args []string) { +// // Global flags +// debugFlag, _ := cmd.Flags().GetBool("debugFlag") +// configFile, _ := cmd.Flags().GetString("config") +// noPrompt, _ := cmd.Flags().GetBool("no-prompt") +// profile, _ := cmd.Flags().GetString("profile") +// +// kfcUsername, _ := cmd.Flags().GetString("kfcUsername") +// kfcPassword, _ := cmd.Flags().GetString("kfcPassword") +// kfcDomain, _ := cmd.Flags().GetString("kfcDomain") +// +// authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) +// +// debugModeEnabled := checkDebug(debugFlag) +// log.Println("Debug mode enabled: ", debugModeEnabled) +// +// templateType, _ := cmd.Flags().GetString("type") +// format, _ := cmd.Flags().GetString("format") +// outPath, _ := cmd.Flags().GetString("outpath") +// storeType, _ := cmd.Flags().GetStringSlice("store-type") +// containerName, _ := cmd.Flags().GetStringSlice("container-name") +// collection, _ := cmd.Flags().GetStringSlice("collection") +// subjectName, _ := cmd.Flags().GetStringSlice("cn") +// stID := -1 +// var storeData []api.GetCertificateStoreResponse +// var csvStoreData [][]string +// var csvCertData [][]string +// var rowLookup = make(map[string]bool) +// kfClient, cErr := initClient(configFile, profile, "", "", noPrompt, authConfig, false) +// if len(storeType) != 0 { +// for _, s := range storeType { +// if cErr != nil { +// log.Fatalf("[ERROR] creating client: %s", cErr) +// } +// var sType *api.CertificateStoreType +// var stErr error +// if s == "all" { +// sType = &api.CertificateStoreType{ +// Name: "", +// ShortName: "", +// Capability: "", +// StoreType: 0, +// ImportType: 0, +// LocalStore: false, +// SupportedOperations: nil, +// Properties: nil, +// EntryParameters: nil, +// PasswordOptions: nil, +// StorePathType: "", +// StorePathValue: "", +// PrivateKeyAllowed: "", +// JobProperties: nil, +// ServerRequired: false, +// PowerShell: false, +// BlueprintAllowed: false, +// CustomAliasAllowed: "", +// ServerRegistration: 0, +// InventoryEndpoint: "", +// InventoryJobType: "", +// ManagementJobType: "", +// DiscoveryJobType: "", +// EnrollmentJobType: "", +// } +// } else { +// // check if s is an int +// sInt, err := strconv.Atoi(s) +// if err == nil { +// sType, stErr = kfClient.GetCertificateStoreTypeById(sInt) +// } else { +// sType, stErr = kfClient.GetCertificateStoreTypeByName(s) +// } +// if stErr != nil { +// fmt.Printf("[ERROR] getting store type '%s'. %s\n", s, stErr) +// continue +// } +// stID = sType.StoreType // This is the template type ID +// } +// +// if stID >= 0 || s == "all" { +// log.Printf("[DEBUG] Store type ID: %d\n", stID) +// params := make(map[string]interface{}) +// stores, sErr := kfClient.ListCertificateStores(¶ms) +// if sErr != nil { +// fmt.Printf("[ERROR] getting certificate stores of type '%s': %s\n", s, sErr) +// log.Fatalf("[ERROR] getting certificate stores of type '%s': %s", s, sErr) +// } +// for _, store := range *stores { +// if store.CertStoreType == stID || s == "all" { +// storeData = append(storeData, store) +// if !rowLookup[store.Id] { +// lineData := []string{ +// //"StoreID", "StoreType", "StoreMachine", "StorePath", "ContainerId" +// store.Id, +// fmt.Sprintf("%s", sType.ShortName), +// store.ClientMachine, +// store.StorePath, +// fmt.Sprintf("%d", store.ContainerId), +// store.ContainerName, +// getCurrentTime(""), +// } +// csvStoreData = append(csvStoreData, lineData) +// rowLookup[store.Id] = true +// } +// } +// } +// } +// } +// fmt.Println("Done") +// } +// if len(containerName) != 0 { +// for _, c := range containerName { +// +// if cErr != nil { +// log.Fatalf("[ERROR] creating client: %s", cErr) +// } +// cStoresResp, scErr := kfClient.GetCertificateStoreByContainerID(c) +// if scErr != nil { +// fmt.Printf("[ERROR] getting store container: %s\n", scErr) +// } +// if cStoresResp != nil { +// for _, store := range *cStoresResp { +// sType, stErr := kfClient.GetCertificateStoreType(store.CertStoreType) +// if stErr != nil { +// fmt.Printf("[ERROR] getting store type: %s\n", stErr) +// continue +// } +// storeData = append(storeData, store) +// if !rowLookup[store.Id] { +// lineData := []string{ +// // "StoreID", "StoreType", "StoreMachine", "StorePath", "ContainerId" +// store.Id, +// sType.ShortName, +// store.ClientMachine, +// store.StorePath, +// fmt.Sprintf("%d", store.ContainerId), +// store.ContainerName, +// getCurrentTime(""), +// } +// csvStoreData = append(csvStoreData, lineData) +// rowLookup[store.Id] = true +// } +// } +// +// } +// } +// } +// if len(collection) != 0 { +// for _, c := range collection { +// if cErr != nil { +// fmt.Println("[ERROR] connecting to Keyfactor. Please check your configuration and try again.") +// log.Fatalf("[ERROR] creating client: %s", cErr) +// } +// q := make(map[string]string) +// q["collection"] = c +// certsResp, scErr := kfClient.ListCertificates(q) +// if scErr != nil { +// fmt.Printf("No certificates found in collection: %s\n", scErr) +// } +// if certsResp != nil { +// for _, cert := range certsResp { +// if !rowLookup[cert.Thumbprint] { +// lineData := []string{ +// // "Thumbprint", "SubjectName", "Issuer", "CertID", "Locations", "LastQueriedDate" +// cert.Thumbprint, +// cert.IssuedCN, +// cert.IssuerDN, +// fmt.Sprintf("%d", cert.Id), +// fmt.Sprintf("%v", cert.Locations), +// getCurrentTime(""), +// } +// csvCertData = append(csvCertData, lineData) +// rowLookup[cert.Thumbprint] = true +// } +// } +// +// } +// } +// } +// if len(subjectName) != 0 { +// for _, s := range subjectName { +// if cErr != nil { +// fmt.Println("[ERROR] connecting to Keyfactor. Please check your configuration and try again.") +// log.Fatalf("[ERROR] creating client: %s", cErr) +// } +// q := make(map[string]string) +// q["subject"] = s +// certsResp, scErr := kfClient.ListCertificates(q) +// if scErr != nil { +// fmt.Printf("No certificates found with CN: %s\n", scErr) +// } +// if certsResp != nil { +// for _, cert := range certsResp { +// if !rowLookup[cert.Thumbprint] { +// locationsFormatted := "" +// for _, loc := range cert.Locations { +// locationsFormatted += fmt.Sprintf("%s:%s\n", loc.StoreMachine, loc.StorePath) +// } +// lineData := []string{ +// // "Thumbprint", "SubjectName", "Issuer", "CertID", "Locations", "LastQueriedDate" +// cert.Thumbprint, +// cert.IssuedCN, +// cert.IssuerDN, +// fmt.Sprintf("%d", cert.Id), +// locationsFormatted, +// getCurrentTime(""), +// } +// csvCertData = append(csvCertData, lineData) +// rowLookup[cert.Thumbprint] = true +// } +// } +// +// } +// } +// } +// // Create CSV template file +// +// var filePath string +// if outPath != "" { +// filePath = outPath +// } else { +// filePath = fmt.Sprintf("%s_template.%s", templateType, format) +// } +// file, err := os.Create(filePath) +// if err != nil { +// fmt.Printf("[ERROR] creating file: %s", err) +// log.Fatal("Cannot create file", err) +// } +// +// switch format { +// case "csv": +// writer := csv.NewWriter(file) +// var data [][]string +// switch templateType { +// case "stores": +// data = append(data, StoreHeader) +// if len(csvStoreData) != 0 { +// data = append(data, csvStoreData...) +// } +// case "certs": +// data = append(data, CertHeader) +// if len(csvCertData) != 0 { +// data = append(data, csvCertData...) +// } +// case "actions": +// data = append(data, AuditHeader) +// } +// csvErr := writer.WriteAll(data) +// if csvErr != nil { +// fmt.Println(csvErr) +// } +// defer file.Close() +// +// case "json": +// writer := bufio.NewWriter(file) +// _, err := writer.WriteString("StoreID,StoreType,StoreMachine,StorePath") +// if err != nil { +// log.Fatal("Cannot write to file", err) +// } +// } +// fmt.Printf("Template file created at %s.\n", filePath) +// }, +// RunE: nil, +// PostRun: nil, +// PostRunE: nil, +// PersistentPostRun: nil, +// PersistentPostRunE: nil, +// FParseErrWhitelist: cobra.FParseErrWhitelist{}, +// CompletionOptions: cobra.CompletionOptions{}, +// TraverseChildren: false, +// Hidden: false, +// SilenceErrors: false, +// SilenceUsage: false, +// DisableFlagParsing: false, +// DisableAutoGenTag: false, +// DisableFlagsInUseLine: false, +// DisableSuggestions: false, +// SuggestionsMinimumDistance: 0, +// } +//) +// +//func init() { +// log.SetFlags(log.LstdFlags | log.Lshortfile) +// log.SetOutput(os.Stdout) +// var ( +// stores string +// addCerts string +// removeCerts string +// minCertsInStore int +// maxPrivateKeys int +// maxLeaves int +// tType = tTypeCerts +// outPath string +// outputFormat string +// inputFile string +// storeTypes []string +// containerNames []string +// collections []string +// subjectNames []string +// ) +// +// storesCmd.AddCommand(rotCmd) +// +// // Root of trust `audit` command +// rotCmd.AddCommand(rotAuditCmd) +// rotAuditCmd.Flags().StringVarP(&stores, "stores", "s", "", "CSV file containing cert stores to enroll into") +// rotAuditCmd.Flags().StringVarP( +// &addCerts, "add-certs", "a", "", +// "CSV file containing cert(s) to enroll into the defined cert stores", +// ) +// rotAuditCmd.Flags().StringVarP( +// &removeCerts, "remove-certs", "r", "", +// "CSV file containing cert(s) to remove from the defined cert stores", +// ) +// rotAuditCmd.Flags().IntVarP( +// &minCertsInStore, +// "min-certs", +// "m", +// -1, +// "The minimum number of certs that should be in a store to be considered a 'root' store. If set to `-1` then all stores will be considered.", +// ) +// rotAuditCmd.Flags().IntVarP( +// &maxPrivateKeys, +// "max-keys", +// "k", +// -1, +// "The max number of private keys that should be in a store to be considered a 'root' store. If set to `-1` then all stores will be considered.", +// ) +// rotAuditCmd.Flags().IntVarP( +// &maxLeaves, +// "max-leaf-certs", +// "l", +// -1, +// "The max number of non-root-certs that should be in a store to be considered a 'root' store. If set to `-1` then all stores will be considered.", +// ) +// rotAuditCmd.Flags().BoolP("dry-run", "d", false, "Dry run mode") +// rotAuditCmd.Flags().StringVarP( +// &outPath, "outpath", "o", "", +// "Path to write the audit report file to. If not specified, the file will be written to the current directory.", +// ) +// +// // Root of trust `reconcile` command +// rotCmd.AddCommand(rotReconcileCmd) +// rotReconcileCmd.Flags().StringVarP(&stores, "stores", "s", "", "CSV file containing cert stores to enroll into") +// rotReconcileCmd.Flags().StringVarP( +// &addCerts, "add-certs", "a", "", +// "CSV file containing cert(s) to enroll into the defined cert stores", +// ) +// rotReconcileCmd.Flags().StringVarP( +// &removeCerts, "remove-certs", "r", "", +// "CSV file containing cert(s) to remove from the defined cert stores", +// ) +// rotReconcileCmd.Flags().IntVarP( +// &minCertsInStore, +// "min-certs", +// "m", +// -1, +// "The minimum number of certs that should be in a store to be considered a 'root' store. If set to `-1` then all stores will be considered.", +// ) +// rotReconcileCmd.Flags().IntVarP( +// &maxPrivateKeys, +// "max-keys", +// "k", +// -1, +// "The max number of private keys that should be in a store to be considered a 'root' store. If set to `-1` then all stores will be considered.", +// ) +// rotReconcileCmd.Flags().IntVarP( +// &maxLeaves, +// "max-leaf-certs", +// "l", +// -1, +// "The max number of non-root-certs that should be in a store to be considered a 'root' store. If set to `-1` then all stores will be considered.", +// ) +// rotReconcileCmd.Flags().BoolP("dry-run", "d", false, "Dry run mode") +// rotReconcileCmd.Flags().BoolP("import-csv", "v", false, "Import an audit report file in CSV format.") +// rotReconcileCmd.Flags().StringVarP( +// &inputFile, "input-file", "i", reconcileDefaultFileName, +// "Path to a file generated by 'stores rot audit' command.", +// ) +// rotReconcileCmd.Flags().StringVarP( +// &outPath, "outpath", "o", "", +// "Path to write the audit report file to. If not specified, the file will be written to the current directory.", +// ) +// //rotReconcileCmd.MarkFlagsRequiredTogether("add-certs", "stores") +// //rotReconcileCmd.MarkFlagsRequiredTogether("remove-certs", "stores") +// rotReconcileCmd.MarkFlagsMutuallyExclusive("add-certs", "import-csv") +// rotReconcileCmd.MarkFlagsMutuallyExclusive("remove-certs", "import-csv") +// rotReconcileCmd.MarkFlagsMutuallyExclusive("stores", "import-csv") +// +// // Root of trust `generate` command +// rotCmd.AddCommand(rotGenStoreTemplateCmd) +// rotGenStoreTemplateCmd.Flags().StringVarP( +// &outPath, "outpath", "o", "", +// "Path to write the template file to. If not specified, the file will be written to the current directory.", +// ) +// rotGenStoreTemplateCmd.Flags().StringVarP( +// &outputFormat, "format", "f", "csv", +// "The type of template to generate. Only `csv` is supported at this time.", +// ) +// rotGenStoreTemplateCmd.Flags().Var( +// &tType, "type", +// `The type of template to generate. Only "certs|stores|actions" are supported at this time.`, +// ) +// rotGenStoreTemplateCmd.Flags().StringSliceVar( +// &storeTypes, +// "store-type", +// []string{}, +// "Multi value flag. Attempt to pre-populate the stores template with the certificate stores matching specified store types. If not specified, the template will be empty.", +// ) +// rotGenStoreTemplateCmd.Flags().StringSliceVar( +// &containerNames, +// "container-name", +// []string{}, +// "Multi value flag. Attempt to pre-populate the stores template with the certificate stores matching specified container types. If not specified, the template will be empty.", +// ) +// rotGenStoreTemplateCmd.Flags().StringSliceVar( +// &subjectNames, +// "cn", +// []string{}, +// "Subject name(s) to pre-populate the 'certs' template with. If not specified, the template will be empty. Does not work with SANs.", +// ) +// rotGenStoreTemplateCmd.Flags().StringSliceVar( +// &collections, +// "collection", +// []string{}, +// "Certificate collection name(s) to pre-populate the stores template with. If not specified, the template will be empty.", +// ) +// +// rotGenStoreTemplateCmd.RegisterFlagCompletionFunc("type", templateTypeCompletion) +// rotGenStoreTemplateCmd.MarkFlagRequired("type") +//} diff --git a/cmd/storeTypes.go b/cmd/storeTypes.go index 7bced1d..354f22d 100644 --- a/cmd/storeTypes.go +++ b/cmd/storeTypes.go @@ -26,7 +26,7 @@ import ( "time" "github.com/AlecAivazis/survey/v2" - "github.com/Keyfactor/keyfactor-go-client/v2/api" + "github.com/Keyfactor/keyfactor-go-client/v3/api" "github.com/rs/zerolog/log" "github.com/spf13/cobra" ) diff --git a/cmd/storeTypes_get.go b/cmd/storeTypes_get.go index 74f8c85..a01ab51 100644 --- a/cmd/storeTypes_get.go +++ b/cmd/storeTypes_get.go @@ -19,8 +19,9 @@ package cmd import ( "encoding/json" "fmt" + "github.com/AlecAivazis/survey/v2" - "github.com/Keyfactor/keyfactor-go-client/v2/api" + "github.com/Keyfactor/keyfactor-go-client/v3/api" "github.com/rs/zerolog/log" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ -65,9 +66,27 @@ func CreateStoreTypesGetFlags() *StoreTypesGetFlags { func (f *StoreTypesGetFlags) AddFlags(flags *pflag.FlagSet) { flags.IntVarP(f.storeTypeID, "id", "i", -1, "ID of the certificate store type to get.") flags.StringVarP(f.storeTypeName, "name", "n", "", "Name of the certificate store type to get.") - flags.BoolVarP(f.genericFormat, "generic", "g", false, "Output the store type in a generic format stripped of all fields specific to the Command instance.") - flags.StringVarP(f.gitRef, FlagGitRef, "b", "main", "The git branch or tag to reference when pulling store-types from the internet.") - flags.BoolVarP(f.outputToIntegrationManifest, "output-to-integration-manifest", "", false, "Update the integration manifest with the store type. It overrides the store type in the manifest if it already exists. If the integration manifest does not exist in the current directory, it will be created.") + flags.BoolVarP( + f.genericFormat, + "generic", + "g", + false, + "Output the store type in a generic format stripped of all fields specific to the Command instance.", + ) + flags.StringVarP( + f.gitRef, + FlagGitRef, + "b", + "main", + "The git branch or tag to reference when pulling store-types from the internet.", + ) + flags.BoolVarP( + f.outputToIntegrationManifest, + "output-to-integration-manifest", + "", + false, + "Update the integration manifest with the store type. It overrides the store type in the manifest if it already exists. If the integration manifest does not exist in the current directory, it will be created.", + ) } func CreateCmdStoreTypesGet() *cobra.Command { @@ -107,7 +126,12 @@ func CreateCmdStoreTypesGet() *cobra.Command { storeTypes, err := kfClient.GetCertificateStoreType(options.storeTypeInterface) if err != nil { - log.Error().Err(err).Msg(fmt.Sprintf("unable to get certificate store type %s", options.storeTypeInterface)) + log.Error().Err(err).Msg( + fmt.Sprintf( + "unable to get certificate store type %s", + options.storeTypeInterface, + ), + ) return err } log.Trace().Msg(fmt.Sprintf("storeTypes: %+v", storeTypes)) @@ -136,7 +160,12 @@ func CreateCmdStoreTypesGet() *cobra.Command { return err } - _, err = cmd.OutOrStdout().Write([]byte(fmt.Sprintf("Successfully updated integration manifest with store type %s\n", options.storeTypeInterface))) + _, err = cmd.OutOrStdout().Write( + []byte(fmt.Sprintf( + "Successfully updated integration manifest with store type %s\n", + options.storeTypeInterface, + )), + ) } else { _, err = cmd.OutOrStdout().Write([]byte(output)) if err != nil { @@ -256,7 +285,10 @@ func (f *StoreTypesGetOptions) Validate() error { return nil } -func formatStoreTypeOutput(storeType *api.CertificateStoreType, outputFormat string, outputType string) (string, error) { +func formatStoreTypeOutput(storeType *api.CertificateStoreType, outputFormat string, outputType string) ( + string, + error, +) { var sOut interface{} sOut = storeType if outputType == "generic" { diff --git a/cmd/storesBulkOperations.go b/cmd/storesBulkOperations.go index 216ed45..dc65efa 100644 --- a/cmd/storesBulkOperations.go +++ b/cmd/storesBulkOperations.go @@ -19,14 +19,15 @@ import ( "encoding/csv" "encoding/json" "fmt" + "os" + "strconv" + "strings" + "github.com/AlecAivazis/survey/v2" "github.com/Jeffail/gabs" - "github.com/Keyfactor/keyfactor-go-client/v2/api" + "github.com/Keyfactor/keyfactor-go-client/v3/api" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - "os" - "strconv" - "strings" ) var ( @@ -46,6 +47,55 @@ var ( } ) +// formatProperties will iterate through the properties of a json object and convert any "int" values to strings +// this is required because the Keyfactor API expects all properties to be strings +func formatProperties(json *gabs.Container, reqPropertiesForStoreType []string) *gabs.Container { + // iterate through required properties and add to json + for _, reqProp := range reqPropertiesForStoreType { + if json.ExistsP("Properties." + reqProp) { + log.Debug().Str("reqProp", reqProp).Msg("Property exists in json") + continue + } + json.Set("", "Properties."+reqProp) + } + + // iterate through properties and convert any "int" values to strings + properties, _ := json.S("Properties").ChildrenMap() + for name, prop := range properties { + if prop.Data() == nil { + log.Debug().Str("name", name).Msg("Property is nil") + continue + } + if _, isInt := prop.Data().(int); isInt { + log.Debug().Str("name", name).Msg("Property is an int") + asStr := strconv.Itoa(prop.Data().(int)) + json.Set(asStr, "Properties."+name) + } + } + return json +} + +func serializeStoreFromTypeDef(storeTypeName string, input string) (string, error) { + // check if storetypename is an integer + storeTypes, _ := readStoreTypesConfig("", "", offline) + log.Debug(). + Str("storeTypeName", storeTypeName). + Msg("checking if storeTypeName is an integer") + sTypeId, err := strconv.Atoi(storeTypeName) + if err == nil { + log.Debug(). + Int("storeTypeId", sTypeId). + Msg("storeTypeName is an integer") + } + for _, st := range storeTypes { + log.Debug(). + Interface("st", st). + Msg("iterating through store types") + } + return "", nil + +} + var importStoresCmd = &cobra.Command{ Use: "import", Short: "Import a file with certificate store parameters and create them in keyfactor.", @@ -107,7 +157,7 @@ var storesCreateFromCSVCmd = &cobra.Command{ } // render list of store types as options for user to select var storeTypeOptions []string - for name, _ := range *sTypes { + for name := range *sTypes { storeTypeOptions = append(storeTypeOptions, fmt.Sprintf("%s", name)) } prompt := &survey.Select{ @@ -212,6 +262,9 @@ var storesCreateFromCSVCmd = &cobra.Command{ continue } reqJson := getJsonForRequest(headerRow, row) + + reqJson = formatProperties(reqJson, reqPropertiesForStoreType) + reqJson.Set(intID, "CertStoreType") // cannot send in 0 as ContainerId, need to omit @@ -231,7 +284,10 @@ var storesCreateFromCSVCmd = &cobra.Command{ if conversionError != nil { //outputError(conversionError, true, outputFormat) - log.Error().Err(conversionError).Msgf("Unable to convert the json into the request parameters object. %s", conversionError.Error()) + log.Error().Err(conversionError).Msgf( + "Unable to convert the json into the request parameters object. %s", + conversionError.Error(), + ) return conversionError } @@ -289,7 +345,8 @@ var storesCreateFromCSVCmd = &cobra.Command{ //fmt.Printf("\nImport results written to %s\n\n", outPath) outputResult(fmt.Sprintf("Import results written to %s", outPath), outputFormat) return nil - }} + }, +} var storesCreateImportTemplateCmd = &cobra.Command{ Use: "generate-template --store-type-id --store-type-name --outpath ", @@ -421,7 +478,10 @@ Store type IDs can be found by running the "store-types" command.`, return csvWriteErr } log.Info().Str("filePath", filePath).Msg("Template file written") - outputResult(fmt.Sprintf("Template file for store type with id %d written to %s", intID, filePath), outputFormat) + outputResult( + fmt.Sprintf("Template file for store type with id %d written to %s", intID, filePath), + outputFormat, + ) return nil }, } @@ -504,7 +564,7 @@ var storesExportCmd = &cobra.Command{ } // render list of store types as options for user to select var storeTypeOptions []string - for name, _ := range *storeTypes { + for name := range *storeTypes { storeTypeOptions = append(storeTypeOptions, fmt.Sprintf("%s", name)) } prompt := &survey.Select{ @@ -992,24 +1052,76 @@ func init() { importStoresCmd.AddCommand(storesCreateImportTemplateCmd) importStoresCmd.AddCommand(storesCreateFromCSVCmd) - storesCreateImportTemplateCmd.Flags().StringVarP(&storeTypeName, "store-type-name", "n", "", "The name of the cert store type for the template. Use if store-type-id is unknown.") - storesCreateImportTemplateCmd.Flags().IntVarP(&storeTypeId, "store-type-id", "i", -1, "The ID of the cert store type for the template.") - storesCreateImportTemplateCmd.Flags().StringVarP(&outPath, "outpath", "o", "", - "Path and name of the template file to generate.. If not specified, the file will be written to the current directory.") + storesCreateImportTemplateCmd.Flags().StringVarP( + &storeTypeName, + "store-type-name", + "n", + "", + "The name of the cert store type for the template. Use if store-type-id is unknown.", + ) + storesCreateImportTemplateCmd.Flags().IntVarP( + &storeTypeId, + "store-type-id", + "i", + -1, + "The ID of the cert store type for the template.", + ) + storesCreateImportTemplateCmd.Flags().StringVarP( + &outPath, + "outpath", + "o", + "", + "Path and name of the template file to generate.. If not specified, the file will be written to the current directory.", + ) storesCreateImportTemplateCmd.MarkFlagsMutuallyExclusive("store-type-name", "store-type-id") - storesCreateFromCSVCmd.Flags().StringVarP(&storeTypeName, "store-type-name", "n", "", "The name of the cert store type. Use if store-type-id is unknown.") - storesCreateFromCSVCmd.Flags().IntVarP(&storeTypeId, "store-type-id", "i", -1, "The ID of the cert store type for the stores.") + storesCreateFromCSVCmd.Flags().StringVarP( + &storeTypeName, + "store-type-name", + "n", + "", + "The name of the cert store type. Use if store-type-id is unknown.", + ) + storesCreateFromCSVCmd.Flags().IntVarP( + &storeTypeId, + "store-type-id", + "i", + -1, + "The ID of the cert store type for the stores.", + ) storesCreateFromCSVCmd.Flags().StringVarP(&file, "file", "f", "", "CSV file containing cert stores to create.") storesCreateFromCSVCmd.MarkFlagRequired("file") storesCreateFromCSVCmd.Flags().BoolP("dry-run", "d", false, "Do not import, just check for necessary fields.") - storesCreateFromCSVCmd.Flags().StringVarP(&resultsPath, "results-path", "o", "", "CSV file containing cert stores to create. defaults to _results.csv") + storesCreateFromCSVCmd.Flags().StringVarP( + &resultsPath, + "results-path", + "o", + "", + "CSV file containing cert stores to create. defaults to _results.csv", + ) storesExportCmd.Flags().BoolVarP(&exportAll, "all", "a", false, "Export all stores grouped by store-type.") - storesExportCmd.Flags().StringVarP(&storeTypeName, "store-type-name", "n", "", "The name of the cert store type for the template. Use if store-type-id is unknown.") - storesExportCmd.Flags().IntVarP(&storeTypeId, "store-type-id", "i", -1, "The ID of the cert store type for the template.") - storesExportCmd.Flags().StringVarP(&outPath, "outpath", "o", "", - "Path and name of the template file to generate.. If not specified, the file will be written to the current directory.") + storesExportCmd.Flags().StringVarP( + &storeTypeName, + "store-type-name", + "n", + "", + "The name of the cert store type for the template. Use if store-type-id is unknown.", + ) + storesExportCmd.Flags().IntVarP( + &storeTypeId, + "store-type-id", + "i", + -1, + "The ID of the cert store type for the template.", + ) + storesExportCmd.Flags().StringVarP( + &outPath, + "outpath", + "o", + "", + "Path and name of the template file to generate.. If not specified, the file will be written to the current directory.", + ) storesExportCmd.MarkFlagsMutuallyExclusive("store-type-name", "store-type-id") } diff --git a/go.mod b/go.mod index d839dc2..14ec5d4 100644 --- a/go.mod +++ b/go.mod @@ -1,14 +1,17 @@ module kfutil -go 1.21 +go 1.23 + +toolchain go1.23.2 require ( github.com/AlecAivazis/survey/v2 v2.3.7 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 github.com/Jeffail/gabs v1.4.0 - github.com/Keyfactor/keyfactor-go-client-sdk v1.0.2 - github.com/Keyfactor/keyfactor-go-client/v2 v2.2.11 + github.com/Keyfactor/keyfactor-auth-client-go v0.0.1-rc.14 + github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.7 + github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.2 github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 github.com/creack/pty v1.1.23 github.com/google/go-cmp v0.6.0 @@ -29,7 +32,10 @@ require ( github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/fatih/color v1.13.0 // indirect github.com/golang-jwt/jwt/v5 v5.2.1 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/terraform-plugin-log v0.9.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/kylelemons/godebug v1.1.0 // indirect @@ -40,9 +46,11 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/spbsoluble/go-pkcs12 v0.3.3 // indirect - go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 // indirect + go.mozilla.org/pkcs7 v0.9.0 // indirect golang.org/x/net v0.27.0 // indirect + golang.org/x/oauth2 v0.23.0 // indirect golang.org/x/sys v0.22.0 // indirect golang.org/x/term v0.22.0 // indirect golang.org/x/text v0.16.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index 2b7305c..9ecf642 100644 --- a/go.sum +++ b/go.sum @@ -10,12 +10,12 @@ github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mx github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/Jeffail/gabs v1.4.0 h1://5fYRRTq1edjfIrQGvdkcd22pkYUrHZ5YC/H2GJVAo= github.com/Jeffail/gabs v1.4.0/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc= -github.com/Keyfactor/keyfactor-go-client v1.4.3 h1:CmGvWcuIbDRFM0PfYOQH6UdtAgplvZBpU++KTU8iseg= -github.com/Keyfactor/keyfactor-go-client v1.4.3/go.mod h1:3ZymLNCaSazglcuYeNfm9nrzn22wcwLjIWURrnUygBo= -github.com/Keyfactor/keyfactor-go-client-sdk v1.0.2 h1:caLlzFCz2L4Dth/9wh+VlypFATmOMmCSQkCPKOKMxw8= -github.com/Keyfactor/keyfactor-go-client-sdk v1.0.2/go.mod h1:Z5pSk8YFGXHbKeQ1wTzVN8A4P/fZmtAwqu3NgBHbDOs= -github.com/Keyfactor/keyfactor-go-client/v2 v2.2.11 h1:Tpk/AKQZmfCZFpODTpLO2+T0XUOgOrvp1ZhQq6J+RSo= -github.com/Keyfactor/keyfactor-go-client/v2 v2.2.11/go.mod h1:fiv/ai955uffPu+ZVye5OfOR+fHoVS/sbfVwTWokNrc= +github.com/Keyfactor/keyfactor-auth-client-go v0.0.1-rc.14 h1:QLnYYZvzDonDamUkHfU0cQWZEr893zCf1vxbF9MSnUg= +github.com/Keyfactor/keyfactor-auth-client-go v0.0.1-rc.14/go.mod h1:UTPLARTONwfc+j1y2SjEa54gbFFCObQucHf3ubQVyDk= +github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.7 h1:OuGkyrGnSiAyQhRN9nxVsK94eNU6V/s+76FP2j6RNUo= +github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.7/go.mod h1:E1IQj9WJv1rrSGQ1LQA5QtrdaPLWGw9kMkZAxQ7h/k8= +github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.2 h1:+7nZp22Y1X0717VVelaXok8Y9MduGi4tGl1A77A5z48= +github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.2/go.mod h1:VbmszVfXWQ9AHDerCJAyd+vu6vQ8x9lq3dSqv3d+6rk= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= @@ -27,6 +27,8 @@ github.com/creack/pty v1.1.23/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfv github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= @@ -34,6 +36,10 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0= +github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow= github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68= github.com/hinshun/vt10x v0.0.0-20220301184237-5011da428d02 h1:AgcIVYPa6XJnU3phs104wLj8l5GEththEw6+F79YsIY= github.com/hinshun/vt10x v0.0.0-20220301184237-5011da428d02/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68= @@ -50,14 +56,20 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -78,11 +90,12 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 h1:CCriYyAfq1Br1aIYettdHZTy8mBTIPo7We18TuO/bak= -go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= +go.mozilla.org/pkcs7 v0.9.0 h1:yM4/HS9dYv7ri2biPtxt8ikvB37a980dg69/pKmS+eI= +go.mozilla.org/pkcs7 v0.9.0/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= @@ -93,12 +106,19 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -124,6 +144,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/pkg/version/version.go b/pkg/version/version.go index f105ad9..db6d381 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -14,4 +14,4 @@ package version -const VERSION = "1.5.1" +const VERSION = "1.5.2" From 58ff55b01f495a5b1598ca77ba4c450864e5c3a5 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Thu, 24 Oct 2024 15:19:23 -0700 Subject: [PATCH 03/19] feat(auth): Basic auth via env vars using `keyfactor-auth-client-go` library Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- cmd/containers.go | 10 +- cmd/export.go | 22 +--- cmd/import.go | 10 +- cmd/inventory.go | 15 +-- cmd/login.go | 19 +--- cmd/orchs.go | 59 ++++++---- cmd/pam.go | 76 +++++++++---- cmd/root.go | 215 +++++++++++++++++++++++------------- cmd/rot.go | 12 +- cmd/storeTypes.go | 9 +- cmd/storeTypes_get.go | 3 +- cmd/stores.go | 9 +- cmd/storesBulkOperations.go | 10 +- go.mod | 6 +- go.sum | 12 +- 15 files changed, 274 insertions(+), 213 deletions(-) diff --git a/cmd/containers.go b/cmd/containers.go index fe8698f..d177845 100644 --- a/cmd/containers.go +++ b/cmd/containers.go @@ -60,7 +60,7 @@ var containersGetCmd = &cobra.Command{ return debugErr } - kfClient, _ := initClient(configFile, profile, providerType, providerProfile, noPrompt, false) + kfClient, _ := initClient(false) agents, aErr := kfClient.GetStoreContainer(id) if aErr != nil { @@ -93,7 +93,7 @@ var containersUpdateCmd = &cobra.Command{ } // Authenticate - //authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) + // // CLI Logic return fmt.Errorf("update store containers not implemented") @@ -117,7 +117,7 @@ var containersDeleteCmd = &cobra.Command{ } // Authenticate - //authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) + // //kfClient, _ := initClient(configFile, profile, providerType, providerProfile, noPrompt, authConfig, false) // CLI Logic @@ -142,8 +142,8 @@ var containersListCmd = &cobra.Command{ } // Authenticate - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) - kfClient, _ := initClient(configFile, profile, providerType, providerProfile, noPrompt, authConfig, false) + // + kfClient, _ := initClient(false) // CLI Logic agents, aErr := kfClient.GetStoreContainers() diff --git a/cmd/export.go b/cmd/export.go index 909589b..e0145c5 100644 --- a/cmd/export.go +++ b/cmd/export.go @@ -137,31 +137,13 @@ var exportCmd = &cobra.Command{ SecurityRoles: []api.CreateSecurityRoleArg{}, } - log.Debug().Msgf("%s: createAuthConfigFromParams", DebugFuncCall) - //authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) - authConfig := createAuthConfigFromParams( - kfcHostName, - kfcUsername, - kfcPassword, - kfcDomain, - kfcAPIPath, - kfcClientId, - kfcClientSecret, - kfcTokenUrl, - ) - - if authConfig == nil { - log.Error().Msg("auth config is nil, invalid client configuration") - return fmt.Errorf(FailedAuthMsg) - } - exportPath := cmd.Flag("file").Value.String() log.Debug().Str("exportPath", exportPath).Msg("exportPath") log.Debug().Msgf("%s: initGenClient", DebugFuncCall) - kfClient, clientErr := initGenClient(configFile, profile, noPrompt, authConfig, false) + kfClient, clientErr := initGenClient(false) log.Debug().Msgf("%s: initClient", DebugFuncCall) - oldkfClient, oldClientErr := initClient(configFile, profile, "", "", noPrompt, authConfig, false) + oldkfClient, oldClientErr := initClient(false) if clientErr != nil { log.Error().Err(clientErr).Send() diff --git a/cmd/import.go b/cmd/import.go index 0432306..e9a3bf7 100644 --- a/cmd/import.go +++ b/cmd/import.go @@ -69,12 +69,6 @@ var importCmd = &cobra.Command{ log.Info().Msg("Running import...") - log.Debug().Msgf("%s: createAuthConfigFromParams", DebugFuncCall) - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) - if authConfig == nil { - return fmt.Errorf("Error: %s", FailedAuthMsg) - } - exportPath := cmd.Flag("file").Value.String() log.Debug().Str("exportPath", exportPath).Msg("exportPath") @@ -107,9 +101,9 @@ var importCmd = &cobra.Command{ return jErr } log.Debug().Msgf("%s: initGenClient", DebugFuncCall) - kfClient, clientErr := initGenClient(configFile, profile, noPrompt, authConfig, false) + kfClient, clientErr := initGenClient(false) log.Debug().Msgf("%s: initClient", DebugFuncExit) - oldkfClient, oldClientErr := initClient(configFile, profile, "", "", noPrompt, authConfig, false) + oldkfClient, oldClientErr := initClient(false) if clientErr != nil { log.Error().Err(clientErr).Send() diff --git a/cmd/inventory.go b/cmd/inventory.go index 92ab084..28d4404 100644 --- a/cmd/inventory.go +++ b/cmd/inventory.go @@ -51,8 +51,6 @@ var inventoryClearCmd = &cobra.Command{ PreRun: nil, PreRunE: nil, Run: func(cmd *cobra.Command, args []string) { - - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) isExperimental := true _, expErr := isExperimentalFeatureEnabled(expEnabled, isExperimental) @@ -72,7 +70,7 @@ var inventoryClearCmd = &cobra.Command{ containerType, _ := cmd.Flags().GetStringSlice("container") allStores, _ := cmd.Flags().GetBool("all") - kfClient, _ := initClient(configFile, profile, "", "", noPrompt, authConfig, false) + kfClient, _ := initClient(false) if storeID == nil && machineName == nil && storeType == nil && containerType == nil && !allStores { fmt.Println("You must specify at least one of the following options: --sid, --client, --store-type, --container, --all") @@ -220,8 +218,6 @@ specified by Keyfactor command store ID, client machine name, store type, or con and one or more certificates must be specified. If multiple stores and/or certificates are specified, the command will attempt to add all the certificate(s) meeting the specified criteria to all stores meeting the specified criteria.`, Run: func(cmd *cobra.Command, args []string) { - - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) isExperimental := true _, expErr := isExperimentalFeatureEnabled(expEnabled, isExperimental) @@ -254,7 +250,7 @@ attempt to add all the certificate(s) meeting the specified criteria to all stor log.Fatalf("At least one certificate must be specified") } - kfClient, _ := initClient(configFile, profile, "", "", noPrompt, authConfig, false) + kfClient, _ := initClient(false) if storeIDs == nil && machineNames == nil && storeTypes == nil && containerType == nil && !allStores { fmt.Println("You must specify at least one of the following options: --sid, --client, --store-type, --container, --all") @@ -411,7 +407,6 @@ var inventoryRemoveCmd = &cobra.Command{ Long: `Removes a certificate from the certificate store inventory.`, Run: func(cmd *cobra.Command, args []string) { - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) isExperimental := true _, expErr := isExperimentalFeatureEnabled(expEnabled, isExperimental) @@ -444,7 +439,7 @@ var inventoryRemoveCmd = &cobra.Command{ log.Fatalf("At least one certificate must be specified") } - kfClient, _ := initClient(configFile, profile, "", "", noPrompt, authConfig, false) + kfClient, _ := initClient(false) if storeIDs == nil && machineNames == nil && storeTypes == nil && containerType == nil && !allStores { fmt.Println("You must specify at least one of the following options: --sid, --client, --store-type, --container, --all") @@ -614,8 +609,6 @@ var inventoryShowCmd = &cobra.Command{ PreRun: nil, PreRunE: nil, Run: func(cmd *cobra.Command, args []string) { - - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) isExperimental := true _, expErr := isExperimentalFeatureEnabled(expEnabled, isExperimental) @@ -631,7 +624,7 @@ var inventoryShowCmd = &cobra.Command{ storeTypes, _ := cmd.Flags().GetStringSlice("store-type") containers, _ := cmd.Flags().GetStringSlice("container") - kfClient, _ := initClient(configFile, profile, "", "", noPrompt, authConfig, false) + kfClient, _ := initClient(false) if len(storeIDs) == 0 && len(clientMachineNames) == 0 && len(storeTypes) == 0 && len(containers) == 0 { fmt.Println("No filters specified. Unable to show inventory. Please specify at least one filter: [--sid, --client, --store-type, --container]") diff --git a/cmd/login.go b/cmd/login.go index 3814906..2fe2dd7 100644 --- a/cmd/login.go +++ b/cmd/login.go @@ -22,7 +22,7 @@ import ( "strings" "syscall" - "github.com/Keyfactor/keyfactor-auth-client-go/auth_config" + "github.com/Keyfactor/keyfactor-auth-client-go/auth_providers" "github.com/Keyfactor/keyfactor-go-client/v3/api" "github.com/google/go-cmp/cmp" "github.com/rs/zerolog/log" @@ -540,7 +540,7 @@ func loadConfigFileData( func authViaProvider() (*api.Client, error) { var clientAuth api.AuthConfig - var commandConfig auth_config.Config + var commandConfig auth_providers.Config if providerType != "" { log.Info().Str("providerType", providerType).Msg("attempting to auth via auth provider") var providerConfig AuthProvider @@ -1203,18 +1203,3 @@ func loadConfigurationFile(filePath string, silent bool) (ConfigurationFile, err return data, nil } - -func createAuthConfigFromParams( - hostname string, - username string, - password string, - domain string, - apiPath string, - clientId string, - clientSecret string, - tokenUrl string, -) *api.AuthConfig { - - serverConfig := auth_config.Server{} - return &output -} diff --git a/cmd/orchs.go b/cmd/orchs.go index 47d85ff..324ec21 100644 --- a/cmd/orchs.go +++ b/cmd/orchs.go @@ -36,8 +36,6 @@ var getOrchestratorCmd = &cobra.Command{ Short: "Get orchestrator by machine/client name.", Long: `Get orchestrator by machine/client name.`, Run: func(cmd *cobra.Command, args []string) { - - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) isExperimental := true _, expErr := isExperimentalFeatureEnabled(expEnabled, isExperimental) @@ -49,7 +47,7 @@ var getOrchestratorCmd = &cobra.Command{ debugModeEnabled := checkDebug(debugFlag) log.Println("Debug mode enabled: ", debugModeEnabled) client := cmd.Flag("client").Value.String() - kfClient, _ := initClient(configFile, profile, "", "", noPrompt, authConfig, false) + kfClient, _ := initClient(false) agents, aErr := kfClient.GetAgent(client) if aErr != nil { fmt.Printf("Error, unable to get orchestrator %s. %s\n", client, aErr) @@ -70,8 +68,6 @@ var approveOrchestratorCmd = &cobra.Command{ Short: "Approve orchestrator by machine/client name.", Long: `Approve orchestrator by machine/client name.`, Run: func(cmd *cobra.Command, args []string) { - - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) isExperimental := true _, expErr := isExperimentalFeatureEnabled(expEnabled, isExperimental) @@ -83,7 +79,7 @@ var approveOrchestratorCmd = &cobra.Command{ debugModeEnabled := checkDebug(debugFlag) log.Println("Debug mode enabled: ", debugModeEnabled) client := cmd.Flag("client").Value.String() - kfClient, cErr := initClient(configFile, profile, "", "", noPrompt, authConfig, false) + kfClient, cErr := initClient(false) if cErr != nil { fmt.Println("Error, unable to connect to Keyfactor.") log.Fatalf("Error: %s", cErr) @@ -110,7 +106,6 @@ var disapproveOrchestratorCmd = &cobra.Command{ Long: `Disapprove orchestrator by machine/client name.`, Run: func(cmd *cobra.Command, args []string) { - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) isExperimental := true _, expErr := isExperimentalFeatureEnabled(expEnabled, isExperimental) @@ -122,7 +117,7 @@ var disapproveOrchestratorCmd = &cobra.Command{ debugModeEnabled := checkDebug(debugFlag) log.Println("Debug mode enabled: ", debugModeEnabled) client := cmd.Flag("client").Value.String() - kfClient, cErr := initClient(configFile, profile, "", "", noPrompt, authConfig, false) + kfClient, cErr := initClient(false) if cErr != nil { fmt.Println("Error, unable to connect to Keyfactor.") log.Fatalf("Error: %s", cErr) @@ -158,8 +153,6 @@ var getLogsOrchestratorCmd = &cobra.Command{ Short: "Get orchestrator logs by machine/client name.", Long: `Get orchestrator logs by machine/client name.`, Run: func(cmd *cobra.Command, args []string) { - - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) isExperimental := true _, expErr := isExperimentalFeatureEnabled(expEnabled, isExperimental) @@ -172,7 +165,7 @@ var getLogsOrchestratorCmd = &cobra.Command{ log.Println("Debug mode enabled: ", debugModeEnabled) client := cmd.Flag("client").Value.String() - kfClient, cErr := initClient(configFile, profile, "", "", noPrompt, authConfig, false) + kfClient, cErr := initClient(false) if cErr != nil { fmt.Println("Error, unable to connect to Keyfactor.") log.Fatalf("Error: %s", cErr) @@ -198,8 +191,6 @@ var listOrchestratorsCmd = &cobra.Command{ Short: "List orchestrators.", Long: `Returns a JSON list of Keyfactor orchestrators.`, Run: func(cmd *cobra.Command, args []string) { - - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) isExperimental := true _, expErr := isExperimentalFeatureEnabled(expEnabled, isExperimental) @@ -210,7 +201,7 @@ var listOrchestratorsCmd = &cobra.Command{ debugModeEnabled := checkDebug(debugFlag) log.Println("Debug mode enabled: ", debugModeEnabled) - kfClient, _ := initClient(configFile, profile, "", "", noPrompt, authConfig, false) + kfClient, _ := initClient(false) agents, aErr := kfClient.GetAgentList() if aErr != nil { fmt.Printf("Error, unable to get orchestrators list. %s\n", aErr) @@ -237,7 +228,13 @@ func init() { orchsCmd.AddCommand(listOrchestratorsCmd) // GET orchestrator command orchsCmd.AddCommand(getOrchestratorCmd) - getOrchestratorCmd.Flags().StringVarP(&client, "client", "c", "", "Get a specific orchestrator by machine or client name.") + getOrchestratorCmd.Flags().StringVarP( + &client, + "client", + "c", + "", + "Get a specific orchestrator by machine or client name.", + ) getOrchestratorCmd.MarkFlagRequired("client") // CREATE orchestrator command //orchsCmd.AddCommand(createOrchestratorCmd) @@ -247,19 +244,43 @@ func init() { //orchsCmd.AddCommand(deleteOrchestratorCmd) // APPROVE orchestrator command orchsCmd.AddCommand(approveOrchestratorCmd) - approveOrchestratorCmd.Flags().StringVarP(&client, "client", "c", "", "Approve a specific orchestrator by machine or client name.") + approveOrchestratorCmd.Flags().StringVarP( + &client, + "client", + "c", + "", + "Approve a specific orchestrator by machine or client name.", + ) approveOrchestratorCmd.MarkFlagRequired("client") // DISAPPROVE orchestrator command orchsCmd.AddCommand(disapproveOrchestratorCmd) - disapproveOrchestratorCmd.Flags().StringVarP(&client, "client", "c", "", "Disapprove a specific orchestrator by machine or client name.") + disapproveOrchestratorCmd.Flags().StringVarP( + &client, + "client", + "c", + "", + "Disapprove a specific orchestrator by machine or client name.", + ) disapproveOrchestratorCmd.MarkFlagRequired("client") // RESET orchestrator command orchsCmd.AddCommand(resetOrchestratorCmd) - resetOrchestratorCmd.Flags().StringVarP(&client, "client", "c", "", "Reset a specific orchestrator by machine or client name.") + resetOrchestratorCmd.Flags().StringVarP( + &client, + "client", + "c", + "", + "Reset a specific orchestrator by machine or client name.", + ) resetOrchestratorCmd.MarkFlagRequired("client") // GET orchestrator logs command orchsCmd.AddCommand(getLogsOrchestratorCmd) - getLogsOrchestratorCmd.Flags().StringVarP(&client, "client", "c", "", "Get logs for a specific orchestrator by machine or client name.") + getLogsOrchestratorCmd.Flags().StringVarP( + &client, + "client", + "c", + "", + "Get logs for a specific orchestrator by machine or client name.", + ) getLogsOrchestratorCmd.MarkFlagRequired("client") // SET orchestrator auth certificate reenrollment command //orchsCmd.AddCommand(setOrchestratorAuthCertReenrollCmd) diff --git a/cmd/pam.go b/cmd/pam.go index 2b3e6ff..1893081 100644 --- a/cmd/pam.go +++ b/cmd/pam.go @@ -18,12 +18,13 @@ import ( "context" "encoding/json" "fmt" - "github.com/Keyfactor/keyfactor-go-client-sdk/api/keyfactor" - "github.com/rs/zerolog/log" - "github.com/spf13/cobra" "io" "net/http" "os" + + "github.com/Keyfactor/keyfactor-go-client-sdk/api/keyfactor" + "github.com/rs/zerolog/log" + "github.com/spf13/cobra" ) type JSONImportableObject interface { @@ -61,8 +62,7 @@ var pamTypesListCmd = &cobra.Command{ log.Info().Msg("list PAM Provider Types") // Authenticate - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) - sdkClient, clientErr := initGenClient(configFile, profile, noPrompt, authConfig, false) + sdkClient, clientErr := initGenClient(false) if clientErr != nil { return clientErr } @@ -135,9 +135,8 @@ https://github.com/Keyfactor/hashicorp-vault-pam/blob/main/integration-manifest. Msg("create PAM Provider Type") // Authenticate - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) //kfClient, _ := initClient(configFile, profile, providerType, providerProfile, noPrompt, authConfig, false) - sdkClient, _ := initGenClient(configFile, profile, noPrompt, authConfig, false) + sdkClient, _ := initGenClient(false) // Check required flags if pamConfigFile == "" && repoName == "" { @@ -229,9 +228,8 @@ var pamProvidersListCmd = &cobra.Command{ log.Info().Msg("list PAM Providers") // Authenticate - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) //kfClient, _ := initClient(configFile, profile, providerType, providerProfile, noPrompt, authConfig, false) - sdkClient, _ := initGenClient(configFile, profile, noPrompt, authConfig, false) + sdkClient, _ := initGenClient(false) // CLI Logic log.Debug().Msg("call: PAMProviderGetPamProviders()") @@ -281,13 +279,15 @@ var pamProvidersGetCmd = &cobra.Command{ Msg("get PAM Provider") // Authenticate - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) //kfClient, _ := initClient(configFile, profile, providerType, providerProfile, noPrompt, authConfig, false) - sdkClient, _ := initGenClient(configFile, profile, noPrompt, authConfig, false) + sdkClient, _ := initGenClient(false) // CLI Logic log.Debug().Msg("call: PAMProviderGetPamProvider()") - pamProvider, httpResponse, err := sdkClient.PAMProviderApi.PAMProviderGetPamProvider(context.Background(), pamProviderId). + pamProvider, httpResponse, err := sdkClient.PAMProviderApi.PAMProviderGetPamProvider( + context.Background(), + pamProviderId, + ). XKeyfactorRequestedWith(XKeyfactorRequestedWith).XKeyfactorApiVersion(XKeyfactorApiVersion). Execute() log.Debug().Msg("returned: PAMProviderGetPamProvider()") @@ -334,9 +334,8 @@ var pamProvidersCreateCmd = &cobra.Command{ Msg("create PAM Provider from file") // Authenticate - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) // kfClient, _ := initClient(configFile, profile, providerType, providerProfile, noPrompt, authConfig, false) - sdkClient, _ := initGenClient(configFile, profile, noPrompt, authConfig, false) + sdkClient, _ := initGenClient(false) // CLI Logic var pamProvider *keyfactor.CSSCMSDataModelModelsProvider @@ -398,9 +397,8 @@ var pamProvidersUpdateCmd = &cobra.Command{ Msg("update PAM Provider from file") // Authenticate - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) //kfClient, _ := initClient(configFile, profile, providerType, providerProfile, noPrompt, authConfig, false) - sdkClient, _ := initGenClient(configFile, profile, noPrompt, authConfig, false) + sdkClient, _ := initGenClient(false) // CLI Logic var pamProvider *keyfactor.CSSCMSDataModelModelsProvider @@ -465,9 +463,8 @@ var pamProvidersDeleteCmd = &cobra.Command{ Msg("delete PAM Provider") // Authenticate - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) //kfClient, _ := initClient(configFile, profile, providerType, providerProfile, noPrompt, authConfig, false) - sdkClient, _ := initGenClient(configFile, profile, noPrompt, authConfig, false) + sdkClient, _ := initGenClient(false) // CLI Logic log.Debug(). @@ -500,7 +497,11 @@ func GetPAMTypeInternet(providerName string, repo string, branch string) (interf branch = "main" } - providerUrl := fmt.Sprintf("https://raw.githubusercontent.com/Keyfactor/%s/%s/integration-manifest.json", repo, branch) + providerUrl := fmt.Sprintf( + "https://raw.githubusercontent.com/Keyfactor/%s/%s/integration-manifest.json", + repo, + branch, + ) log.Debug().Str("providerUrl", providerUrl). Msg("Getting PAM Type from Internet") response, err := http.Get(providerUrl) @@ -558,7 +559,10 @@ func GetPAMTypeInternet(providerName string, repo string, branch string) (interf return pamTypeJson, nil } -func GetTypeFromInternet[T JSONImportableObject](providerName string, repo string, branch string, returnType *T) (*T, error) { +func GetTypeFromInternet[T JSONImportableObject](providerName string, repo string, branch string, returnType *T) ( + *T, + error, +) { log.Debug().Str("providerName", providerName). Str("repo", repo). Str("branch", branch). @@ -629,10 +633,22 @@ func init() { // PAM Provider Types Create pamCmd.AddCommand(pamTypesCreateCmd) - pamTypesCreateCmd.Flags().StringVarP(&filePath, FlagFromFile, "f", "", "Path to a JSON file containing the PAM Type Object Data.") + pamTypesCreateCmd.Flags().StringVarP( + &filePath, + FlagFromFile, + "f", + "", + "Path to a JSON file containing the PAM Type Object Data.", + ) pamTypesCreateCmd.Flags().StringVarP(&name, "name", "n", "", "Name of the PAM Provider Type.") pamTypesCreateCmd.Flags().StringVarP(&repo, "repo", "r", "", "Keyfactor repository name of the PAM Provider Type.") - pamTypesCreateCmd.Flags().StringVarP(&branch, "branch", "b", "", "Branch name for the repository. Defaults to 'main'.") + pamTypesCreateCmd.Flags().StringVarP( + &branch, + "branch", + "b", + "", + "Branch name for the repository. Defaults to 'main'.", + ) // PAM Providers pamCmd.AddCommand(pamProvidersListCmd) @@ -641,11 +657,23 @@ func init() { pamProvidersGetCmd.MarkFlagRequired("id") pamCmd.AddCommand(pamProvidersCreateCmd) - pamProvidersCreateCmd.Flags().StringVarP(&filePath, FlagFromFile, "f", "", "Path to a JSON file containing the PAM Provider Object Data.") + pamProvidersCreateCmd.Flags().StringVarP( + &filePath, + FlagFromFile, + "f", + "", + "Path to a JSON file containing the PAM Provider Object Data.", + ) pamProvidersCreateCmd.MarkFlagRequired(FlagFromFile) pamCmd.AddCommand(pamProvidersUpdateCmd) - pamProvidersUpdateCmd.Flags().StringVarP(&filePath, FlagFromFile, "f", "", "Path to a JSON file containing the PAM Provider Object Data.") + pamProvidersUpdateCmd.Flags().StringVarP( + &filePath, + FlagFromFile, + "f", + "", + "Path to a JSON file containing the PAM Provider Object Data.", + ) pamProvidersUpdateCmd.MarkFlagRequired(FlagFromFile) pamCmd.AddCommand(pamProvidersDeleteCmd) diff --git a/cmd/root.go b/cmd/root.go index 0c3b8d9..3c4afc1 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -15,7 +15,6 @@ package cmd import ( - "context" _ "embed" "fmt" "io" @@ -23,7 +22,6 @@ import ( "os" "strings" - "github.com/Keyfactor/keyfactor-auth-client-go/auth_config" "github.com/Keyfactor/keyfactor-auth-client-go/auth_providers" "github.com/Keyfactor/keyfactor-go-client-sdk/api/keyfactor" "github.com/Keyfactor/keyfactor-go-client/v3/api" @@ -73,9 +71,9 @@ func hashSecretValue(secretValue string) string { return string(hashedPassword) } -func getServerConfigFromFile(configFile string, profile string) (*auth_config.Server, error) { - var commandConfig *auth_config.Config - var serverConfig auth_config.Server +func getServerConfigFromFile(configFile string, profile string) (*auth_providers.Server, error) { + var commandConfig *auth_providers.Config + var serverConfig auth_providers.Server log.Debug(). Str("configFile", configFile). @@ -90,12 +88,12 @@ func getServerConfigFromFile(configFile string, profile string) (*auth_config.Se } var cfgReadErr error if strings.HasSuffix(configFile, ".yaml") || strings.HasSuffix(configFile, ".yml") { - log.Debug().Msg("call: auth_config.ReadConfigFromYAML()") - //commandConfig, cfgReadErr = auth_config.ReadConfigFromYAML(configFile) - commandConfig, cfgReadErr = auth_config.ReadConfigFromJSON(configFile) + log.Debug().Msg("call: auth_providers.ReadConfigFromYAML()") + //commandConfig, cfgReadErr = auth_providers.ReadConfigFromYAML(configFile) + commandConfig, cfgReadErr = auth_providers.ReadConfigFromJSON(configFile) } else { - log.Debug().Msg("call: auth_config.ReadConfigFromJSON()") - commandConfig, cfgReadErr = auth_config.ReadConfigFromJSON(configFile) + log.Debug().Msg("call: auth_providers.ReadConfigFromJSON()") + commandConfig, cfgReadErr = auth_providers.ReadConfigFromJSON(configFile) } if cfgReadErr != nil { @@ -114,13 +112,15 @@ func getServerConfigFromFile(configFile string, profile string) (*auth_config.Se return &serverConfig, nil } -func getServerConfigFromEnv() (*auth_config.Server, error) { +func getServerConfigFromEnv() (*auth_providers.Server, error) { log.Debug().Msg("Enter getServerConfigFromEnv()") oAuthNoParamsConfig := &auth_providers.CommandConfigOauth{} basicAuthNoParamsConfig := &auth_providers.CommandAuthConfigBasic{} + log.Debug().Msg("call: basicAuthNoParamsConfig.Authenticate()") bErr := basicAuthNoParamsConfig.Authenticate() + log.Debug().Msg("complete: basicAuthNoParamsConfig.Authenticate()") if bErr == nil { log.Debug().Msg("return: getServerConfigFromEnv()") return basicAuthNoParamsConfig.GetServerConfig(), nil @@ -175,6 +175,41 @@ func authViaConfigFile(cfgFile string, cfgProfile string) (*api.Client, error) { log.Error().Msg("unable to authenticate via config file") return nil, fmt.Errorf("unable to authenticate via config file '%s' using profile '%s'", cfgFile, cfgProfile) } +func authSdkViaConfigFile(cfgFile string, cfgProfile string) (*keyfactor.APIClient, error) { + var ( + c *keyfactor.APIClient + cErr error + ) + log.Debug().Msg("call: getServerConfigFromFile()") + conf, err := getServerConfigFromFile(cfgFile, cfgProfile) + log.Debug().Msg("complete: getServerConfigFromFile()") + if err != nil { + log.Error(). + Err(err). + Msg("unable to get server config from file") + return nil, err + } + if conf != nil { + log.Debug().Msg("call: keyfactor.NewAPIClient()") + c = keyfactor.NewAPIClient(conf) + log.Debug().Msg("complete: keyfactor.NewAPIClient()") + if cErr != nil { + log.Error(). + Err(cErr). + Msg("unable to create Keyfactor client") + return nil, cErr + } + log.Debug().Msg("call: c.AuthClient.Authenticate()") + authErr := c.AuthClient.Authenticate() + log.Debug().Msg("complete: c.AuthClient.Authenticate()") + if authErr == nil { + return c, nil + } + + } + log.Error().Msg("unable to authenticate via config file") + return nil, fmt.Errorf("unable to authenticate via config file '%s' using profile '%s'", cfgFile, cfgProfile) +} func authViaEnvVars() (*api.Client, error) { var ( @@ -213,6 +248,43 @@ func authViaEnvVars() (*api.Client, error) { log.Debug().Msg("return: authViaEnvVars()") return nil, fmt.Errorf("unable to authenticate via environment variables") } +func authSdkViaEnvVars() (*keyfactor.APIClient, error) { + var ( + c *keyfactor.APIClient + cErr error + ) + log.Debug().Msg("enter: authViaEnvVars()") + log.Debug().Msg("call: getServerConfigFromEnv()") + conf, err := getServerConfigFromEnv() + log.Debug().Msg("complete: getServerConfigFromEnv()") + if err != nil { + log.Error().Err(err).Msg("unable to authenticate via environment variables") + log.Debug().Msg("return: authViaEnvVars()") + return nil, err + } + if conf != nil { + log.Debug().Msg("call: api.NewKeyfactorClient()") + c = keyfactor.NewAPIClient(conf) + log.Debug().Msg("complete: api.NewKeyfactorClient()") + if cErr != nil { + log.Error().Err(cErr).Msg("unable to create Keyfactor client") + log.Debug().Msg("return: authViaEnvVars()") + return nil, cErr + } + log.Debug().Msg("call: c.AuthClient.Authenticate()") + authErr := c.AuthClient.Authenticate() + log.Debug().Msg("complete: c.AuthClient.Authenticate()") + if authErr != nil { + log.Error().Err(authErr).Msg("unable to authenticate via environment variables") + return nil, authErr + } + log.Debug().Msg("return: authViaEnvVars()") + return c, nil + } + log.Error().Msg("unable to authenticate via environment variables") + log.Debug().Msg("return: authViaEnvVars()") + return nil, fmt.Errorf("unable to authenticate via environment variables") +} func initClient(saveConfig bool) (*api.Client, error) { log.Debug(). @@ -268,85 +340,80 @@ func initClient(saveConfig bool) (*api.Client, error) { } } + if !authenticated { + log.Error().Msg("unable to authenticate") + if cErr != nil { + log.Debug().Err(cErr).Msg("return: initClient()") + return nil, cErr + } + log.Debug().Msg("return: initClient()") + return nil, fmt.Errorf("unable to authenticate to Keyfactor Command") + } + log.Info().Msg("Keyfactor Command client created") return c, nil } func initGenClient( - flagConfig string, - flagProfile string, - noPrompt bool, - authConfig *auth_config.Config, saveConfig bool, ) (*keyfactor.APIClient, error) { + log.Debug(). + Str("configFile", configFile). + Str("profile", profile). + Str("providerType", providerType). + Str("providerProfile", providerProfile). + Bool("noPrompt", noPrompt). + Bool("saveConfig", saveConfig). + Str("hostname", kfcHostName). + Str("username", kfcUsername). + Str("password", hashSecretValue(kfcPassword)). + Str("domain", kfcDomain). + Str("clientId", kfcClientId). + Str("clientSecret", hashSecretValue(kfcClientSecret)). + Str("apiPath", kfcAPIPath). + Str("providerType", providerType). + Str("providerProfile", providerProfile). + Msg("enter: initGenClient()") - baseConfig := auth_providers.CommandAuthConfig{} - baseConfig.WithCommandHostName(kfcHostName). - WithCommandAPIPath(kfcAPIPath). - WithConfigProfile(flagProfile). - WithConfigFile(flagConfig) - - oClient := auth_providers.CommandConfigOauth{ - CommandAuthConfig: baseConfig, - } + var ( + authenticated bool + c *keyfactor.APIClient + cErr error + ) - bClient := auth_providers.CommandAuthConfigBasic{ - CommandAuthConfig: baseConfig, + if providerType != "" { + log.Debug(). + Str("providerType", providerType). + Msg("call: authViaProvider()") + //return authViaProvider() + return nil, fmt.Errorf("provider auth not supported using Keyfactor Command SDK") } + log.Debug(). + Msg("providerType is empty attempting to authenticate via params") - serverConfig := auth_config.Server{} - if authConfig == nil { - var bErr error - var oErr error - if kfcUsername != "" && kfcPassword != "" { - bErr = bClient.WithUsername(kfcUsername). - WithPassword(kfcPassword). - WithDomain(kfcDomain). - Authenticate() - } else if kfcClientId != "" && kfcClientSecret != "" && kfcTokenUrl != "" { - oErr = oClient.WithClientId(kfcClientId). - WithClientSecret(kfcClientSecret). - WithTokenUrl(kfcTokenUrl). - Authenticate() - } else { - // Try both? - bErr = bClient.WithUsername(kfcUsername). - WithPassword(kfcPassword). - WithDomain(kfcDomain). - Authenticate() - oErr = oClient.WithClientId(kfcClientId). - WithClientSecret(kfcClientSecret). - WithTokenUrl(kfcTokenUrl). - Authenticate() + if configFile != "" || profile != "" { + c, cErr = authSdkViaConfigFile(configFile, profile) + if cErr == nil { + log.Info(). + Str("configFile", configFile). + Str("profile", profile). + Msgf("Authenticated via config file %s using profile %s", configFile, profile) + authenticated = true } + } - if bErr != nil && oErr != nil { - log.Error().Msg("Unable to authenticate with provided credentials") - //combine errors - return nil, fmt.Errorf("unable to authenticate with provided credentials: %s, %s", bErr, oErr) - } else if bErr == nil { - serverConfig.Username = bClient.Username - serverConfig.Password = bClient.Password - serverConfig.Domain = bClient.Domain - serverConfig.Host = bClient.CommandHostName - serverConfig.APIPath = bClient.CommandAPIPath - } else { - serverConfig.ClientID = oClient.ClientID - serverConfig.ClientSecret = oClient.ClientSecret - serverConfig.Host = bClient.CommandHostName - serverConfig.APIPath = bClient.CommandAPIPath + if !authenticated { + log.Debug().Msg("call: authViaEnvVars()") + c, cErr = authSdkViaEnvVars() + log.Debug().Msg("returned: authViaEnvVars()") + if cErr == nil { + log.Info().Msg("Authenticated via environment variables") + authenticated = true } } - apiClient := keyfactor.NewAPIClient(&serverConfig) - resp, r, err := apiClient.StatusApi.StatusGetEndpoints(context.Background()).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `StatusApi.StatusGetEndpoints``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `StatusGetEndpoints`: []string - fmt.Fprintf(os.Stdout, "Response from `StatusApi.StatusGetEndpoints`: %v\n", resp) - return apiClient, nil + log.Info().Msg("Keyfactor Command client created") + return c, nil } //func initGenClientV1( diff --git a/cmd/rot.go b/cmd/rot.go index 6a2bfa2..2a7478c 100644 --- a/cmd/rot.go +++ b/cmd/rot.go @@ -521,12 +521,12 @@ package cmd // kfcPassword, _ := cmd.Flags().GetString("kfcPassword") // kfcDomain, _ := cmd.Flags().GetString("kfcDomain") // -// authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) +// // // debugModeEnabled := checkDebug(debugFlag) // log.Println("Debug mode enabled: ", debugModeEnabled) // var lookupFailures []string -// kfClient, _ := initClient(configFile, profile, "", "", noPrompt, authConfig, false) +// kfClient, _ := initClient(false) // storesFile, _ := cmd.Flags().GetString("stores") // addRootsFile, _ := cmd.Flags().GetString("add-certs") // removeRootsFile, _ := cmd.Flags().GetString("remove-certs") @@ -687,14 +687,14 @@ package cmd // kfcPassword, _ := cmd.Flags().GetString("kfcPassword") // kfcDomain, _ := cmd.Flags().GetString("kfcDomain") // -// authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) +// // // debugModeEnabled := checkDebug(debugFlag) // // log.Println("Debug mode enabled: ", debugModeEnabled) // // var lookupFailures []string -// kfClient, _ := initClient(configFile, profile, "", "", noPrompt, authConfig, false) +// kfClient, _ := initClient(false) // storesFile, _ := cmd.Flags().GetString("stores") // addRootsFile, _ := cmd.Flags().GetString("add-certs") // isCSV, _ := cmd.Flags().GetBool("import-csv") @@ -998,7 +998,7 @@ package cmd // kfcPassword, _ := cmd.Flags().GetString("kfcPassword") // kfcDomain, _ := cmd.Flags().GetString("kfcDomain") // -// authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) +// // // debugModeEnabled := checkDebug(debugFlag) // log.Println("Debug mode enabled: ", debugModeEnabled) @@ -1015,7 +1015,7 @@ package cmd // var csvStoreData [][]string // var csvCertData [][]string // var rowLookup = make(map[string]bool) -// kfClient, cErr := initClient(configFile, profile, "", "", noPrompt, authConfig, false) +// kfClient, cErr := initClient(false) // if len(storeType) != 0 { // for _, s := range storeType { // if cErr != nil { diff --git a/cmd/storeTypes.go b/cmd/storeTypes.go index 354f22d..765d8ed 100644 --- a/cmd/storeTypes.go +++ b/cmd/storeTypes.go @@ -55,8 +55,7 @@ var storesTypesListCmd = &cobra.Command{ informDebug(debugFlag) // Authenticate - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) - kfClient, _ := initClient(configFile, profile, providerType, providerProfile, noPrompt, authConfig, false) + kfClient, _ := initClient(false) // CLI Logic storeTypes, err := kfClient.ListCertificateStoreTypes() @@ -99,8 +98,7 @@ var storesTypeCreateCmd = &cobra.Command{ informDebug(debugFlag) // Authenticate - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) - kfClient, _ := initClient(configFile, profile, providerType, providerProfile, noPrompt, authConfig, false) + kfClient, _ := initClient(false) // CLI Logic if gitRef == "" { @@ -244,11 +242,10 @@ var storesTypeDeleteCmd = &cobra.Command{ Msg("delete command flags") // Authenticate - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) if gitRef == "" { gitRef = "main" } - kfClient, _ := initClient(configFile, profile, providerType, providerProfile, noPrompt, authConfig, false) + kfClient, _ := initClient(false) var validStoreTypes []string var removeStoreTypes []interface{} diff --git a/cmd/storeTypes_get.go b/cmd/storeTypes_get.go index a01ab51..e630d11 100644 --- a/cmd/storeTypes_get.go +++ b/cmd/storeTypes_get.go @@ -117,8 +117,7 @@ func CreateCmdStoreTypesGet() *cobra.Command { } // Authenticate - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) - kfClient, _ := initClient(configFile, profile, providerType, providerProfile, noPrompt, authConfig, false) + kfClient, _ := initClient(false) if kfClient == nil { return fmt.Errorf("failed to initialize Keyfactor client") diff --git a/cmd/stores.go b/cmd/stores.go index 9205d1f..9a0c19a 100644 --- a/cmd/stores.go +++ b/cmd/stores.go @@ -51,8 +51,7 @@ var storesListCmd = &cobra.Command{ informDebug(debugFlag) // Authenticate - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) - kfClient, _ := initClient(configFile, profile, providerType, providerProfile, noPrompt, authConfig, false) + kfClient, _ := initClient(false) // CLI Logic params := make(map[string]interface{}) @@ -94,8 +93,7 @@ var storesGetCmd = &cobra.Command{ informDebug(debugFlag) // Authenticate - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) - kfClient, _ := initClient(configFile, profile, providerType, providerProfile, noPrompt, authConfig, false) + kfClient, _ := initClient(false) // CLI Logic stores, err := kfClient.GetCertificateStoreByID(storeID) @@ -134,8 +132,7 @@ var storesDeleteCmd = &cobra.Command{ informDebug(debugFlag) // Authenticate - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) - kfClient, _ := initClient(configFile, profile, providerType, providerProfile, noPrompt, authConfig, false) + kfClient, _ := initClient(false) // CLI Logic log.Info().Str("storeID", storeID).Msg("Deleting certificate store") diff --git a/cmd/storesBulkOperations.go b/cmd/storesBulkOperations.go index dc65efa..ada8184 100644 --- a/cmd/storesBulkOperations.go +++ b/cmd/storesBulkOperations.go @@ -132,8 +132,7 @@ var storesCreateFromCSVCmd = &cobra.Command{ informDebug(debugFlag) // Authenticate - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) - kfClient, _ := initClient(configFile, profile, "", "", noPrompt, authConfig, false) + kfClient, _ := initClient(false) // CLI Logic log.Info().Msg("Importing certificate stores") @@ -376,8 +375,7 @@ Store type IDs can be found by running the "store-types" command.`, informDebug(debugFlag) // Authenticate - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) - kfClient, clientErr := initClient(configFile, profile, "", "", noPrompt, authConfig, false) + kfClient, clientErr := initClient(false) if clientErr != nil { log.Error().Err(clientErr).Msg("Error initializing client") return clientErr @@ -516,8 +514,8 @@ var storesExportCmd = &cobra.Command{ informDebug(debugFlag) // Authenticate - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) - kfClient, _ := initClient(configFile, profile, "", "", noPrompt, authConfig, false) + + kfClient, _ := initClient(false) // CLI Logic log.Info(). diff --git a/go.mod b/go.mod index 14ec5d4..5b5eebc 100644 --- a/go.mod +++ b/go.mod @@ -9,9 +9,9 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 github.com/Jeffail/gabs v1.4.0 - github.com/Keyfactor/keyfactor-auth-client-go v0.0.1-rc.14 - github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.7 - github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.2 + github.com/Keyfactor/keyfactor-auth-client-go v0.0.1-rc.18 + github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.11 + github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.5 github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 github.com/creack/pty v1.1.23 github.com/google/go-cmp v0.6.0 diff --git a/go.sum b/go.sum index 9ecf642..16fb269 100644 --- a/go.sum +++ b/go.sum @@ -10,12 +10,12 @@ github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mx github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/Jeffail/gabs v1.4.0 h1://5fYRRTq1edjfIrQGvdkcd22pkYUrHZ5YC/H2GJVAo= github.com/Jeffail/gabs v1.4.0/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc= -github.com/Keyfactor/keyfactor-auth-client-go v0.0.1-rc.14 h1:QLnYYZvzDonDamUkHfU0cQWZEr893zCf1vxbF9MSnUg= -github.com/Keyfactor/keyfactor-auth-client-go v0.0.1-rc.14/go.mod h1:UTPLARTONwfc+j1y2SjEa54gbFFCObQucHf3ubQVyDk= -github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.7 h1:OuGkyrGnSiAyQhRN9nxVsK94eNU6V/s+76FP2j6RNUo= -github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.7/go.mod h1:E1IQj9WJv1rrSGQ1LQA5QtrdaPLWGw9kMkZAxQ7h/k8= -github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.2 h1:+7nZp22Y1X0717VVelaXok8Y9MduGi4tGl1A77A5z48= -github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.2/go.mod h1:VbmszVfXWQ9AHDerCJAyd+vu6vQ8x9lq3dSqv3d+6rk= +github.com/Keyfactor/keyfactor-auth-client-go v0.0.1-rc.18 h1:e00P5wkrBC5GtdGyCyPRxl+Fz6e7+T9yn+OAk2Wevyk= +github.com/Keyfactor/keyfactor-auth-client-go v0.0.1-rc.18/go.mod h1:UTPLARTONwfc+j1y2SjEa54gbFFCObQucHf3ubQVyDk= +github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.11 h1:RLRewkuJPp1b5ZBwlq99YYKMDxjZIQrYLvq8jouaCmA= +github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.11/go.mod h1:mRtSR6m2IRlQHZ3nTD6VamQwXicAnYHHDmD+0OFBmJk= +github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.5 h1:6sGoYJD0fSAcxrYps7oasKFz8PnGK5PcOvvdXVa76iw= +github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.5/go.mod h1:9EyZ/Uh/UqCwJo4h4ovGF1GcgNC2cUdU7YDy0R5+uj4= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= From 199fb70925025fe6c46102a80a9665975e6f4f51 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Mon, 28 Oct 2024 08:53:34 -0700 Subject: [PATCH 04/19] feat(auth): determine auth type when trying config from environmental variables rather than blind auth Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- cmd/root.go | 95 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 84 insertions(+), 11 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 3c4afc1..ee86549 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -118,25 +118,86 @@ func getServerConfigFromEnv() (*auth_providers.Server, error) { oAuthNoParamsConfig := &auth_providers.CommandConfigOauth{} basicAuthNoParamsConfig := &auth_providers.CommandAuthConfigBasic{} - log.Debug().Msg("call: basicAuthNoParamsConfig.Authenticate()") - bErr := basicAuthNoParamsConfig.Authenticate() - log.Debug().Msg("complete: basicAuthNoParamsConfig.Authenticate()") - if bErr == nil { + username, uOk := os.LookupEnv(auth_providers.EnvKeyfactorUsername) + password, pOk := os.LookupEnv(auth_providers.EnvKeyfactorPassword) + domain, dOk := os.LookupEnv(auth_providers.EnvKeyfactorDomain) + hostname, hOk := os.LookupEnv(auth_providers.EnvKeyfactorHostName) + apiPath, aOk := os.LookupEnv(auth_providers.EnvKeyfactorAPIPath) + clientId, cOk := os.LookupEnv(auth_providers.EnvKeyfactorClientID) + clientSecret, csOk := os.LookupEnv(auth_providers.EnvKeyfactorClientSecret) + tokenUrl, tOk := os.LookupEnv(auth_providers.EnvKeyfactorAuthTokenURL) + skipVerify, svOk := os.LookupEnv(auth_providers.EnvKeyfactorSkipVerify) + var skipVerifyBool bool + + isBasicAuth := uOk && pOk + isOAuth := cOk && csOk && tOk + + if svOk { + //convert to bool + skipVerify = strings.ToLower(skipVerify) + skipVerifyBool = skipVerify == "true" || skipVerify == "1" || skipVerify == "yes" || skipVerify == "y" || skipVerify == "t" + log.Debug().Bool("skipVerifyBool", skipVerifyBool).Msg("skipVerifyBool") + } + if dOk { + log.Debug().Str("domain", domain).Msg("domain found in environment") + } + if hOk { + log.Debug().Str("hostname", hostname).Msg("hostname found in environment") + } + if aOk { + log.Debug().Str("apiPath", apiPath).Msg("apiPath found in environment") + } + + if isBasicAuth { + log.Debug(). + Str("username", username). + Str("password", hashSecretValue(password)). + Str("domain", domain). + Str("hostname", hostname). + Str("apiPath", apiPath). + Bool("skipVerify", skipVerifyBool). + Msg("call: basicAuthNoParamsConfig.Authenticate()") + bErr := basicAuthNoParamsConfig. + WithUsername(username). + WithPassword(password). + WithDomain(domain). + WithCommandHostName(hostname). + WithCommandAPIPath(apiPath). + WithSkipVerify(skipVerifyBool). + Authenticate() + log.Debug().Msg("complete: basicAuthNoParamsConfig.Authenticate()") + if bErr != nil { + log.Error().Err(bErr).Msg("unable to authenticate with provided credentials") + return nil, bErr + } log.Debug().Msg("return: getServerConfigFromEnv()") return basicAuthNoParamsConfig.GetServerConfig(), nil - } + } else if isOAuth { + log.Debug(). + Str("clientId", clientId). + Str("clientSecret", hashSecretValue(clientSecret)). + Str("tokenUrl", tokenUrl). + Str("hostname", hostname). + Str("apiPath", apiPath). + Bool("skipVerify", skipVerifyBool). + Msg("call: oAuthNoParamsConfig.Authenticate()") + _ = oAuthNoParamsConfig.CommandAuthConfig.WithCommandHostName(hostname). + WithCommandAPIPath(apiPath). + WithSkipVerify(skipVerifyBool) + oErr := oAuthNoParamsConfig.Authenticate() + log.Debug().Msg("complete: oAuthNoParamsConfig.Authenticate()") + if oErr != nil { + log.Error().Err(oErr).Msg("unable to authenticate with provided credentials") + return nil, oErr + } - oErr := oAuthNoParamsConfig.Authenticate() - if oErr == nil { log.Debug().Msg("return: getServerConfigFromEnv()") return oAuthNoParamsConfig.GetServerConfig(), nil + } log.Error().Msg("unable to authenticate with provided credentials") - if bErr != nil { - return nil, bErr - } - return nil, oErr + return nil, fmt.Errorf("incomplete environment variable configuration") } @@ -340,6 +401,18 @@ func initClient(saveConfig bool) (*api.Client, error) { } } + if !authenticated { + log.Debug().Msg("call: authViaConfigFile()") + c, cErr = authViaConfigFile("", "") + if cErr == nil { + log.Info(). + Str("configFile", configFile). + Str("profile", profile). + Msgf("Authenticated via config file %s using profile %s", configFile, profile) + authenticated = true + } + } + if !authenticated { log.Error().Msg("unable to authenticate") if cErr != nil { From 97e3a9fde56499baef780ccc3fd15ac317da6356 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Mon, 28 Oct 2024 09:13:51 -0700 Subject: [PATCH 05/19] chore(deps): Bump client libs Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 5b5eebc..9b83ad5 100644 --- a/go.mod +++ b/go.mod @@ -10,8 +10,8 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 github.com/Jeffail/gabs v1.4.0 github.com/Keyfactor/keyfactor-auth-client-go v0.0.1-rc.18 - github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.11 - github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.5 + github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.12 + github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.6 github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 github.com/creack/pty v1.1.23 github.com/google/go-cmp v0.6.0 diff --git a/go.sum b/go.sum index 16fb269..75d2932 100644 --- a/go.sum +++ b/go.sum @@ -12,10 +12,10 @@ github.com/Jeffail/gabs v1.4.0 h1://5fYRRTq1edjfIrQGvdkcd22pkYUrHZ5YC/H2GJVAo= github.com/Jeffail/gabs v1.4.0/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc= github.com/Keyfactor/keyfactor-auth-client-go v0.0.1-rc.18 h1:e00P5wkrBC5GtdGyCyPRxl+Fz6e7+T9yn+OAk2Wevyk= github.com/Keyfactor/keyfactor-auth-client-go v0.0.1-rc.18/go.mod h1:UTPLARTONwfc+j1y2SjEa54gbFFCObQucHf3ubQVyDk= -github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.11 h1:RLRewkuJPp1b5ZBwlq99YYKMDxjZIQrYLvq8jouaCmA= -github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.11/go.mod h1:mRtSR6m2IRlQHZ3nTD6VamQwXicAnYHHDmD+0OFBmJk= -github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.5 h1:6sGoYJD0fSAcxrYps7oasKFz8PnGK5PcOvvdXVa76iw= -github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.5/go.mod h1:9EyZ/Uh/UqCwJo4h4ovGF1GcgNC2cUdU7YDy0R5+uj4= +github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.12 h1:3Acqe/D9kjzE4lKaZK51zodZM0W5yCWcn+tr+4eVQFQ= +github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.12/go.mod h1:mRtSR6m2IRlQHZ3nTD6VamQwXicAnYHHDmD+0OFBmJk= +github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.6 h1:GxfJyGkDn0ug/Tbx5MWe39G4hGyBuXW2SxBTOf2+nvo= +github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.6/go.mod h1:9EyZ/Uh/UqCwJo4h4ovGF1GcgNC2cUdU7YDy0R5+uj4= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= From 207e1628e1f72379e9c673aed5130b1d19c2c553 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Thu, 31 Oct 2024 12:47:51 -0700 Subject: [PATCH 06/19] chore(deps): Bump client libs Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 9b83ad5..7ea5dc4 100644 --- a/go.mod +++ b/go.mod @@ -9,9 +9,9 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 github.com/Jeffail/gabs v1.4.0 - github.com/Keyfactor/keyfactor-auth-client-go v0.0.1-rc.18 - github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.12 - github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.6 + github.com/Keyfactor/keyfactor-auth-client-go v1.0.0-rc.2 + github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.13 + github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.7 github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 github.com/creack/pty v1.1.23 github.com/google/go-cmp v0.6.0 diff --git a/go.sum b/go.sum index 75d2932..c8ed3b8 100644 --- a/go.sum +++ b/go.sum @@ -10,12 +10,12 @@ github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mx github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/Jeffail/gabs v1.4.0 h1://5fYRRTq1edjfIrQGvdkcd22pkYUrHZ5YC/H2GJVAo= github.com/Jeffail/gabs v1.4.0/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc= -github.com/Keyfactor/keyfactor-auth-client-go v0.0.1-rc.18 h1:e00P5wkrBC5GtdGyCyPRxl+Fz6e7+T9yn+OAk2Wevyk= -github.com/Keyfactor/keyfactor-auth-client-go v0.0.1-rc.18/go.mod h1:UTPLARTONwfc+j1y2SjEa54gbFFCObQucHf3ubQVyDk= -github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.12 h1:3Acqe/D9kjzE4lKaZK51zodZM0W5yCWcn+tr+4eVQFQ= -github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.12/go.mod h1:mRtSR6m2IRlQHZ3nTD6VamQwXicAnYHHDmD+0OFBmJk= -github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.6 h1:GxfJyGkDn0ug/Tbx5MWe39G4hGyBuXW2SxBTOf2+nvo= -github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.6/go.mod h1:9EyZ/Uh/UqCwJo4h4ovGF1GcgNC2cUdU7YDy0R5+uj4= +github.com/Keyfactor/keyfactor-auth-client-go v1.0.0-rc.2 h1:/61pAEjAhTAGtFCvAcp04qEZWV9pMYH5fxADReN2KdU= +github.com/Keyfactor/keyfactor-auth-client-go v1.0.0-rc.2/go.mod h1:UTPLARTONwfc+j1y2SjEa54gbFFCObQucHf3ubQVyDk= +github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.13 h1:jNv5bn0gU1JqnBOsLDt0po1cGtYqEz/2DdtscWzbOKE= +github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.13/go.mod h1:+hmc9YAh4cqlkFe9rHXpQBPssHuoCq/FRYmez5Vrlrg= +github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.7 h1:5IMqu0MtdNe6HMTN7LlseeL1WcOvTJ/E57g808p/hsE= +github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.7/go.mod h1:HWb+S60YAALFVSfB8QuQ8ugjsjr+FHLQET0/4K7EVWw= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= From a3f51312a5bc14f89915758c85f46866f5d5c77a Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Thu, 31 Oct 2024 14:02:44 -0700 Subject: [PATCH 07/19] chore(deps): Bumps deps Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 7ea5dc4..9b3dc71 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 github.com/Jeffail/gabs v1.4.0 github.com/Keyfactor/keyfactor-auth-client-go v1.0.0-rc.2 - github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.13 + github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.0 github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.7 github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 github.com/creack/pty v1.1.23 diff --git a/go.sum b/go.sum index c8ed3b8..a93e680 100644 --- a/go.sum +++ b/go.sum @@ -12,8 +12,8 @@ github.com/Jeffail/gabs v1.4.0 h1://5fYRRTq1edjfIrQGvdkcd22pkYUrHZ5YC/H2GJVAo= github.com/Jeffail/gabs v1.4.0/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc= github.com/Keyfactor/keyfactor-auth-client-go v1.0.0-rc.2 h1:/61pAEjAhTAGtFCvAcp04qEZWV9pMYH5fxADReN2KdU= github.com/Keyfactor/keyfactor-auth-client-go v1.0.0-rc.2/go.mod h1:UTPLARTONwfc+j1y2SjEa54gbFFCObQucHf3ubQVyDk= -github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.13 h1:jNv5bn0gU1JqnBOsLDt0po1cGtYqEz/2DdtscWzbOKE= -github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.13/go.mod h1:+hmc9YAh4cqlkFe9rHXpQBPssHuoCq/FRYmez5Vrlrg= +github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.0 h1:wpiq9UhNxomecw6lhI/EaSWO63HKcuONKq58vsgKmXY= +github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.0/go.mod h1:+hmc9YAh4cqlkFe9rHXpQBPssHuoCq/FRYmez5Vrlrg= github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.7 h1:5IMqu0MtdNe6HMTN7LlseeL1WcOvTJ/E57g808p/hsE= github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.7/go.mod h1:HWb+S60YAALFVSfB8QuQ8ugjsjr+FHLQET0/4K7EVWw= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= From c28674fc28bc9eb4ff928139434889d6831e5956 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Thu, 31 Oct 2024 14:30:38 -0700 Subject: [PATCH 08/19] fix(ci): Use build token to pull private deps Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- .github/workflows/tests.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index fddeab9..776cf80 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -22,14 +22,19 @@ jobs: - name: Set up Go uses: actions/setup-go@v5 with: - go-version: "1.21" + go-version: "1.22" + - name: Set up private repo access for go get + run: | + git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + env: + GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} + - name: Install dependencies run: go mod download && go mod tidy - name: Install Azure CLI run: | curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash az --version - # 10.x.x kf_10_x_x: runs-on: ubuntu-latest From ee567857dd81dec3730b6858c0d44b7e0df71da4 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Thu, 31 Oct 2024 14:39:23 -0700 Subject: [PATCH 09/19] fix(ci): Use build token to pull private deps during tests Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- .github/workflows/tests.yml | 44 ++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 776cf80..422d65c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -58,9 +58,13 @@ jobs: KEYFACTOR_DOMAIN: "command" KEYFACTOR_USERNAME: ${{ secrets.LAB_USERNAME }} KEYFACTOR_PASSWORD: ${{ secrets.LAB_PASSWORD }} + GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} steps: - name: Checkout code uses: actions/checkout@v4 + - name: Set up private repo access for go get + run: | + git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" - name: Run tests run: | export KFUTIL_DEBUG=1 @@ -79,9 +83,13 @@ jobs: KEYFACTOR_DOMAIN: "command" KEYFACTOR_USERNAME: ${{ secrets.LAB_USERNAME }} KEYFACTOR_PASSWORD: ${{ secrets.LAB_PASSWORD }} + GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} steps: - name: Checkout code uses: actions/checkout@v4 + - name: Set up private repo access for go get + run: | + git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" - name: Run tests run: go test -v ./cmd -run "^Test_Stores_*" @@ -98,9 +106,13 @@ jobs: KEYFACTOR_DOMAIN: "command" KEYFACTOR_USERNAME: ${{ secrets.LAB_USERNAME }} KEYFACTOR_PASSWORD: ${{ secrets.LAB_PASSWORD }} + GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} steps: - name: Checkout code uses: actions/checkout@v4 + - name: Set up private repo access for go get + run: | + git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" - name: Run tests run: | unset KFUTIL_DEBUG @@ -120,7 +132,10 @@ jobs: - name: Set up Go uses: actions/setup-go@v5 with: - go-version: "1.21" + go-version: "1.23" + - name: Set up private repo access for go get + run: | + git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" - name: Install dependencies run: go mod download && go mod tidy - name: Get secret from Azure Key Vault @@ -158,6 +173,7 @@ jobs: KEYFACTOR_DOMAIN: "command" KEYFACTOR_USERNAME: ${{ secrets.LAB_USERNAME }} KEYFACTOR_PASSWORD: ${{ secrets.LAB_PASSWORD }} + GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} steps: - name: Checkout code uses: actions/checkout@v4 @@ -180,9 +196,13 @@ jobs: KEYFACTOR_DOMAIN: "command" KEYFACTOR_USERNAME: ${{ secrets.LAB_USERNAME }} KEYFACTOR_PASSWORD: ${{ secrets.LAB_PASSWORD }} + GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} steps: - name: Checkout code uses: actions/checkout@v4 + - name: Set up private repo access for go get + run: | + git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" - name: Run tests run: go test -v ./cmd -run "^Test_Stores_*" @@ -199,9 +219,13 @@ jobs: KEYFACTOR_DOMAIN: "command" KEYFACTOR_USERNAME: ${{ secrets.LAB_USERNAME }} KEYFACTOR_PASSWORD: ${{ secrets.LAB_PASSWORD }} + GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} steps: - name: Checkout code uses: actions/checkout@v4 + - name: Set up private repo access for go get + run: | + git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" - name: Run tests run: | unset KFUTIL_DEBUG @@ -222,6 +246,9 @@ jobs: uses: actions/setup-go@v5 with: go-version: "1.21" + - name: Set up private repo access for go get + run: | + git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" - name: Install dependencies run: go mod download && go mod tidy - name: Get secret from Azure Key Vault @@ -250,9 +277,13 @@ jobs: KEYFACTOR_DOMAIN: "command" KEYFACTOR_USERNAME: ${{ secrets.LAB_USERNAME }} KEYFACTOR_PASSWORD: ${{ secrets.LAB_PASSWORD }} + GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} steps: - name: Checkout code uses: actions/checkout@v4 + - name: Set up private repo access for go get + run: | + git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" - name: Run tests run: | unset KFUTIL_DEBUG @@ -272,9 +303,13 @@ jobs: KEYFACTOR_DOMAIN: "command" KEYFACTOR_USERNAME: ${{ secrets.LAB_USERNAME }} KEYFACTOR_PASSWORD: ${{ secrets.LAB_PASSWORD }} + GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} steps: - name: Checkout code uses: actions/checkout@v4 + - name: Set up private repo access for go get + run: | + git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" - name: Run tests run: go test -v ./cmd -run "^Test_Stores_*" @@ -291,9 +326,13 @@ jobs: KEYFACTOR_DOMAIN: "command" KEYFACTOR_USERNAME: ${{ secrets.LAB_USERNAME }} KEYFACTOR_PASSWORD: ${{ secrets.LAB_PASSWORD }} + GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} steps: - name: Checkout code uses: actions/checkout@v4 + - name: Set up private repo access for go get + run: | + git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" - name: Run tests run: | unset KFUTIL_DEBUG @@ -314,6 +353,9 @@ jobs: uses: actions/setup-go@v5 with: go-version: "1.21" + - name: Set up private repo access for go get + run: | + git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" - name: Install dependencies run: go mod download && go mod tidy - name: Get secret from Azure Key Vault From 58c58fbdd65007a6a1ed4d5ff48551e8694fdde4 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Fri, 1 Nov 2024 08:35:39 -0700 Subject: [PATCH 10/19] fix(ci): Simplify tests workflow Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- .github/workflows/tests.yml | 453 ++++++------------------------------ 1 file changed, 77 insertions(+), 376 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 422d65c..aadf201 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,14 +1,6 @@ name: go tests on: - # workflow_dispatch: - # workflow_run: - # workflows: - # - "Check and Update Package Version" - # types: - # - completed - # branches: - # - "*" push: branches: - '*' @@ -27,257 +19,80 @@ jobs: run: | git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" env: - GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} - + GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN }} - name: Install dependencies run: go mod download && go mod tidy - name: Install Azure CLI run: | curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash az --version - # 10.x.x - kf_10_x_x: - runs-on: ubuntu-latest - needs: - - build - steps: - - name: Checkout code - uses: actions/checkout@v4 - - name: Run tests - run: echo "Running tests for KF 10.x.x" - - ### Store Type Tests - Test_StoreTypes_KFC_10_5_0: - runs-on: ubuntu-latest - needs: - - build - - kf_10_x_x - env: - SECRET_NAME: "command-config-1050-clean" - KEYFACTOR_HOSTNAME: "int1050-test-clean.kfdelivery.com" - KEYFACTOR_DOMAIN: "command" - KEYFACTOR_USERNAME: ${{ secrets.LAB_USERNAME }} - KEYFACTOR_PASSWORD: ${{ secrets.LAB_PASSWORD }} - GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} - steps: - - name: Checkout code - uses: actions/checkout@v4 - - name: Set up private repo access for go get - run: | - git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" - - name: Run tests - run: | - export KFUTIL_DEBUG=1 - go test -v ./cmd -run "^Test_StoreTypes*" - - ### Store Tests - Test_Stores_KFC_10_5_0: - runs-on: ubuntu-latest - needs: - - build - - kf_10_x_x - - Test_StoreTypes_KFC_10_5_0 - env: - SECRET_NAME: "command-config-1050" - KEYFACTOR_HOSTNAME: "integrations1050-lab.kfdelivery.com" - KEYFACTOR_DOMAIN: "command" - KEYFACTOR_USERNAME: ${{ secrets.LAB_USERNAME }} - KEYFACTOR_PASSWORD: ${{ secrets.LAB_PASSWORD }} - GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} - steps: - - name: Checkout code - uses: actions/checkout@v4 - - name: Set up private repo access for go get - run: | - git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" - - name: Run tests - run: go test -v ./cmd -run "^Test_Stores_*" - - ### PAM Tests - Test_PAM_KFC_10_5_0: - runs-on: ubuntu-latest - needs: - - build - - kf_10_x_x - - Test_StoreTypes_KFC_10_5_0 - env: - SECRET_NAME: "command-config-1050" - KEYFACTOR_HOSTNAME: "integrations1050-lab.kfdelivery.com" - KEYFACTOR_DOMAIN: "command" - KEYFACTOR_USERNAME: ${{ secrets.LAB_USERNAME }} - KEYFACTOR_PASSWORD: ${{ secrets.LAB_PASSWORD }} - GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} - steps: - - name: Checkout code - uses: actions/checkout@v4 - - name: Set up private repo access for go get - run: | - git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" - - name: Run tests - run: | - unset KFUTIL_DEBUG - go test -v ./cmd -run "^Test_PAM*" - - - ### PAM Tests AKV Auth Provider - Test_AKV_PAM_KFC_10_5_0: - runs-on: self-hosted - needs: - - Test_PAM_KFC_10_5_0 - env: - SECRET_NAME: "command-config-1050-az" - steps: - - name: Checkout code - uses: actions/checkout@v4 - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version: "1.23" - - name: Set up private repo access for go get - run: | - git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" - - name: Install dependencies - run: go mod download && go mod tidy - - name: Get secret from Azure Key Vault - run: | - . ./examples/auth/akv/akv_auth.sh - cat $HOME/.keyfactor/command_config.json - - name: Install kfutil - run: | - make install - - name: Run tests - run: | - go test -v ./cmd -run "^Test_PAM*" - - - ## KFC 11.x.x - kf_11_x_x: - runs-on: ubuntu-latest - needs: - - build - steps: - - name: Checkout code - uses: actions/checkout@v4 - - name: Run tests - run: echo "Running tests for KF 11.x.x" - - ### Store Type Tests - Test_StoreTypes_KFC_11_1_2: - runs-on: ubuntu-latest - needs: - - build - - kf_11_x_x - env: - SECRET_NAME: "command-config-1112-clean" - KEYFACTOR_HOSTNAME: "int1112-test-clean.kfdelivery.com" - KEYFACTOR_DOMAIN: "command" - KEYFACTOR_USERNAME: ${{ secrets.LAB_USERNAME }} - KEYFACTOR_PASSWORD: ${{ secrets.LAB_PASSWORD }} - GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} - steps: - - name: Checkout code - uses: actions/checkout@v4 - - name: Run tests - run: | - unset KFUTIL_DEBUG - go test -v ./cmd -run "^Test_StoreTypes*" - - - ### Store Tests - Test_Stores_KFC_11_1_2: - runs-on: ubuntu-latest - needs: - - build - - kf_11_x_x - - Test_StoreTypes_KFC_11_1_2 - env: - SECRET_NAME: "command-config-1112" - KEYFACTOR_HOSTNAME: "integrations1112-lab.kfdelivery.com" - KEYFACTOR_DOMAIN: "command" - KEYFACTOR_USERNAME: ${{ secrets.LAB_USERNAME }} - KEYFACTOR_PASSWORD: ${{ secrets.LAB_PASSWORD }} - GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} - steps: - - name: Checkout code - uses: actions/checkout@v4 - - name: Set up private repo access for go get - run: | - git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" - - name: Run tests - run: go test -v ./cmd -run "^Test_Stores_*" - - ### PAM Tests - Test_PAM_KFC_11_1_2: - runs-on: ubuntu-latest - needs: - - build - - kf_11_x_x - - Test_StoreTypes_KFC_11_1_2 - env: - SECRET_NAME: "command-config-1112" - KEYFACTOR_HOSTNAME: "integrations1112-lab.kfdelivery.com" - KEYFACTOR_DOMAIN: "command" - KEYFACTOR_USERNAME: ${{ secrets.LAB_USERNAME }} - KEYFACTOR_PASSWORD: ${{ secrets.LAB_PASSWORD }} - GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} - steps: - - name: Checkout code - uses: actions/checkout@v4 - - name: Set up private repo access for go get - run: | - git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" - - name: Run tests - run: | - unset KFUTIL_DEBUG - go test -v ./cmd -run "^Test_PAM*" - - ### PAM Tests AKV Auth Provider - Test_AKV_PAM_KFC_11_1_2: - runs-on: self-hosted - needs: - - Test_PAM_KFC_11_1_2 - env: - SECRET_NAME: "command-config-1112-az" - steps: - - name: Checkout code - uses: actions/checkout@v4 - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version: "1.21" - - name: Set up private repo access for go get - run: | - git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" - - name: Install dependencies - run: go mod download && go mod tidy - - name: Get secret from Azure Key Vault - run: | - . ./examples/auth/akv/akv_auth.sh - cat $HOME/.keyfactor/command_config.json - - name: Install kfutil - run: | - make install - - name: Run tests - run: | - go test -v ./cmd -run "^Test_PAM*" - - - - ## KFC 12.x.x - ### Store Type Tests - Test_StoreTypes_KFC_12_2_0: + test: runs-on: ubuntu-latest - needs: - - build - - kf_11_x_x + needs: build + strategy: + matrix: + version: [ 10_5_0, 11_1_2, 12_2_0 ] + test_type: [ StoreTypes, Stores, PAM, AKV_PAM ] + include: + - version: 10_5_0 + test_type: StoreTypes + SECRET_NAME: "command-config-1050-clean" + KEYFACTOR_HOSTNAME: "int1050-test-clean.kfdelivery.com" + KEYFACTOR_DOMAIN: "command" + - version: 10_5_0 + test_type: Stores + SECRET_NAME: "command-config-1050" + KEYFACTOR_HOSTNAME: "integrations1050-lab.kfdelivery.com" + KEYFACTOR_DOMAIN: "command" + - version: 10_5_0 + test_type: PAM + SECRET_NAME: "command-config-1050" + KEYFACTOR_HOSTNAME: "integrations1050-lab.kfdelivery.com" + KEYFACTOR_DOMAIN: "command" + - version: 10_5_0 + test_type: AKV_PAM + SECRET_NAME: "command-config-1050-az" + - version: 11_1_2 + test_type: StoreTypes + SECRET_NAME: "command-config-1112-clean" + KEYFACTOR_HOSTNAME: "int1112-test-clean.kfdelivery.com" + KEYFACTOR_DOMAIN: "command" + - version: 11_1_2 + test_type: Stores + SECRET_NAME: "command-config-1112" + KEYFACTOR_HOSTNAME: "integrations1112-lab.kfdelivery.com" + KEYFACTOR_DOMAIN: "command" + - version: 11_1_2 + test_type: PAM + SECRET_NAME: "command-config-1112" + KEYFACTOR_HOSTNAME: "integrations1112-lab.kfdelivery.com" + KEYFACTOR_DOMAIN: "command" + - version: 11_1_2 + test_type: AKV_PAM + SECRET_NAME: "command-config-1112-az" + - version: 12_2_0 + test_type: StoreTypes + SECRET_NAME: "command-config-1220-clean" + KEYFACTOR_HOSTNAME: "int1220-test-clean.kfdelivery.com" + KEYFACTOR_DOMAIN: "command" + - version: 12_2_0 + test_type: Stores + SECRET_NAME: "command-config-1220" + KEYFACTOR_HOSTNAME: "integrations1220-lab.kfdelivery.com" + KEYFACTOR_DOMAIN: "command" + - version: 12_2_0 + test_type: PAM + SECRET_NAME: "command-config-1220" + KEYFACTOR_HOSTNAME: "integrations1220-lab.kfdelivery.com" + KEYFACTOR_DOMAIN: "command" + - version: 12_2_0 + test_type: AKV_PAM + SECRET_NAME: "command-config-1220-az" env: - SECRET_NAME: "command-config-1220-clean" - KEYFACTOR_HOSTNAME: "int1220-test-clean.kfdelivery.com" - KEYFACTOR_DOMAIN: "command" + GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN }} KEYFACTOR_USERNAME: ${{ secrets.LAB_USERNAME }} KEYFACTOR_PASSWORD: ${{ secrets.LAB_PASSWORD }} - GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} steps: - name: Checkout code uses: actions/checkout@v4 @@ -286,131 +101,17 @@ jobs: git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" - name: Run tests run: | - unset KFUTIL_DEBUG - go test -v ./cmd -run "^Test_StoreTypes*" - - - ### Store Tests - Test_Stores_KFC_12_2_0: - runs-on: ubuntu-latest - needs: - - build - - kf_11_x_x - - Test_StoreTypes_KFC_12_2_0 - env: - SECRET_NAME: "command-config-1220" - KEYFACTOR_HOSTNAME: "integrations1220-lab.kfdelivery.com" - KEYFACTOR_DOMAIN: "command" - KEYFACTOR_USERNAME: ${{ secrets.LAB_USERNAME }} - KEYFACTOR_PASSWORD: ${{ secrets.LAB_PASSWORD }} - GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} - steps: - - name: Checkout code - uses: actions/checkout@v4 - - name: Set up private repo access for go get - run: | - git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" - - name: Run tests - run: go test -v ./cmd -run "^Test_Stores_*" - - ### PAM Tests - Test_PAM_KFC_12_2_0: - runs-on: ubuntu-latest - needs: - - build - - kf_11_x_x - - Test_StoreTypes_KFC_12_2_0 - env: - SECRET_NAME: "command-config-1220" - KEYFACTOR_HOSTNAME: "integrations1220-lab.kfdelivery.com" - KEYFACTOR_DOMAIN: "command" - KEYFACTOR_USERNAME: ${{ secrets.LAB_USERNAME }} - KEYFACTOR_PASSWORD: ${{ secrets.LAB_PASSWORD }} - GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} - steps: - - name: Checkout code - uses: actions/checkout@v4 - - name: Set up private repo access for go get - run: | - git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" - - name: Run tests - run: | - unset KFUTIL_DEBUG - go test -v ./cmd -run "^Test_PAM*" - - - ### PAM Tests AKV Auth Provider - Test_AKV_PAM_KFC_12_2_0: - runs-on: self-hosted - needs: - - Test_PAM_KFC_12_2_0 - env: - SECRET_NAME: "command-config-1220-az" - steps: - - name: Checkout code - uses: actions/checkout@v4 - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version: "1.21" - - name: Set up private repo access for go get - run: | - git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" - - name: Install dependencies - run: go mod download && go mod tidy - - name: Get secret from Azure Key Vault - run: | - . ./examples/auth/akv/akv_auth.sh - cat $HOME/.keyfactor/command_config.json - - name: Install kfutil - run: | - make install - - name: Run tests - run: | - go test -v ./cmd -run "^Test_PAM*" - - - - # Tester Install Script - Test_Install_Script: - runs-on: ubuntu-latest - steps: - - name: Test Quick Install Script - run: | - sudo apt update && sudo apt upgrade -y && sudo apt install -y curl wget unzip jq openssl && sudo apt clean - echo curl -s "https://raw.githubusercontent.com/Keyfactor/kfutil/${GITHUB_REF_NAME}/install.sh" - GITHUB_REF_NAME_ENCODED=$(echo -n "${GITHUB_REF_NAME}" | jq -sRr @uri) - VERIFY_CHECKSUM=0 - bash <(curl -s "https://raw.githubusercontent.com/Keyfactor/kfutil/${GITHUB_REF_NAME_ENCODED}/install.sh") - which kfutil - kfutil version - rm $(which kfutil) - - # Package Tests - Test_Kfutil_pkg: - runs-on: ubuntu-latest - needs: - - build - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - steps: - # Checkout code - # https://github.com/actions/checkout - - name: Checkout code - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 - - # Setup GoLang build environment - # https://github.com/actions/setup-go - - name: Set up Go 1.x - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 - with: - go-version-file: 'go.mod' - cache: true - - # Install dependencies - - name: Install dependencies - run: go mod download - - # Run the tests with coverage found in the pkg directory - - name: Run tests - run: go test -v -cover ./pkg/... + if [ "${{ matrix.test_type }}" == "StoreTypes" ]; then + export KFUTIL_DEBUG=1 + go test -v ./cmd -run "^Test_StoreTypes*" + elif [ "${{ matrix.test_type }}" == "Stores" ]; then + go test -v ./cmd -run "^Test_Stores_*" + elif [ "${{ matrix.test_type }}" == "PAM" ]; then + unset KFUTIL_DEBUG + go test -v ./cmd -run "^Test_PAM*" + elif [ "${{ matrix.test_type }}" == "AKV_PAM" ]; then + . ./examples/auth/akv/akv_auth.sh + cat $HOME/.keyfactor/command_config.json + make install + go test -v ./cmd -run "^Test_PAM*" + fi \ No newline at end of file From 15cd9557a562b3234a1cee57b7ba139839ce07e8 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Fri, 1 Nov 2024 08:36:28 -0700 Subject: [PATCH 11/19] TODO: don't run any other workflows Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- .github/workflows/container.yml | 332 +++++++------- .../keyfactor-bootstrap-workflow.yml | 420 +++++++++--------- .github/workflows/update-stores.yml | 394 ++++++++-------- 3 files changed, 573 insertions(+), 573 deletions(-) diff --git a/.github/workflows/container.yml b/.github/workflows/container.yml index a245712..e429892 100644 --- a/.github/workflows/container.yml +++ b/.github/workflows/container.yml @@ -1,166 +1,166 @@ -name: Build and Release Container -on: - release: - types: [released] - push: - branches: - - '*' - -env: - REGISTRY: ghcr.io - -jobs: - build: - name: Build Containers - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - platform: - - linux/386 - - linux/amd64 - - linux/arm/v6 - - linux/arm/v7 - - linux/arm64/v8 - - linux/ppc64le - - linux/s390x - - permissions: - contents: read - packages: write - - steps: - - - name: Set IMAGE_NAME - run: | - echo "IMAGE_NAME=${GITHUB_REPOSITORY,,}" >>${GITHUB_ENV} - - # Checkout code - # https://github.com/actions/checkout - - name: Checkout code - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 - - # Extract metadata (tags, labels) for Docker - # If the pull request is not merged, do not include the edge tag and only include the sha tag. - # https://github.com/docker/metadata-action - - name: Extract Docker metadata - uses: docker/metadata-action@31cebacef4805868f9ce9a0cb03ee36c32df2ac4 # v5.3.0 - with: - images: | - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - tags: | - type=semver,pattern=v{{version}} - type=sha - - # Set up QEMU - # https://github.com/docker/setup-qemu-action - - name: Set up QEMU - uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3 # v3.0.0 - - # Set up BuildKit Docker container builder to be able to build - # multi-platform images and export cache - # https://github.com/docker/setup-buildx-action - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 - - # Login to Docker registry - # https://github.com/docker/login-action - - name: Log into registry ${{ env.REGISTRY }} - uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - # Build and push Docker image with Buildx - # https://github.com/docker/build-push-action - - name: Build and push Docker image - id: build - uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 # v5.1.0 - with: - context: . - platforms: ${{ matrix.platform }} - labels: ${{ env.DOCKER_METADATA_OUTPUT_LABELS }} - push: true - outputs: type=image,name=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true - - # Export digest - - name: Export digest - run: | - mkdir -p /tmp/digests - digest="${{ steps.build.outputs.digest }}" - touch "/tmp/digests/${digest#sha256:}" - - # Upload digest - - name: Upload digest - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 - with: - name: digests - path: /tmp/digests/* - if-no-files-found: error - retention-days: 1 - - merge: - name: Merge Container Manifests - runs-on: ubuntu-latest - needs: - - build - steps: - - name: Set IMAGE_NAME - run: | - echo "IMAGE_NAME=${GITHUB_REPOSITORY,,}" >>${GITHUB_ENV} - - # Download digests - # https://github.com/actions/download-artifact - - name: Download digests - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 - with: - name: digests - path: /tmp/digests - - # Set up BuildKit Docker container builder to be able to build - # multi-platform images and export cache - # https://github.com/docker/setup-buildx-action - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 - - # Extract metadata (tags, labels) for Docker - # If the pull request is not merged, do not include the edge tag and only include the sha tag. - # https://github.com/docker/metadata-action - - name: Extract Docker metadata - uses: docker/metadata-action@31cebacef4805868f9ce9a0cb03ee36c32df2ac4 # v5.3.0 - with: - images: | - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - tags: | - type=semver,pattern=v{{version}} - type=sha - - # Login to Docker registry - # https://github.com/docker/login-action - - name: Log into registry ${{ env.REGISTRY }} - uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - # Create manifest list and push - - name: Create manifest list and push - working-directory: /tmp/digests - run: | - # Base command to create a manifest list with the selected tag(s) and push - CMD="docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ - $(printf '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *)" - - # If the branch is 'release-*', add the 'edge' tag - if [[ "${{ github.ref }}" == refs/heads/release-* ]]; then - CMD="$CMD -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:edge" - fi - - # Execute the command - eval "$CMD" - - - name: Inspect image - run: | - docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.DOCKER_METADATA_OUTPUT_VERSION }} \ No newline at end of file +#name: Build and Release Container +#on: +# release: +# types: [released] +# push: +# branches: +# - '*' +# +#env: +# REGISTRY: ghcr.io +# +#jobs: +# build: +# name: Build Containers +# runs-on: ubuntu-latest +# strategy: +# fail-fast: false +# matrix: +# platform: +# - linux/386 +# - linux/amd64 +# - linux/arm/v6 +# - linux/arm/v7 +# - linux/arm64/v8 +# - linux/ppc64le +# - linux/s390x +# +# permissions: +# contents: read +# packages: write +# +# steps: +# +# - name: Set IMAGE_NAME +# run: | +# echo "IMAGE_NAME=${GITHUB_REPOSITORY,,}" >>${GITHUB_ENV} +# +# # Checkout code +# # https://github.com/actions/checkout +# - name: Checkout code +# uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 +# +# # Extract metadata (tags, labels) for Docker +# # If the pull request is not merged, do not include the edge tag and only include the sha tag. +# # https://github.com/docker/metadata-action +# - name: Extract Docker metadata +# uses: docker/metadata-action@31cebacef4805868f9ce9a0cb03ee36c32df2ac4 # v5.3.0 +# with: +# images: | +# ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} +# tags: | +# type=semver,pattern=v{{version}} +# type=sha +# +# # Set up QEMU +# # https://github.com/docker/setup-qemu-action +# - name: Set up QEMU +# uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3 # v3.0.0 +# +# # Set up BuildKit Docker container builder to be able to build +# # multi-platform images and export cache +# # https://github.com/docker/setup-buildx-action +# - name: Set up Docker Buildx +# uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 +# +# # Login to Docker registry +# # https://github.com/docker/login-action +# - name: Log into registry ${{ env.REGISTRY }} +# uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 +# with: +# registry: ${{ env.REGISTRY }} +# username: ${{ github.actor }} +# password: ${{ secrets.GITHUB_TOKEN }} +# +# # Build and push Docker image with Buildx +# # https://github.com/docker/build-push-action +# - name: Build and push Docker image +# id: build +# uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 # v5.1.0 +# with: +# context: . +# platforms: ${{ matrix.platform }} +# labels: ${{ env.DOCKER_METADATA_OUTPUT_LABELS }} +# push: true +# outputs: type=image,name=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true +# +# # Export digest +# - name: Export digest +# run: | +# mkdir -p /tmp/digests +# digest="${{ steps.build.outputs.digest }}" +# touch "/tmp/digests/${digest#sha256:}" +# +# # Upload digest +# - name: Upload digest +# uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 +# with: +# name: digests +# path: /tmp/digests/* +# if-no-files-found: error +# retention-days: 1 +# +# merge: +# name: Merge Container Manifests +# runs-on: ubuntu-latest +# needs: +# - build +# steps: +# - name: Set IMAGE_NAME +# run: | +# echo "IMAGE_NAME=${GITHUB_REPOSITORY,,}" >>${GITHUB_ENV} +# +# # Download digests +# # https://github.com/actions/download-artifact +# - name: Download digests +# uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 +# with: +# name: digests +# path: /tmp/digests +# +# # Set up BuildKit Docker container builder to be able to build +# # multi-platform images and export cache +# # https://github.com/docker/setup-buildx-action +# - name: Set up Docker Buildx +# uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 +# +# # Extract metadata (tags, labels) for Docker +# # If the pull request is not merged, do not include the edge tag and only include the sha tag. +# # https://github.com/docker/metadata-action +# - name: Extract Docker metadata +# uses: docker/metadata-action@31cebacef4805868f9ce9a0cb03ee36c32df2ac4 # v5.3.0 +# with: +# images: | +# ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} +# tags: | +# type=semver,pattern=v{{version}} +# type=sha +# +# # Login to Docker registry +# # https://github.com/docker/login-action +# - name: Log into registry ${{ env.REGISTRY }} +# uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 +# with: +# registry: ${{ env.REGISTRY }} +# username: ${{ github.actor }} +# password: ${{ secrets.GITHUB_TOKEN }} +# +# # Create manifest list and push +# - name: Create manifest list and push +# working-directory: /tmp/digests +# run: | +# # Base command to create a manifest list with the selected tag(s) and push +# CMD="docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ +# $(printf '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *)" +# +# # If the branch is 'release-*', add the 'edge' tag +# if [[ "${{ github.ref }}" == refs/heads/release-* ]]; then +# CMD="$CMD -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:edge" +# fi +# +# # Execute the command +# eval "$CMD" +# +# - name: Inspect image +# run: | +# docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.DOCKER_METADATA_OUTPUT_VERSION }} \ No newline at end of file diff --git a/.github/workflows/keyfactor-bootstrap-workflow.yml b/.github/workflows/keyfactor-bootstrap-workflow.yml index a4c7eaf..78f5d45 100644 --- a/.github/workflows/keyfactor-bootstrap-workflow.yml +++ b/.github/workflows/keyfactor-bootstrap-workflow.yml @@ -1,226 +1,226 @@ -name: Keyfactor Bootstrap Workflow - -on: - workflow_dispatch: - pull_request: - types: [ opened, closed, synchronize, edited, reopened ] - push: - create: - branches: - - 'release-*.*' - -jobs: - get-versions: - runs-on: ubuntu-latest - outputs: - PR_BASE_REF: ${{ steps.set-outputs.outputs.PR_BASE_REF }} - PR_COMMIT_SHA: ${{ steps.set-outputs.outputs.PR_COMMIT_SHA }} - GITHUB_SHA: ${{ steps.set-outputs.outputs.GITHUB_SHA }} - PR_BASE_TAG: ${{ steps.set-outputs.outputs.PR_BASE_TAG }} - IS_FULL_RELEASE: ${{ steps.set-outputs.outputs.IS_FULL_RELEASE }} - IS_PRE_RELEASE: ${{ steps.set-outputs.outputs.IS_PRE_RELEASE }} - INC_LEVEL: ${{ steps.set-outputs.outputs.INC_LEVEL }} - IS_RELEASE_BRANCH: ${{ steps.set-outputs.outputs.IS_RELEASE_BRANCH }} - IS_HOTFIX: ${{ steps.set-outputs.outputs.IS_HOTFIX }} - LATEST_TAG: ${{ steps.set-outputs.outputs.LATEST_TAG }} - NEXT_VERSION: ${{ steps.set-outputs.outputs.NEW_PKG_VERSION }} - - steps: - - name: Check out the code - uses: actions/checkout@v3 - with: - token: ${{ secrets.V2BUILDTOKEN}} - - - name: Display base.ref from Pull Request - if: github.event_name == 'pull_request' - id: display-from-pr - run: | - echo "Event: ${{ github.event_name }}" | tee -a $GITHUB_STEP_SUMMARY - echo "Event Action: ${{ github.event.action }}" | tee -a $GITHUB_STEP_SUMMARY - echo "PR_BASE_REF=${{ github.event.pull_request.base.ref }}" | tee -a "$GITHUB_ENV" | tee -a $GITHUB_STEP_SUMMARY - echo "PR_STATE=${{ github.event.pull_request.state }}" | tee -a "$GITHUB_ENV" | tee -a $GITHUB_STEP_SUMMARY - echo "PR_MERGED=${{ github.event.pull_request.merged }}" | tee -a "$GITHUB_ENV" | tee -a $GITHUB_STEP_SUMMARY - echo "PR_COMMIT_SHA=${{ github.event.pull_request.merge_commit_sha }}" | tee -a "$GITHUB_ENV" | tee -a $GITHUB_STEP_SUMMARY - echo "GITHUB_SHA=${{ github.sha }}" | tee -a "$GITHUB_ENV" | tee -a $GITHUB_STEP_SUMMARY - baseref="${{ github.event.pull_request.base.ref }}" - basetag="${baseref#release-}" - echo "PR_BASE_TAG=$basetag" | tee -a "$GITHUB_ENV" | tee -a $GITHUB_STEP_SUMMARY - - - name: Display base_ref from Push Event - if: github.event_name == 'push' - id: display-from-push - run: | - echo "Branch Ref: ${{ github.ref }}" | tee -a $GITHUB_STEP_SUMMARY - echo "Event: ${{ github.event_name }}" | tee -a $GITHUB_STEP_SUMMARY - echo "github.sha: ${{ github.sha }}" | tee -a $GITHUB_STEP_SUMMARY - - - name: Find Latest Tag - if: github.event_name == 'pull_request' - id: find-latest-tag - run: | - prbasetag="${{env.PR_BASE_TAG}}" - git fetch --tags - if [[ -n `git tag` ]]; then - echo "Setting vars" - allBranchTags=`git tag --sort=-v:refname | grep "^$prbasetag" || echo ""` - allRepoTags=`git tag --sort=-v:refname` - branchTagBase=`git tag --sort=-v:refname | grep "^$prbasetag" | grep -o '^[0-9.]*' | head -n 1 || echo ""` - latestTagBase=`git tag --sort=-v:refname | grep -o '^[0-9.]*' | head -n 1` - latestBranchTag=`git tag --sort=-v:refname | grep "^$prbasetag" | grep "^$branchTagBase" | head -n 1 || echo ""` - latestReleasedTag=`git tag --sort=-v:refname | grep "^$prbasetag" | grep "^$branchTagBase$" | head -n 1 || echo ""` - - # If the *TagBase values are not found in the list of tags, it means no final release was produced, and the latest*Tag vars will be empty - if [[ -z "$latestReleasedTag" ]]; then - latestTag="$latestBranchTag" - else - latestTag="$latestReleasedTag" - fi - echo "LATEST_TAG=${latestTag}" | tee -a "$GITHUB_ENV" - - if [[ "$latestTagBase" == *"$branchTagBase" ]]; then - hf="False" - else - hf="True" - fi - - # The intention is to use this to set the make_latest:false property when - # dispatching the create-release action, but it is not *yet* a configurable option - echo "IS_HOTFIX=$hf" | tee -a "$GITHUB_ENV" - else - echo "No tags exist in this repo" - echo "LATEST_TAG=" | tee -a "$GITHUB_ENV" - fi - - name: Set Outputs - id: set-outputs - run: | - echo "PR_BASE_REF=${{ env.PR_BASE_REF }}" | tee -a "$GITHUB_OUTPUT" - echo "PR_STATE=${{ env.PR_STATE }}" - echo "PR_MERGED=${{ env.PR_MERGED }}" - if [[ "${{ env.PR_STATE }}" == "closed" && "${{ env.PR_MERGED }}" == "true" && "${{ env.PR_COMMIT_SHA }}" == "${{ env.GITHUB_SHA }}" ]]; then - echo "IS_FULL_RELEASE=True" | tee -a "$GITHUB_OUTPUT" - echo "INC_LEVEL=patch" | tee -a "$GITHUB_OUTPUT" - fi - if [[ "${{ env.PR_STATE }}" == "open" ]]; then - echo "IS_PRE_RELEASE=True" | tee -a "$GITHUB_OUTPUT" | tee -a "$GITHUB_ENV" - echo "INC_LEVEL=prerelease" | tee -a "$GITHUB_OUTPUT" - fi - if [[ "${{ env.PR_BASE_REF }}" == "release-"* ]]; then - echo "IS_RELEASE_BRANCH=True" | tee -a "$GITHUB_OUTPUT" | tee -a "$GITHUB_ENV" - fi - echo "PR_COMMIT_SHA=${{ env.PR_COMMIT_SHA }}" | tee -a "$GITHUB_OUTPUT" - echo "GITHUB_SHA=${{ env.GITHUB_SHA }}" | tee -a "$GITHUB_OUTPUT" - echo "PR_BASE_TAG=${{ env.PR_BASE_TAG }}" | tee -a "$GITHUB_OUTPUT" - echo "IS_HOTFIX=${{ env.IS_HOTFIX }}" | tee -a "$GITHUB_OUTPUT" - echo "LATEST_TAG=${{ env.LATEST_TAG }}" | tee -a "$GITHUB_OUTPUT" - -# check-package-version: -# needs: get-versions -# if: github.event_name == 'pull_request' && needs.get-versions.outputs.IS_RELEASE_BRANCH == 'True' -# outputs: -# release_version: ${{ steps.create_release.outputs.current_tag }} -# release_url: ${{ steps.create_release.outputs.upload_url }} -# update_version: ${{ steps.check_version.outputs.update_version }} -# next_version: ${{ steps.set-semver-info.outputs.new_version }} +#name: Keyfactor Bootstrap Workflow +# +#on: +# workflow_dispatch: +# pull_request: +# types: [ opened, closed, synchronize, edited, reopened ] +# push: +# create: +# branches: +# - 'release-*.*' +# +#jobs: +# get-versions: # runs-on: ubuntu-latest +# outputs: +# PR_BASE_REF: ${{ steps.set-outputs.outputs.PR_BASE_REF }} +# PR_COMMIT_SHA: ${{ steps.set-outputs.outputs.PR_COMMIT_SHA }} +# GITHUB_SHA: ${{ steps.set-outputs.outputs.GITHUB_SHA }} +# PR_BASE_TAG: ${{ steps.set-outputs.outputs.PR_BASE_TAG }} +# IS_FULL_RELEASE: ${{ steps.set-outputs.outputs.IS_FULL_RELEASE }} +# IS_PRE_RELEASE: ${{ steps.set-outputs.outputs.IS_PRE_RELEASE }} +# INC_LEVEL: ${{ steps.set-outputs.outputs.INC_LEVEL }} +# IS_RELEASE_BRANCH: ${{ steps.set-outputs.outputs.IS_RELEASE_BRANCH }} +# IS_HOTFIX: ${{ steps.set-outputs.outputs.IS_HOTFIX }} +# LATEST_TAG: ${{ steps.set-outputs.outputs.LATEST_TAG }} +# NEXT_VERSION: ${{ steps.set-outputs.outputs.NEW_PKG_VERSION }} +# # steps: # - name: Check out the code # uses: actions/checkout@v3 -# - run: | -# echo "INC_LEVEL=${{ needs.get-versions.outputs.INC_LEVEL}}" -# - name: Check if initial release -# if: needs.get-versions.outputs.LATEST_TAG == '' -# run: | -# echo "INITIAL_VERSION=${{needs.get-versions.outputs.PR_BASE_TAG}}.0-rc.0" | tee -a "$GITHUB_STEP_SUMMARY" | tee -a "$GITHUB_ENV" -# echo "MANUAL_VERSION=${{needs.get-versions.outputs.PR_BASE_TAG}}.0-rc.0" | tee -a "$GITHUB_ENV" -# - name: Set semver info -# id: set-semver-info -# if: needs.get-versions.outputs.LATEST_TAG != '' -# uses: fiddlermikey/action-bump-semver@main # with: -# current_version: ${{ needs.get-versions.outputs.LATEST_TAG}} -# level: ${{ needs.get-versions.outputs.INC_LEVEL}} -# preID: rc -# - name: Show next sem-version -# if: needs.get-versions.outputs.LATEST_TAG != '' +# token: ${{ secrets.V2BUILDTOKEN}} +# +# - name: Display base.ref from Pull Request +# if: github.event_name == 'pull_request' +# id: display-from-pr # run: | -# echo "MANUAL_VERSION=${{ steps.set-semver-info.outputs.new_version }}" > "$GITHUB_ENV" -# - run: | -# echo "Next version: ${{ env.MANUAL_VERSION }}" | tee -a "$GITHUB_STEP_SUMMARY" +# echo "Event: ${{ github.event_name }}" | tee -a $GITHUB_STEP_SUMMARY +# echo "Event Action: ${{ github.event.action }}" | tee -a $GITHUB_STEP_SUMMARY +# echo "PR_BASE_REF=${{ github.event.pull_request.base.ref }}" | tee -a "$GITHUB_ENV" | tee -a $GITHUB_STEP_SUMMARY +# echo "PR_STATE=${{ github.event.pull_request.state }}" | tee -a "$GITHUB_ENV" | tee -a $GITHUB_STEP_SUMMARY +# echo "PR_MERGED=${{ github.event.pull_request.merged }}" | tee -a "$GITHUB_ENV" | tee -a $GITHUB_STEP_SUMMARY +# echo "PR_COMMIT_SHA=${{ github.event.pull_request.merge_commit_sha }}" | tee -a "$GITHUB_ENV" | tee -a $GITHUB_STEP_SUMMARY +# echo "GITHUB_SHA=${{ github.sha }}" | tee -a "$GITHUB_ENV" | tee -a $GITHUB_STEP_SUMMARY +# baseref="${{ github.event.pull_request.base.ref }}" +# basetag="${baseref#release-}" +# echo "PR_BASE_TAG=$basetag" | tee -a "$GITHUB_ENV" | tee -a $GITHUB_STEP_SUMMARY # -# - name: Get Package Version -# id: get-pkg-version +# - name: Display base_ref from Push Event +# if: github.event_name == 'push' +# id: display-from-push # run: | -# pwd -# ls -la -# echo "CURRENT_PKG_VERSION=$(cat pkg/version/version.go | grep 'const VERSION' | awk '{print $NF}' | tr -d '"')" | tee -a "$GITHUB_ENV" -# - name: Compare package version -# id: check_version +# echo "Branch Ref: ${{ github.ref }}" | tee -a $GITHUB_STEP_SUMMARY +# echo "Event: ${{ github.event_name }}" | tee -a $GITHUB_STEP_SUMMARY +# echo "github.sha: ${{ github.sha }}" | tee -a $GITHUB_STEP_SUMMARY +# +# - name: Find Latest Tag +# if: github.event_name == 'pull_request' +# id: find-latest-tag # run: | -# if [ "${{ env.CURRENT_PKG_VERSION }}" != "${{ env.MANUAL_VERSION }}" ]; then -# echo "Updating version in version.go" -# echo "update_version=true" | tee -a $GITHUB_ENV | tee -a $GITHUB_OUTPUT -# echo "update_version=true" | tee -a "$GITHUB_STEP_SUMMARY" +# prbasetag="${{env.PR_BASE_TAG}}" +# git fetch --tags +# if [[ -n `git tag` ]]; then +# echo "Setting vars" +# allBranchTags=`git tag --sort=-v:refname | grep "^$prbasetag" || echo ""` +# allRepoTags=`git tag --sort=-v:refname` +# branchTagBase=`git tag --sort=-v:refname | grep "^$prbasetag" | grep -o '^[0-9.]*' | head -n 1 || echo ""` +# latestTagBase=`git tag --sort=-v:refname | grep -o '^[0-9.]*' | head -n 1` +# latestBranchTag=`git tag --sort=-v:refname | grep "^$prbasetag" | grep "^$branchTagBase" | head -n 1 || echo ""` +# latestReleasedTag=`git tag --sort=-v:refname | grep "^$prbasetag" | grep "^$branchTagBase$" | head -n 1 || echo ""` +# +# # If the *TagBase values are not found in the list of tags, it means no final release was produced, and the latest*Tag vars will be empty +# if [[ -z "$latestReleasedTag" ]]; then +# latestTag="$latestBranchTag" +# else +# latestTag="$latestReleasedTag" +# fi +# echo "LATEST_TAG=${latestTag}" | tee -a "$GITHUB_ENV" +# +# if [[ "$latestTagBase" == *"$branchTagBase" ]]; then +# hf="False" +# else +# hf="True" +# fi +# +# # The intention is to use this to set the make_latest:false property when +# # dispatching the create-release action, but it is not *yet* a configurable option +# echo "IS_HOTFIX=$hf" | tee -a "$GITHUB_ENV" # else -# echo "Versions match, no update needed" -# echo "update_version=false" | tee -a $GITHUB_ENV | tee -a $GITHUB_OUTPUT -# echo "update_version=false" | tee -a $GITHUB_STEP_SUMMARY +# echo "No tags exist in this repo" +# echo "LATEST_TAG=" | tee -a "$GITHUB_ENV" # fi -# env: -# UPDATE_VERSION: ${{ steps.check_version.outputs.update_version }} -# # - name: Set Outputs # id: set-outputs -# if: needs.get-versions.outputs.LATEST_TAG != '' # run: | -# echo "UPDATE_VERSION=${{ steps.check_version.outputs.update_version }}" | tee -a "$GITHUB_OUTPUT" -# echo "CURRENT_PKG_VERSION=${{ env.CURRENT_PKG_VERSION }}" | tee -a "$GITHUB_OUTPUT" -# echo "MANUAL_VERSION=${{ env.MANUAL_VERSION }}" | tee -a "$GITHUB_OUTPUT" -# echo "NEW_PKG_VERSION=${{ env.MANUAL_VERSION }}" | tee -a "$GITHUB_OUTPUT" +# echo "PR_BASE_REF=${{ env.PR_BASE_REF }}" | tee -a "$GITHUB_OUTPUT" +# echo "PR_STATE=${{ env.PR_STATE }}" +# echo "PR_MERGED=${{ env.PR_MERGED }}" +# if [[ "${{ env.PR_STATE }}" == "closed" && "${{ env.PR_MERGED }}" == "true" && "${{ env.PR_COMMIT_SHA }}" == "${{ env.GITHUB_SHA }}" ]]; then +# echo "IS_FULL_RELEASE=True" | tee -a "$GITHUB_OUTPUT" +# echo "INC_LEVEL=patch" | tee -a "$GITHUB_OUTPUT" +# fi +# if [[ "${{ env.PR_STATE }}" == "open" ]]; then +# echo "IS_PRE_RELEASE=True" | tee -a "$GITHUB_OUTPUT" | tee -a "$GITHUB_ENV" +# echo "INC_LEVEL=prerelease" | tee -a "$GITHUB_OUTPUT" +# fi +# if [[ "${{ env.PR_BASE_REF }}" == "release-"* ]]; then +# echo "IS_RELEASE_BRANCH=True" | tee -a "$GITHUB_OUTPUT" | tee -a "$GITHUB_ENV" +# fi +# echo "PR_COMMIT_SHA=${{ env.PR_COMMIT_SHA }}" | tee -a "$GITHUB_OUTPUT" +# echo "GITHUB_SHA=${{ env.GITHUB_SHA }}" | tee -a "$GITHUB_OUTPUT" +# echo "PR_BASE_TAG=${{ env.PR_BASE_TAG }}" | tee -a "$GITHUB_OUTPUT" +# echo "IS_HOTFIX=${{ env.IS_HOTFIX }}" | tee -a "$GITHUB_OUTPUT" +# echo "LATEST_TAG=${{ env.LATEST_TAG }}" | tee -a "$GITHUB_OUTPUT" # -# update-pkg-version: -# needs: -# - check-package-version -# runs-on: ubuntu-latest +## check-package-version: +## needs: get-versions +## if: github.event_name == 'pull_request' && needs.get-versions.outputs.IS_RELEASE_BRANCH == 'True' +## outputs: +## release_version: ${{ steps.create_release.outputs.current_tag }} +## release_url: ${{ steps.create_release.outputs.upload_url }} +## update_version: ${{ steps.check_version.outputs.update_version }} +## next_version: ${{ steps.set-semver-info.outputs.new_version }} +## runs-on: ubuntu-latest +## steps: +## - name: Check out the code +## uses: actions/checkout@v3 +## - run: | +## echo "INC_LEVEL=${{ needs.get-versions.outputs.INC_LEVEL}}" +## - name: Check if initial release +## if: needs.get-versions.outputs.LATEST_TAG == '' +## run: | +## echo "INITIAL_VERSION=${{needs.get-versions.outputs.PR_BASE_TAG}}.0-rc.0" | tee -a "$GITHUB_STEP_SUMMARY" | tee -a "$GITHUB_ENV" +## echo "MANUAL_VERSION=${{needs.get-versions.outputs.PR_BASE_TAG}}.0-rc.0" | tee -a "$GITHUB_ENV" +## - name: Set semver info +## id: set-semver-info +## if: needs.get-versions.outputs.LATEST_TAG != '' +## uses: fiddlermikey/action-bump-semver@main +## with: +## current_version: ${{ needs.get-versions.outputs.LATEST_TAG}} +## level: ${{ needs.get-versions.outputs.INC_LEVEL}} +## preID: rc +## - name: Show next sem-version +## if: needs.get-versions.outputs.LATEST_TAG != '' +## run: | +## echo "MANUAL_VERSION=${{ steps.set-semver-info.outputs.new_version }}" > "$GITHUB_ENV" +## - run: | +## echo "Next version: ${{ env.MANUAL_VERSION }}" | tee -a "$GITHUB_STEP_SUMMARY" +## +## - name: Get Package Version +## id: get-pkg-version +## run: | +## pwd +## ls -la +## echo "CURRENT_PKG_VERSION=$(cat pkg/version/version.go | grep 'const VERSION' | awk '{print $NF}' | tr -d '"')" | tee -a "$GITHUB_ENV" +## - name: Compare package version +## id: check_version +## run: | +## if [ "${{ env.CURRENT_PKG_VERSION }}" != "${{ env.MANUAL_VERSION }}" ]; then +## echo "Updating version in version.go" +## echo "update_version=true" | tee -a $GITHUB_ENV | tee -a $GITHUB_OUTPUT +## echo "update_version=true" | tee -a "$GITHUB_STEP_SUMMARY" +## else +## echo "Versions match, no update needed" +## echo "update_version=false" | tee -a $GITHUB_ENV | tee -a $GITHUB_OUTPUT +## echo "update_version=false" | tee -a $GITHUB_STEP_SUMMARY +## fi +## env: +## UPDATE_VERSION: ${{ steps.check_version.outputs.update_version }} +## +## - name: Set Outputs +## id: set-outputs +## if: needs.get-versions.outputs.LATEST_TAG != '' +## run: | +## echo "UPDATE_VERSION=${{ steps.check_version.outputs.update_version }}" | tee -a "$GITHUB_OUTPUT" +## echo "CURRENT_PKG_VERSION=${{ env.CURRENT_PKG_VERSION }}" | tee -a "$GITHUB_OUTPUT" +## echo "MANUAL_VERSION=${{ env.MANUAL_VERSION }}" | tee -a "$GITHUB_OUTPUT" +## echo "NEW_PKG_VERSION=${{ env.MANUAL_VERSION }}" | tee -a "$GITHUB_OUTPUT" +## +## update-pkg-version: +## needs: +## - check-package-version +## runs-on: ubuntu-latest +## +## steps: +## - name: Checkout repository +## uses: actions/checkout@v3 +## with: +## token: ${{ secrets.V2BUILDTOKEN}} +## - name: No Update +## if: ${{ needs.check-package-version.outputs.update_version != 'true' }} +## run: | +## echo "Versions match, no update needed" +## exit 0 +## +## - name: Commit to PR branch +## id: commit-version +## if: ${{ needs.check-package-version.outputs.update_version == 'true' }} +## env: +## AUTHOR_EMAIL: keyfactor@keyfactor.github.io +## AUTHOR_NAME: Keyfactor Robot +## GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} +## run: | +## git remote -v +## echo "Checking out ${{ github.head_ref }}" +## git fetch +## echo "git checkout -b ${{ github.head_ref }}" +## git checkout -b ${{ github.head_ref }} +## git reset --hard origin/${{ github.head_ref }} +## sed -i "s/const VERSION = .*/const VERSION = \"${{ needs.check-package-version.outputs.next_version }}\"/" pkg/version/version.go +## git add pkg/version/version.go +## git config --global user.email "${{ env.AUTHOR_EMAIL }}" +## git config --global user.name "${{ env.AUTHOR_NAME }}" +## git commit -m "Bump package version to ${{ needs.check-package-version.outputs.next_version }}" +## git push --set-upstream origin ${{ github.head_ref }} +## echo "Version mismatch! Please create a new pull request with the updated version." +## exit 1 # -# steps: -# - name: Checkout repository -# uses: actions/checkout@v3 -# with: -# token: ${{ secrets.V2BUILDTOKEN}} -# - name: No Update -# if: ${{ needs.check-package-version.outputs.update_version != 'true' }} -# run: | -# echo "Versions match, no update needed" -# exit 0 -# -# - name: Commit to PR branch -# id: commit-version -# if: ${{ needs.check-package-version.outputs.update_version == 'true' }} -# env: -# AUTHOR_EMAIL: keyfactor@keyfactor.github.io -# AUTHOR_NAME: Keyfactor Robot -# GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} -# run: | -# git remote -v -# echo "Checking out ${{ github.head_ref }}" -# git fetch -# echo "git checkout -b ${{ github.head_ref }}" -# git checkout -b ${{ github.head_ref }} -# git reset --hard origin/${{ github.head_ref }} -# sed -i "s/const VERSION = .*/const VERSION = \"${{ needs.check-package-version.outputs.next_version }}\"/" pkg/version/version.go -# git add pkg/version/version.go -# git config --global user.email "${{ env.AUTHOR_EMAIL }}" -# git config --global user.name "${{ env.AUTHOR_NAME }}" -# git commit -m "Bump package version to ${{ needs.check-package-version.outputs.next_version }}" -# git push --set-upstream origin ${{ github.head_ref }} -# echo "Version mismatch! Please create a new pull request with the updated version." -# exit 1 - - call-starter-workflow: - uses: keyfactor/actions/.github/workflows/starter.yml@v2 - needs: get-versions - secrets: - token: ${{ secrets.V2BUILDTOKEN}} - APPROVE_README_PUSH: ${{ secrets.APPROVE_README_PUSH}} - gpg_key: ${{ secrets.KF_GPG_PRIVATE_KEY }} - gpg_pass: ${{ secrets.KF_GPG_PASSPHRASE }} \ No newline at end of file +# call-starter-workflow: +# uses: keyfactor/actions/.github/workflows/starter.yml@v2 +# needs: get-versions +# secrets: +# token: ${{ secrets.V2BUILDTOKEN}} +# APPROVE_README_PUSH: ${{ secrets.APPROVE_README_PUSH}} +# gpg_key: ${{ secrets.KF_GPG_PRIVATE_KEY }} +# gpg_pass: ${{ secrets.KF_GPG_PASSPHRASE }} \ No newline at end of file diff --git a/.github/workflows/update-stores.yml b/.github/workflows/update-stores.yml index 3d6bd4a..e15a993 100644 --- a/.github/workflows/update-stores.yml +++ b/.github/workflows/update-stores.yml @@ -1,197 +1,197 @@ -name: Create Cert Store Update Pull Request - -on: - repository_dispatch: - types: targetRepo-event - workflow_dispatch: - inputs: - targetRepo: - description: 'Target repository for workflow_dispatch' - default: 'all' - targetRef: - description: 'Target ref for workflow_dispatch' - default: 'latest' - -jobs: - create_pull_request: - runs-on: ubuntu-latest - steps: - - name: Set TARGET_REPO_BRANCH from workflow_dispatch input - if: github.event_name == 'workflow_dispatch' - id: set-local-env-vars - run: | - echo "TARGET_REPO_BRANCH=${{ inputs.targetRef }}" | tee -a $GITHUB_ENV - echo "KFUTIL_ARG=${{ inputs.targetRepo }}" | tee -a $GITHUB_ENV - - name: Set TARGET_REPO_BRANCH from repository_dispatch input - if: github.event_name == 'repository_dispatch' - id: set-env-vars-from-payload - run: | - echo "TARGET_REPO_BRANCH=${{ github.event.client_payload.targetRef }}" | tee -a $GITHUB_ENV - echo "KFUTIL_ARG=${{ github.event.client_payload.targetRepo }}" | tee -a $GITHUB_ENV - - name: Check Open PRs for Existing Branch - id: check-branch - uses: actions/github-script@v7 - with: - script: | - // Look for open pull requests - const owner = context.repo.owner; - const repo = context.repo.repo; - const pulls = await github.rest.pulls.list({ - owner, - repo, - state: "open" - }); - // Filter out ones matching the KFUTIL_ARG from payload (repository_dispatch) or input (workflow_dispatch) - const filteredData = pulls.data.filter(item => item.head.ref === '${{ env.KFUTIL_ARG }}'); // Look for an existing branch with the orchestrator repo name - const isBranch = (filteredData.length > 0) - if (isBranch) { - const { - head: { ref: incomingBranch }, base: { ref: baseBranch } - } = pulls.data[0] - core.setOutput('PR_BRANCH', 'commit'); // Just commit since the branch exists - console.log(`incomingBranch: ${incomingBranch}`) - console.log(`baseBranch: ${baseBranch}`) - } else { - core.setOutput('PR_BRANCH', 'create') // No branch, create one - } - console.log(`Branch exists?`) - console.log(filteredData.length > 0) - console.log(`targetRepo: ${{env.KFUTIL_ARG}}`) - - name: set env.PR_BRANCH value for jobs - run: | - echo "PR_BRANCH=${{steps.check-branch.outputs.PR_BRANCH}}" | tee -a $GITHUB_ENV - -# If the branch with an open PR already exists, first check out that branch from kfutil - - name: Check out existing repo merge branch - if: env.PR_BRANCH == 'commit' - uses: actions/checkout@v4 - with: - repository: 'keyfactor/kfutil' - sparse-checkout: | - .github - path: './merge-folder/' - token: ${{ secrets.V2BUILDTOKEN }} - ref: '${{env.KFUTIL_ARG}}' - -# If the branch does not exist, first check out the main branch from kfutil. - - name: Check out main - if: env.PR_BRANCH == 'create' - uses: actions/checkout@v4 - with: - repository: 'keyfactor/kfutil' - sparse-checkout: | - .github - path: './merge-folder/' - token: ${{ secrets.V2BUILDTOKEN }} - -# Save a copy of the original json - - name: Save original store_types.json - run: | - echo "Saving original store_types.json as store_types.sav.json" - cp ./merge-folder/store_types.json ./merge-folder/store_types.sav.json - -# Checkout and run the python tool - - name: Check out python merge tool repo - uses: actions/checkout@v4 - with: - repository: 'keyfactor/integration-tools' - path: './tools/' - token: ${{ secrets.V2BUILDTOKEN }} - - - name: Run Python Script - working-directory: ./tools/store-type-merge - run: | - python main.py --repo-name ${{ env.KFUTIL_ARG }} --ref ${{ env.TARGET_REPO_BRANCH }} - cat store_types.json - env: - GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN }} - - - name: Save Store Types JSON Artifact - if: success() - uses: actions/upload-artifact@v3 - with: - name: store-types - path: | - ./tools/store-type-merge/store_types.json - ./merge-folder/store_types.sav.json - - - name: Save Invalid Store Types JSON Artifact - if: success() - uses: actions/upload-artifact@v3 - with: - name: invalid-repos - path: ./tools/store-type-merge/invalid_repos.json - - - name: Save logs directory - if: success() - uses: actions/upload-artifact@v3 - with: - name: logs - path: ./tools/store-type-merge/log - -# Copy the result to the pr commit folder - - name: Copy store-type-merge results - run: | - echo "Saving original store_types.json as store_types.sav.json" - cp -f ./tools/store-type-merge/store_types.json ./merge-folder/store_types.json - -# Diff the new json against the saved copy and set an UPDATE_FILE variable - - name: Diff the results - run: | - echo "Diff the results" - echo "Set UPDATE_FILE=1 if differences" - if cmp -s ./merge-folder/store_types.json ./merge-folder/store_types.sav.json ; - then echo "UPDATE_FILE=F" | tee -a $GITHUB_ENV; - else echo "UPDATE_FILE=T" | tee -a $GITHUB_ENV; - fi - diff ./merge-folder/store_types.json ./merge-folder/store_types.sav.json || true - -# There are two different steps with a condition to check the PR_BRANCH env var -# Both steps will contain a check for the UPDATE_FILE variable before running - - name: Add and Commit to newly created branch - if: ${{ env.UPDATE_FILE == 'T' && env.PR_BRANCH == 'create' }} - uses: Keyfactor/add-and-commit@v9.1.3 - env: - GITHUB_TOKEN: ${{ secrets.SDK_SYNC_PAT }} - with: - add: store_types.json --force - message: Update store_types.json for ${{env.KFUTIL_ARG}}:${{env.TARGET_REPO_BRANCH}} - author_name: Keyfactor - author_email: keyfactor@keyfactor.github.io - cwd: './merge-folder/' - new_branch: ${{env.KFUTIL_ARG}} - - - name: Add and Commit to existing branch - if: ${{ env.UPDATE_FILE == 'T' && env.PR_BRANCH == 'commit' }} - uses: Keyfactor/add-and-commit@v9.1.3 - env: - GITHUB_TOKEN: ${{ secrets.SDK_SYNC_PAT }} - with: - add: store_types.json --force - message: Update store_types.json for ${{env.KFUTIL_ARG}}:${{env.TARGET_REPO_BRANCH}} - author_name: Keyfactor - author_email: keyfactor@keyfactor.github.io - cwd: './merge-folder/' - - - name: Create new PR for the newly created branch - if: env.UPDATE_FILE == 'T' && env.PR_BRANCH == 'create' - uses: actions/github-script@v7 - with: - script: | - console.log(`Created ${{env.KFUTIL_ARG}} `) - console.log("Commit to ${{env.KFUTIL_ARG}} for PR") - const owner = context.repo.owner; - const repo = context.repo.repo; - const baseBranch = 'main'; - const newBranch = '${{env.KFUTIL_ARG}}'; - const response = await github.rest.pulls.create({ - owner, - repo, - title: 'New Pull Request - ${{env.KFUTIL_ARG}}:${{env.TARGET_REPO_BRANCH}}', - head: newBranch, - base: baseBranch, - body: 'The cert store update from ${{env.KFUTIL_ARG}}:${{env.TARGET_REPO_BRANCH}} needs to be verified and merged if correct.', - }); - console.log(`Pull request created: ${{env.KFUTIL_ARG}}:${{env.TARGET_REPO_BRANCH}} : ${response.data.html_url}`); - env: - GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN }} +#name: Create Cert Store Update Pull Request +# +#on: +# repository_dispatch: +# types: targetRepo-event +# workflow_dispatch: +# inputs: +# targetRepo: +# description: 'Target repository for workflow_dispatch' +# default: 'all' +# targetRef: +# description: 'Target ref for workflow_dispatch' +# default: 'latest' +# +#jobs: +# create_pull_request: +# runs-on: ubuntu-latest +# steps: +# - name: Set TARGET_REPO_BRANCH from workflow_dispatch input +# if: github.event_name == 'workflow_dispatch' +# id: set-local-env-vars +# run: | +# echo "TARGET_REPO_BRANCH=${{ inputs.targetRef }}" | tee -a $GITHUB_ENV +# echo "KFUTIL_ARG=${{ inputs.targetRepo }}" | tee -a $GITHUB_ENV +# - name: Set TARGET_REPO_BRANCH from repository_dispatch input +# if: github.event_name == 'repository_dispatch' +# id: set-env-vars-from-payload +# run: | +# echo "TARGET_REPO_BRANCH=${{ github.event.client_payload.targetRef }}" | tee -a $GITHUB_ENV +# echo "KFUTIL_ARG=${{ github.event.client_payload.targetRepo }}" | tee -a $GITHUB_ENV +# - name: Check Open PRs for Existing Branch +# id: check-branch +# uses: actions/github-script@v7 +# with: +# script: | +# // Look for open pull requests +# const owner = context.repo.owner; +# const repo = context.repo.repo; +# const pulls = await github.rest.pulls.list({ +# owner, +# repo, +# state: "open" +# }); +# // Filter out ones matching the KFUTIL_ARG from payload (repository_dispatch) or input (workflow_dispatch) +# const filteredData = pulls.data.filter(item => item.head.ref === '${{ env.KFUTIL_ARG }}'); // Look for an existing branch with the orchestrator repo name +# const isBranch = (filteredData.length > 0) +# if (isBranch) { +# const { +# head: { ref: incomingBranch }, base: { ref: baseBranch } +# } = pulls.data[0] +# core.setOutput('PR_BRANCH', 'commit'); // Just commit since the branch exists +# console.log(`incomingBranch: ${incomingBranch}`) +# console.log(`baseBranch: ${baseBranch}`) +# } else { +# core.setOutput('PR_BRANCH', 'create') // No branch, create one +# } +# console.log(`Branch exists?`) +# console.log(filteredData.length > 0) +# console.log(`targetRepo: ${{env.KFUTIL_ARG}}`) +# - name: set env.PR_BRANCH value for jobs +# run: | +# echo "PR_BRANCH=${{steps.check-branch.outputs.PR_BRANCH}}" | tee -a $GITHUB_ENV +# +## If the branch with an open PR already exists, first check out that branch from kfutil +# - name: Check out existing repo merge branch +# if: env.PR_BRANCH == 'commit' +# uses: actions/checkout@v4 +# with: +# repository: 'keyfactor/kfutil' +# sparse-checkout: | +# .github +# path: './merge-folder/' +# token: ${{ secrets.V2BUILDTOKEN }} +# ref: '${{env.KFUTIL_ARG}}' +# +## If the branch does not exist, first check out the main branch from kfutil. +# - name: Check out main +# if: env.PR_BRANCH == 'create' +# uses: actions/checkout@v4 +# with: +# repository: 'keyfactor/kfutil' +# sparse-checkout: | +# .github +# path: './merge-folder/' +# token: ${{ secrets.V2BUILDTOKEN }} +# +## Save a copy of the original json +# - name: Save original store_types.json +# run: | +# echo "Saving original store_types.json as store_types.sav.json" +# cp ./merge-folder/store_types.json ./merge-folder/store_types.sav.json +# +## Checkout and run the python tool +# - name: Check out python merge tool repo +# uses: actions/checkout@v4 +# with: +# repository: 'keyfactor/integration-tools' +# path: './tools/' +# token: ${{ secrets.V2BUILDTOKEN }} +# +# - name: Run Python Script +# working-directory: ./tools/store-type-merge +# run: | +# python main.py --repo-name ${{ env.KFUTIL_ARG }} --ref ${{ env.TARGET_REPO_BRANCH }} +# cat store_types.json +# env: +# GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN }} +# +# - name: Save Store Types JSON Artifact +# if: success() +# uses: actions/upload-artifact@v3 +# with: +# name: store-types +# path: | +# ./tools/store-type-merge/store_types.json +# ./merge-folder/store_types.sav.json +# +# - name: Save Invalid Store Types JSON Artifact +# if: success() +# uses: actions/upload-artifact@v3 +# with: +# name: invalid-repos +# path: ./tools/store-type-merge/invalid_repos.json +# +# - name: Save logs directory +# if: success() +# uses: actions/upload-artifact@v3 +# with: +# name: logs +# path: ./tools/store-type-merge/log +# +## Copy the result to the pr commit folder +# - name: Copy store-type-merge results +# run: | +# echo "Saving original store_types.json as store_types.sav.json" +# cp -f ./tools/store-type-merge/store_types.json ./merge-folder/store_types.json +# +## Diff the new json against the saved copy and set an UPDATE_FILE variable +# - name: Diff the results +# run: | +# echo "Diff the results" +# echo "Set UPDATE_FILE=1 if differences" +# if cmp -s ./merge-folder/store_types.json ./merge-folder/store_types.sav.json ; +# then echo "UPDATE_FILE=F" | tee -a $GITHUB_ENV; +# else echo "UPDATE_FILE=T" | tee -a $GITHUB_ENV; +# fi +# diff ./merge-folder/store_types.json ./merge-folder/store_types.sav.json || true +# +## There are two different steps with a condition to check the PR_BRANCH env var +## Both steps will contain a check for the UPDATE_FILE variable before running +# - name: Add and Commit to newly created branch +# if: ${{ env.UPDATE_FILE == 'T' && env.PR_BRANCH == 'create' }} +# uses: Keyfactor/add-and-commit@v9.1.3 +# env: +# GITHUB_TOKEN: ${{ secrets.SDK_SYNC_PAT }} +# with: +# add: store_types.json --force +# message: Update store_types.json for ${{env.KFUTIL_ARG}}:${{env.TARGET_REPO_BRANCH}} +# author_name: Keyfactor +# author_email: keyfactor@keyfactor.github.io +# cwd: './merge-folder/' +# new_branch: ${{env.KFUTIL_ARG}} +# +# - name: Add and Commit to existing branch +# if: ${{ env.UPDATE_FILE == 'T' && env.PR_BRANCH == 'commit' }} +# uses: Keyfactor/add-and-commit@v9.1.3 +# env: +# GITHUB_TOKEN: ${{ secrets.SDK_SYNC_PAT }} +# with: +# add: store_types.json --force +# message: Update store_types.json for ${{env.KFUTIL_ARG}}:${{env.TARGET_REPO_BRANCH}} +# author_name: Keyfactor +# author_email: keyfactor@keyfactor.github.io +# cwd: './merge-folder/' +# +# - name: Create new PR for the newly created branch +# if: env.UPDATE_FILE == 'T' && env.PR_BRANCH == 'create' +# uses: actions/github-script@v7 +# with: +# script: | +# console.log(`Created ${{env.KFUTIL_ARG}} `) +# console.log("Commit to ${{env.KFUTIL_ARG}} for PR") +# const owner = context.repo.owner; +# const repo = context.repo.repo; +# const baseBranch = 'main'; +# const newBranch = '${{env.KFUTIL_ARG}}'; +# const response = await github.rest.pulls.create({ +# owner, +# repo, +# title: 'New Pull Request - ${{env.KFUTIL_ARG}}:${{env.TARGET_REPO_BRANCH}}', +# head: newBranch, +# base: baseBranch, +# body: 'The cert store update from ${{env.KFUTIL_ARG}}:${{env.TARGET_REPO_BRANCH}} needs to be verified and merged if correct.', +# }); +# console.log(`Pull request created: ${{env.KFUTIL_ARG}}:${{env.TARGET_REPO_BRANCH}} : ${response.data.html_url}`); +# env: +# GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN }} From 58c0079053247c9a435a762d118a93d5cccd9854 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Fri, 1 Nov 2024 12:07:18 -0700 Subject: [PATCH 12/19] fix(auth): Basic auth constructor chore(ci): Update test environments Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- .github/config/.terraform.lock.hcl | 25 ++ .github/config/MODULE.MD | 57 +++ .github/config/Makefile | 26 ++ .github/config/README.md | 108 ++++++ .github/config/environments.tf | 116 ++++++ .github/config/providers.tf | 20 + .github/config/repo.tf | 3 + .github/config/variables.tf | 90 +++++ .github/workflows/tests.yml | 573 ++++++++++++++++++++++++----- cmd/helpers.go | 3 + cmd/root.go | 7 +- cmd/storeTypes.go | 4 + go.mod | 2 +- go.sum | 4 +- 14 files changed, 950 insertions(+), 88 deletions(-) create mode 100644 .github/config/.terraform.lock.hcl create mode 100644 .github/config/MODULE.MD create mode 100644 .github/config/Makefile create mode 100644 .github/config/README.md create mode 100644 .github/config/environments.tf create mode 100644 .github/config/providers.tf create mode 100644 .github/config/repo.tf create mode 100644 .github/config/variables.tf diff --git a/.github/config/.terraform.lock.hcl b/.github/config/.terraform.lock.hcl new file mode 100644 index 0000000..567b5b4 --- /dev/null +++ b/.github/config/.terraform.lock.hcl @@ -0,0 +1,25 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/integrations/github" { + version = "6.3.1" + constraints = ">= 6.2.0" + hashes = [ + "h1:fMctJXbbaQU4sBAxAayAVa9wDyIIdSBZX8KzFphKFC0=", + "zh:25ae1cb97ec528e6b7e9330489f4a33acc0fa80b909c113a8445656bc524c5b9", + "zh:3e1f6300dc10e52a54f13352770ed79f25ff4ba9ac49b776c52a655a3488a20b", + "zh:4aaf2877ec22e63358d7c9cd48c7d7947d1a1dc4d03231f0af193d8975d5918a", + "zh:4b904a81fac12a2a7606c8d811cb9c4e13581adcaaa19e503a067ac95c515925", + "zh:54fe7e0dca04e698631a5b86bdd43ef09a31375e68f8f89970b4315cd5fc6312", + "zh:6b14f92cf62784eaf20f43ef58ce966735f30d43deeab077943bd410c0d8b8b2", + "zh:86c49a1c11c024b26b6750c446f104922a3fe8464d3706a5fb9a4a05c6ca0b0a", + "zh:8939fb6332c4a58c4e90245eb9f0110987ccafff06b45a7ed513f2759a2abe6a", + "zh:8b4068a78c1f357325d1151facdb1aff506b9cd79d2bab21a55651255a130e2f", + "zh:ae22f5e52f534f19811d7f9480b4eb442f12ff16367b3893abb4e449b029ff6b", + "zh:afae9cfd9d49002ddfea552aa4844074b9974bd56ff2c2458f2297fe0df56a5b", + "zh:bc7a434408eb16a4fbceec0bd86b108a491408b727071402ad572cdb1afa2eb7", + "zh:c8e4728ea2d2c6e3d2c1bc5e7d92ed1121c02bab687702ec2748e3a6a0844150", + "zh:f6314b2cff0c0a07a216501cda51b35e6a4c66a2418c7c9966ccfe701e01b6b0", + "zh:fbd1fee2c9df3aa19cf8851ce134dea6e45ea01cb85695c1726670c285797e25", + ] +} diff --git a/.github/config/MODULE.MD b/.github/config/MODULE.MD new file mode 100644 index 0000000..4f93801 --- /dev/null +++ b/.github/config/MODULE.MD @@ -0,0 +1,57 @@ +## Requirements + +| Name | Version | +|---------------------------------------------------------------------------|---------| +| [terraform](#requirement\_terraform) | >= 1.0 | +| [github](#requirement\_github) | >=6.2 | + +## Providers + +| Name | Version | +|------------------------------------------------------------|---------| +| [github](#provider\_github) | 6.3.1 | + +## Modules + +| Name | Source | Version | +|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------|---------| +| [keyfactor\_github\_test\_environment\_10\_5\_0](#module\_keyfactor\_github\_test\_environment\_10\_5\_0) | git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git | main | +| [keyfactor\_github\_test\_environment\_10\_5\_0\_CLEAN](#module\_keyfactor\_github\_test\_environment\_10\_5\_0\_CLEAN) | git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git | main | +| [keyfactor\_github\_test\_environment\_11\_5\_0](#module\_keyfactor\_github\_test\_environment\_11\_5\_0) | git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git | main | +| [keyfactor\_github\_test\_environment\_11\_5\_0\_CLEAN](#module\_keyfactor\_github\_test\_environment\_11\_5\_0\_CLEAN) | git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git | main | +| [keyfactor\_github\_test\_environment\_11\_5\_0\_OAUTH](#module\_keyfactor\_github\_test\_environment\_11\_5\_0\_OAUTH) | git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git | main | +| [keyfactor\_github\_test\_environment\_11\_5\_0\_OAUTH\_CLEAN](#module\_keyfactor\_github\_test\_environment\_11\_5\_0\_OAUTH\_CLEAN) | git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git | main | +| [keyfactor\_github\_test\_environment\_12\_3\_0\_AD](#module\_keyfactor\_github\_test\_environment\_12\_3\_0\_AD) | git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git | main | +| [keyfactor\_github\_test\_environment\_12\_3\_0\_AD\_CLEAN](#module\_keyfactor\_github\_test\_environment\_12\_3\_0\_AD\_CLEAN) | git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git | main | +| [keyfactor\_github\_test\_environment\_12\_3\_0\_OAUTH](#module\_keyfactor\_github\_test\_environment\_12\_3\_0\_OAUTH) | git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git | main | +| [keyfactor\_github\_test\_environment\_12\_3\_0\_OAUTH\_CLEAN](#module\_keyfactor\_github\_test\_environment\_12\_3\_0\_OAUTH\_CLEAN) | git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git | main | + +## Resources + +| Name | Type | +|---------------------------------------------------------------------------------------------------------------------------|-------------| +| [github_repository.repo](https://registry.terraform.io/providers/integrations/github/latest/docs/data-sources/repository) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|---------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------|----------|---------------------------------------------------------------------------------------------------------|:--------:| +| [keyfactor\_auth\_token\_url](#input\_keyfactor\_auth\_token\_url) | The token URL to authenticate with the Keyfactor instance using oauth2 client credentials | `string` | `"https://int-oidc-lab.eastus2.cloudapp.azure.com:8444/realms/Keyfactor/protocol/openid-connect/token"` | no | +| [keyfactor\_client\_id](#input\_keyfactor\_client\_id) | The client ID to authenticate with the Keyfactor instance using oauth2 client credentials | `string` | n/a | yes | +| [keyfactor\_client\_secret](#input\_keyfactor\_client\_secret) | The client secret to authenticate with the Keyfactor instance using oauth2 client credentials | `string` | n/a | yes | +| [keyfactor\_hostname\_10\_5\_0](#input\_keyfactor\_hostname\_10\_5\_0) | The hostname of the Keyfactor v10.5.x instance | `string` | `"integrations1050-lab.kfdelivery.com"` | no | +| [keyfactor\_hostname\_10\_5\_0\_CLEAN](#input\_keyfactor\_hostname\_10\_5\_0\_CLEAN) | The hostname of the Keyfactor v10.5.x instance with no stores or orchestrators. This is used for store-type tests. | `string` | `"int1050-test-clean.kfdelivery.com"` | no | +| [keyfactor\_hostname\_11\_5\_0](#input\_keyfactor\_hostname\_11\_5\_0) | The hostname of the Keyfactor v11.5.x instance | `string` | `"integrations1150-lab.kfdelivery.com"` | no | +| [keyfactor\_hostname\_11\_5\_0\_CLEAN](#input\_keyfactor\_hostname\_11\_5\_0\_CLEAN) | The hostname of the Keyfactor v11.5.x instance with no stores or orchestrators. This is used for store-type tests. | `string` | `"int1150-test-clean.kfdelivery.com"` | no | +| [keyfactor\_hostname\_11\_5\_0\_OAUTH](#input\_keyfactor\_hostname\_11\_5\_0\_OAUTH) | The hostname of the Keyfactor instance | `string` | `"int-oidc-lab.eastus2.cloudapp.azure.com"` | no | +| [keyfactor\_hostname\_11\_5\_0\_OAUTH\_CLEAN](#input\_keyfactor\_hostname\_11\_5\_0\_OAUTH\_CLEAN) | The hostname of the Keyfactor instance | `string` | `"int1150-oauth-test-clean.eastus2.cloudapp.azure.com"` | no | +| [keyfactor\_hostname\_12\_3\_0](#input\_keyfactor\_hostname\_12\_3\_0) | The hostname of the Keyfactor v12.3.x instance | `string` | `"integrations1230-lab.kfdelivery.com"` | no | +| [keyfactor\_hostname\_12\_3\_0\_CLEAN](#input\_keyfactor\_hostname\_12\_3\_0\_CLEAN) | The hostname of the Keyfactor v12.3.x instance with no stores or orchestrators. This is used for store-type tests. | `string` | `"int1230-test-clean.kfdelivery.com"` | no | +| [keyfactor\_hostname\_12\_3\_0\_OAUTH](#input\_keyfactor\_hostname\_12\_3\_0\_OAUTH) | The hostname of the Keyfactor instance | `string` | `"int-oidc-lab.eastus2.cloudapp.azure.com"` | no | +| [keyfactor\_hostname\_12\_3\_0\_OAUTH\_CLEAN](#input\_keyfactor\_hostname\_12\_3\_0\_OAUTH\_CLEAN) | The hostname of the Keyfactor instance | `string` | `"int1230-oauth-test-clean.eastus2.cloudapp.azure.com"` | no | +| [keyfactor\_password\_AD](#input\_keyfactor\_password\_AD) | The password to authenticate with Keyfactor instance that uses AD authentication | `string` | n/a | yes | +| [keyfactor\_username\_AD](#input\_keyfactor\_username\_AD) | The username to authenticate with a Keyfactor instance that uses AD authentication | `string` | n/a | yes | + +## Outputs + +No outputs. diff --git a/.github/config/Makefile b/.github/config/Makefile new file mode 100644 index 0000000..f67d9df --- /dev/null +++ b/.github/config/Makefile @@ -0,0 +1,26 @@ +.DEFAULT_GOAL := help + +##@ Utility +help: ## Display this help + @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) + +deps: ## Install deps for macos + @brew install pre-commit tflint terraform terraform-docs + +docs: ## Run terraform-docs to update module docs. + @terraform-docs markdown . > MODULE.MD + @terraform-docs markdown table --output-file README.md --output-mode inject . + +lint: ## Run tflint + @tflint + +validate: ## Run terraform validate + @terraform init --upgrade + @terraform validate + +precommit/add: ## Install pre-commit hook + @pre-commit install + +precommit/remove: ## Uninstall pre-commit hook + @pre-commit uninstall + diff --git a/.github/config/README.md b/.github/config/README.md new file mode 100644 index 0000000..d2e66e2 --- /dev/null +++ b/.github/config/README.md @@ -0,0 +1,108 @@ +# GitHub Test Environment Setup + +This code sets up GitHub environments for testing against Keyfactor Command instances that are configured to use +Active Directory or Keycloak for authentication. + +## Requirements + +1. Terraform >= 1.0 +2. GitHub Provider >= 6.2 +3. Keyfactor Command instance(s) configured to use Active Directory or Keycloak for authentication +4. AD or Keycloak credentials for authenticating to the Keyfactor Command instance(s) +5. A GitHub token with access and permissions to the repository where the environments will be created + +## Adding a new environment + +Modify the `environments.tf` file to include the new environment module. The module should be named appropriately. +Example: + +### Active Directory Environment + +```hcl +module "keyfactor_github_test_environment_ad_10_5_0" { + source = "git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git?ref=main" + + gh_environment_name = "KFC_10_5_0" # Keyfactor Command 10.5.0 environment using Active Directory(/Basic Auth) + gh_repo_name = data.github_repository.repo.name + keyfactor_hostname = var.keyfactor_hostname_10_5_0 + keyfactor_username = var.keyfactor_username_AD + keyfactor_password = var.keyfactor_password_AD +} +``` + +### oAuth Client Environment + +```hcl +module "keyfactor_github_test_environment_12_3_0_kc" { + source = "git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-kc.git?ref=main" + + gh_environment_name = "KFC_12_3_0_KC" # Keyfactor Command 12.3.0 environment using Keycloak + gh_repo_name = data.github_repository.repo.name + keyfactor_hostname = var.keyfactor_hostname_12_3_0_OAUTH + keyfactor_auth_token_url = var.keyfactor_auth_token_url + keyfactor_client_id = var.keyfactor_client_id + keyfactor_client_secret = var.keyfactor_client_secret + keyfactor_tls_skip_verify = true +} +``` + + + +## Requirements + +| Name | Version | +|---------------------------------------------------------------------------|---------| +| [terraform](#requirement\_terraform) | >= 1.0 | +| [github](#requirement\_github) | >=6.2 | + +## Providers + +| Name | Version | +|------------------------------------------------------------|---------| +| [github](#provider\_github) | 6.3.1 | + +## Modules + +| Name | Source | Version | +|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------|---------| +| [keyfactor\_github\_test\_environment\_10\_5\_0](#module\_keyfactor\_github\_test\_environment\_10\_5\_0) | git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git | main | +| [keyfactor\_github\_test\_environment\_10\_5\_0\_CLEAN](#module\_keyfactor\_github\_test\_environment\_10\_5\_0\_CLEAN) | git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git | main | +| [keyfactor\_github\_test\_environment\_11\_5\_0](#module\_keyfactor\_github\_test\_environment\_11\_5\_0) | git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git | main | +| [keyfactor\_github\_test\_environment\_11\_5\_0\_CLEAN](#module\_keyfactor\_github\_test\_environment\_11\_5\_0\_CLEAN) | git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git | main | +| [keyfactor\_github\_test\_environment\_11\_5\_0\_OAUTH](#module\_keyfactor\_github\_test\_environment\_11\_5\_0\_OAUTH) | git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git | main | +| [keyfactor\_github\_test\_environment\_11\_5\_0\_OAUTH\_CLEAN](#module\_keyfactor\_github\_test\_environment\_11\_5\_0\_OAUTH\_CLEAN) | git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git | main | +| [keyfactor\_github\_test\_environment\_12\_3\_0\_AD](#module\_keyfactor\_github\_test\_environment\_12\_3\_0\_AD) | git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git | main | +| [keyfactor\_github\_test\_environment\_12\_3\_0\_AD\_CLEAN](#module\_keyfactor\_github\_test\_environment\_12\_3\_0\_AD\_CLEAN) | git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git | main | +| [keyfactor\_github\_test\_environment\_12\_3\_0\_OAUTH](#module\_keyfactor\_github\_test\_environment\_12\_3\_0\_OAUTH) | git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git | main | +| [keyfactor\_github\_test\_environment\_12\_3\_0\_OAUTH\_CLEAN](#module\_keyfactor\_github\_test\_environment\_12\_3\_0\_OAUTH\_CLEAN) | git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git | main | + +## Resources + +| Name | Type | +|---------------------------------------------------------------------------------------------------------------------------|-------------| +| [github_repository.repo](https://registry.terraform.io/providers/integrations/github/latest/docs/data-sources/repository) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|---------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------|----------|---------------------------------------------------------------------------------------------------------|:--------:| +| [keyfactor\_auth\_token\_url](#input\_keyfactor\_auth\_token\_url) | The token URL to authenticate with the Keyfactor instance using oauth2 client credentials | `string` | `"https://int-oidc-lab.eastus2.cloudapp.azure.com:8444/realms/Keyfactor/protocol/openid-connect/token"` | no | +| [keyfactor\_client\_id](#input\_keyfactor\_client\_id) | The client ID to authenticate with the Keyfactor instance using oauth2 client credentials | `string` | n/a | yes | +| [keyfactor\_client\_secret](#input\_keyfactor\_client\_secret) | The client secret to authenticate with the Keyfactor instance using oauth2 client credentials | `string` | n/a | yes | +| [keyfactor\_hostname\_10\_5\_0](#input\_keyfactor\_hostname\_10\_5\_0) | The hostname of the Keyfactor v10.5.x instance | `string` | `"integrations1050-lab.kfdelivery.com"` | no | +| [keyfactor\_hostname\_10\_5\_0\_CLEAN](#input\_keyfactor\_hostname\_10\_5\_0\_CLEAN) | The hostname of the Keyfactor v10.5.x instance with no stores or orchestrators. This is used for store-type tests. | `string` | `"int1050-test-clean.kfdelivery.com"` | no | +| [keyfactor\_hostname\_11\_5\_0](#input\_keyfactor\_hostname\_11\_5\_0) | The hostname of the Keyfactor v11.5.x instance | `string` | `"integrations1150-lab.kfdelivery.com"` | no | +| [keyfactor\_hostname\_11\_5\_0\_CLEAN](#input\_keyfactor\_hostname\_11\_5\_0\_CLEAN) | The hostname of the Keyfactor v11.5.x instance with no stores or orchestrators. This is used for store-type tests. | `string` | `"int1150-test-clean.kfdelivery.com"` | no | +| [keyfactor\_hostname\_11\_5\_0\_OAUTH](#input\_keyfactor\_hostname\_11\_5\_0\_OAUTH) | The hostname of the Keyfactor instance | `string` | `"int-oidc-lab.eastus2.cloudapp.azure.com"` | no | +| [keyfactor\_hostname\_11\_5\_0\_OAUTH\_CLEAN](#input\_keyfactor\_hostname\_11\_5\_0\_OAUTH\_CLEAN) | The hostname of the Keyfactor instance | `string` | `"int1150-oauth-test-clean.eastus2.cloudapp.azure.com"` | no | +| [keyfactor\_hostname\_12\_3\_0](#input\_keyfactor\_hostname\_12\_3\_0) | The hostname of the Keyfactor v12.3.x instance | `string` | `"integrations1230-lab.kfdelivery.com"` | no | +| [keyfactor\_hostname\_12\_3\_0\_CLEAN](#input\_keyfactor\_hostname\_12\_3\_0\_CLEAN) | The hostname of the Keyfactor v12.3.x instance with no stores or orchestrators. This is used for store-type tests. | `string` | `"int1230-test-clean.kfdelivery.com"` | no | +| [keyfactor\_hostname\_12\_3\_0\_OAUTH](#input\_keyfactor\_hostname\_12\_3\_0\_OAUTH) | The hostname of the Keyfactor instance | `string` | `"int-oidc-lab.eastus2.cloudapp.azure.com"` | no | +| [keyfactor\_hostname\_12\_3\_0\_OAUTH\_CLEAN](#input\_keyfactor\_hostname\_12\_3\_0\_OAUTH\_CLEAN) | The hostname of the Keyfactor instance | `string` | `"int1230-oauth-test-clean.eastus2.cloudapp.azure.com"` | no | +| [keyfactor\_password\_AD](#input\_keyfactor\_password\_AD) | The password to authenticate with Keyfactor instance that uses AD authentication | `string` | n/a | yes | +| [keyfactor\_username\_AD](#input\_keyfactor\_username\_AD) | The username to authenticate with a Keyfactor instance that uses AD authentication | `string` | n/a | yes | + +## Outputs + +No outputs. + \ No newline at end of file diff --git a/.github/config/environments.tf b/.github/config/environments.tf new file mode 100644 index 0000000..d645abe --- /dev/null +++ b/.github/config/environments.tf @@ -0,0 +1,116 @@ +module "keyfactor_github_test_environment_10_5_0" { + source = "git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git?ref=main" + + gh_environment_name = "KFC_10_5_0" + gh_repo_name = data.github_repository.repo.name + keyfactor_hostname = var.keyfactor_hostname_10_5_0 + keyfactor_username = var.keyfactor_username_AD + keyfactor_password = var.keyfactor_password_AD + keyfactor_config_file = base64encode(file("${path.module}/command_config.json")) +} + +module "keyfactor_github_test_environment_10_5_0_CLEAN" { + source = "git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git?ref=main" + + gh_environment_name = "KFC_10_5_0_CLEAN" + gh_repo_name = data.github_repository.repo.name + keyfactor_hostname = var.keyfactor_hostname_10_5_0 + keyfactor_username = var.keyfactor_username_AD + keyfactor_password = var.keyfactor_password_AD + keyfactor_config_file = base64encode(file("${path.module}/command_config.json")) +} + +module "keyfactor_github_test_environment_11_5_0" { + source = "git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git?ref=main" + + gh_environment_name = "KFC_11_5_0" + gh_repo_name = data.github_repository.repo.name + keyfactor_hostname = var.keyfactor_hostname_11_5_0 + keyfactor_username = var.keyfactor_username_AD + keyfactor_password = var.keyfactor_password_AD + keyfactor_config_file = base64encode(file("${path.module}/command_config.json")) +} + +module "keyfactor_github_test_environment_11_5_0_CLEAN" { + source = "git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git?ref=main" + + gh_environment_name = "KFC_11_5_0_CLEAN" + gh_repo_name = data.github_repository.repo.name + keyfactor_hostname = var.keyfactor_hostname_11_5_0 + keyfactor_username = var.keyfactor_username_AD + keyfactor_password = var.keyfactor_password_AD + keyfactor_config_file = base64encode(file("${path.module}/command_config.json")) +} + +module "keyfactor_github_test_environment_11_5_0_OAUTH" { + source = "git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git?ref=main" + + gh_environment_name = "KFC_11_5_0_OAUTH" + gh_repo_name = data.github_repository.repo.name + keyfactor_hostname = var.keyfactor_hostname_11_5_0_OAUTH + keyfactor_auth_token_url = var.keyfactor_auth_token_url + keyfactor_client_id = var.keyfactor_client_id + keyfactor_client_secret = var.keyfactor_client_secret + keyfactor_tls_skip_verify = true + keyfactor_config_file = base64encode(file("${path.module}/command_config.json")) +} + +module "keyfactor_github_test_environment_11_5_0_OAUTH_CLEAN" { + source = "git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git?ref=main" + + gh_environment_name = "KFC_11_5_0_OAUTH_CLEAN" + gh_repo_name = data.github_repository.repo.name + keyfactor_hostname = var.keyfactor_hostname_11_5_0_OAUTH_CLEAN + keyfactor_auth_token_url = var.keyfactor_auth_token_url + keyfactor_client_id = var.keyfactor_client_id + keyfactor_client_secret = var.keyfactor_client_secret + keyfactor_tls_skip_verify = true + keyfactor_config_file = base64encode(file("${path.module}/command_config.json")) +} + +module "keyfactor_github_test_environment_12_3_0_AD_CLEAN" { + source = "git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git?ref=main" + gh_environment_name = "KFC_12_3_0_AD_CLEAN" + gh_repo_name = data.github_repository.repo.name + keyfactor_hostname = var.keyfactor_hostname_12_3_0_CLEAN + keyfactor_username = var.keyfactor_username_AD + keyfactor_password = var.keyfactor_password_AD + keyfactor_tls_skip_verify = true + keyfactor_config_file = base64encode(file("${path.module}/command_config.json")) +} + +module "keyfactor_github_test_environment_12_3_0_AD" { + source = "git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git?ref=main" + gh_environment_name = "KFC_12_3_0_AD" + gh_repo_name = data.github_repository.repo.name + keyfactor_hostname = var.keyfactor_hostname_12_3_0 + keyfactor_username = var.keyfactor_username_AD + keyfactor_password = var.keyfactor_password_AD + keyfactor_tls_skip_verify = true + keyfactor_config_file = base64encode(file("${path.module}/command_config.json")) +} + +module "keyfactor_github_test_environment_12_3_0_OAUTH" { + source = "git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git?ref=main" + + gh_environment_name = "KFC_12_3_0_OAUTH" + gh_repo_name = data.github_repository.repo.name + keyfactor_hostname = var.keyfactor_hostname_12_3_0_OAUTH + keyfactor_auth_token_url = var.keyfactor_auth_token_url + keyfactor_client_id = var.keyfactor_client_id + keyfactor_client_secret = var.keyfactor_client_secret + keyfactor_tls_skip_verify = true + keyfactor_config_file = base64encode(file("${path.module}/command_config.json")) +} + +module "keyfactor_github_test_environment_12_3_0_OAUTH_CLEAN" { + source = "git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git?ref=main" + gh_environment_name = "KFC_12_3_0_OAUTH_CLEAN" + gh_repo_name = data.github_repository.repo.name + keyfactor_hostname = var.keyfactor_hostname_12_3_0_OAUTH_CLEAN + keyfactor_auth_token_url = var.keyfactor_auth_token_url + keyfactor_client_id = var.keyfactor_client_id + keyfactor_client_secret = var.keyfactor_client_secret + keyfactor_tls_skip_verify = true + keyfactor_config_file = base64encode(file("${path.module}/command_config.json")) +} diff --git a/.github/config/providers.tf b/.github/config/providers.tf new file mode 100644 index 0000000..0de8b5c --- /dev/null +++ b/.github/config/providers.tf @@ -0,0 +1,20 @@ +terraform { + required_version = ">= 1.0" + required_providers { + github = { + source = "integrations/github" + version = ">=6.2" + } + } + backend "azurerm" { + resource_group_name = "integrations-infra" + storage_account_name = "integrationstfstate" + container_name = "tfstate" + key = "github/repos/kfutil/environments.tfstate" + } +} + +provider "github" { + # Configuration options + owner = "Keyfactor" +} \ No newline at end of file diff --git a/.github/config/repo.tf b/.github/config/repo.tf new file mode 100644 index 0000000..7ac3974 --- /dev/null +++ b/.github/config/repo.tf @@ -0,0 +1,3 @@ +data "github_repository" "repo" { + name = "kfutil" +} \ No newline at end of file diff --git a/.github/config/variables.tf b/.github/config/variables.tf new file mode 100644 index 0000000..d6df78f --- /dev/null +++ b/.github/config/variables.tf @@ -0,0 +1,90 @@ +// Hosts +variable "keyfactor_hostname_10_5_0" { + description = "The hostname of the Keyfactor v10.5.x instance" + type = string + default = "integrations1050-lab.kfdelivery.com" +} + +variable "keyfactor_hostname_10_5_0_CLEAN" { + description = "The hostname of the Keyfactor v10.5.x instance with no stores or orchestrators. This is used for store-type tests." + type = string + default = "int1050-test-clean.kfdelivery.com" +} + + +variable "keyfactor_hostname_11_5_0" { + description = "The hostname of the Keyfactor v11.5.x instance" + type = string + default = "integrations1150-lab.kfdelivery.com" +} + +variable "keyfactor_hostname_11_5_0_CLEAN" { + description = "The hostname of the Keyfactor v11.5.x instance with no stores or orchestrators. This is used for store-type tests." + type = string + default = "int1150-test-clean.kfdelivery.com" +} + +variable "keyfactor_hostname_11_5_0_OAUTH" { + description = "The hostname of the Keyfactor instance" + type = string + default = "int-oidc-lab.eastus2.cloudapp.azure.com" +} + +variable "keyfactor_hostname_11_5_0_OAUTH_CLEAN" { + description = "The hostname of the Keyfactor instance" + type = string + default = "int1150-oauth-test-clean.eastus2.cloudapp.azure.com" +} + + +variable "keyfactor_hostname_12_3_0" { + description = "The hostname of the Keyfactor v12.3.x instance" + type = string + default = "integrations1230-lab.kfdelivery.com" +} + +variable "keyfactor_hostname_12_3_0_CLEAN" { + description = "The hostname of the Keyfactor v12.3.x instance with no stores or orchestrators. This is used for store-type tests." + type = string + default = "int1230-test-clean.kfdelivery.com" +} + +variable "keyfactor_hostname_12_3_0_OAUTH" { + description = "The hostname of the Keyfactor instance" + type = string + default = "int-oidc-lab.eastus2.cloudapp.azure.com" +} + +variable "keyfactor_hostname_12_3_0_OAUTH_CLEAN" { + description = "The hostname of the Keyfactor instance" + type = string + default = "int1230-oauth-test-clean.eastus2.cloudapp.azure.com" +} + +// Authentication +variable "keyfactor_username_AD" { + description = "The username to authenticate with a Keyfactor instance that uses AD authentication" + type = string +} + +variable "keyfactor_password_AD" { + description = "The password to authenticate with Keyfactor instance that uses AD authentication" + type = string +} + +variable "keyfactor_client_id" { + description = "The client ID to authenticate with the Keyfactor instance using oauth2 client credentials" + type = string +} + +variable "keyfactor_client_secret" { + description = "The client secret to authenticate with the Keyfactor instance using oauth2 client credentials" + type = string +} + +variable "keyfactor_auth_token_url" { + description = "The token URL to authenticate with the Keyfactor instance using oauth2 client credentials" + type = string + default = "https://int-oidc-lab.eastus2.cloudapp.azure.com:8444/realms/Keyfactor/protocol/openid-connect/token" +} + diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index aadf201..e9310ef 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,117 +1,526 @@ name: go tests on: + # workflow_dispatch: + # workflow_run: + # workflows: + # - "Check and Update Package Version" + # types: + # - completed + # branches: + # - "*" push: branches: - '*' jobs: build: - runs-on: ubuntu-latest + runs-on: kfutil-runner-set steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Go uses: actions/setup-go@v5 with: - go-version: "1.22" + go-version: "1.23" - name: Set up private repo access for go get run: | git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" env: - GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN }} + GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} + - name: Install dependencies run: go mod download && go mod tidy - name: Install Azure CLI run: | curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash az --version + # 10.x.x + kf_10_x_x: + runs-on: kfutil-runner-set + needs: + - build + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Run tests + run: echo "Running tests for KF 10.x.x" + + ### Store Type Tests + Test_StoreTypes_KFC_10_5_0: + runs-on: kfutil-runner-set + needs: + - build + - kf_10_x_x + environment: "KFC_10_5_0_CLEAN" + env: + GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Set up private repo access for go get + run: | + git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + - name: Run tests + run: | + export KFUTIL_DEBUG=1 + go test -v ./cmd -run "^Test_StoreTypes*" + + ### Store Tests + Test_Stores_KFC_10_5_0: + runs-on: kfutil-runner-set + needs: + - build + - kf_10_x_x + - Test_StoreTypes_KFC_10_5_0 + environment: "KFC_10_5_0" + env: + GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Set up private repo access for go get + run: | + git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + - name: Run tests + run: go test -v ./cmd -run "^Test_Stores_*" + + ### PAM Tests + Test_PAM_KFC_10_5_0: + runs-on: kfutil-runner-set + needs: + - build + - kf_10_x_x + - Test_StoreTypes_KFC_10_5_0 + environment: "KFC_10_5_0" + env: + GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} + KEYFACTOR_PASSWORD: ${{ secrets.KEYFACTOR_PASSWORD }} + KEYFACTOR_USERNAME: ${{ secrets.KEYFACTOR_USERNAME }} + KEYFACTOR_AUTH_CONFIG_B64: ${{ secrets.KEYFACTOR_AUTH_CONFIG_B64 }} + KEYFACTOR_HOSTNAME: ${{ vars.KEYFACTOR_HOSTNAME }} + KEYFACTOR_AUTH_HOSTNAME: ${{ vars.KEYFACTOR_AUTH_HOSTNAME }} + KEYFACTOR_SKIP_VERIFY: ${{ vars.KEYFACTOR_SKIP_VERIFY }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Set up private repo access for go get + run: | + git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + - name: Run tests + run: | + unset KFUTIL_DEBUG + go test -v ./cmd -run "^Test_PAM*" + + ### PAM Tests AKV Auth Provider + Test_AKV_PAM_KFC_10_5_0: + runs-on: self-hosted + needs: + - Test_PAM_KFC_10_5_0 + environment: "KFC_10_5_0" + env: + SECRET_NAME: "command-config-1050-az" + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: "1.23" + - name: Set up private repo access for go get + run: | + git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + - name: Install dependencies + run: go mod download && go mod tidy + - name: Get secret from Azure Key Vault + run: | + . ./examples/auth/akv/akv_auth.sh + cat $HOME/.keyfactor/command_config.json + - name: Install kfutil + run: | + make install + - name: Run tests + run: | + go test -v ./cmd -run "^Test_PAM*" + + + # ## KFC 11.x.x + # kf_11_x_x: + # runs-on: kfutil-runner-set + # needs: + # - build + # steps: + # - name: Checkout code + # uses: actions/checkout@v4 + # - name: Run tests + # run: echo "Running tests for KF 11.x.x" + # + # ### Store Type Tests + # Test_StoreTypes_KFC_11_1_2: + # runs-on: kfutil-runner-set + # needs: + # - build + # - kf_11_x_x + # env: + # SECRET_NAME: "command-config-1112-clean" + # KEYFACTOR_HOSTNAME: "int1112-test-clean.kfdelivery.com" + # KEYFACTOR_DOMAIN: "command" + # KEYFACTOR_USERNAME: ${{ secrets.LAB_USERNAME }} + # KEYFACTOR_PASSWORD: ${{ secrets.LAB_PASSWORD }} + # GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} + # steps: + # - name: Checkout code + # uses: actions/checkout@v4 + # - name: Run tests + # run: | + # unset KFUTIL_DEBUG + # go test -v ./cmd -run "^Test_StoreTypes*" + # + # + # ### Store Tests + # Test_Stores_KFC_11_1_2: + # runs-on: kfutil-runner-set + # needs: + # - build + # - kf_11_x_x + # - Test_StoreTypes_KFC_11_1_2 + # env: + # SECRET_NAME: "command-config-1112" + # KEYFACTOR_HOSTNAME: "integrations1112-lab.kfdelivery.com" + # KEYFACTOR_DOMAIN: "command" + # KEYFACTOR_USERNAME: ${{ secrets.LAB_USERNAME }} + # KEYFACTOR_PASSWORD: ${{ secrets.LAB_PASSWORD }} + # GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} + # steps: + # - name: Checkout code + # uses: actions/checkout@v4 + # - name: Set up private repo access for go get + # run: | + # git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + # - name: Run tests + # run: go test -v ./cmd -run "^Test_Stores_*" + # + # ### PAM Tests + # Test_PAM_KFC_11_1_2: + # runs-on: kfutil-runner-set + # needs: + # - build + # - kf_11_x_x + # - Test_StoreTypes_KFC_11_1_2 + # env: + # SECRET_NAME: "command-config-1112" + # KEYFACTOR_HOSTNAME: "integrations1112-lab.kfdelivery.com" + # KEYFACTOR_DOMAIN: "command" + # KEYFACTOR_USERNAME: ${{ secrets.LAB_USERNAME }} + # KEYFACTOR_PASSWORD: ${{ secrets.LAB_PASSWORD }} + # GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} + # steps: + # - name: Checkout code + # uses: actions/checkout@v4 + # - name: Set up private repo access for go get + # run: | + # git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + # - name: Run tests + # run: | + # unset KFUTIL_DEBUG + # go test -v ./cmd -run "^Test_PAM*" + # + # + # ### PAM Tests AKV Auth Provider + # Test_AKV_PAM_KFC_11_1_2: + # runs-on: self-hosted + # needs: + # - Test_PAM_KFC_11_1_2 + # env: + # SECRET_NAME: "command-config-1112-az" + # steps: + # - name: Checkout code + # uses: actions/checkout@v4 + # - name: Set up Go + # uses: actions/setup-go@v5 + # with: + # go-version: "1.21" + # - name: Set up private repo access for go get + # run: | + # git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + # - name: Install dependencies + # run: go mod download && go mod tidy + # - name: Get secret from Azure Key Vault + # run: | + # . ./examples/auth/akv/akv_auth.sh + # cat $HOME/.keyfactor/command_config.json + # - name: Install kfutil + # run: | + # make install + # - name: Run tests + # run: | + # go test -v ./cmd -run "^Test_PAM*" + + ## KFC 12.x.x + kf_12_x_x: + runs-on: kfutil-runner-set + needs: + - build + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Run tests + run: echo "Running tests for KF 12.x.x" + + ### Store Type Tests + Test_StoreTypes_KFC_12_3_0: + runs-on: kfutil-runner-set + needs: + - build + - kf_12_x_x + environment: "KFC_12_3_0_CLEAN" + env: + GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} + KEYFACTOR_PASSWORD: ${{ secrets.KEYFACTOR_PASSWORD }} + KEYFACTOR_USERNAME: ${{ secrets.KEYFACTOR_USERNAME }} + KEYFACTOR_AUTH_CONFIG_B64: ${{ secrets.KEYFACTOR_AUTH_CONFIG_B64 }} + KEYFACTOR_HOSTNAME: ${{ vars.KEYFACTOR_HOSTNAME }} + KEYFACTOR_SKIP_VERIFY: ${{ vars.KEYFACTOR_SKIP_VERIFY }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Set up private repo access for go get + run: | + git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + - name: Run tests + run: | + unset KFUTIL_DEBUG + go test -v ./cmd -run "^Test_StoreTypes*" + + Test_StoreTypes_KFC_12_3_0_OAUTH: + runs-on: kfutil-runner-set + needs: + - build + - kf_12_x_x + environment: "KFC_12_3_0_OAUTH_CLEAN" + env: + GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} + KEYFACTOR_AUTH_CONFIG_B64: ${{ secrets.KEYFACTOR_AUTH_CONFIG_B64 }} + KEYFACTOR_AUTH_CLIENT_ID: ${{ secrets.KEYFACTOR_AUTH_CLIENT_ID }} + KEYFACTOR_AUTH_CLIENT_SECRET: ${{ secrets.KEYFACTOR_AUTH_CLIENT_SECRET }} + KEYFACTOR_AUTH_TOKEN_URL: ${{ vars.KEYFACTOR_AUTH_TOKEN_URL }} + KEYFACTOR_HOSTNAME: ${{ vars.KEYFACTOR_HOSTNAME }} + KEYFACTOR_AUTH_HOSTNAME: ${{ vars.KEYFACTOR_AUTH_HOSTNAME }} + KEYFACTOR_SKIP_VERIFY: ${{ vars.KEYFACTOR_SKIP_VERIFY }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Set up private repo access for go get + run: | + git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + - name: Run tests + run: | + unset KFUTIL_DEBUG + go test -v ./cmd -run "^Test_StoreTypes*" + + ### Store Tests + Test_Stores_KFC_12_3_0: + runs-on: kfutil-runner-set + needs: + - build + - kf_12_x_x + - Test_StoreTypes_KFC_12_3_0 + environment: "KFC_12_3_0" + env: + GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} + KEYFACTOR_PASSWORD: ${{ secrets.KEYFACTOR_PASSWORD }} + KEYFACTOR_USERNAME: ${{ secrets.KEYFACTOR_USERNAME }} + KEYFACTOR_AUTH_CONFIG_B64: ${{ secrets.KEYFACTOR_AUTH_CONFIG_B64 }} + KEYFACTOR_HOSTNAME: ${{ vars.KEYFACTOR_HOSTNAME }} + KEYFACTOR_SKIP_VERIFY: ${{ vars.KEYFACTOR_SKIP_VERIFY }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Set up private repo access for go get + run: | + git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + - name: Run tests + run: go test -v ./cmd -run "^Test_Stores_*" + Test_Stores_KFC_12_3_0_OAUTH: + runs-on: kfutil-runner-set + needs: + - build + - kf_12_x_x + - Test_StoreTypes_KFC_12_3_0_OAUTH + environment: "KFC_12_3_0_OAUTH" + env: + GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} + KEYFACTOR_AUTH_CONFIG_B64: ${{ secrets.KEYFACTOR_AUTH_CONFIG_B64 }} + KEYFACTOR_AUTH_CLIENT_ID: ${{ secrets.KEYFACTOR_AUTH_CLIENT_ID }} + KEYFACTOR_AUTH_CLIENT_SECRET: ${{ secrets.KEYFACTOR_AUTH_CLIENT_SECRET }} + KEYFACTOR_AUTH_TOKEN_URL: ${{ vars.KEYFACTOR_AUTH_TOKEN_URL }} + KEYFACTOR_HOSTNAME: ${{ vars.KEYFACTOR_HOSTNAME }} + KEYFACTOR_AUTH_HOSTNAME: ${{ vars.KEYFACTOR_AUTH_HOSTNAME }} + KEYFACTOR_SKIP_VERIFY: ${{ vars.KEYFACTOR_SKIP_VERIFY }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Set up private repo access for go get + run: | + git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + - name: Run tests + run: go test -v ./cmd -run "^Test_Stores_*" + + ### PAM Tests + Test_PAM_KFC_12_3_0: + runs-on: kfutil-runner-set + needs: + - build + - kf_12_x_x + - Test_StoreTypes_KFC_12_3_0 + environment: "KFC_12_3_0" + env: + GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} + KEYFACTOR_PASSWORD: ${{ secrets.KEYFACTOR_PASSWORD }} + KEYFACTOR_USERNAME: ${{ secrets.KEYFACTOR_USERNAME }} + KEYFACTOR_AUTH_CONFIG_B64: ${{ secrets.KEYFACTOR_AUTH_CONFIG_B64 }} + KEYFACTOR_HOSTNAME: ${{ vars.KEYFACTOR_HOSTNAME }} + KEYFACTOR_SKIP_VERIFY: ${{ vars.KEYFACTOR_SKIP_VERIFY }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Set up private repo access for go get + run: | + git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + - name: Run tests + run: | + unset KFUTIL_DEBUG + go test -v ./cmd -run "^Test_PAM*" + + Test_PAM_KFC_12_3_0_OAUTH: + runs-on: self-hosted + needs: + - build + - kf_12_x_x + - Test_StoreTypes_KFC_12_3_0_OAUTH + environment: "KFC_12_3_0_OAUTH" + env: + GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} + KEYFACTOR_AUTH_CONFIG_B64: ${{ secrets.KEYFACTOR_AUTH_CONFIG_B64 }} + KEYFACTOR_AUTH_CLIENT_ID: ${{ secrets.KEYFACTOR_AUTH_CLIENT_ID }} + KEYFACTOR_AUTH_CLIENT_SECRET: ${{ secrets.KEYFACTOR_AUTH_CLIENT_SECRET }} + KEYFACTOR_AUTH_TOKEN_URL: ${{ vars.KEYFACTOR_AUTH_TOKEN_URL }} + KEYFACTOR_HOSTNAME: ${{ vars.KEYFACTOR_HOSTNAME }} + KEYFACTOR_AUTH_HOSTNAME: ${{ vars.KEYFACTOR_AUTH_HOSTNAME }} + KEYFACTOR_SKIP_VERIFY: ${{ vars.KEYFACTOR_SKIP_VERIFY }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Set up private repo access for go get + run: | + git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + - name: Run tests + run: | + unset KFUTIL_DEBUG + go test -v ./cmd -run "^Test_PAM*" - test: - runs-on: ubuntu-latest - needs: build - strategy: - matrix: - version: [ 10_5_0, 11_1_2, 12_2_0 ] - test_type: [ StoreTypes, Stores, PAM, AKV_PAM ] - include: - - version: 10_5_0 - test_type: StoreTypes - SECRET_NAME: "command-config-1050-clean" - KEYFACTOR_HOSTNAME: "int1050-test-clean.kfdelivery.com" - KEYFACTOR_DOMAIN: "command" - - version: 10_5_0 - test_type: Stores - SECRET_NAME: "command-config-1050" - KEYFACTOR_HOSTNAME: "integrations1050-lab.kfdelivery.com" - KEYFACTOR_DOMAIN: "command" - - version: 10_5_0 - test_type: PAM - SECRET_NAME: "command-config-1050" - KEYFACTOR_HOSTNAME: "integrations1050-lab.kfdelivery.com" - KEYFACTOR_DOMAIN: "command" - - version: 10_5_0 - test_type: AKV_PAM - SECRET_NAME: "command-config-1050-az" - - version: 11_1_2 - test_type: StoreTypes - SECRET_NAME: "command-config-1112-clean" - KEYFACTOR_HOSTNAME: "int1112-test-clean.kfdelivery.com" - KEYFACTOR_DOMAIN: "command" - - version: 11_1_2 - test_type: Stores - SECRET_NAME: "command-config-1112" - KEYFACTOR_HOSTNAME: "integrations1112-lab.kfdelivery.com" - KEYFACTOR_DOMAIN: "command" - - version: 11_1_2 - test_type: PAM - SECRET_NAME: "command-config-1112" - KEYFACTOR_HOSTNAME: "integrations1112-lab.kfdelivery.com" - KEYFACTOR_DOMAIN: "command" - - version: 11_1_2 - test_type: AKV_PAM - SECRET_NAME: "command-config-1112-az" - - version: 12_2_0 - test_type: StoreTypes - SECRET_NAME: "command-config-1220-clean" - KEYFACTOR_HOSTNAME: "int1220-test-clean.kfdelivery.com" - KEYFACTOR_DOMAIN: "command" - - version: 12_2_0 - test_type: Stores - SECRET_NAME: "command-config-1220" - KEYFACTOR_HOSTNAME: "integrations1220-lab.kfdelivery.com" - KEYFACTOR_DOMAIN: "command" - - version: 12_2_0 - test_type: PAM - SECRET_NAME: "command-config-1220" - KEYFACTOR_HOSTNAME: "integrations1220-lab.kfdelivery.com" - KEYFACTOR_DOMAIN: "command" - - version: 12_2_0 - test_type: AKV_PAM - SECRET_NAME: "command-config-1220-az" + + ### PAM Tests AKV Auth Provider + Test_AKV_PAM_KFC_12_3_0: + runs-on: self-hosted + needs: + - Test_PAM_KFC_12_3_0 + environment: "KFC_12_3_0" env: - GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN }} - KEYFACTOR_USERNAME: ${{ secrets.LAB_USERNAME }} - KEYFACTOR_PASSWORD: ${{ secrets.LAB_PASSWORD }} + SECRET_NAME: "command-config-1230-az" steps: - name: Checkout code uses: actions/checkout@v4 + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: "1.23" + - name: Set up private repo access for go get + run: | + git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + - name: Install dependencies + run: go mod download && go mod tidy + - name: Get secret from Azure Key Vault + run: | + . ./examples/auth/akv/akv_auth.sh + cat $HOME/.keyfactor/command_config.json + - name: Install kfutil + run: | + make install + - name: Run tests + run: | + go test -v ./cmd -run "^Test_PAM*" + + Test_AKV_PAM_KFC_12_3_0_OAUTH: + runs-on: self-hosted + needs: + - Test_PAM_KFC_12_3_0 + environment: "KFC_12_3_0_OAUTH" + env: + SECRET_NAME: "command-config-1230-oauth-az" + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: "1.23" - name: Set up private repo access for go get run: | git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + - name: Install dependencies + run: go mod download && go mod tidy + - name: Get secret from Azure Key Vault + run: | + . ./examples/auth/akv/akv_auth.sh + cat $HOME/.keyfactor/command_config.json + - name: Install kfutil + run: | + make install - name: Run tests run: | - if [ "${{ matrix.test_type }}" == "StoreTypes" ]; then - export KFUTIL_DEBUG=1 - go test -v ./cmd -run "^Test_StoreTypes*" - elif [ "${{ matrix.test_type }}" == "Stores" ]; then - go test -v ./cmd -run "^Test_Stores_*" - elif [ "${{ matrix.test_type }}" == "PAM" ]; then - unset KFUTIL_DEBUG - go test -v ./cmd -run "^Test_PAM*" - elif [ "${{ matrix.test_type }}" == "AKV_PAM" ]; then - . ./examples/auth/akv/akv_auth.sh - cat $HOME/.keyfactor/command_config.json - make install - go test -v ./cmd -run "^Test_PAM*" - fi \ No newline at end of file + go test -v ./cmd -run "^Test_PAM*" + + # Tester Install Script + Test_Install_Script: + runs-on: kfutil-runner-set + steps: + - name: Test Quick Install Script + run: | + sudo apt update && sudo apt upgrade -y && sudo apt install -y curl wget unzip jq openssl && sudo apt clean + echo curl -s "https://raw.githubusercontent.com/Keyfactor/kfutil/${GITHUB_REF_NAME}/install.sh" + GITHUB_REF_NAME_ENCODED=$(echo -n "${GITHUB_REF_NAME}" | jq -sRr @uri) + VERIFY_CHECKSUM=0 + bash <(curl -s "https://raw.githubusercontent.com/Keyfactor/kfutil/${GITHUB_REF_NAME_ENCODED}/install.sh") + which kfutil + kfutil version + rm $(which kfutil) + + # Package Tests + Test_Kfutil_pkg: + runs-on: kfutil-runner-set + needs: + - build + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + # Checkout code + # https://github.com/actions/checkout + - name: Checkout code + uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + + # Setup GoLang build environment + # https://github.com/actions/setup-go + - name: Set up Go 1.x + uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 + with: + go-version-file: 'go.mod' + cache: true + + # Install dependencies + - name: Install dependencies + run: go mod download + + # Run the tests with coverage found in the pkg directory + - name: Run tests + run: go test -v -cover ./pkg/... diff --git a/cmd/helpers.go b/cmd/helpers.go index 74c79d0..743eba8 100644 --- a/cmd/helpers.go +++ b/cmd/helpers.go @@ -30,6 +30,8 @@ import ( "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/spf13/cobra" + + stdlog "log" ) func boolToPointer(b bool) *bool { @@ -188,6 +190,7 @@ func informDebug(debugFlag bool) { } func initLogger() { + stdlog.SetOutput(io.Discard) zerolog.TimeFieldFormat = zerolog.TimeFormatUnix zerolog.SetGlobalLevel(zerolog.Disabled) // default to disabled log.Logger = log.With().Caller().Logger() diff --git a/cmd/root.go b/cmd/root.go index ee86549..96b1a19 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -157,13 +157,14 @@ func getServerConfigFromEnv() (*auth_providers.Server, error) { Str("apiPath", apiPath). Bool("skipVerify", skipVerifyBool). Msg("call: basicAuthNoParamsConfig.Authenticate()") + basicAuthNoParamsConfig.WithCommandHostName(hostname). + WithCommandAPIPath(apiPath). + WithSkipVerify(skipVerifyBool) + bErr := basicAuthNoParamsConfig. WithUsername(username). WithPassword(password). WithDomain(domain). - WithCommandHostName(hostname). - WithCommandAPIPath(apiPath). - WithSkipVerify(skipVerifyBool). Authenticate() log.Debug().Msg("complete: basicAuthNoParamsConfig.Authenticate()") if bErr != nil { diff --git a/cmd/storeTypes.go b/cmd/storeTypes.go index 765d8ed..c7af55a 100644 --- a/cmd/storeTypes.go +++ b/cmd/storeTypes.go @@ -25,6 +25,8 @@ import ( "strings" "time" + stdlog "log" + "github.com/AlecAivazis/survey/v2" "github.com/Keyfactor/keyfactor-go-client/v3/api" "github.com/rs/zerolog/log" @@ -52,12 +54,14 @@ var storesTypesListCmd = &cobra.Command{ if debugErr != nil { return debugErr } + stdlog.SetOutput(io.Discard) informDebug(debugFlag) // Authenticate kfClient, _ := initClient(false) // CLI Logic + storeTypes, err := kfClient.ListCertificateStoreTypes() if err != nil { diff --git a/go.mod b/go.mod index 9b3dc71..66d1c99 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/Jeffail/gabs v1.4.0 github.com/Keyfactor/keyfactor-auth-client-go v1.0.0-rc.2 github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.0 - github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.7 + github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.11 github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 github.com/creack/pty v1.1.23 github.com/google/go-cmp v0.6.0 diff --git a/go.sum b/go.sum index a93e680..8565933 100644 --- a/go.sum +++ b/go.sum @@ -14,8 +14,8 @@ github.com/Keyfactor/keyfactor-auth-client-go v1.0.0-rc.2 h1:/61pAEjAhTAGtFCvAcp github.com/Keyfactor/keyfactor-auth-client-go v1.0.0-rc.2/go.mod h1:UTPLARTONwfc+j1y2SjEa54gbFFCObQucHf3ubQVyDk= github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.0 h1:wpiq9UhNxomecw6lhI/EaSWO63HKcuONKq58vsgKmXY= github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.0/go.mod h1:+hmc9YAh4cqlkFe9rHXpQBPssHuoCq/FRYmez5Vrlrg= -github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.7 h1:5IMqu0MtdNe6HMTN7LlseeL1WcOvTJ/E57g808p/hsE= -github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.7/go.mod h1:HWb+S60YAALFVSfB8QuQ8ugjsjr+FHLQET0/4K7EVWw= +github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.11 h1:nYc7fEidu26ZKGwEByQNr2EWPCsCs0zxnHUKnRT6/rY= +github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.11/go.mod h1:HWb+S60YAALFVSfB8QuQ8ugjsjr+FHLQET0/4K7EVWw= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= From 0709f702de9bf6dde8d8d16e8f02576e424fd313 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Fri, 1 Nov 2024 12:19:52 -0700 Subject: [PATCH 13/19] fix(ci): Add go setup Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- .github/config/README.md | 1 - .github/workflows/tests.yml | 186 ++++++++++++++++++++++++++++++------ 2 files changed, 158 insertions(+), 29 deletions(-) diff --git a/.github/config/README.md b/.github/config/README.md index d2e66e2..f231d24 100644 --- a/.github/config/README.md +++ b/.github/config/README.md @@ -47,7 +47,6 @@ module "keyfactor_github_test_environment_12_3_0_kc" { ``` - ## Requirements | Name | Version | diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e9310ef..ff9e7eb 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -56,11 +56,21 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} steps: - - name: Checkout code + - name: Check out code uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: 1.23 + + - name: Get Public IP + run: curl -s https://api.ipify.org + - name: Set up private repo access for go get run: | git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + - name: Run tests run: | export KFUTIL_DEBUG=1 @@ -77,11 +87,21 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} steps: - - name: Checkout code + - name: Check out code uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: 1.23 + + - name: Get Public IP + run: curl -s https://api.ipify.org + - name: Set up private repo access for go get run: | git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + - name: Run tests run: go test -v ./cmd -run "^Test_Stores_*" @@ -102,11 +122,21 @@ jobs: KEYFACTOR_AUTH_HOSTNAME: ${{ vars.KEYFACTOR_AUTH_HOSTNAME }} KEYFACTOR_SKIP_VERIFY: ${{ vars.KEYFACTOR_SKIP_VERIFY }} steps: - - name: Checkout code + - name: Check out code uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: 1.23 + + - name: Get Public IP + run: curl -s https://api.ipify.org + - name: Set up private repo access for go get run: | git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + - name: Run tests run: | unset KFUTIL_DEBUG @@ -121,24 +151,33 @@ jobs: env: SECRET_NAME: "command-config-1050-az" steps: - - name: Checkout code + - name: Check out code uses: actions/checkout@v4 + - name: Set up Go uses: actions/setup-go@v5 with: - go-version: "1.23" + go-version: 1.23 + + - name: Get Public IP + run: curl -s https://api.ipify.org + - name: Set up private repo access for go get run: | git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + - name: Install dependencies run: go mod download && go mod tidy + - name: Get secret from Azure Key Vault run: | . ./examples/auth/akv/akv_auth.sh cat $HOME/.keyfactor/command_config.json + - name: Install kfutil run: | make install + - name: Run tests run: | go test -v ./cmd -run "^Test_PAM*" @@ -262,8 +301,21 @@ jobs: needs: - build steps: - - name: Checkout code + - name: Check out code uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: 1.23 + + - name: Get Public IP + run: curl -s https://api.ipify.org + + - name: Set up private repo access for go get + run: | + git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + - name: Run tests run: echo "Running tests for KF 12.x.x" @@ -282,11 +334,21 @@ jobs: KEYFACTOR_HOSTNAME: ${{ vars.KEYFACTOR_HOSTNAME }} KEYFACTOR_SKIP_VERIFY: ${{ vars.KEYFACTOR_SKIP_VERIFY }} steps: - - name: Checkout code + - name: Check out code uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: 1.23 + + - name: Get Public IP + run: curl -s https://api.ipify.org + - name: Set up private repo access for go get run: | git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + - name: Run tests run: | unset KFUTIL_DEBUG @@ -308,11 +370,21 @@ jobs: KEYFACTOR_AUTH_HOSTNAME: ${{ vars.KEYFACTOR_AUTH_HOSTNAME }} KEYFACTOR_SKIP_VERIFY: ${{ vars.KEYFACTOR_SKIP_VERIFY }} steps: - - name: Checkout code + - name: Check out code uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: 1.23 + + - name: Get Public IP + run: curl -s https://api.ipify.org + - name: Set up private repo access for go get run: | git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + - name: Run tests run: | unset KFUTIL_DEBUG @@ -334,11 +406,21 @@ jobs: KEYFACTOR_HOSTNAME: ${{ vars.KEYFACTOR_HOSTNAME }} KEYFACTOR_SKIP_VERIFY: ${{ vars.KEYFACTOR_SKIP_VERIFY }} steps: - - name: Checkout code + - name: Check out code uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: 1.23 + + - name: Get Public IP + run: curl -s https://api.ipify.org + - name: Set up private repo access for go get run: | git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + - name: Run tests run: go test -v ./cmd -run "^Test_Stores_*" Test_Stores_KFC_12_3_0_OAUTH: @@ -358,11 +440,21 @@ jobs: KEYFACTOR_AUTH_HOSTNAME: ${{ vars.KEYFACTOR_AUTH_HOSTNAME }} KEYFACTOR_SKIP_VERIFY: ${{ vars.KEYFACTOR_SKIP_VERIFY }} steps: - - name: Checkout code + - name: Check out code uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: 1.23 + + - name: Get Public IP + run: curl -s https://api.ipify.org + - name: Set up private repo access for go get run: | git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + - name: Run tests run: go test -v ./cmd -run "^Test_Stores_*" @@ -382,11 +474,21 @@ jobs: KEYFACTOR_HOSTNAME: ${{ vars.KEYFACTOR_HOSTNAME }} KEYFACTOR_SKIP_VERIFY: ${{ vars.KEYFACTOR_SKIP_VERIFY }} steps: - - name: Checkout code + - name: Check out code uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: 1.23 + + - name: Get Public IP + run: curl -s https://api.ipify.org + - name: Set up private repo access for go get run: | git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + - name: Run tests run: | unset KFUTIL_DEBUG @@ -409,11 +511,21 @@ jobs: KEYFACTOR_AUTH_HOSTNAME: ${{ vars.KEYFACTOR_AUTH_HOSTNAME }} KEYFACTOR_SKIP_VERIFY: ${{ vars.KEYFACTOR_SKIP_VERIFY }} steps: - - name: Checkout code + - name: Check out code uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: 1.23 + + - name: Get Public IP + run: curl -s https://api.ipify.org + - name: Set up private repo access for go get run: | git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + - name: Run tests run: | unset KFUTIL_DEBUG @@ -429,21 +541,29 @@ jobs: env: SECRET_NAME: "command-config-1230-az" steps: - - name: Checkout code + - name: Check out code uses: actions/checkout@v4 + - name: Set up Go uses: actions/setup-go@v5 with: - go-version: "1.23" + go-version: 1.23 + + - name: Get Public IP + run: curl -s https://api.ipify.org + - name: Set up private repo access for go get run: | git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + - name: Install dependencies run: go mod download && go mod tidy + - name: Get secret from Azure Key Vault run: | . ./examples/auth/akv/akv_auth.sh cat $HOME/.keyfactor/command_config.json + - name: Install kfutil run: | make install @@ -459,24 +579,33 @@ jobs: env: SECRET_NAME: "command-config-1230-oauth-az" steps: - - name: Checkout code + - name: Check out code uses: actions/checkout@v4 + - name: Set up Go uses: actions/setup-go@v5 with: - go-version: "1.23" + go-version: 1.23 + + - name: Get Public IP + run: curl -s https://api.ipify.org + - name: Set up private repo access for go get run: | git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + - name: Install dependencies run: go mod download && go mod tidy + - name: Get secret from Azure Key Vault run: | . ./examples/auth/akv/akv_auth.sh cat $HOME/.keyfactor/command_config.json + - name: Install kfutil run: | make install + - name: Run tests run: | go test -v ./cmd -run "^Test_PAM*" @@ -504,22 +633,23 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - # Checkout code - # https://github.com/actions/checkout - - name: Checkout code - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - name: Check out code + uses: actions/checkout@v4 - # Setup GoLang build environment - # https://github.com/actions/setup-go - - name: Set up Go 1.x - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 + - name: Set up Go + uses: actions/setup-go@v5 with: - go-version-file: 'go.mod' - cache: true + go-version: 1.23 + + - name: Get Public IP + run: curl -s https://api.ipify.org + + - name: Set up private repo access for go get + run: | + git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" - # Install dependencies - name: Install dependencies - run: go mod download + run: go mod download && go mod tidy # Run the tests with coverage found in the pkg directory - name: Run tests From f1c3d5506506c89f196a839fe5f3f8eb369f10bf Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Fri, 1 Nov 2024 12:32:57 -0700 Subject: [PATCH 14/19] fix(ci): Update 1050 env vars Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- .github/config/MODULE.MD | 2 +- .github/config/README.md | 2 +- .github/config/variables.tf | 2 +- .github/workflows/tests.yml | 13 +++++++++++++ 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.github/config/MODULE.MD b/.github/config/MODULE.MD index 4f93801..4e1d569 100644 --- a/.github/config/MODULE.MD +++ b/.github/config/MODULE.MD @@ -48,7 +48,7 @@ | [keyfactor\_hostname\_12\_3\_0](#input\_keyfactor\_hostname\_12\_3\_0) | The hostname of the Keyfactor v12.3.x instance | `string` | `"integrations1230-lab.kfdelivery.com"` | no | | [keyfactor\_hostname\_12\_3\_0\_CLEAN](#input\_keyfactor\_hostname\_12\_3\_0\_CLEAN) | The hostname of the Keyfactor v12.3.x instance with no stores or orchestrators. This is used for store-type tests. | `string` | `"int1230-test-clean.kfdelivery.com"` | no | | [keyfactor\_hostname\_12\_3\_0\_OAUTH](#input\_keyfactor\_hostname\_12\_3\_0\_OAUTH) | The hostname of the Keyfactor instance | `string` | `"int-oidc-lab.eastus2.cloudapp.azure.com"` | no | -| [keyfactor\_hostname\_12\_3\_0\_OAUTH\_CLEAN](#input\_keyfactor\_hostname\_12\_3\_0\_OAUTH\_CLEAN) | The hostname of the Keyfactor instance | `string` | `"int1230-oauth-test-clean.eastus2.cloudapp.azure.com"` | no | +| [keyfactor\_hostname\_12\_3\_0\_OAUTH\_CLEAN](#input\_keyfactor\_hostname\_12\_3\_0\_OAUTH\_CLEAN) | The hostname of the Keyfactor instance | `string` | `"int-oidc-lab.eastus2.cloudapp.azure.com"` | no | | [keyfactor\_password\_AD](#input\_keyfactor\_password\_AD) | The password to authenticate with Keyfactor instance that uses AD authentication | `string` | n/a | yes | | [keyfactor\_username\_AD](#input\_keyfactor\_username\_AD) | The username to authenticate with a Keyfactor instance that uses AD authentication | `string` | n/a | yes | diff --git a/.github/config/README.md b/.github/config/README.md index f231d24..3a92963 100644 --- a/.github/config/README.md +++ b/.github/config/README.md @@ -97,7 +97,7 @@ module "keyfactor_github_test_environment_12_3_0_kc" { | [keyfactor\_hostname\_12\_3\_0](#input\_keyfactor\_hostname\_12\_3\_0) | The hostname of the Keyfactor v12.3.x instance | `string` | `"integrations1230-lab.kfdelivery.com"` | no | | [keyfactor\_hostname\_12\_3\_0\_CLEAN](#input\_keyfactor\_hostname\_12\_3\_0\_CLEAN) | The hostname of the Keyfactor v12.3.x instance with no stores or orchestrators. This is used for store-type tests. | `string` | `"int1230-test-clean.kfdelivery.com"` | no | | [keyfactor\_hostname\_12\_3\_0\_OAUTH](#input\_keyfactor\_hostname\_12\_3\_0\_OAUTH) | The hostname of the Keyfactor instance | `string` | `"int-oidc-lab.eastus2.cloudapp.azure.com"` | no | -| [keyfactor\_hostname\_12\_3\_0\_OAUTH\_CLEAN](#input\_keyfactor\_hostname\_12\_3\_0\_OAUTH\_CLEAN) | The hostname of the Keyfactor instance | `string` | `"int1230-oauth-test-clean.eastus2.cloudapp.azure.com"` | no | +| [keyfactor\_hostname\_12\_3\_0\_OAUTH\_CLEAN](#input\_keyfactor\_hostname\_12\_3\_0\_OAUTH\_CLEAN) | The hostname of the Keyfactor instance | `string` | `"int-oidc-lab.eastus2.cloudapp.azure.com"` | no | | [keyfactor\_password\_AD](#input\_keyfactor\_password\_AD) | The password to authenticate with Keyfactor instance that uses AD authentication | `string` | n/a | yes | | [keyfactor\_username\_AD](#input\_keyfactor\_username\_AD) | The username to authenticate with a Keyfactor instance that uses AD authentication | `string` | n/a | yes | diff --git a/.github/config/variables.tf b/.github/config/variables.tf index d6df78f..38e66c1 100644 --- a/.github/config/variables.tf +++ b/.github/config/variables.tf @@ -58,7 +58,7 @@ variable "keyfactor_hostname_12_3_0_OAUTH" { variable "keyfactor_hostname_12_3_0_OAUTH_CLEAN" { description = "The hostname of the Keyfactor instance" type = string - default = "int1230-oauth-test-clean.eastus2.cloudapp.azure.com" + default = "int-oidc-lab.eastus2.cloudapp.azure.com" } // Authentication diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ff9e7eb..0983db1 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -55,6 +55,13 @@ jobs: environment: "KFC_10_5_0_CLEAN" env: GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} + KEYFACTOR_PASSWORD: ${{ secrets.KEYFACTOR_PASSWORD }} + KEYFACTOR_USERNAME: ${{ secrets.KEYFACTOR_USERNAME }} + KEYFACTOR_AUTH_CONFIG_B64: ${{ secrets.KEYFACTOR_AUTH_CONFIG_B64 }} + KEYFACTOR_HOSTNAME: ${{ vars.KEYFACTOR_HOSTNAME }} + KEYFACTOR_AUTH_HOSTNAME: ${{ vars.KEYFACTOR_AUTH_HOSTNAME }} + KEYFACTOR_SKIP_VERIFY: ${{ vars.KEYFACTOR_SKIP_VERIFY }} + steps: - name: Check out code uses: actions/checkout@v4 @@ -86,6 +93,12 @@ jobs: environment: "KFC_10_5_0" env: GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} + KEYFACTOR_PASSWORD: ${{ secrets.KEYFACTOR_PASSWORD }} + KEYFACTOR_USERNAME: ${{ secrets.KEYFACTOR_USERNAME }} + KEYFACTOR_AUTH_CONFIG_B64: ${{ secrets.KEYFACTOR_AUTH_CONFIG_B64 }} + KEYFACTOR_HOSTNAME: ${{ vars.KEYFACTOR_HOSTNAME }} + KEYFACTOR_AUTH_HOSTNAME: ${{ vars.KEYFACTOR_AUTH_HOSTNAME }} + KEYFACTOR_SKIP_VERIFY: ${{ vars.KEYFACTOR_SKIP_VERIFY }} steps: - name: Check out code uses: actions/checkout@v4 From 12cffde2be8a2ba94bdd5da8fc4afee98894e6ae Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Fri, 1 Nov 2024 12:38:28 -0700 Subject: [PATCH 15/19] fix(ci): Correct env config for 1050_CLEAN Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- .github/config/environments.tf | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/config/environments.tf b/.github/config/environments.tf index d645abe..6e6471f 100644 --- a/.github/config/environments.tf +++ b/.github/config/environments.tf @@ -14,7 +14,7 @@ module "keyfactor_github_test_environment_10_5_0_CLEAN" { gh_environment_name = "KFC_10_5_0_CLEAN" gh_repo_name = data.github_repository.repo.name - keyfactor_hostname = var.keyfactor_hostname_10_5_0 + keyfactor_hostname = var.keyfactor_hostname_10_5_0_CLEAN keyfactor_username = var.keyfactor_username_AD keyfactor_password = var.keyfactor_password_AD keyfactor_config_file = base64encode(file("${path.module}/command_config.json")) @@ -36,7 +36,7 @@ module "keyfactor_github_test_environment_11_5_0_CLEAN" { gh_environment_name = "KFC_11_5_0_CLEAN" gh_repo_name = data.github_repository.repo.name - keyfactor_hostname = var.keyfactor_hostname_11_5_0 + keyfactor_hostname = var.keyfactor_hostname_11_5_0_CLEAN keyfactor_username = var.keyfactor_username_AD keyfactor_password = var.keyfactor_password_AD keyfactor_config_file = base64encode(file("${path.module}/command_config.json")) @@ -68,22 +68,22 @@ module "keyfactor_github_test_environment_11_5_0_OAUTH_CLEAN" { keyfactor_config_file = base64encode(file("${path.module}/command_config.json")) } -module "keyfactor_github_test_environment_12_3_0_AD_CLEAN" { +module "keyfactor_github_test_environment_12_3_0_AD" { source = "git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git?ref=main" - gh_environment_name = "KFC_12_3_0_AD_CLEAN" + gh_environment_name = "KFC_12_3_0_AD" gh_repo_name = data.github_repository.repo.name - keyfactor_hostname = var.keyfactor_hostname_12_3_0_CLEAN + keyfactor_hostname = var.keyfactor_hostname_12_3_0 keyfactor_username = var.keyfactor_username_AD keyfactor_password = var.keyfactor_password_AD keyfactor_tls_skip_verify = true keyfactor_config_file = base64encode(file("${path.module}/command_config.json")) } -module "keyfactor_github_test_environment_12_3_0_AD" { +module "keyfactor_github_test_environment_12_3_0_AD_CLEAN" { source = "git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git?ref=main" - gh_environment_name = "KFC_12_3_0_AD" + gh_environment_name = "KFC_12_3_0_AD_CLEAN" gh_repo_name = data.github_repository.repo.name - keyfactor_hostname = var.keyfactor_hostname_12_3_0 + keyfactor_hostname = var.keyfactor_hostname_12_3_0_CLEAN keyfactor_username = var.keyfactor_username_AD keyfactor_password = var.keyfactor_password_AD keyfactor_tls_skip_verify = true From 1e31f7ddd1ee85029eeaa8f5fb9d27f44547e7a5 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Mon, 4 Nov 2024 11:19:18 -0800 Subject: [PATCH 16/19] fix(ci): Remove non-working 1230 environment tests. Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- .github/config/environments.tf | 22 +-- .github/config/int1230c_ad.tf | 16 ++ .github/config/int1230c_oauth.tf | 33 ++++ .github/config/variables.tf | 5 - .github/workflows/tests.yml | 274 +++++++++++++++---------------- integration-manifest.json | 3 +- 6 files changed, 189 insertions(+), 164 deletions(-) create mode 100644 .github/config/int1230c_ad.tf create mode 100644 .github/config/int1230c_oauth.tf diff --git a/.github/config/environments.tf b/.github/config/environments.tf index 6e6471f..52b5bf3 100644 --- a/.github/config/environments.tf +++ b/.github/config/environments.tf @@ -79,16 +79,6 @@ module "keyfactor_github_test_environment_12_3_0_AD" { keyfactor_config_file = base64encode(file("${path.module}/command_config.json")) } -module "keyfactor_github_test_environment_12_3_0_AD_CLEAN" { - source = "git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git?ref=main" - gh_environment_name = "KFC_12_3_0_AD_CLEAN" - gh_repo_name = data.github_repository.repo.name - keyfactor_hostname = var.keyfactor_hostname_12_3_0_CLEAN - keyfactor_username = var.keyfactor_username_AD - keyfactor_password = var.keyfactor_password_AD - keyfactor_tls_skip_verify = true - keyfactor_config_file = base64encode(file("${path.module}/command_config.json")) -} module "keyfactor_github_test_environment_12_3_0_OAUTH" { source = "git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git?ref=main" @@ -103,14 +93,4 @@ module "keyfactor_github_test_environment_12_3_0_OAUTH" { keyfactor_config_file = base64encode(file("${path.module}/command_config.json")) } -module "keyfactor_github_test_environment_12_3_0_OAUTH_CLEAN" { - source = "git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git?ref=main" - gh_environment_name = "KFC_12_3_0_OAUTH_CLEAN" - gh_repo_name = data.github_repository.repo.name - keyfactor_hostname = var.keyfactor_hostname_12_3_0_OAUTH_CLEAN - keyfactor_auth_token_url = var.keyfactor_auth_token_url - keyfactor_client_id = var.keyfactor_client_id - keyfactor_client_secret = var.keyfactor_client_secret - keyfactor_tls_skip_verify = true - keyfactor_config_file = base64encode(file("${path.module}/command_config.json")) -} + diff --git a/.github/config/int1230c_ad.tf b/.github/config/int1230c_ad.tf new file mode 100644 index 0000000..63ca3d1 --- /dev/null +++ b/.github/config/int1230c_ad.tf @@ -0,0 +1,16 @@ +variable "kfc1230c_ad_hostname" { + description = "The hostname of the Keyfactor instance" + type = string + default = "int1230c-ad.eastus2.cloudapp.azure.com" +} + +module "keyfactor_github_test_environment_12_3_0_AD_CLEAN" { + source = "git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git?ref=main" + gh_environment_name = "KFC_12_3_0_AD_CLEAN" + gh_repo_name = data.github_repository.repo.name + keyfactor_hostname = var.kfc1230c_ad_hostname + keyfactor_username = var.keyfactor_username_AD + keyfactor_password = var.keyfactor_password_AD + keyfactor_tls_skip_verify = true + keyfactor_config_file = base64encode(file("${path.module}/command_config.json")) +} \ No newline at end of file diff --git a/.github/config/int1230c_oauth.tf b/.github/config/int1230c_oauth.tf new file mode 100644 index 0000000..b1a34d1 --- /dev/null +++ b/.github/config/int1230c_oauth.tf @@ -0,0 +1,33 @@ +variable "kfc1230c_oauth_hostname" { + description = "The hostname of the Keyfactor instance" + type = string + default = "int1230c-oauth.eastus2.cloudapp.azure.com" +} + +variable "kfc1230c_oauth_token_url" { + description = "The hostname of the Keyfactor instance" + type = string + default = "https://int1230c-oauth.eastus2.cloudapp.azure.com:8444/realms/Keyfactor/protocol/openid-connect/token" +} + + +variable "kfc1230c_client_id" { + description = "The client ID to authenticate with the Keyfactor instance using oauth2 client credentials" + type = string + +} +variable "kfc1230c_client_secret" { + description = "The client secret to authenticate with the Keyfactor instance using oauth2 client credentials" + type = string +} +module "keyfactor_github_test_environment_12_3_0_OAUTH_CLEAN" { + source = "git::ssh://git@github.com/Keyfactor/terraform-module-keyfactor-github-test-environment-ad.git?ref=main" + gh_environment_name = "KFC_12_3_0_OAUTH_CLEAN" + gh_repo_name = data.github_repository.repo.name + keyfactor_hostname = var.kfc1230c_oauth_hostname + keyfactor_auth_token_url = var.kfc1230c_oauth_token_url + keyfactor_client_id = var.kfc1230c_client_id + keyfactor_client_secret = var.kfc1230c_client_secret + keyfactor_tls_skip_verify = true + keyfactor_config_file = base64encode(file("${path.module}/int1230c_oauth_command_config.json")) +} \ No newline at end of file diff --git a/.github/config/variables.tf b/.github/config/variables.tf index 38e66c1..3d557a2 100644 --- a/.github/config/variables.tf +++ b/.github/config/variables.tf @@ -55,11 +55,6 @@ variable "keyfactor_hostname_12_3_0_OAUTH" { default = "int-oidc-lab.eastus2.cloudapp.azure.com" } -variable "keyfactor_hostname_12_3_0_OAUTH_CLEAN" { - description = "The hostname of the Keyfactor instance" - type = string - default = "int-oidc-lab.eastus2.cloudapp.azure.com" -} // Authentication variable "keyfactor_username_AD" { diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0983db1..100807c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -333,39 +333,39 @@ jobs: run: echo "Running tests for KF 12.x.x" ### Store Type Tests - Test_StoreTypes_KFC_12_3_0: - runs-on: kfutil-runner-set - needs: - - build - - kf_12_x_x - environment: "KFC_12_3_0_CLEAN" - env: - GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} - KEYFACTOR_PASSWORD: ${{ secrets.KEYFACTOR_PASSWORD }} - KEYFACTOR_USERNAME: ${{ secrets.KEYFACTOR_USERNAME }} - KEYFACTOR_AUTH_CONFIG_B64: ${{ secrets.KEYFACTOR_AUTH_CONFIG_B64 }} - KEYFACTOR_HOSTNAME: ${{ vars.KEYFACTOR_HOSTNAME }} - KEYFACTOR_SKIP_VERIFY: ${{ vars.KEYFACTOR_SKIP_VERIFY }} - steps: - - name: Check out code - uses: actions/checkout@v4 - - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version: 1.23 - - - name: Get Public IP - run: curl -s https://api.ipify.org - - - name: Set up private repo access for go get - run: | - git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" - - - name: Run tests - run: | - unset KFUTIL_DEBUG - go test -v ./cmd -run "^Test_StoreTypes*" + # Test_StoreTypes_KFC_12_3_0: + # runs-on: kfutil-runner-set + # needs: + # - build + # - kf_12_x_x + # environment: "KFC_12_3_0_CLEAN" + # env: + # GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} + # KEYFACTOR_PASSWORD: ${{ secrets.KEYFACTOR_PASSWORD }} + # KEYFACTOR_USERNAME: ${{ secrets.KEYFACTOR_USERNAME }} + # KEYFACTOR_AUTH_CONFIG_B64: ${{ secrets.KEYFACTOR_AUTH_CONFIG_B64 }} + # KEYFACTOR_HOSTNAME: ${{ vars.KEYFACTOR_HOSTNAME }} + # KEYFACTOR_SKIP_VERIFY: ${{ vars.KEYFACTOR_SKIP_VERIFY }} + # steps: + # - name: Check out code + # uses: actions/checkout@v4 + # + # - name: Set up Go + # uses: actions/setup-go@v5 + # with: + # go-version: 1.23 + # + # - name: Get Public IP + # run: curl -s https://api.ipify.org + # + # - name: Set up private repo access for go get + # run: | + # git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + # + # - name: Run tests + # run: | + # unset KFUTIL_DEBUG + # go test -v ./cmd -run "^Test_StoreTypes*" Test_StoreTypes_KFC_12_3_0_OAUTH: runs-on: kfutil-runner-set @@ -404,38 +404,38 @@ jobs: go test -v ./cmd -run "^Test_StoreTypes*" ### Store Tests - Test_Stores_KFC_12_3_0: - runs-on: kfutil-runner-set - needs: - - build - - kf_12_x_x - - Test_StoreTypes_KFC_12_3_0 - environment: "KFC_12_3_0" - env: - GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} - KEYFACTOR_PASSWORD: ${{ secrets.KEYFACTOR_PASSWORD }} - KEYFACTOR_USERNAME: ${{ secrets.KEYFACTOR_USERNAME }} - KEYFACTOR_AUTH_CONFIG_B64: ${{ secrets.KEYFACTOR_AUTH_CONFIG_B64 }} - KEYFACTOR_HOSTNAME: ${{ vars.KEYFACTOR_HOSTNAME }} - KEYFACTOR_SKIP_VERIFY: ${{ vars.KEYFACTOR_SKIP_VERIFY }} - steps: - - name: Check out code - uses: actions/checkout@v4 - - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version: 1.23 - - - name: Get Public IP - run: curl -s https://api.ipify.org - - - name: Set up private repo access for go get - run: | - git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" - - - name: Run tests - run: go test -v ./cmd -run "^Test_Stores_*" + # Test_Stores_KFC_12_3_0: + # runs-on: kfutil-runner-set + # needs: + # - build + # - kf_12_x_x + # - Test_StoreTypes_KFC_12_3_0 + # environment: "KFC_12_3_0" + # env: + # GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} + # KEYFACTOR_PASSWORD: ${{ secrets.KEYFACTOR_PASSWORD }} + # KEYFACTOR_USERNAME: ${{ secrets.KEYFACTOR_USERNAME }} + # KEYFACTOR_AUTH_CONFIG_B64: ${{ secrets.KEYFACTOR_AUTH_CONFIG_B64 }} + # KEYFACTOR_HOSTNAME: ${{ vars.KEYFACTOR_HOSTNAME }} + # KEYFACTOR_SKIP_VERIFY: ${{ vars.KEYFACTOR_SKIP_VERIFY }} + # steps: + # - name: Check out code + # uses: actions/checkout@v4 + # + # - name: Set up Go + # uses: actions/setup-go@v5 + # with: + # go-version: 1.23 + # + # - name: Get Public IP + # run: curl -s https://api.ipify.org + # + # - name: Set up private repo access for go get + # run: | + # git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + # + # - name: Run tests + # run: go test -v ./cmd -run "^Test_Stores_*" Test_Stores_KFC_12_3_0_OAUTH: runs-on: kfutil-runner-set needs: @@ -472,40 +472,40 @@ jobs: run: go test -v ./cmd -run "^Test_Stores_*" ### PAM Tests - Test_PAM_KFC_12_3_0: - runs-on: kfutil-runner-set - needs: - - build - - kf_12_x_x - - Test_StoreTypes_KFC_12_3_0 - environment: "KFC_12_3_0" - env: - GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} - KEYFACTOR_PASSWORD: ${{ secrets.KEYFACTOR_PASSWORD }} - KEYFACTOR_USERNAME: ${{ secrets.KEYFACTOR_USERNAME }} - KEYFACTOR_AUTH_CONFIG_B64: ${{ secrets.KEYFACTOR_AUTH_CONFIG_B64 }} - KEYFACTOR_HOSTNAME: ${{ vars.KEYFACTOR_HOSTNAME }} - KEYFACTOR_SKIP_VERIFY: ${{ vars.KEYFACTOR_SKIP_VERIFY }} - steps: - - name: Check out code - uses: actions/checkout@v4 - - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version: 1.23 - - - name: Get Public IP - run: curl -s https://api.ipify.org - - - name: Set up private repo access for go get - run: | - git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" - - - name: Run tests - run: | - unset KFUTIL_DEBUG - go test -v ./cmd -run "^Test_PAM*" + # Test_PAM_KFC_12_3_0: + # runs-on: kfutil-runner-set + # needs: + # - build + # - kf_12_x_x + # - Test_StoreTypes_KFC_12_3_0 + # environment: "KFC_12_3_0" + # env: + # GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} + # KEYFACTOR_PASSWORD: ${{ secrets.KEYFACTOR_PASSWORD }} + # KEYFACTOR_USERNAME: ${{ secrets.KEYFACTOR_USERNAME }} + # KEYFACTOR_AUTH_CONFIG_B64: ${{ secrets.KEYFACTOR_AUTH_CONFIG_B64 }} + # KEYFACTOR_HOSTNAME: ${{ vars.KEYFACTOR_HOSTNAME }} + # KEYFACTOR_SKIP_VERIFY: ${{ vars.KEYFACTOR_SKIP_VERIFY }} + # steps: + # - name: Check out code + # uses: actions/checkout@v4 + # + # - name: Set up Go + # uses: actions/setup-go@v5 + # with: + # go-version: 1.23 + # + # - name: Get Public IP + # run: curl -s https://api.ipify.org + # + # - name: Set up private repo access for go get + # run: | + # git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + # + # - name: Run tests + # run: | + # unset KFUTIL_DEBUG + # go test -v ./cmd -run "^Test_PAM*" Test_PAM_KFC_12_3_0_OAUTH: runs-on: self-hosted @@ -546,48 +546,48 @@ jobs: ### PAM Tests AKV Auth Provider - Test_AKV_PAM_KFC_12_3_0: - runs-on: self-hosted - needs: - - Test_PAM_KFC_12_3_0 - environment: "KFC_12_3_0" - env: - SECRET_NAME: "command-config-1230-az" - steps: - - name: Check out code - uses: actions/checkout@v4 - - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version: 1.23 - - - name: Get Public IP - run: curl -s https://api.ipify.org - - - name: Set up private repo access for go get - run: | - git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" - - - name: Install dependencies - run: go mod download && go mod tidy - - - name: Get secret from Azure Key Vault - run: | - . ./examples/auth/akv/akv_auth.sh - cat $HOME/.keyfactor/command_config.json - - - name: Install kfutil - run: | - make install - - name: Run tests - run: | - go test -v ./cmd -run "^Test_PAM*" + # Test_AKV_PAM_KFC_12_3_0: + # runs-on: self-hosted + # needs: + # - Test_PAM_KFC_12_3_0 + # environment: "KFC_12_3_0" + # env: + # SECRET_NAME: "command-config-1230-az" + # steps: + # - name: Check out code + # uses: actions/checkout@v4 + # + # - name: Set up Go + # uses: actions/setup-go@v5 + # with: + # go-version: 1.23 + # + # - name: Get Public IP + # run: curl -s https://api.ipify.org + # + # - name: Set up private repo access for go get + # run: | + # git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + # + # - name: Install dependencies + # run: go mod download && go mod tidy + # + # - name: Get secret from Azure Key Vault + # run: | + # . ./examples/auth/akv/akv_auth.sh + # cat $HOME/.keyfactor/command_config.json + # + # - name: Install kfutil + # run: | + # make install + # - name: Run tests + # run: | + # go test -v ./cmd -run "^Test_PAM*" Test_AKV_PAM_KFC_12_3_0_OAUTH: runs-on: self-hosted needs: - - Test_PAM_KFC_12_3_0 + - Test_PAM_KFC_12_3_0_OAUTH environment: "KFC_12_3_0_OAUTH" env: SECRET_NAME: "command-config-1230-oauth-az" diff --git a/integration-manifest.json b/integration-manifest.json index 61ae251..11b12e4 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -6,6 +6,7 @@ "description": "`kfutil` is a go-lang CLI wrapper for Keyfactor Command API. It also includes other utility/helper functions around automating common Keyfactor Command operations.", "support_level": "kf-community", "link_github": false, - "update_catalog": false + "update_catalog": false, + "release_dir": "bin" } From 6627bc3831ed95af1ee416ea44791a04db388944 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Mon, 4 Nov 2024 11:37:37 -0800 Subject: [PATCH 17/19] chore(docs): Update docs Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- README.md | 114 +++++++++++++----- docs/kfutil.md | 2 +- docs/kfutil_completion.md | 2 +- docs/kfutil_completion_bash.md | 2 +- docs/kfutil_completion_fish.md | 2 +- docs/kfutil_completion_powershell.md | 2 +- docs/kfutil_completion_zsh.md | 2 +- docs/kfutil_containers.md | 2 +- docs/kfutil_containers_get.md | 2 +- docs/kfutil_containers_list.md | 2 +- docs/kfutil_export.md | 2 +- docs/kfutil_helm.md | 2 +- docs/kfutil_helm_uo.md | 2 +- docs/kfutil_import.md | 2 +- docs/kfutil_login.md | 2 +- docs/kfutil_logout.md | 2 +- docs/kfutil_orchs.md | 2 +- docs/kfutil_orchs_approve.md | 2 +- docs/kfutil_orchs_disapprove.md | 2 +- docs/kfutil_orchs_ext.md | 2 +- docs/kfutil_orchs_get.md | 2 +- docs/kfutil_orchs_list.md | 2 +- docs/kfutil_orchs_logs.md | 2 +- docs/kfutil_orchs_reset.md | 2 +- docs/kfutil_pam.md | 2 +- docs/kfutil_pam_create.md | 2 +- docs/kfutil_pam_delete.md | 2 +- docs/kfutil_pam_get.md | 2 +- docs/kfutil_pam_list.md | 2 +- docs/kfutil_pam_types-create.md | 2 +- docs/kfutil_pam_types-list.md | 2 +- docs/kfutil_pam_update.md | 2 +- docs/kfutil_status.md | 2 +- docs/kfutil_store-types.md | 2 +- docs/kfutil_store-types_create.md | 2 +- docs/kfutil_store-types_delete.md | 2 +- docs/kfutil_store-types_get.md | 2 +- docs/kfutil_store-types_list.md | 2 +- docs/kfutil_store-types_templates-fetch.md | 2 +- docs/kfutil_stores.md | 3 +- docs/kfutil_stores_delete.md | 2 +- docs/kfutil_stores_export.md | 2 +- docs/kfutil_stores_get.md | 2 +- docs/kfutil_stores_import.md | 2 +- docs/kfutil_stores_import_csv.md | 2 +- .../kfutil_stores_import_generate-template.md | 2 +- docs/kfutil_stores_inventory.md | 2 +- docs/kfutil_stores_inventory_add.md | 2 +- docs/kfutil_stores_inventory_remove.md | 2 +- docs/kfutil_stores_inventory_show.md | 2 +- docs/kfutil_stores_list.md | 2 +- docs/kfutil_version.md | 2 +- main.go | 16 +-- pkg/version/version.go | 2 +- readme_source.md | 92 +++++++++++--- 55 files changed, 218 insertions(+), 109 deletions(-) diff --git a/README.md b/README.md index 08fc1b1..c4214ef 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ - # Keyfactor Command Utility (kfutil) -`kfutil` is a go-lang CLI wrapper for Keyfactor Command API. It also includes other utility/helper functions around automating common Keyfactor Command operations. +`kfutil` is a go-lang CLI wrapper for Keyfactor Command API. It also includes other utility/helper functions around +automating common Keyfactor Command operations. #### Integration status: Production - Ready for use in production environments. @@ -11,21 +11,21 @@ This API client allows for programmatic management of Keyfactor resources. ## Support for Keyfactor Command Utility (kfutil) -Keyfactor Command Utility (kfutil) is open source and supported on best effort level for this tool/library/client. This means customers can report Bugs, Feature Requests, Documentation amendment or questions as well as requests for customer information required for setup that needs Keyfactor access to obtain. Such requests do not follow normal SLA commitments for response or resolution. If you have a support issue, please open a support ticket via the Keyfactor Support Portal at https://support.keyfactor.com/ - -###### To report a problem or suggest a new feature, use the **[Issues](../../issues)** tab. If you want to contribute actual bug fixes or proposed enhancements, use the **[Pull requests](../../pulls)** tab. - ---- - - ---- - +Keyfactor Command Utility (kfutil) is open source and supported on best effort level for this tool/library/client. This +means customers can report Bugs, Feature Requests, Documentation amendment or questions as well as requests for customer +information required for setup that needs Keyfactor access to obtain. Such requests do not follow normal SLA commitments +for response or resolution. If you have a support issue, please open a support ticket via the Keyfactor Support Portal +at https://support.keyfactor.com/ +To report a problem or suggest a new feature, use the **[Issues](../../issues)** tab. If you want to contribute actual +bug fixes or proposed enhancements, use the **[Pull requests](../../pulls)** tab. ## Quickstart ### Linux/MacOS + #### Prerequisites: + - [jq](https://stedolan.github.io/jq/download/) CLI tool, used to parse JSON output. - Either - [curl](https://curl.se/download.html) CLI tool, used to download the release files. @@ -35,15 +35,19 @@ Keyfactor Command Utility (kfutil) is open source and supported on best effort l - `$HOME/.local/bin` in your `$PATH` and exists if not running as root, else `/usr/local/bin` if running as root. #### Installation: + ```bash bash <(curl -s https://raw.githubusercontent.com/Keyfactor/kfutil/main/install.sh) ```` ### Windows + #### Prerequisites: + - Powershell 5.1 or later #### Installation: + ```powershell Invoke-WebRequest -Uri "https://raw.githubusercontent.com/Keyfactor/kfutil/main/install.ps1" -OutFile "install.ps1" # Install kfutil to $HOME/AppData/Local/Microsoft/WindowsApps. @@ -51,31 +55,72 @@ Invoke-WebRequest -Uri "https://raw.githubusercontent.com/Keyfactor/kfutil/main/ .\install.ps1 ``` -## Environmental Variables +## Environment Variables + +### Global + +| Name | Description | Default | +|-------------------------------|-----------------------------------------------------------------------------------------------------------------|----------------------------------------| +| KEYFACTOR_HOSTNAME | Keyfactor Command hostname without protocol and port | | +| KEYFACTOR_PORT | Keyfactor Command port | `443` | +| KEYFACTOR_API_PATH | Keyfactor Command API Path | `KeyfactorAPI` | +| KEYFACTOR_SKIP_VERIFY | Skip TLS verification when connecting to Keyfactor Command | `false` | +| KEYFACTOR_CA_CERT | Either a file path or PEM encoded string to a CA certificate to trust when communicating with Keyfactor Command | | +| KEYFACTOR_CLIENT_TIMEOUT | Timeout for HTTP client requests to Keyfactor Command | `60s` | +| KEYFACTOR_AUTH_CONFIG_FILE | Path to a JSON file containing the authentication configuration | `$HOME/.keyfactor/command_config.json` | +| KEYFACTOR_AUTH_CONFIG_PROFILE | Profile to use from the authentication configuration file | `default` | + +### Basic Auth + +Currently, only Active Directory `Basic` authentication is supported. + +| Name | Description | Default | +|--------------------|---------------------------------------------------------------------------------------------|---------| +| KEYFACTOR_USERNAME | Active Directory username to authenticate to Keyfactor Command API | | +| KEYFACTOR_PASSWORD | Password associated with Active Directory username to authenticate to Keyfactor Command API | | +| KEYFACTOR_DOMAIN | Active Directory domain of user. Can be implied from username if it contains `@` or `\\` | | + +### oAuth Client Credentials + +| Name | Description | Default | +|------------------------------|---------------------------------------------------------------------------------------------------------------------------------|----------| +| KEYFACTOR_AUTH_CLIENT_ID | Keyfactor Auth Client ID | | +| KEYFACTOR_AUTH_CLIENT_SECRET | Keyfactor Auth Client Secret | | +| KEYFACTOR_AUTH_TOKEN_URL | URL to request an access token from Keyfactor Auth | | +| KEYFACTOR_AUTH_SCOPES | Scopes to request when authenticating to Keyfactor Command API | `openid` | +| KEYFACTOR_AUTH_ACCESS_TOKEN | Access token to use to authenticate to Keyfactor Command API. This can be supplied directly or generated via client credentials | | + +### kfutil specific All the variables listed below need to be set in your environment. The `kfutil` command will look for these variables -and use them if they are set. If they are not set, the utility will fail to connect to Keyfactor. - -| Variable Name | Description | -|--------------------|------------------------------------------------------------------------------------------| -| KEYFACTOR_HOSTNAME | The hostname of your Keyfactor instance. ex: `my.domain.com` | -| KEYFACTOR_USERNAME | The username to use to connect to Keyfactor. Do not include the domain. ex: `myusername` | -| KEYFACTOR_PASSWORD | The password to use to connect to Keyfactor. ex: `mypassword` | -| KEYFACTOR_DOMAIN | The domain to use to connect to Keyfactor. ex: `mydomain` | -| KEYFACTOR_API_PATH | The path to the Keyfactor API. Defaults to `/KeyfactorAPI`. | -| KFUTIL_EXP | Set to `1` or `true` to enable experimental features. | -| KFUTIL_DEBUG | Set to `1` or `true` to enable debug logging. | +and use them if they are set. + +| Variable Name | Description | +|---------------|-------------------------------------------------------| +| KFUTIL_EXP | Set to `1` or `true` to enable experimental features. | +| KFUTIL_DEBUG | Set to `1` or `true` to enable debug logging. | ### Linux/MacOS: +#### Active Directory Basic Authentication + ```bash export KEYFACTOR_HOSTNAME="" -export KEYFACTOR_USERNAME="" # Do not include domain +export KEYFACTOR_USERNAME="" export KEYFACTOR_PASSWORD="" -export KEYFACTOR_DOMAIN="" +export KEYFACTOR_DOMAIN="" # Optional if username contains domain ``` -Additional variables: +#### oAuth Client Credentials + +```bash +export KEYFACTOR_HOSTNAME="" +export KEYFACTOR_AUTH_CLIENT_ID=" -p 'Cmd' ``` - - diff --git a/docs/kfutil.md b/docs/kfutil.md index c784705..4f93efa 100644 --- a/docs/kfutil.md +++ b/docs/kfutil.md @@ -43,4 +43,4 @@ A CLI wrapper around the Keyfactor Platform API. * [kfutil stores](kfutil_stores.md) - Keyfactor certificate stores APIs and utilities. * [kfutil version](kfutil_version.md) - Shows version of kfutil -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_completion.md b/docs/kfutil_completion.md index 14d566b..c334bf6 100644 --- a/docs/kfutil_completion.md +++ b/docs/kfutil_completion.md @@ -42,4 +42,4 @@ See each sub-command's help for details on how to use the generated script. * [kfutil completion powershell](kfutil_completion_powershell.md) - Generate the autocompletion script for powershell * [kfutil completion zsh](kfutil_completion_zsh.md) - Generate the autocompletion script for zsh -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_completion_bash.md b/docs/kfutil_completion_bash.md index f961da7..859cfbe 100644 --- a/docs/kfutil_completion_bash.md +++ b/docs/kfutil_completion_bash.md @@ -61,4 +61,4 @@ kfutil completion bash * [kfutil completion](kfutil_completion.md) - Generate the autocompletion script for the specified shell -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_completion_fish.md b/docs/kfutil_completion_fish.md index a0d386f..a5bea76 100644 --- a/docs/kfutil_completion_fish.md +++ b/docs/kfutil_completion_fish.md @@ -52,4 +52,4 @@ kfutil completion fish [flags] * [kfutil completion](kfutil_completion.md) - Generate the autocompletion script for the specified shell -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_completion_powershell.md b/docs/kfutil_completion_powershell.md index e96bc99..232cd60 100644 --- a/docs/kfutil_completion_powershell.md +++ b/docs/kfutil_completion_powershell.md @@ -49,4 +49,4 @@ kfutil completion powershell [flags] * [kfutil completion](kfutil_completion.md) - Generate the autocompletion script for the specified shell -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_completion_zsh.md b/docs/kfutil_completion_zsh.md index 98b4917..01c4f8a 100644 --- a/docs/kfutil_completion_zsh.md +++ b/docs/kfutil_completion_zsh.md @@ -63,4 +63,4 @@ kfutil completion zsh [flags] * [kfutil completion](kfutil_completion.md) - Generate the autocompletion script for the specified shell -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_containers.md b/docs/kfutil_containers.md index 625c7e5..1c19404 100644 --- a/docs/kfutil_containers.md +++ b/docs/kfutil_containers.md @@ -38,4 +38,4 @@ A collections of APIs and utilities for interacting with Keyfactor certificate s * [kfutil containers get](kfutil_containers_get.md) - Get certificate store container by ID or name. * [kfutil containers list](kfutil_containers_list.md) - List certificate store containers. -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_containers_get.md b/docs/kfutil_containers_get.md index fa8c3e0..3eac513 100644 --- a/docs/kfutil_containers_get.md +++ b/docs/kfutil_containers_get.md @@ -41,4 +41,4 @@ kfutil containers get [flags] * [kfutil containers](kfutil_containers.md) - Keyfactor certificate store container API and utilities. -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_containers_list.md b/docs/kfutil_containers_list.md index 465cc19..0b51479 100644 --- a/docs/kfutil_containers_list.md +++ b/docs/kfutil_containers_list.md @@ -40,4 +40,4 @@ kfutil containers list [flags] * [kfutil containers](kfutil_containers.md) - Keyfactor certificate store container API and utilities. -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_export.md b/docs/kfutil_export.md index fb69f13..13a71eb 100644 --- a/docs/kfutil_export.md +++ b/docs/kfutil_export.md @@ -52,4 +52,4 @@ kfutil export [flags] * [kfutil](kfutil.md) - Keyfactor CLI utilities -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_helm.md b/docs/kfutil_helm.md index a7c8bf5..7874174 100644 --- a/docs/kfutil_helm.md +++ b/docs/kfutil_helm.md @@ -43,4 +43,4 @@ kubectl helm uo | helm install -f - keyfactor-universal-orchestrator keyfactor/k * [kfutil](kfutil.md) - Keyfactor CLI utilities * [kfutil helm uo](kfutil_helm_uo.md) - Configure the Keyfactor Universal Orchestrator Helm Chart -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_helm_uo.md b/docs/kfutil_helm_uo.md index eca60b9..eeb4bb4 100644 --- a/docs/kfutil_helm_uo.md +++ b/docs/kfutil_helm_uo.md @@ -47,4 +47,4 @@ kfutil helm uo [-t ] [-o ] [-f ] [-e -e @,@ -o ./app/extension * [kfutil orchs](kfutil_orchs.md) - Keyfactor agents/orchestrators APIs and utilities. -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_orchs_get.md b/docs/kfutil_orchs_get.md index 580fcd5..3da99b1 100644 --- a/docs/kfutil_orchs_get.md +++ b/docs/kfutil_orchs_get.md @@ -41,4 +41,4 @@ kfutil orchs get [flags] * [kfutil orchs](kfutil_orchs.md) - Keyfactor agents/orchestrators APIs and utilities. -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_orchs_list.md b/docs/kfutil_orchs_list.md index 5873538..6c08283 100644 --- a/docs/kfutil_orchs_list.md +++ b/docs/kfutil_orchs_list.md @@ -40,4 +40,4 @@ kfutil orchs list [flags] * [kfutil orchs](kfutil_orchs.md) - Keyfactor agents/orchestrators APIs and utilities. -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_orchs_logs.md b/docs/kfutil_orchs_logs.md index f65cea8..d793da8 100644 --- a/docs/kfutil_orchs_logs.md +++ b/docs/kfutil_orchs_logs.md @@ -41,4 +41,4 @@ kfutil orchs logs [flags] * [kfutil orchs](kfutil_orchs.md) - Keyfactor agents/orchestrators APIs and utilities. -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_orchs_reset.md b/docs/kfutil_orchs_reset.md index b7c5d7e..12020ff 100644 --- a/docs/kfutil_orchs_reset.md +++ b/docs/kfutil_orchs_reset.md @@ -41,4 +41,4 @@ kfutil orchs reset [flags] * [kfutil orchs](kfutil_orchs.md) - Keyfactor agents/orchestrators APIs and utilities. -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_pam.md b/docs/kfutil_pam.md index 45a5a4f..17d0554 100644 --- a/docs/kfutil_pam.md +++ b/docs/kfutil_pam.md @@ -45,4 +45,4 @@ programmatically create, delete, edit, and list PAM Providers. * [kfutil pam types-list](kfutil_pam_types-list.md) - Returns a list of all available PAM provider types. * [kfutil pam update](kfutil_pam_update.md) - Updates an existing PAM Provider, currently only supported from file. -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_pam_create.md b/docs/kfutil_pam_create.md index f2446b6..092ab86 100644 --- a/docs/kfutil_pam_create.md +++ b/docs/kfutil_pam_create.md @@ -41,4 +41,4 @@ kfutil pam create [flags] * [kfutil pam](kfutil_pam.md) - Keyfactor PAM Provider APIs. -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_pam_delete.md b/docs/kfutil_pam_delete.md index 133f103..895189e 100644 --- a/docs/kfutil_pam_delete.md +++ b/docs/kfutil_pam_delete.md @@ -41,4 +41,4 @@ kfutil pam delete [flags] * [kfutil pam](kfutil_pam.md) - Keyfactor PAM Provider APIs. -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_pam_get.md b/docs/kfutil_pam_get.md index 03c66a0..3e887b1 100644 --- a/docs/kfutil_pam_get.md +++ b/docs/kfutil_pam_get.md @@ -41,4 +41,4 @@ kfutil pam get [flags] * [kfutil pam](kfutil_pam.md) - Keyfactor PAM Provider APIs. -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_pam_list.md b/docs/kfutil_pam_list.md index 2e11dfb..0ba111d 100644 --- a/docs/kfutil_pam_list.md +++ b/docs/kfutil_pam_list.md @@ -40,4 +40,4 @@ kfutil pam list [flags] * [kfutil pam](kfutil_pam.md) - Keyfactor PAM Provider APIs. -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_pam_types-create.md b/docs/kfutil_pam_types-create.md index 7002cbe..f445588 100644 --- a/docs/kfutil_pam_types-create.md +++ b/docs/kfutil_pam_types-create.md @@ -48,4 +48,4 @@ kfutil pam types-create [flags] * [kfutil pam](kfutil_pam.md) - Keyfactor PAM Provider APIs. -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_pam_types-list.md b/docs/kfutil_pam_types-list.md index 6354470..1e17c7f 100644 --- a/docs/kfutil_pam_types-list.md +++ b/docs/kfutil_pam_types-list.md @@ -40,4 +40,4 @@ kfutil pam types-list [flags] * [kfutil pam](kfutil_pam.md) - Keyfactor PAM Provider APIs. -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_pam_update.md b/docs/kfutil_pam_update.md index abb7db5..9d17ba5 100644 --- a/docs/kfutil_pam_update.md +++ b/docs/kfutil_pam_update.md @@ -41,4 +41,4 @@ kfutil pam update [flags] * [kfutil pam](kfutil_pam.md) - Keyfactor PAM Provider APIs. -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_status.md b/docs/kfutil_status.md index 8c30015..fd866f6 100644 --- a/docs/kfutil_status.md +++ b/docs/kfutil_status.md @@ -40,4 +40,4 @@ kfutil status [flags] * [kfutil](kfutil.md) - Keyfactor CLI utilities -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_store-types.md b/docs/kfutil_store-types.md index 239320a..cada1e9 100644 --- a/docs/kfutil_store-types.md +++ b/docs/kfutil_store-types.md @@ -41,4 +41,4 @@ A collections of APIs and utilities for interacting with Keyfactor certificate s * [kfutil store-types list](kfutil_store-types_list.md) - List certificate store types. * [kfutil store-types templates-fetch](kfutil_store-types_templates-fetch.md) - Fetches store type templates from Keyfactor's Github. -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_store-types_create.md b/docs/kfutil_store-types_create.md index 9b071b5..22b1c67 100644 --- a/docs/kfutil_store-types_create.md +++ b/docs/kfutil_store-types_create.md @@ -45,4 +45,4 @@ kfutil store-types create [flags] * [kfutil store-types](kfutil_store-types.md) - Keyfactor certificate store types APIs and utilities. -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_store-types_delete.md b/docs/kfutil_store-types_delete.md index ff64309..673a9d2 100644 --- a/docs/kfutil_store-types_delete.md +++ b/docs/kfutil_store-types_delete.md @@ -44,4 +44,4 @@ kfutil store-types delete [flags] * [kfutil store-types](kfutil_store-types.md) - Keyfactor certificate store types APIs and utilities. -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_store-types_get.md b/docs/kfutil_store-types_get.md index 2cddccc..9a8ede9 100644 --- a/docs/kfutil_store-types_get.md +++ b/docs/kfutil_store-types_get.md @@ -45,4 +45,4 @@ kfutil store-types get [-i | -n ] [-b * [kfutil store-types](kfutil_store-types.md) - Keyfactor certificate store types APIs and utilities. -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_store-types_list.md b/docs/kfutil_store-types_list.md index feefa24..40ab223 100644 --- a/docs/kfutil_store-types_list.md +++ b/docs/kfutil_store-types_list.md @@ -40,4 +40,4 @@ kfutil store-types list [flags] * [kfutil store-types](kfutil_store-types.md) - Keyfactor certificate store types APIs and utilities. -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_store-types_templates-fetch.md b/docs/kfutil_store-types_templates-fetch.md index 558db74..54a53cc 100644 --- a/docs/kfutil_store-types_templates-fetch.md +++ b/docs/kfutil_store-types_templates-fetch.md @@ -41,4 +41,4 @@ kfutil store-types templates-fetch [flags] * [kfutil store-types](kfutil_store-types.md) - Keyfactor certificate store types APIs and utilities. -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_stores.md b/docs/kfutil_stores.md index 11cd523..3da52fe 100644 --- a/docs/kfutil_stores.md +++ b/docs/kfutil_stores.md @@ -41,6 +41,5 @@ A collections of APIs and utilities for interacting with Keyfactor certificate s * [kfutil stores import](kfutil_stores_import.md) - Import a file with certificate store parameters and create them in keyfactor. * [kfutil stores inventory](kfutil_stores_inventory.md) - Commands related to certificate store inventory management * [kfutil stores list](kfutil_stores_list.md) - List certificate stores. -* [kfutil stores rot](kfutil_stores_rot.md) - Root of trust utility -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_stores_delete.md b/docs/kfutil_stores_delete.md index 18a6b60..5e5b0ac 100644 --- a/docs/kfutil_stores_delete.md +++ b/docs/kfutil_stores_delete.md @@ -43,4 +43,4 @@ kfutil stores delete [flags] * [kfutil stores](kfutil_stores.md) - Keyfactor certificate stores APIs and utilities. -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_stores_export.md b/docs/kfutil_stores_export.md index bcd5fdf..fa88093 100644 --- a/docs/kfutil_stores_export.md +++ b/docs/kfutil_stores_export.md @@ -44,4 +44,4 @@ kfutil stores export [flags] * [kfutil stores](kfutil_stores.md) - Keyfactor certificate stores APIs and utilities. -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_stores_get.md b/docs/kfutil_stores_get.md index 97a0f40..5e77298 100644 --- a/docs/kfutil_stores_get.md +++ b/docs/kfutil_stores_get.md @@ -41,4 +41,4 @@ kfutil stores get [flags] * [kfutil stores](kfutil_stores.md) - Keyfactor certificate stores APIs and utilities. -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_stores_import.md b/docs/kfutil_stores_import.md index fc7b75e..808bc07 100644 --- a/docs/kfutil_stores_import.md +++ b/docs/kfutil_stores_import.md @@ -38,4 +38,4 @@ Tools for generating import templates and importing certificate stores * [kfutil stores import csv](kfutil_stores_import_csv.md) - Create certificate stores from CSV file. * [kfutil stores import generate-template](kfutil_stores_import_generate-template.md) - For generating a CSV template with headers for bulk store creation. -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_stores_import_csv.md b/docs/kfutil_stores_import_csv.md index 67d1239..4d54318 100644 --- a/docs/kfutil_stores_import_csv.md +++ b/docs/kfutil_stores_import_csv.md @@ -48,4 +48,4 @@ kfutil stores import csv --file --store-type-id --store-t * [kfutil stores import](kfutil_stores_import.md) - Import a file with certificate store parameters and create them in keyfactor. -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_stores_inventory.md b/docs/kfutil_stores_inventory.md index ee55cfc..89d0868 100644 --- a/docs/kfutil_stores_inventory.md +++ b/docs/kfutil_stores_inventory.md @@ -39,4 +39,4 @@ Commands related to certificate store inventory management * [kfutil stores inventory remove](kfutil_stores_inventory_remove.md) - Removes a certificate from the certificate store inventory. * [kfutil stores inventory show](kfutil_stores_inventory_show.md) - Show the inventory of a certificate store. -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_stores_inventory_add.md b/docs/kfutil_stores_inventory_add.md index be3e5d9..bb282ed 100644 --- a/docs/kfutil_stores_inventory_add.md +++ b/docs/kfutil_stores_inventory_add.md @@ -54,4 +54,4 @@ kfutil stores inventory add [flags] * [kfutil stores inventory](kfutil_stores_inventory.md) - Commands related to certificate store inventory management -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_stores_inventory_remove.md b/docs/kfutil_stores_inventory_remove.md index 706058f..5771177 100644 --- a/docs/kfutil_stores_inventory_remove.md +++ b/docs/kfutil_stores_inventory_remove.md @@ -50,4 +50,4 @@ kfutil stores inventory remove [flags] * [kfutil stores inventory](kfutil_stores_inventory.md) - Commands related to certificate store inventory management -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_stores_inventory_show.md b/docs/kfutil_stores_inventory_show.md index 25948fb..3d72acd 100644 --- a/docs/kfutil_stores_inventory_show.md +++ b/docs/kfutil_stores_inventory_show.md @@ -44,4 +44,4 @@ kfutil stores inventory show [flags] * [kfutil stores inventory](kfutil_stores_inventory.md) - Commands related to certificate store inventory management -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_stores_list.md b/docs/kfutil_stores_list.md index cedc3b2..68836c2 100644 --- a/docs/kfutil_stores_list.md +++ b/docs/kfutil_stores_list.md @@ -40,4 +40,4 @@ kfutil stores list [flags] * [kfutil stores](kfutil_stores.md) - Keyfactor certificate stores APIs and utilities. -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/docs/kfutil_version.md b/docs/kfutil_version.md index 383c1de..93296e4 100644 --- a/docs/kfutil_version.md +++ b/docs/kfutil_version.md @@ -40,4 +40,4 @@ kfutil version [flags] * [kfutil](kfutil.md) - Keyfactor CLI utilities -###### Auto generated by spf13/cobra on 8-Sep-2024 +###### Auto generated by spf13/cobra on 4-Nov-2024 diff --git a/main.go b/main.go index 15e0228..68cf1d6 100644 --- a/main.go +++ b/main.go @@ -16,19 +16,21 @@ package main import ( _ "embed" + "flag" + "os" "github.com/spf13/cobra/doc" "kfutil/cmd" ) func main() { - //var docsFlag bool - //flag.BoolVar(&docsFlag, "makedocs", false, "Create markdown docs.") - //flag.Parse() - //if docsFlag { - // docs() - // os.Exit(0) - //} + var docsFlag bool + flag.BoolVar(&docsFlag, "makedocs", false, "Create markdown docs.") + flag.Parse() + if docsFlag { + docs() + os.Exit(0) + } cmd.Execute() } diff --git a/pkg/version/version.go b/pkg/version/version.go index db6d381..3294bc0 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -14,4 +14,4 @@ package version -const VERSION = "1.5.2" +const VERSION = "1.6.0" diff --git a/readme_source.md b/readme_source.md index 0cc81d6..0f6cd9f 100644 --- a/readme_source.md +++ b/readme_source.md @@ -1,7 +1,9 @@ ## Quickstart ### Linux/MacOS + #### Prerequisites: + - [jq](https://stedolan.github.io/jq/download/) CLI tool, used to parse JSON output. - Either - [curl](https://curl.se/download.html) CLI tool, used to download the release files. @@ -11,15 +13,19 @@ - `$HOME/.local/bin` in your `$PATH` and exists if not running as root, else `/usr/local/bin` if running as root. #### Installation: + ```bash bash <(curl -s https://raw.githubusercontent.com/Keyfactor/kfutil/main/install.sh) ```` ### Windows + #### Prerequisites: + - Powershell 5.1 or later #### Installation: + ```powershell Invoke-WebRequest -Uri "https://raw.githubusercontent.com/Keyfactor/kfutil/main/install.ps1" -OutFile "install.ps1" # Install kfutil to $HOME/AppData/Local/Microsoft/WindowsApps. @@ -27,31 +33,72 @@ Invoke-WebRequest -Uri "https://raw.githubusercontent.com/Keyfactor/kfutil/main/ .\install.ps1 ``` -## Environmental Variables +## Environment Variables + +### Global + +| Name | Description | Default | +|-------------------------------|-----------------------------------------------------------------------------------------------------------------|----------------------------------------| +| KEYFACTOR_HOSTNAME | Keyfactor Command hostname without protocol and port | | +| KEYFACTOR_PORT | Keyfactor Command port | `443` | +| KEYFACTOR_API_PATH | Keyfactor Command API Path | `KeyfactorAPI` | +| KEYFACTOR_SKIP_VERIFY | Skip TLS verification when connecting to Keyfactor Command | `false` | +| KEYFACTOR_CA_CERT | Either a file path or PEM encoded string to a CA certificate to trust when communicating with Keyfactor Command | | +| KEYFACTOR_CLIENT_TIMEOUT | Timeout for HTTP client requests to Keyfactor Command | `60s` | +| KEYFACTOR_AUTH_CONFIG_FILE | Path to a JSON file containing the authentication configuration | `$HOME/.keyfactor/command_config.json` | +| KEYFACTOR_AUTH_CONFIG_PROFILE | Profile to use from the authentication configuration file | `default` | + +### Basic Auth + +Currently, only Active Directory `Basic` authentication is supported. + +| Name | Description | Default | +|--------------------|---------------------------------------------------------------------------------------------|---------| +| KEYFACTOR_USERNAME | Active Directory username to authenticate to Keyfactor Command API | | +| KEYFACTOR_PASSWORD | Password associated with Active Directory username to authenticate to Keyfactor Command API | | +| KEYFACTOR_DOMAIN | Active Directory domain of user. Can be implied from username if it contains `@` or `\\` | | + +### oAuth Client Credentials + +| Name | Description | Default | +|------------------------------|---------------------------------------------------------------------------------------------------------------------------------|----------| +| KEYFACTOR_AUTH_CLIENT_ID | Keyfactor Auth Client ID | | +| KEYFACTOR_AUTH_CLIENT_SECRET | Keyfactor Auth Client Secret | | +| KEYFACTOR_AUTH_TOKEN_URL | URL to request an access token from Keyfactor Auth | | +| KEYFACTOR_AUTH_SCOPES | Scopes to request when authenticating to Keyfactor Command API | `openid` | +| KEYFACTOR_AUTH_ACCESS_TOKEN | Access token to use to authenticate to Keyfactor Command API. This can be supplied directly or generated via client credentials | | + +### kfutil specific All the variables listed below need to be set in your environment. The `kfutil` command will look for these variables -and use them if they are set. If they are not set, the utility will fail to connect to Keyfactor. - -| Variable Name | Description | -|--------------------|------------------------------------------------------------------------------------------| -| KEYFACTOR_HOSTNAME | The hostname of your Keyfactor instance. ex: `my.domain.com` | -| KEYFACTOR_USERNAME | The username to use to connect to Keyfactor. Do not include the domain. ex: `myusername` | -| KEYFACTOR_PASSWORD | The password to use to connect to Keyfactor. ex: `mypassword` | -| KEYFACTOR_DOMAIN | The domain to use to connect to Keyfactor. ex: `mydomain` | -| KEYFACTOR_API_PATH | The path to the Keyfactor API. Defaults to `/KeyfactorAPI`. | -| KFUTIL_EXP | Set to `1` or `true` to enable experimental features. | -| KFUTIL_DEBUG | Set to `1` or `true` to enable debug logging. | +and use them if they are set. + +| Variable Name | Description | +|---------------|-------------------------------------------------------| +| KFUTIL_EXP | Set to `1` or `true` to enable experimental features. | +| KFUTIL_DEBUG | Set to `1` or `true` to enable debug logging. | ### Linux/MacOS: +#### Active Directory Basic Authentication + ```bash export KEYFACTOR_HOSTNAME="" -export KEYFACTOR_USERNAME="" # Do not include domain +export KEYFACTOR_USERNAME="" export KEYFACTOR_PASSWORD="" -export KEYFACTOR_DOMAIN="" +export KEYFACTOR_DOMAIN="" # Optional if username contains domain ``` -Additional variables: +#### oAuth Client Credentials + +```bash +export KEYFACTOR_HOSTNAME="" +export KEYFACTOR_AUTH_CLIENT_ID=" Date: Wed, 6 Nov 2024 11:09:43 -0800 Subject: [PATCH 18/19] fix(login): Add oauth support for `login` and update login tests. Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- cmd/helm_uo.go | 27 +- cmd/login.go | 493 +++++++++++------- cmd/login_test.go | 449 +++++++++++----- cmd/root.go | 25 + cmd/storeTypes.go | 6 +- docs/kfutil.md | 5 +- docs/kfutil_completion.md | 5 +- docs/kfutil_completion_bash.md | 5 +- docs/kfutil_completion_fish.md | 5 +- docs/kfutil_completion_powershell.md | 5 +- docs/kfutil_completion_zsh.md | 5 +- docs/kfutil_containers.md | 5 +- docs/kfutil_containers_get.md | 5 +- docs/kfutil_containers_list.md | 5 +- docs/kfutil_export.md | 5 +- docs/kfutil_helm.md | 5 +- docs/kfutil_helm_uo.md | 5 +- docs/kfutil_import.md | 5 +- docs/kfutil_login.md | 17 +- docs/kfutil_logout.md | 5 +- docs/kfutil_orchs.md | 5 +- docs/kfutil_orchs_approve.md | 5 +- docs/kfutil_orchs_disapprove.md | 5 +- docs/kfutil_orchs_ext.md | 5 +- docs/kfutil_orchs_get.md | 5 +- docs/kfutil_orchs_list.md | 5 +- docs/kfutil_orchs_logs.md | 5 +- docs/kfutil_orchs_reset.md | 5 +- docs/kfutil_pam.md | 5 +- docs/kfutil_pam_create.md | 5 +- docs/kfutil_pam_delete.md | 5 +- docs/kfutil_pam_get.md | 5 +- docs/kfutil_pam_list.md | 5 +- docs/kfutil_pam_types-create.md | 5 +- docs/kfutil_pam_types-list.md | 5 +- docs/kfutil_pam_update.md | 5 +- docs/kfutil_status.md | 5 +- docs/kfutil_store-types.md | 5 +- docs/kfutil_store-types_create.md | 5 +- docs/kfutil_store-types_delete.md | 5 +- docs/kfutil_store-types_get.md | 5 +- docs/kfutil_store-types_list.md | 5 +- docs/kfutil_store-types_templates-fetch.md | 5 +- docs/kfutil_stores.md | 5 +- docs/kfutil_stores_delete.md | 5 +- docs/kfutil_stores_export.md | 5 +- docs/kfutil_stores_get.md | 5 +- docs/kfutil_stores_import.md | 5 +- docs/kfutil_stores_import_csv.md | 5 +- .../kfutil_stores_import_generate-template.md | 5 +- docs/kfutil_stores_inventory.md | 5 +- docs/kfutil_stores_inventory_add.md | 5 +- docs/kfutil_stores_inventory_remove.md | 5 +- docs/kfutil_stores_inventory_show.md | 5 +- docs/kfutil_stores_list.md | 5 +- docs/kfutil_version.md | 5 +- go.mod | 2 +- go.sum | 4 +- main.go | 16 +- 59 files changed, 915 insertions(+), 374 deletions(-) diff --git a/cmd/helm_uo.go b/cmd/helm_uo.go index 44107e5..2060926 100644 --- a/cmd/helm_uo.go +++ b/cmd/helm_uo.go @@ -18,12 +18,13 @@ package cmd import ( "fmt" + "log" + "github.com/spf13/cobra" "github.com/spf13/pflag" "kfutil/pkg/cmdutil" "kfutil/pkg/cmdutil/flags" "kfutil/pkg/helm" - "log" ) // DefaultValuesLocation TODO when Helm is ready, set this to the default values.yaml location in Git @@ -68,9 +69,27 @@ func (f *HelmUoFlags) AddFlags(flags *pflag.FlagSet) { f.FilenameFlags.AddFlags(flags) // Add custom flags - flags.StringVarP(f.GithubToken, "token", "t", *f.GithubToken, "Token used for related authentication - required for private repositories") - flags.StringVarP(f.OutPath, "out", "o", *f.OutPath, "Path to output the modified values.yaml file. This file can then be used with helm install -f to override the default values.") - flags.StringSliceVarP(f.Extensions, "extension", "e", *f.Extensions, "List of extensions to install. Should be in the format @. If no version is specified, the latest version will be downloaded.") + flags.StringVarP( + f.GithubToken, + "token", + "t", + *f.GithubToken, + "Token used for related authentication - required for private repositories", + ) + flags.StringVarP( + f.OutPath, + "out", + "o", + *f.OutPath, + "Path to output the modified values.yaml file. This file can then be used with helm install -f to override the default values.", + ) + flags.StringSliceVarP( + f.Extensions, + "extension", + "e", + *f.Extensions, + "List of extensions to install. Should be in the format @. If no version is specified, the latest version will be downloaded.", + ) } func NewCmdHelmUo() *cobra.Command { diff --git a/cmd/login.go b/cmd/login.go index 2fe2dd7..41d0b89 100644 --- a/cmd/login.go +++ b/cmd/login.go @@ -15,19 +15,21 @@ package cmd import ( + "bufio" "encoding/json" "fmt" + "io" + stdlog "log" "os" "path" "strings" - "syscall" "github.com/Keyfactor/keyfactor-auth-client-go/auth_providers" "github.com/Keyfactor/keyfactor-go-client/v3/api" "github.com/google/go-cmp/cmp" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - "golang.org/x/crypto/ssh/terminal" + "golang.org/x/term" ) var loginCmd = &cobra.Command{ @@ -36,14 +38,15 @@ var loginCmd = &cobra.Command{ SuggestFor: nil, Short: "User interactive login to Keyfactor. Stores the credentials in the config file '$HOME/.keyfactor/command_config.json'.", GroupID: "", - Long: `Will prompt the user for a kfcUsername and kfcPassword and then attempt to login to Keyfactor. + Long: `Will prompt the user for a Username and Password and then attempt to login to Keyfactor. You can provide the --config flag to specify a config file to use. If not provided, the default config file will be used. The default config file is located at $HOME/.keyfactor/command_config.json. -To prevent the prompt for kfcUsername and kfcPassword, use the --no-prompt flag. If this flag is provided then -the CLI will default to using the environment variables: KEYFACTOR_HOSTNAME, KEYFACTOR_USERNAME, -KEYFACTOR_PASSWORD and KEYFACTOR_DOMAIN. +To prevent the prompt for Username and Password, use the --no-prompt flag. If this flag is provided then +the CLI will default to using the environment variables. -WARNING: The 'username'' and 'password' will be stored in the config file in plain text at: +For more information on the environment variables review the docs: https://github.com/Keyfactor/kfutil/tree/main?tab=readme-ov-file#environmental-variables + +WARNING: This will write the environmental credentials to disk and will be stored in the config file in plain text at: '$HOME/.keyfactor/command_config.json.' `, Example: "", @@ -61,150 +64,204 @@ WARNING: The 'username'' and 'password' will be stored in the config file in pla PreRunE: nil, RunE: func(cmd *cobra.Command, args []string) error { log.Info().Msg("Running login command") - logGlobals() + cmd.SilenceUsage = true // expEnabled checks isExperimental := false debugErr := warnExperimentalFeature(expEnabled, isExperimental) if debugErr != nil { return debugErr } + stdlog.SetOutput(io.Discard) + informDebug(debugFlag) + logGlobals() - // CLI Logic + var authType string var ( - authConfigFileErrs []error - authConfig ConfigurationFile - authErr error + isValidConfig bool + kfcOAuth *auth_providers.CommandConfigOauth + kfcBasicAuth *auth_providers.CommandAuthConfigBasic ) - if profile == "" && configFile == "" { + log.Debug().Msg("calling getEnvConfig()") + envConfig, envErr := getServerConfigFromEnv() + if envErr == nil { + log.Debug().Msg("getEnvConfig() returned") + log.Info(). + Str("host", envConfig.Host). + Str("authType", envConfig.AuthType). + Msg("Login successful via environment variables") + outputResult(fmt.Sprintf("Login successful via environment variables to %s", envConfig.Host), outputFormat) + if profile == "" { + profile = "default" + } + if configFile == "" { + userHomeDir, hErr := prepHomeDir() + if hErr != nil { + log.Error().Err(hErr) + return hErr + } + configFile = path.Join(userHomeDir, DefaultConfigFileName) + } + envConfigFile := auth_providers.Config{ + Servers: map[string]auth_providers.Server{}, + } + envConfigFile.Servers[profile] = *envConfig + wcErr := writeConfigFile(&envConfigFile, configFile) + if wcErr != nil { + return wcErr + } + return nil + } + + log.Error().Err(envErr).Msg("Unable to authenticate via environment variables") + + if profile == "" { profile = "default" - log.Info().Msg("Using default profile") - // Check for environment variables - var authEnvErr []error - if noPrompt { - log.Info().Msg("Using environment variables for configuration data.") - // First try to auth with environment variables - authConfig, authEnvErr = authEnvVars( - configFile, - profile, - true, - ) // always save config file is login is called - if authEnvErr != nil { - for _, err := range authEnvErr { - log.Error().Err(err) - //outputError(err, false, "") + } + if configFile == "" { + userHomeDir, hErr := prepHomeDir() + if hErr != nil { + log.Error().Err(hErr) + return hErr + } + configFile = path.Join(userHomeDir, DefaultConfigFileName) + } + + log.Debug(). + Str("configFile", configFile). + Str("profile", profile). + Msg("call: auth_providers.ReadConfigFromJSON()") + aConfig, aErr := auth_providers.ReadConfigFromJSON(configFile) + if aErr != nil { + log.Error().Err(aErr) + //return aErr + } + log.Debug().Msg("auth_providers.ReadConfigFromJSON() returned") + + var outputServer *auth_providers.Server + + // Attempt to read existing configuration file + if aConfig != nil { + serverConfig, serverExists := aConfig.Servers[profile] + if serverExists { + // validate the config and prompt for missing values + authType = serverConfig.GetAuthType() + switch authType { + case "oauth": + oauthConfig, oErr := serverConfig.GetOAuthClientConfig() + if oErr != nil { + log.Error().Err(oErr) } - } - if !validConfigFileEntry(authConfig, profile) { - // Attempt to auth with config file - log.Info().Msgf("Attempting to authenticate via config '%s' profile.", profile) - authConfig, authEnvErr = authConfigFile( - configFile, - profile, - "", - noPrompt, - true, - ) // always save config file is login is called - if authEnvErr != nil { - // Print out the error messages - for _, err := range authEnvErr { - log.Error().Err(err) - } + if oauthConfig == nil { + log.Error().Msg("OAuth configuration is empty") + break } - if !validConfigFileEntry(authConfig, profile) { - errMsg := fmt.Errorf("unable to authenticate with environment variables or config file, please review setup") - //log.Fatal(errMsg) - log.Error().Err(errMsg) - return errMsg + vErr := oauthConfig.ValidateAuthConfig() + if vErr == nil { + isValidConfig = true + } else { + log.Error(). + Err(vErr). + Msg("invalid OAuth configuration") + //break } - } - } else { - // Try user interactive login - log.Info().Msg("Attempting to implicitly authenticate via environment variables.") - log.Debug().Str("configFile", configFile). - Str("profile", profile). - Bool("noPrompt", noPrompt). - Msg("call: authEnvVars()") - authConfig, _ = authEnvVars(configFile, profile, false) // Silently load via env what you can - if !validConfigFileEntry(authConfig, profile) || !noPrompt { - log.Info().Msg("Attempting to authenticate via user interactive login.") - existingAuth := authConfig.Servers[profile] - log.Debug().Str("hostname", existingAuth.Hostname). - Str("username", existingAuth.Username). - Str("password", hashSecretValue(existingAuth.Password)). - Str("domain", existingAuth.Domain). - Str("apiPath", existingAuth.APIPath). - Msg("call: authInteractive()") - authConfig, authErr = authInteractive( - existingAuth.Hostname, - existingAuth.Username, - existingAuth.Password, - existingAuth.Domain, - existingAuth.APIPath, - profile, - !noPrompt, - true, - configFile, - ) - log.Debug().Msg("authInteractive() returned") - if authErr != nil { - log.Error().Err(authErr) - return authErr + outputServer = oauthConfig.GetServerConfig() + kfcOAuth = oauthConfig + case "basic": + basicConfig, bErr := serverConfig.GetBasicAuthClientConfig() + if bErr != nil { + log.Error().Err(bErr) + } + if basicConfig == nil { + log.Error().Msg("Basic Auth configuration is empty") + break + } + vErr := basicConfig.ValidateAuthConfig() + if vErr == nil { + isValidConfig = true + } else { + log.Error(). + Err(vErr). + Msg("invalid Basic Auth configuration") + //break } + outputServer = basicConfig.GetServerConfig() + kfcBasicAuth = basicConfig + default: + log.Error(). + Str("authType", authType). + Str("profile", profile). + Str("configFile", configFile). + Msg("unable to determine auth type from configuration") } } - //fmt.Println(fmt.Sprintf("Login successful!")) - outputResult(SuccessfulAuthMsg, outputFormat) - return nil - } else if configFile != "" || profile != "" { - // Attempt to auth with config file - log.Info().Msgf("Attempting to authenticate via config '%s' profile.", profile) - log.Debug().Str("configFile", configFile). - Str("profile", profile). - Bool("noPrompt", noPrompt). - Msg("call: authConfigFile()") - authConfig, authConfigFileErrs = authConfigFile( - configFile, - profile, - "", - noPrompt, - true, - ) // always save config file is login is called - log.Debug().Msg("authConfigFile() returned") - if authConfigFileErrs != nil { - // Print out the error messages - for _, err := range authConfigFileErrs { - //log.Println(err) - log.Error().Err(err) - outputError(err, false, outputFormat) - } + } + + if !noPrompt { + log.Debug().Msg("prompting for interactive login") + iConfig, iErr := authInteractive(outputServer, profile, !noPrompt, true, configFile) + if iErr != nil { + log.Error().Err(iErr) + return iErr } - if !validConfigFileEntry(authConfig, profile) && !noPrompt { - //Attempt to auth with user interactive login - log.Info().Msg("Attempting to authenticate via user interactive login.") - authEntry := authConfig.Servers[profile] - authConfig, authErr = authInteractive( - authEntry.Hostname, - authEntry.Username, - authEntry.Password, - authEntry.Domain, - authEntry.APIPath, - profile, - false, - true, - configFile, - ) - if authErr != nil { - //log.Println(authErr) - log.Error().Err(authErr) - outputResult(FailedAuthMsg, outputFormat) - return authErr + iServer, iServerExists := iConfig.Servers[profile] + if iServerExists { + authType = iServer.GetAuthType() + switch authType { + case "oauth": + kfcOAuth, _ = iServer.GetOAuthClientConfig() + outputServer = kfcOAuth.GetServerConfig() + oErr := kfcOAuth.ValidateAuthConfig() + if oErr == nil { + isValidConfig = true + } else { + log.Error().Err(oErr) + } + case "basic": + kfcBasicAuth, _ = iServer.GetBasicAuthClientConfig() + outputServer = kfcBasicAuth.GetServerConfig() + bErr := kfcBasicAuth.ValidateAuthConfig() + if bErr == nil { + isValidConfig = true + } else { + log.Error().Err(bErr) + } + default: + log.Error().Msg("unable to determine auth type from interactive configuration") } } - outputResult(SuccessfulAuthMsg, outputFormat) - return nil } + + if !isValidConfig { + log.Debug().Msg("prompting for interactive login") + return fmt.Errorf("unable to determine valid configuration") + } + + if authType == "oauth" { + log.Debug().Msg("attempting to authenticate via OAuth") + aErr := kfcOAuth.Authenticate() + if aErr != nil { + log.Error().Err(aErr) + return aErr + } + } else if authType == "basic" { + log.Debug().Msg("attempting to authenticate via Basic Auth") + aErr := kfcBasicAuth.Authenticate() + if aErr != nil { + log.Error().Err(aErr) + //outputError(aErr, true, outputFormat) + return aErr + } + } + + log.Info(). + Str("profile", profile). + Str("configFile", configFile). + Str("host", outputServer.Host). + Str("authType", authType). + Msg("Login successful") + outputResult(fmt.Sprintf("Login successful to %s", outputServer.Host), outputFormat) return nil }, PostRun: nil, @@ -228,30 +285,39 @@ func init() { RootCmd.AddCommand(loginCmd) } -func validConfig(hostname string, username string, password string, domain string) bool { - if hostname == "" || username == "" || password == "" { - return false - } - if domain == "" && (!strings.Contains(username, "@") || !strings.Contains(username, "\\")) { - return false +func writeConfigFile(configFile *auth_providers.Config, configPath string) error { + existingConfig, exErr := auth_providers.ReadConfigFromJSON(configPath) + if exErr != nil { + log.Error().Err(exErr) + wErr := auth_providers.WriteConfigToJSON(configPath, configFile) + if wErr != nil { + log.Error().Err(wErr) + return wErr + } + log.Info().Str("configPath", configPath).Msg("Configuration file written") + return nil } - return true -} -func validConfigFileEntry(configFile ConfigurationFile, profile string) bool { - if profile == "" { - profile = "default" + // Compare the existing config with the new config + if cmp.Equal(existingConfig, configFile) { + log.Info().Msg("Configuration file unchanged") + return nil } - if configFile.Servers[profile].Hostname == "" || configFile.Servers[profile].Username == "" || configFile.Servers[profile].Password == "" { - return false + + // Merge the existing config with the new config + mergedConfig, mErr := auth_providers.MergeConfigFromFile(configPath, configFile) + if mErr != nil { + log.Error().Err(mErr) + return mErr } - if configFile.Servers[profile].Domain == "" && (!strings.Contains( - configFile.Servers[profile].Username, - "@", - ) || !strings.Contains(configFile.Servers[profile].Username, "\\")) { - return false + wErr := auth_providers.WriteConfigToJSON(configPath, mergedConfig) + if wErr != nil { + log.Error().Err(wErr) + return wErr } - return true + log.Info().Str("configPath", configPath).Msg("Configuration file updated") + return nil + } func getDomainFromUsername(username string) string { @@ -309,16 +375,37 @@ func promptForInteractivePassword(parameterName string, defaultValue string) str if defaultValue != "" { passwordFill = "********" } - //log.Println("[DEBUG] kfcPassword: " + defaultValue) - fmt.Printf("Enter %s [%s]: \n", parameterName, passwordFill) - bytePassword, _ := terminal.ReadPassword(int(syscall.Stdin)) - // check if bytePassword is empty if so the return the default value - if len(bytePassword) == 0 { + fmt.Printf("Enter %s [%s]: ", parameterName, passwordFill) + + var password string + + // Check if we're in a terminal environment + if term.IsTerminal(int(os.Stdin.Fd())) { + // Terminal mode: read password securely + bytePassword, err := term.ReadPassword(int(os.Stdin.Fd())) + fmt.Println("") // for newline after password input + if err != nil { + fmt.Println("\nError reading password:", err) + return defaultValue + } + password = string(bytePassword) + } else { + // Non-terminal mode: read password as plain text + reader := bufio.NewReader(os.Stdin) + input, err := reader.ReadString('\n') + if err != nil { + fmt.Println("\nError reading password:", err) + return defaultValue + } + password = input + } + + // Trim newline and check if password is empty; if so, return default + password = password[:len(password)-1] + if password == "" { return defaultValue } - password := string(bytePassword) - fmt.Println("") return password } @@ -355,49 +442,101 @@ func saveConfigFile(configFile ConfigurationFile, configPath string, profileName } func authInteractive( - hostname string, - username string, - password string, - domain string, - apiPath string, + serverConf *auth_providers.Server, profileName string, forcePrompt bool, saveConfig bool, configPath string, -) (ConfigurationFile, error) { - if hostname == "" || forcePrompt { - hostname = promptForInteractiveParameter("Keyfactor Command kfcHostName", hostname) +) (auth_providers.Config, error) { + if serverConf == nil { + serverConf = &auth_providers.Server{} } - if username == "" || forcePrompt { - username = promptForInteractiveParameter("Keyfactor Command kfcUsername", username) + + if serverConf.Host == "" || forcePrompt { + serverConf.Host = promptForInteractiveParameter("Keyfactor Command HostName", serverConf.Host) } - if password == "" || forcePrompt { - password = promptForInteractivePassword("Keyfactor Command kfcPassword", password) + if serverConf.AuthType == "" || forcePrompt { + for { + serverConf.AuthType = promptForInteractiveParameter( + "Keyfactor Command AuthType [basic,oauth]", + serverConf.AuthType, + ) + if serverConf.AuthType == "oauth" || serverConf.AuthType == "basic" { + break + } else { + fmt.Println("Invalid auth type. Valid auth types are: oauth, basic") + } + } } - if domain == "" || forcePrompt { - domain = getDomainFromUsername(username) - if domain == "" { - domain = promptForInteractiveParameter("Keyfactor Command AD kfcDomain", domain) + if serverConf.AuthType == "basic" { + if serverConf.Username == "" || forcePrompt { + serverConf.Username = promptForInteractiveParameter("Keyfactor Command Username", serverConf.Username) + } + if serverConf.Password == "" || forcePrompt { + serverConf.Password = promptForInteractivePassword("Keyfactor Command Password", serverConf.Password) + } + if serverConf.Domain == "" || forcePrompt { + userDomain := getDomainFromUsername(serverConf.Username) + if userDomain == "" { + serverConf.Domain = promptForInteractiveParameter("Keyfactor Command AD Domain", serverConf.Domain) + } else { + serverConf.Domain = userDomain + } + } + } else if serverConf.AuthType == "oauth" { + if serverConf.ClientID == "" || forcePrompt { + serverConf.ClientID = promptForInteractiveParameter( + "Keyfactor Command OAuth Client ID", + serverConf.ClientID, + ) + } + if serverConf.ClientSecret == "" || forcePrompt { + serverConf.ClientSecret = promptForInteractivePassword( + "Keyfactor Command OAuth Client Secret", + serverConf.ClientSecret, + ) + } + if serverConf.OAuthTokenUrl == "" || forcePrompt { + serverConf.OAuthTokenUrl = promptForInteractiveParameter( + "Keyfactor Command OAuth Token URL", + serverConf.OAuthTokenUrl, + ) } } - if apiPath == "" || forcePrompt { - apiPath = promptForInteractiveParameter("Keyfactor Command API path", apiPath) + + if serverConf.APIPath == "" || forcePrompt { + serverConf.APIPath = promptForInteractiveParameter("Keyfactor Command API path", serverConf.APIPath) + } + + if serverConf.CACertPath == "" || forcePrompt { + serverConf.CACertPath = promptForInteractiveParameter("Keyfactor Command CA Cert Path", serverConf.CACertPath) } if profileName == "" { profileName = "default" } + if configPath == "" { + userHomeDir, hErr := prepHomeDir() + if hErr != nil { + //log.Println("[ERROR] Unable to create home directory: ", hErr) + log.Error().Err(hErr) + return auth_providers.Config{}, hErr + } + configPath = path.Join(userHomeDir, DefaultConfigFileName) + } - confFile := createConfigFile(hostname, username, password, domain, apiPath, profileName) + confFile := auth_providers.Config{ + Servers: map[string]auth_providers.Server{}, + } + confFile.Servers[profileName] = *serverConf if saveConfig { - savedConfigFile, saveErr := saveConfigFile(confFile, configPath, profileName) + saveErr := writeConfigFile(&confFile, configPath) if saveErr != nil { //log.Println("[ERROR] Unable to save configuration file to disk: ", saveErr) log.Error().Err(saveErr) return confFile, saveErr } - return savedConfigFile, nil } return confFile, nil } @@ -704,7 +843,7 @@ func authViaProviderParams(providerConfig *AuthProvider) (ConfigurationFile, err func validAuthProvider(providerType string) bool { log.Debug().Str("providerType", providerType).Msg("validAuthProvider() called") if providerType == "" { - return true // default to kfcUsername/kfcPassword + return true // default to Username/Password } for _, validProvider := range ValidAuthProviders { if validProvider == providerType { diff --git a/cmd/login_test.go b/cmd/login_test.go index 6fda933..658baf5 100644 --- a/cmd/login_test.go +++ b/cmd/login_test.go @@ -17,12 +17,15 @@ package cmd import ( "encoding/json" "fmt" - "github.com/joho/godotenv" - "github.com/stretchr/testify/assert" "os" - "os/user" + "path" "path/filepath" + "strings" "testing" + + "github.com/Keyfactor/keyfactor-auth-client-go/auth_providers" + "github.com/joho/godotenv" + "github.com/stretchr/testify/assert" ) func Test_LoginHelpCmd(t *testing.T) { @@ -50,27 +53,24 @@ func Test_LoginHelpCmd(t *testing.T) { } func Test_LoginCmdNoPrompt(t *testing.T) { - // Get the current user's information - currentUser, err := user.Current() - if err != nil { - fmt.Println("Error:", err) - return - } + homeDir, _ := os.UserHomeDir() // Define the path to the file in the user's home directory - filePath := filepath.Join(currentUser.HomeDir, ".keyfactor/command_config.json") - testEnvCredsOnly(t, filePath, false) - testLoginNoPrompt(t, filePath) + configFilePath := filepath.Join(homeDir, auth_providers.DefaultConfigFilePath) + testEnvCredsOnly(t, configFilePath, false) + testLoginNoPrompt(t, configFilePath) } func Test_LoginCmdConfigParams(t *testing.T) { testCmd := RootCmd // test testCmd.SetArgs([]string{"stores", "list", "--exp", "--config", "$HOME/.keyfactor/extra_config.json"}) - output := captureOutput(func() { - err := testCmd.Execute() - assert.NoError(t, err) - }) + output := captureOutput( + func() { + err := testCmd.Execute() + assert.NoError(t, err) + }, + ) t.Logf("output: %s", output) var stores []string if err := json.Unmarshal([]byte(output), &stores); err != nil { @@ -81,35 +81,48 @@ func Test_LoginCmdConfigParams(t *testing.T) { assert.True(t, len(stores) >= 0, "Expected non-empty list of stores") } -func testLogout(t *testing.T) { - t.Run(fmt.Sprintf("Logout"), func(t *testing.T) { - testCmd := RootCmd - // test - testCmd.SetArgs([]string{"logout"}) - output := captureOutput(func() { - err := testCmd.Execute() - assert.NoError(t, err) - }) - t.Logf("output: %s", output) - - assert.Contains(t, output, "Logged out successfully!") - - // Get the current user's information - currentUser, err := user.Current() - if err != nil { - fmt.Println("Error:", err) - return - } +func testLogout(t *testing.T, configFilePath string, restoreConfig bool) { + t.Run( + fmt.Sprintf("Logout"), func(t *testing.T) { + testCmd := RootCmd + //store current config in memory + if restoreConfig { + homeDir, _ := os.UserHomeDir() + configFilePath := path.Join(homeDir, auth_providers.DefaultConfigFilePath) + existingConfig, exErr := auth_providers.ReadConfigFromJSON(configFilePath) + defer func() { + //restore config file + if existingConfig != nil { + wErr := auth_providers.WriteConfigToJSON(configFilePath, existingConfig) + if wErr != nil { + t.Errorf("Error writing existing config: %s", wErr) + t.FailNow() + } + } + }() + if exErr != nil { + t.Errorf("Error reading existing config: %s", exErr) + t.FailNow() + } + } + testCmd.SetArgs([]string{"logout"}) + output := captureOutput( + func() { + err := testCmd.Execute() + assert.NoError(t, err) + }, + ) + t.Logf("output: %s", output) - // Define the path to the file in the user's home directory - filePath := filepath.Join(currentUser.HomeDir, ".keyfactor/command_config.json") - _, err = os.Stat(filePath) + assert.Contains(t, output, "Logged out successfully!") - // Test that the config file does not exist - if _, fErr := os.Stat(filePath); !os.IsNotExist(fErr) { - t.Errorf("Config file %s still exists, please remove", filePath) - } - }) + // Test that the config file does not exist + if _, fErr := os.Stat(configFile); !os.IsNotExist(fErr) { + t.Errorf("Config file %s still exists, please remove", configFilePath) + t.FailNow() + } + }, + ) } @@ -120,26 +133,36 @@ func testConfigValid(t *testing.T) { //t.Logf("envUsername: %s", envUsername) //t.Logf("envPassword: %s", envPassword) t.Logf("Attempting to run `store-types list`") - t.Run(fmt.Sprintf("List store types"), func(t *testing.T) { - testCmd := RootCmd - t.Log("Setting args") - testCmd.SetArgs([]string{"store-types", "list"}) - t.Logf("args: %v", testCmd.Args) - t.Log("Capturing output") - output := captureOutput(func() { - tErr := testCmd.Execute() - assert.NoError(t, tErr) - }) - t.Logf("output: %s", output) - - var storeTypes []map[string]interface{} - if err := json.Unmarshal([]byte(output), &storeTypes); err != nil { - t.Fatalf("Error unmarshalling JSON: %v", err) - } + t.Run( + fmt.Sprintf("List store types"), func(t *testing.T) { + skipVerify := os.Getenv(auth_providers.EnvKeyfactorSkipVerify) + t.Logf("skipVerify: %s", skipVerify) + testCmd := RootCmd + t.Log("Setting args") + testCmd.SetArgs([]string{"store-types", "list"}) + t.Logf("args: %v", testCmd.Args) + t.Log("Capturing output") + output := captureOutput( + func() { + tErr := testCmd.Execute() + assert.NoError(t, tErr) + if tErr != nil { + t.Errorf("Error running command: %s", tErr) + t.FailNow() + } + }, + ) + t.Logf("output: %s", output) - // Verify that the length of the response is greater than 0 - assert.True(t, len(storeTypes) >= 0, "Expected non-empty list of store types") - }) + var storeTypes []map[string]interface{} + if err := json.Unmarshal([]byte(output), &storeTypes); err != nil { + t.Fatalf("Error unmarshalling JSON: %v", err) + } + + // Verify that the length of the response is greater than 0 + assert.True(t, len(storeTypes) >= 0, "Expected non-empty list of store types") + }, + ) } func testConfigExists(t *testing.T, filePath string, allowExist bool) { @@ -149,77 +172,255 @@ func testConfigExists(t *testing.T, filePath string, allowExist bool) { } else { testName = "Config file does not exist" } - t.Run(fmt.Sprintf(testName), func(t *testing.T) { - _, fErr := os.Stat(filePath) - if allowExist { - assert.True(t, allowExist && fErr == nil) - // Load the config file from JSON to map[string]interface{} - fileConfigJSON := make(map[string]interface{}) - file, _ := os.Open(filePath) - defer file.Close() - decoder := json.NewDecoder(file) - err := decoder.Decode(&fileConfigJSON) + t.Run( + fmt.Sprintf(testName), func(t *testing.T) { + _, fErr := os.Stat(filePath) + if allowExist { + assert.True(t, allowExist && fErr == nil) + // Load the config file from JSON to map[string]interface{} + fileConfigJSON := make(map[string]interface{}) + file, _ := os.Open(filePath) + defer file.Close() + decoder := json.NewDecoder(file) + err := decoder.Decode(&fileConfigJSON) + if err != nil { + t.Errorf("Error decoding config file: %s", err) + } + // Verify that the config file has the correct keys + assert.Contains(t, fileConfigJSON, "servers") + kfcServers, ok := fileConfigJSON["servers"].(map[string]interface{}) + if !ok { + t.Errorf("Error decoding config file: %s", err) + assert.False(t, ok, "Error decoding config file") + return + } + assert.Contains(t, kfcServers, "default") + defaultServer := kfcServers["default"].(map[string]interface{}) + assert.Contains(t, defaultServer, "host") + confUsername, uOk := defaultServer["username"] + confPassword, pOk := defaultServer["password"] + confDomain, _ := defaultServer["domain"] + confClientID, cOk := defaultServer["client_id"] + confClientSecret, sOk := defaultServer["client_secret"] + confTokenUrl, tOk := defaultServer["token_url"] + t.Logf("confUsername: %s", confUsername) + t.Logf("confPassword: %s", hashSecretValue(fmt.Sprintf("%v", confPassword))) + t.Logf("confDomain: %s", confDomain) + t.Logf("confClientID: %s", confClientID) + t.Logf("confClientSecret: %s", hashSecretValue(fmt.Sprintf("%v", confClientSecret))) + t.Logf("confTokenUrl: %s", confTokenUrl) + + if (uOk && pOk) || (cOk && sOk && tOk) { + assert.True(t, uOk && pOk || cOk && sOk && tOk) + } else { + t.Errorf("Config file does not contain valid credentials") + } + } else { + assert.True(t, !allowExist && os.IsNotExist(fErr)) + } + }, + ) +} + +func testEnvCredsOnly(t *testing.T, configFilePath string, allowExist bool) { + t.Run( + fmt.Sprintf("Auth w/ env ONLY"), func(t *testing.T) { + envUsername, envPassword, envDomain := exportBasicEnvVariables() + envClientId, envClientSecret, envTokenUrl := exportOAuthEnvVariables() + os.Setenv(auth_providers.EnvKeyfactorSkipVerify, "true") + if (envUsername == "" || envPassword == "" || envDomain == "") && (envClientId == "" || envClientSecret == "" || envTokenUrl == "") { + t.Errorf("Environment variables are not set") + t.FailNow() + } + if configFilePath == "" { + homeDir, _ := os.UserHomeDir() + configFilePath = path.Join(homeDir, auth_providers.DefaultConfigFilePath) + } + + existingConfig, exErr := auth_providers.ReadConfigFromJSON(configFilePath) + if exErr != nil { + t.Errorf("Error reading existing config: %s", exErr) + t.FailNow() + } + defer func() { + //restore config file + if existingConfig != nil { + wErr := auth_providers.WriteConfigToJSON(configFilePath, existingConfig) + if wErr != nil { + t.Errorf("Error writing existing config: %s", wErr) + t.FailNow() + } + } + }() + testLogout(t, configFilePath, false) + testConfigExists(t, configFilePath, false) + testConfigValid(t) + }, + ) +} + +func testEnvCredsToFile(t *testing.T, filePath string, allowExist bool) { + t.Run( + fmt.Sprintf("Auth w/ env ONLY"), func(t *testing.T) { + // Load .env file + err := godotenv.Load("../.env_1040") if err != nil { - t.Errorf("Error decoding config file: %s", err) + t.Errorf("Error loading .env file") } - // Verify that the config file has the correct keys - assert.Contains(t, fileConfigJSON, "servers") - kfcServers, ok := fileConfigJSON["servers"].(map[string]interface{}) - if !ok { - t.Errorf("Error decoding config file: %s", err) - assert.False(t, ok, "Error decoding config file") - return + testLogout(t, filePath, false) + testConfigExists(t, filePath, false) + testConfigValid(t) + }, + ) +} + +func testLoginNoPrompt(t *testing.T, configFilePath string) { + // Test logging in w/o args and w/o prompt + username, password, domain := exportBasicEnvVariables() + clientId, clientSecret, tokenUrl := exportOAuthEnvVariables() + envUsername, envPassword, envDomain := exportBasicEnvVariables() + envClientId, envClientSecret, envTokenUrl := exportOAuthEnvVariables() + os.Setenv(auth_providers.EnvKeyfactorSkipVerify, "true") + if (envUsername == "" || envPassword == "" || envDomain == "") && (envClientId == "" || envClientSecret == "" || envTokenUrl == "") { + t.Errorf("Environment variables are not set") + t.FailNow() + } + if configFilePath == "" { + homeDir, _ := os.UserHomeDir() + configFilePath = path.Join(homeDir, auth_providers.DefaultConfigFilePath) + } + existingConfig, exErr := auth_providers.ReadConfigFromJSON(configFilePath) + if exErr != nil { + t.Errorf("Error reading existing config: %s", exErr) + t.FailNow() + } + defer func() { + //restore config file + if existingConfig != nil { + wErr := auth_providers.WriteConfigToJSON(configFilePath, existingConfig) + if wErr != nil { + t.Errorf("Error writing existing config: %s", wErr) + t.FailNow() } - assert.Contains(t, kfcServers, "default") - defaultServer := kfcServers["default"].(map[string]interface{}) - assert.Contains(t, defaultServer, "host") - assert.Contains(t, defaultServer, "kfcUsername") - assert.Contains(t, defaultServer, "kfcPassword") - } else { - assert.True(t, !allowExist && os.IsNotExist(fErr)) } - }) + }() + t.Run( + fmt.Sprintf("login no prompt from file"), func(t *testing.T) { + unsetOAuthEnvVariables() + unsetBasicEnvVariables() + defer setOAuthEnvVariables(clientId, clientSecret, tokenUrl) + defer setBasicEnvVariables(username, password, domain) + + npfCmd := RootCmd + npfCmd.SetArgs([]string{"login", "--no-prompt"}) + + output := captureOutput( + func() { + noPromptErr := npfCmd.Execute() + if noPromptErr != nil { + t.Errorf("RootCmd() = %v, should pass %v", noPromptErr, true) + t.FailNow() + } + }, + ) + t.Logf("output: %s", output) + assert.Contains(t, output, "Login successful to") + testConfigExists(t, configFilePath, true) + testConfigValid(t) + //testLogout(t) + }, + ) + t.Run( + fmt.Sprintf("login no prompt from env"), func(t *testing.T) { + testLogout(t, configFilePath, false) + + setOAuthEnvVariables(clientId, clientSecret, tokenUrl) + setBasicEnvVariables(username, password, domain) + npeCmd := RootCmd + npeCmd.SetArgs([]string{"login", " --no-prompt"}) + output := captureOutput( + func() { + noPromptErr := npeCmd.Execute() + if noPromptErr != nil { + t.Errorf("RootCmd() = %v, should pass %v", noPromptErr, true) + t.FailNow() + } + }, + ) + t.Logf("output: %s", output) + assert.Contains(t, output, "Login successful via environment variables") + testConfigExists(t, configFilePath, true) + testConfigValid(t) + //testLogout(t) + }, + ) } -func testEnvCredsOnly(t *testing.T, filePath string, allowExist bool) { - t.Run(fmt.Sprintf("Auth w/ env ONLY"), func(t *testing.T) { - // Load .env file - err := godotenv.Load("../.env_1040") - if err != nil { - t.Errorf("Error loading .env file") - } - testLogout(t) - testConfigExists(t, filePath, false) - testConfigValid(t) - }) +// setOAuthEnvVariables sets the oAuth environment variables +func setOAuthEnvVariables(clientId, clientSecret, tokenUrl string) { + os.Setenv(auth_providers.EnvKeyfactorClientID, clientId) + os.Setenv(auth_providers.EnvKeyfactorClientSecret, clientSecret) + os.Setenv(auth_providers.EnvKeyfactorAuthTokenURL, tokenUrl) } -func testEnvCredsToFile(t *testing.T, filePath string, allowExist bool) { - t.Run(fmt.Sprintf("Auth w/ env ONLY"), func(t *testing.T) { - // Load .env file - err := godotenv.Load("../.env_1040") - if err != nil { - t.Errorf("Error loading .env file") +func exportEnvVarsWithPrefix(prefix string) map[string]string { + result := make(map[string]string) + for _, env := range os.Environ() { + // Each environment variable is in the format "KEY=VALUE" + pair := strings.SplitN(env, "=", 2) + key := pair[0] + value := pair[1] + + if strings.HasPrefix(key, prefix) { + result[key] = value } - testLogout(t) - testConfigExists(t, filePath, false) - testConfigValid(t) - }) + } + return result } -func testLoginNoPrompt(t *testing.T, filePath string) { - // Test logging in w/o args and w/o prompt - t.Run(fmt.Sprintf("login no prompt"), func(t *testing.T) { - testCmd := RootCmd - testCmd.SetArgs([]string{"login", "--no-prompt"}) - noPromptErr := testCmd.Execute() - if noPromptErr != nil { - t.Errorf("RootCmd() = %v, shouldNotPass %v", noPromptErr, true) - } - testConfigExists(t, filePath, true) - os.Unsetenv("KEYFACTOR_USERNAME") - os.Unsetenv("KEYFACTOR_PASSWORD") - testConfigValid(t) - //testLogout(t) - }) +// exportOAuthEnvVariables sets the oAuth environment variables +func exportOAuthEnvVariables() (string, string, string) { + clientId := os.Getenv(auth_providers.EnvKeyfactorClientID) + clientSecret := os.Getenv(auth_providers.EnvKeyfactorClientSecret) + tokenUrl := os.Getenv(auth_providers.EnvKeyfactorAuthTokenURL) + return clientId, clientSecret, tokenUrl +} + +// unsetOAuthEnvVariables unsets the oAuth environment variables +func unsetOAuthEnvVariables() { + os.Unsetenv(auth_providers.EnvKeyfactorClientID) + os.Unsetenv(auth_providers.EnvKeyfactorClientSecret) + os.Unsetenv(auth_providers.EnvKeyfactorAuthTokenURL) + //os.Unsetenv(auth_providers.EnvKeyfactorSkipVerify) + //os.Unsetenv(auth_providers.EnvKeyfactorConfigFile) + //os.Unsetenv(auth_providers.EnvKeyfactorAuthProfile) + //os.Unsetenv(auth_providers.EnvKeyfactorCACert) + //os.Unsetenv(auth_providers.EnvAuthCACert) + //os.Unsetenv(auth_providers.EnvKeyfactorHostName) + //os.Unsetenv(auth_providers.EnvKeyfactorUsername) + //os.Unsetenv(auth_providers.EnvKeyfactorPassword) + //os.Unsetenv(auth_providers.EnvKeyfactorDomain) + +} + +// setBasicEnvVariables sets the basic environment variables +func setBasicEnvVariables(username, password, domain string) { + os.Setenv(auth_providers.EnvKeyfactorUsername, username) + os.Setenv(auth_providers.EnvKeyfactorPassword, password) + os.Setenv(auth_providers.EnvKeyfactorDomain, domain) +} + +// exportBasicEnvVariables sets the basic environment variables +func exportBasicEnvVariables() (string, string, string) { + username := os.Getenv(auth_providers.EnvKeyfactorUsername) + password := os.Getenv(auth_providers.EnvKeyfactorPassword) + domain := os.Getenv(auth_providers.EnvKeyfactorDomain) + return username, password, domain +} + +// unsetBasicEnvVariables unsets the basic environment variables +func unsetBasicEnvVariables() { + os.Unsetenv(auth_providers.EnvKeyfactorUsername) + os.Unsetenv(auth_providers.EnvKeyfactorPassword) + os.Unsetenv(auth_providers.EnvKeyfactorDomain) } diff --git a/cmd/root.go b/cmd/root.go index 96b1a19..c5d7e53 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -678,6 +678,31 @@ func init() { "", "Username to use for authenticating to Keyfactor Command.", ) + + RootCmd.PersistentFlags().StringVarP( + &kfcClientId, + "client-id", + "", + "", + "OAuth2 client-id to use for authenticating to Keyfactor Command.", + ) + + RootCmd.PersistentFlags().StringVarP( + &kfcClientSecret, + "client-secret", + "", + "", + "OAuth2 client-secret to use for authenticating to Keyfactor Command.", + ) + + RootCmd.PersistentFlags().StringVarP( + &kfcClientId, + "token-url", + "", + "", + "OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command.", + ) + RootCmd.PersistentFlags().StringVarP( &kfcHostName, "hostname", diff --git a/cmd/storeTypes.go b/cmd/storeTypes.go index c7af55a..068e7ca 100644 --- a/cmd/storeTypes.go +++ b/cmd/storeTypes.go @@ -58,7 +58,11 @@ var storesTypesListCmd = &cobra.Command{ informDebug(debugFlag) // Authenticate - kfClient, _ := initClient(false) + kfClient, cErr := initClient(false) + if cErr != nil { + log.Error().Err(cErr).Msg("unable to authenticate") + return cErr + } // CLI Logic diff --git a/docs/kfutil.md b/docs/kfutil.md index 4f93efa..1644a76 100644 --- a/docs/kfutil.md +++ b/docs/kfutil.md @@ -12,6 +12,8 @@ A CLI wrapper around the Keyfactor Platform API. --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -24,6 +26,7 @@ A CLI wrapper around the Keyfactor Platform API. --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -43,4 +46,4 @@ A CLI wrapper around the Keyfactor Platform API. * [kfutil stores](kfutil_stores.md) - Keyfactor certificate stores APIs and utilities. * [kfutil version](kfutil_version.md) - Shows version of kfutil -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_completion.md b/docs/kfutil_completion.md index c334bf6..8121f78 100644 --- a/docs/kfutil_completion.md +++ b/docs/kfutil_completion.md @@ -20,6 +20,8 @@ See each sub-command's help for details on how to use the generated script. --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -31,6 +33,7 @@ See each sub-command's help for details on how to use the generated script. --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -42,4 +45,4 @@ See each sub-command's help for details on how to use the generated script. * [kfutil completion powershell](kfutil_completion_powershell.md) - Generate the autocompletion script for powershell * [kfutil completion zsh](kfutil_completion_zsh.md) - Generate the autocompletion script for zsh -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_completion_bash.md b/docs/kfutil_completion_bash.md index 859cfbe..7f3da87 100644 --- a/docs/kfutil_completion_bash.md +++ b/docs/kfutil_completion_bash.md @@ -43,6 +43,8 @@ kfutil completion bash --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -54,6 +56,7 @@ kfutil completion bash --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -61,4 +64,4 @@ kfutil completion bash * [kfutil completion](kfutil_completion.md) - Generate the autocompletion script for the specified shell -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_completion_fish.md b/docs/kfutil_completion_fish.md index a5bea76..bd17588 100644 --- a/docs/kfutil_completion_fish.md +++ b/docs/kfutil_completion_fish.md @@ -34,6 +34,8 @@ kfutil completion fish [flags] --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -45,6 +47,7 @@ kfutil completion fish [flags] --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -52,4 +55,4 @@ kfutil completion fish [flags] * [kfutil completion](kfutil_completion.md) - Generate the autocompletion script for the specified shell -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_completion_powershell.md b/docs/kfutil_completion_powershell.md index 232cd60..e9d0fe2 100644 --- a/docs/kfutil_completion_powershell.md +++ b/docs/kfutil_completion_powershell.md @@ -31,6 +31,8 @@ kfutil completion powershell [flags] --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -42,6 +44,7 @@ kfutil completion powershell [flags] --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -49,4 +52,4 @@ kfutil completion powershell [flags] * [kfutil completion](kfutil_completion.md) - Generate the autocompletion script for the specified shell -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_completion_zsh.md b/docs/kfutil_completion_zsh.md index 01c4f8a..503bbd5 100644 --- a/docs/kfutil_completion_zsh.md +++ b/docs/kfutil_completion_zsh.md @@ -45,6 +45,8 @@ kfutil completion zsh [flags] --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -56,6 +58,7 @@ kfutil completion zsh [flags] --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -63,4 +66,4 @@ kfutil completion zsh [flags] * [kfutil completion](kfutil_completion.md) - Generate the autocompletion script for the specified shell -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_containers.md b/docs/kfutil_containers.md index 1c19404..2252311 100644 --- a/docs/kfutil_containers.md +++ b/docs/kfutil_containers.md @@ -18,6 +18,8 @@ A collections of APIs and utilities for interacting with Keyfactor certificate s --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -29,6 +31,7 @@ A collections of APIs and utilities for interacting with Keyfactor certificate s --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -38,4 +41,4 @@ A collections of APIs and utilities for interacting with Keyfactor certificate s * [kfutil containers get](kfutil_containers_get.md) - Get certificate store container by ID or name. * [kfutil containers list](kfutil_containers_list.md) - List certificate store containers. -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_containers_get.md b/docs/kfutil_containers_get.md index 3eac513..80f5b79 100644 --- a/docs/kfutil_containers_get.md +++ b/docs/kfutil_containers_get.md @@ -23,6 +23,8 @@ kfutil containers get [flags] --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -34,6 +36,7 @@ kfutil containers get [flags] --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -41,4 +44,4 @@ kfutil containers get [flags] * [kfutil containers](kfutil_containers.md) - Keyfactor certificate store container API and utilities. -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_containers_list.md b/docs/kfutil_containers_list.md index 0b51479..97c27e1 100644 --- a/docs/kfutil_containers_list.md +++ b/docs/kfutil_containers_list.md @@ -22,6 +22,8 @@ kfutil containers list [flags] --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -33,6 +35,7 @@ kfutil containers list [flags] --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -40,4 +43,4 @@ kfutil containers list [flags] * [kfutil containers](kfutil_containers.md) - Keyfactor certificate store container API and utilities. -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_export.md b/docs/kfutil_export.md index 13a71eb..c7fe906 100644 --- a/docs/kfutil_export.md +++ b/docs/kfutil_export.md @@ -34,6 +34,8 @@ kfutil export [flags] --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -45,6 +47,7 @@ kfutil export [flags] --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -52,4 +55,4 @@ kfutil export [flags] * [kfutil](kfutil.md) - Keyfactor CLI utilities -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_helm.md b/docs/kfutil_helm.md index 7874174..45ea1c9 100644 --- a/docs/kfutil_helm.md +++ b/docs/kfutil_helm.md @@ -24,6 +24,8 @@ kubectl helm uo | helm install -f - keyfactor-universal-orchestrator keyfactor/k --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -35,6 +37,7 @@ kubectl helm uo | helm install -f - keyfactor-universal-orchestrator keyfactor/k --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -43,4 +46,4 @@ kubectl helm uo | helm install -f - keyfactor-universal-orchestrator keyfactor/k * [kfutil](kfutil.md) - Keyfactor CLI utilities * [kfutil helm uo](kfutil_helm_uo.md) - Configure the Keyfactor Universal Orchestrator Helm Chart -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_helm_uo.md b/docs/kfutil_helm_uo.md index eeb4bb4..a4e2326 100644 --- a/docs/kfutil_helm_uo.md +++ b/docs/kfutil_helm_uo.md @@ -29,6 +29,8 @@ kfutil helm uo [-t ] [-o ] [-f ] [-e ] [-o ] [-f ] [-e ] [-o ] [-f ] [-e -e @,@ -o ./app/extension --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) @@ -50,6 +52,7 @@ ext -t -e @,@ -o ./app/extension --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -57,4 +60,4 @@ ext -t -e @,@ -o ./app/extension * [kfutil orchs](kfutil_orchs.md) - Keyfactor agents/orchestrators APIs and utilities. -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_orchs_get.md b/docs/kfutil_orchs_get.md index 3da99b1..b8147aa 100644 --- a/docs/kfutil_orchs_get.md +++ b/docs/kfutil_orchs_get.md @@ -23,6 +23,8 @@ kfutil orchs get [flags] --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -34,6 +36,7 @@ kfutil orchs get [flags] --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -41,4 +44,4 @@ kfutil orchs get [flags] * [kfutil orchs](kfutil_orchs.md) - Keyfactor agents/orchestrators APIs and utilities. -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_orchs_list.md b/docs/kfutil_orchs_list.md index 6c08283..2d1df65 100644 --- a/docs/kfutil_orchs_list.md +++ b/docs/kfutil_orchs_list.md @@ -22,6 +22,8 @@ kfutil orchs list [flags] --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -33,6 +35,7 @@ kfutil orchs list [flags] --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -40,4 +43,4 @@ kfutil orchs list [flags] * [kfutil orchs](kfutil_orchs.md) - Keyfactor agents/orchestrators APIs and utilities. -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_orchs_logs.md b/docs/kfutil_orchs_logs.md index d793da8..122a01e 100644 --- a/docs/kfutil_orchs_logs.md +++ b/docs/kfutil_orchs_logs.md @@ -23,6 +23,8 @@ kfutil orchs logs [flags] --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -34,6 +36,7 @@ kfutil orchs logs [flags] --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -41,4 +44,4 @@ kfutil orchs logs [flags] * [kfutil orchs](kfutil_orchs.md) - Keyfactor agents/orchestrators APIs and utilities. -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_orchs_reset.md b/docs/kfutil_orchs_reset.md index 12020ff..bfd668b 100644 --- a/docs/kfutil_orchs_reset.md +++ b/docs/kfutil_orchs_reset.md @@ -23,6 +23,8 @@ kfutil orchs reset [flags] --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -34,6 +36,7 @@ kfutil orchs reset [flags] --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -41,4 +44,4 @@ kfutil orchs reset [flags] * [kfutil orchs](kfutil_orchs.md) - Keyfactor agents/orchestrators APIs and utilities. -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_pam.md b/docs/kfutil_pam.md index 17d0554..37b2039 100644 --- a/docs/kfutil_pam.md +++ b/docs/kfutil_pam.md @@ -20,6 +20,8 @@ programmatically create, delete, edit, and list PAM Providers. --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -31,6 +33,7 @@ programmatically create, delete, edit, and list PAM Providers. --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -45,4 +48,4 @@ programmatically create, delete, edit, and list PAM Providers. * [kfutil pam types-list](kfutil_pam_types-list.md) - Returns a list of all available PAM provider types. * [kfutil pam update](kfutil_pam_update.md) - Updates an existing PAM Provider, currently only supported from file. -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_pam_create.md b/docs/kfutil_pam_create.md index 092ab86..8d883ff 100644 --- a/docs/kfutil_pam_create.md +++ b/docs/kfutil_pam_create.md @@ -23,6 +23,8 @@ kfutil pam create [flags] --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -34,6 +36,7 @@ kfutil pam create [flags] --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -41,4 +44,4 @@ kfutil pam create [flags] * [kfutil pam](kfutil_pam.md) - Keyfactor PAM Provider APIs. -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_pam_delete.md b/docs/kfutil_pam_delete.md index 895189e..409740f 100644 --- a/docs/kfutil_pam_delete.md +++ b/docs/kfutil_pam_delete.md @@ -23,6 +23,8 @@ kfutil pam delete [flags] --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -34,6 +36,7 @@ kfutil pam delete [flags] --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -41,4 +44,4 @@ kfutil pam delete [flags] * [kfutil pam](kfutil_pam.md) - Keyfactor PAM Provider APIs. -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_pam_get.md b/docs/kfutil_pam_get.md index 3e887b1..1607c36 100644 --- a/docs/kfutil_pam_get.md +++ b/docs/kfutil_pam_get.md @@ -23,6 +23,8 @@ kfutil pam get [flags] --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -34,6 +36,7 @@ kfutil pam get [flags] --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -41,4 +44,4 @@ kfutil pam get [flags] * [kfutil pam](kfutil_pam.md) - Keyfactor PAM Provider APIs. -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_pam_list.md b/docs/kfutil_pam_list.md index 0ba111d..d7118c2 100644 --- a/docs/kfutil_pam_list.md +++ b/docs/kfutil_pam_list.md @@ -22,6 +22,8 @@ kfutil pam list [flags] --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -33,6 +35,7 @@ kfutil pam list [flags] --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -40,4 +43,4 @@ kfutil pam list [flags] * [kfutil pam](kfutil_pam.md) - Keyfactor PAM Provider APIs. -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_pam_types-create.md b/docs/kfutil_pam_types-create.md index f445588..246aa13 100644 --- a/docs/kfutil_pam_types-create.md +++ b/docs/kfutil_pam_types-create.md @@ -30,6 +30,8 @@ kfutil pam types-create [flags] --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -41,6 +43,7 @@ kfutil pam types-create [flags] --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -48,4 +51,4 @@ kfutil pam types-create [flags] * [kfutil pam](kfutil_pam.md) - Keyfactor PAM Provider APIs. -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_pam_types-list.md b/docs/kfutil_pam_types-list.md index 1e17c7f..4e71281 100644 --- a/docs/kfutil_pam_types-list.md +++ b/docs/kfutil_pam_types-list.md @@ -22,6 +22,8 @@ kfutil pam types-list [flags] --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -33,6 +35,7 @@ kfutil pam types-list [flags] --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -40,4 +43,4 @@ kfutil pam types-list [flags] * [kfutil pam](kfutil_pam.md) - Keyfactor PAM Provider APIs. -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_pam_update.md b/docs/kfutil_pam_update.md index 9d17ba5..fb76e01 100644 --- a/docs/kfutil_pam_update.md +++ b/docs/kfutil_pam_update.md @@ -23,6 +23,8 @@ kfutil pam update [flags] --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -34,6 +36,7 @@ kfutil pam update [flags] --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -41,4 +44,4 @@ kfutil pam update [flags] * [kfutil pam](kfutil_pam.md) - Keyfactor PAM Provider APIs. -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_status.md b/docs/kfutil_status.md index fd866f6..ce08c15 100644 --- a/docs/kfutil_status.md +++ b/docs/kfutil_status.md @@ -22,6 +22,8 @@ kfutil status [flags] --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -33,6 +35,7 @@ kfutil status [flags] --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -40,4 +43,4 @@ kfutil status [flags] * [kfutil](kfutil.md) - Keyfactor CLI utilities -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_store-types.md b/docs/kfutil_store-types.md index cada1e9..04756e8 100644 --- a/docs/kfutil_store-types.md +++ b/docs/kfutil_store-types.md @@ -18,6 +18,8 @@ A collections of APIs and utilities for interacting with Keyfactor certificate s --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -29,6 +31,7 @@ A collections of APIs and utilities for interacting with Keyfactor certificate s --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -41,4 +44,4 @@ A collections of APIs and utilities for interacting with Keyfactor certificate s * [kfutil store-types list](kfutil_store-types_list.md) - List certificate store types. * [kfutil store-types templates-fetch](kfutil_store-types_templates-fetch.md) - Fetches store type templates from Keyfactor's Github. -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_store-types_create.md b/docs/kfutil_store-types_create.md index 22b1c67..9f2f511 100644 --- a/docs/kfutil_store-types_create.md +++ b/docs/kfutil_store-types_create.md @@ -27,6 +27,8 @@ kfutil store-types create [flags] --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -38,6 +40,7 @@ kfutil store-types create [flags] --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -45,4 +48,4 @@ kfutil store-types create [flags] * [kfutil store-types](kfutil_store-types.md) - Keyfactor certificate store types APIs and utilities. -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_store-types_delete.md b/docs/kfutil_store-types_delete.md index 673a9d2..8a6016d 100644 --- a/docs/kfutil_store-types_delete.md +++ b/docs/kfutil_store-types_delete.md @@ -26,6 +26,8 @@ kfutil store-types delete [flags] --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -37,6 +39,7 @@ kfutil store-types delete [flags] --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -44,4 +47,4 @@ kfutil store-types delete [flags] * [kfutil store-types](kfutil_store-types.md) - Keyfactor certificate store types APIs and utilities. -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_store-types_get.md b/docs/kfutil_store-types_get.md index 9a8ede9..1347b28 100644 --- a/docs/kfutil_store-types_get.md +++ b/docs/kfutil_store-types_get.md @@ -27,6 +27,8 @@ kfutil store-types get [-i | -n ] [-b --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -38,6 +40,7 @@ kfutil store-types get [-i | -n ] [-b --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -45,4 +48,4 @@ kfutil store-types get [-i | -n ] [-b * [kfutil store-types](kfutil_store-types.md) - Keyfactor certificate store types APIs and utilities. -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_store-types_list.md b/docs/kfutil_store-types_list.md index 40ab223..07eed0a 100644 --- a/docs/kfutil_store-types_list.md +++ b/docs/kfutil_store-types_list.md @@ -22,6 +22,8 @@ kfutil store-types list [flags] --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -33,6 +35,7 @@ kfutil store-types list [flags] --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -40,4 +43,4 @@ kfutil store-types list [flags] * [kfutil store-types](kfutil_store-types.md) - Keyfactor certificate store types APIs and utilities. -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_store-types_templates-fetch.md b/docs/kfutil_store-types_templates-fetch.md index 54a53cc..4beaadd 100644 --- a/docs/kfutil_store-types_templates-fetch.md +++ b/docs/kfutil_store-types_templates-fetch.md @@ -23,6 +23,8 @@ kfutil store-types templates-fetch [flags] --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -34,6 +36,7 @@ kfutil store-types templates-fetch [flags] --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -41,4 +44,4 @@ kfutil store-types templates-fetch [flags] * [kfutil store-types](kfutil_store-types.md) - Keyfactor certificate store types APIs and utilities. -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_stores.md b/docs/kfutil_stores.md index 3da52fe..1f2e2cf 100644 --- a/docs/kfutil_stores.md +++ b/docs/kfutil_stores.md @@ -18,6 +18,8 @@ A collections of APIs and utilities for interacting with Keyfactor certificate s --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -29,6 +31,7 @@ A collections of APIs and utilities for interacting with Keyfactor certificate s --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -42,4 +45,4 @@ A collections of APIs and utilities for interacting with Keyfactor certificate s * [kfutil stores inventory](kfutil_stores_inventory.md) - Commands related to certificate store inventory management * [kfutil stores list](kfutil_stores_list.md) - List certificate stores. -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_stores_delete.md b/docs/kfutil_stores_delete.md index 5e5b0ac..7c17a1b 100644 --- a/docs/kfutil_stores_delete.md +++ b/docs/kfutil_stores_delete.md @@ -25,6 +25,8 @@ kfutil stores delete [flags] --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -36,6 +38,7 @@ kfutil stores delete [flags] --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -43,4 +46,4 @@ kfutil stores delete [flags] * [kfutil stores](kfutil_stores.md) - Keyfactor certificate stores APIs and utilities. -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_stores_export.md b/docs/kfutil_stores_export.md index fa88093..75d2b05 100644 --- a/docs/kfutil_stores_export.md +++ b/docs/kfutil_stores_export.md @@ -26,6 +26,8 @@ kfutil stores export [flags] --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -37,6 +39,7 @@ kfutil stores export [flags] --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -44,4 +47,4 @@ kfutil stores export [flags] * [kfutil stores](kfutil_stores.md) - Keyfactor certificate stores APIs and utilities. -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_stores_get.md b/docs/kfutil_stores_get.md index 5e77298..96cea90 100644 --- a/docs/kfutil_stores_get.md +++ b/docs/kfutil_stores_get.md @@ -23,6 +23,8 @@ kfutil stores get [flags] --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -34,6 +36,7 @@ kfutil stores get [flags] --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -41,4 +44,4 @@ kfutil stores get [flags] * [kfutil stores](kfutil_stores.md) - Keyfactor certificate stores APIs and utilities. -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_stores_import.md b/docs/kfutil_stores_import.md index 808bc07..6858875 100644 --- a/docs/kfutil_stores_import.md +++ b/docs/kfutil_stores_import.md @@ -18,6 +18,8 @@ Tools for generating import templates and importing certificate stores --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -29,6 +31,7 @@ Tools for generating import templates and importing certificate stores --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -38,4 +41,4 @@ Tools for generating import templates and importing certificate stores * [kfutil stores import csv](kfutil_stores_import_csv.md) - Create certificate stores from CSV file. * [kfutil stores import generate-template](kfutil_stores_import_generate-template.md) - For generating a CSV template with headers for bulk store creation. -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_stores_import_csv.md b/docs/kfutil_stores_import_csv.md index 4d54318..c6e2a02 100644 --- a/docs/kfutil_stores_import_csv.md +++ b/docs/kfutil_stores_import_csv.md @@ -30,6 +30,8 @@ kfutil stores import csv --file --store-type-id --store-type-id --store-type-id --store-t --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -39,6 +41,7 @@ kfutil stores import generate-template --store-type-id --store-t --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -46,4 +49,4 @@ kfutil stores import generate-template --store-type-id --store-t * [kfutil stores import](kfutil_stores_import.md) - Import a file with certificate store parameters and create them in keyfactor. -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_stores_inventory.md b/docs/kfutil_stores_inventory.md index 89d0868..b57dd0e 100644 --- a/docs/kfutil_stores_inventory.md +++ b/docs/kfutil_stores_inventory.md @@ -18,6 +18,8 @@ Commands related to certificate store inventory management --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -29,6 +31,7 @@ Commands related to certificate store inventory management --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -39,4 +42,4 @@ Commands related to certificate store inventory management * [kfutil stores inventory remove](kfutil_stores_inventory_remove.md) - Removes a certificate from the certificate store inventory. * [kfutil stores inventory show](kfutil_stores_inventory_show.md) - Show the inventory of a certificate store. -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_stores_inventory_add.md b/docs/kfutil_stores_inventory_add.md index bb282ed..eed7bb6 100644 --- a/docs/kfutil_stores_inventory_add.md +++ b/docs/kfutil_stores_inventory_add.md @@ -36,6 +36,8 @@ kfutil stores inventory add [flags] --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -47,6 +49,7 @@ kfutil stores inventory add [flags] --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -54,4 +57,4 @@ kfutil stores inventory add [flags] * [kfutil stores inventory](kfutil_stores_inventory.md) - Commands related to certificate store inventory management -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_stores_inventory_remove.md b/docs/kfutil_stores_inventory_remove.md index 5771177..ba4a0fa 100644 --- a/docs/kfutil_stores_inventory_remove.md +++ b/docs/kfutil_stores_inventory_remove.md @@ -32,6 +32,8 @@ kfutil stores inventory remove [flags] --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -43,6 +45,7 @@ kfutil stores inventory remove [flags] --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -50,4 +53,4 @@ kfutil stores inventory remove [flags] * [kfutil stores inventory](kfutil_stores_inventory.md) - Commands related to certificate store inventory management -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_stores_inventory_show.md b/docs/kfutil_stores_inventory_show.md index 3d72acd..1dbdd3d 100644 --- a/docs/kfutil_stores_inventory_show.md +++ b/docs/kfutil_stores_inventory_show.md @@ -26,6 +26,8 @@ kfutil stores inventory show [flags] --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -37,6 +39,7 @@ kfutil stores inventory show [flags] --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -44,4 +47,4 @@ kfutil stores inventory show [flags] * [kfutil stores inventory](kfutil_stores_inventory.md) - Commands related to certificate store inventory management -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_stores_list.md b/docs/kfutil_stores_list.md index 68836c2..57fe589 100644 --- a/docs/kfutil_stores_list.md +++ b/docs/kfutil_stores_list.md @@ -22,6 +22,8 @@ kfutil stores list [flags] --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -33,6 +35,7 @@ kfutil stores list [flags] --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -40,4 +43,4 @@ kfutil stores list [flags] * [kfutil stores](kfutil_stores.md) - Keyfactor certificate stores APIs and utilities. -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_version.md b/docs/kfutil_version.md index 93296e4..e50f95a 100644 --- a/docs/kfutil_version.md +++ b/docs/kfutil_version.md @@ -22,6 +22,8 @@ kfutil version [flags] --api-path string API Path to use for authenticating to Keyfactor Command. (default is KeyfactorAPI) (default "KeyfactorAPI") --auth-provider-profile string The profile to use defined in the securely stored config. If not specified the config named 'default' will be used if it exists. (default "default") --auth-provider-type string Provider type choices: (azid) + --client-id string OAuth2 client-id to use for authenticating to Keyfactor Command. + --client-secret string OAuth2 client-secret to use for authenticating to Keyfactor Command. --config string Full path to config file in JSON format. (default is $HOME/.keyfactor/command_config.json) --debug Enable debugFlag logging. --domain string Domain to use for authenticating to Keyfactor Command. @@ -33,6 +35,7 @@ kfutil version [flags] --offline Will not attempt to connect to GitHub for latest release information and resources. --password string Password to use for authenticating to Keyfactor Command. WARNING: Remember to delete your console history if providing kfcPassword here in plain text. --profile string Use a specific profile from your config file. If not specified the config named 'default' will be used if it exists. + --token-url string OAuth2 token endpoint full URL to use for authenticating to Keyfactor Command. --username string Username to use for authenticating to Keyfactor Command. ``` @@ -40,4 +43,4 @@ kfutil version [flags] * [kfutil](kfutil.md) - Keyfactor CLI utilities -###### Auto generated by spf13/cobra on 4-Nov-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/go.mod b/go.mod index 66d1c99..092f499 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 github.com/Jeffail/gabs v1.4.0 - github.com/Keyfactor/keyfactor-auth-client-go v1.0.0-rc.2 + github.com/Keyfactor/keyfactor-auth-client-go v1.0.0-rc.6 github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.0 github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.11 github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 diff --git a/go.sum b/go.sum index 8565933..99162bc 100644 --- a/go.sum +++ b/go.sum @@ -10,8 +10,8 @@ github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mx github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/Jeffail/gabs v1.4.0 h1://5fYRRTq1edjfIrQGvdkcd22pkYUrHZ5YC/H2GJVAo= github.com/Jeffail/gabs v1.4.0/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc= -github.com/Keyfactor/keyfactor-auth-client-go v1.0.0-rc.2 h1:/61pAEjAhTAGtFCvAcp04qEZWV9pMYH5fxADReN2KdU= -github.com/Keyfactor/keyfactor-auth-client-go v1.0.0-rc.2/go.mod h1:UTPLARTONwfc+j1y2SjEa54gbFFCObQucHf3ubQVyDk= +github.com/Keyfactor/keyfactor-auth-client-go v1.0.0-rc.6 h1:DyEYKoQRQGqJuSllK31Lp/2Xcuijp6LGru1adASQaq4= +github.com/Keyfactor/keyfactor-auth-client-go v1.0.0-rc.6/go.mod h1:UTPLARTONwfc+j1y2SjEa54gbFFCObQucHf3ubQVyDk= github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.0 h1:wpiq9UhNxomecw6lhI/EaSWO63HKcuONKq58vsgKmXY= github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.0/go.mod h1:+hmc9YAh4cqlkFe9rHXpQBPssHuoCq/FRYmez5Vrlrg= github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.11 h1:nYc7fEidu26ZKGwEByQNr2EWPCsCs0zxnHUKnRT6/rY= diff --git a/main.go b/main.go index 68cf1d6..15e0228 100644 --- a/main.go +++ b/main.go @@ -16,21 +16,19 @@ package main import ( _ "embed" - "flag" - "os" "github.com/spf13/cobra/doc" "kfutil/cmd" ) func main() { - var docsFlag bool - flag.BoolVar(&docsFlag, "makedocs", false, "Create markdown docs.") - flag.Parse() - if docsFlag { - docs() - os.Exit(0) - } + //var docsFlag bool + //flag.BoolVar(&docsFlag, "makedocs", false, "Create markdown docs.") + //flag.Parse() + //if docsFlag { + // docs() + // os.Exit(0) + //} cmd.Execute() } From 259ba7fa30c6bbfd7c8c8da0c5a9c3d78592fdbf Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Wed, 6 Nov 2024 20:49:17 -0800 Subject: [PATCH 19/19] fix(login): Don't trim input password if no input is provided Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- cmd/login.go | 4 +- cmd/login_test.go | 152 ++++++++++++++++++++-------------------------- 2 files changed, 68 insertions(+), 88 deletions(-) diff --git a/cmd/login.go b/cmd/login.go index 41d0b89..578990e 100644 --- a/cmd/login.go +++ b/cmd/login.go @@ -402,7 +402,9 @@ func promptForInteractivePassword(parameterName string, defaultValue string) str } // Trim newline and check if password is empty; if so, return default - password = password[:len(password)-1] + if len(password) > 0 { + password = password[:len(password)-1] + } if password == "" { return defaultValue } diff --git a/cmd/login_test.go b/cmd/login_test.go index 658baf5..c9dad5d 100644 --- a/cmd/login_test.go +++ b/cmd/login_test.go @@ -52,19 +52,79 @@ func Test_LoginHelpCmd(t *testing.T) { } } -func Test_LoginCmdNoPrompt(t *testing.T) { - +func Test_LoginCmdEnvOnly(t *testing.T) { homeDir, _ := os.UserHomeDir() // Define the path to the file in the user's home directory configFilePath := filepath.Join(homeDir, auth_providers.DefaultConfigFilePath) testEnvCredsOnly(t, configFilePath, false) - testLoginNoPrompt(t, configFilePath) + +} + +func Test_LoginFileNoPrompt(t *testing.T) { + homeDir, _ := os.UserHomeDir() + configFilePath := filepath.Join(homeDir, auth_providers.DefaultConfigFilePath) + // Test logging in w/o args and w/o prompt + username, password, domain := exportBasicEnvVariables() + clientId, clientSecret, tokenUrl := exportOAuthEnvVariables() + envUsername, envPassword, envDomain := exportBasicEnvVariables() + envClientId, envClientSecret, envTokenUrl := exportOAuthEnvVariables() + os.Setenv(auth_providers.EnvKeyfactorSkipVerify, "true") + if (envUsername == "" || envPassword == "" || envDomain == "") && (envClientId == "" || envClientSecret == "" || envTokenUrl == "") { + t.Errorf("Environment variables are not set") + t.FailNow() + } + existingConfig, exErr := auth_providers.ReadConfigFromJSON(configFilePath) + if exErr != nil { + t.Errorf("Error reading existing config: %s", exErr) + t.FailNow() + } + defer func() { + //restore config file + if existingConfig != nil { + wErr := auth_providers.WriteConfigToJSON(configFilePath, existingConfig) + if wErr != nil { + t.Errorf("Error writing existing config: %s", wErr) + t.FailNow() + } + } + }() + t.Run( + fmt.Sprintf("login no prompt from file"), func(t *testing.T) { + unsetOAuthEnvVariables() + unsetBasicEnvVariables() + defer setOAuthEnvVariables(clientId, clientSecret, tokenUrl) + defer setBasicEnvVariables(username, password, domain) + + npfCmd := RootCmd + npfCmd.SetArgs([]string{"login", "--no-prompt"}) + + output := captureOutput( + func() { + noPromptErr := npfCmd.Execute() + if noPromptErr != nil { + t.Errorf(noPromptErr.Error()) + t.FailNow() + } + }, + ) + t.Logf("output: %s", output) + assert.Contains(t, output, "Login successful to") + testConfigExists(t, configFilePath, true) + testConfigValid(t) + //testLogout(t) + }, + ) } func Test_LoginCmdConfigParams(t *testing.T) { testCmd := RootCmd // test - testCmd.SetArgs([]string{"stores", "list", "--exp", "--config", "$HOME/.keyfactor/extra_config.json"}) + testCmd.SetArgs( + []string{ + "stores", "list", "--exp", "--config", "$HOME/.keyfactor/extra_config.json", "--profile", + "oauth", + }, + ) output := captureOutput( func() { err := testCmd.Execute() @@ -72,7 +132,7 @@ func Test_LoginCmdConfigParams(t *testing.T) { }, ) t.Logf("output: %s", output) - var stores []string + var stores []map[string]interface{} if err := json.Unmarshal([]byte(output), &stores); err != nil { t.Fatalf("Error unmarshalling JSON: %v", err) } @@ -274,88 +334,6 @@ func testEnvCredsToFile(t *testing.T, filePath string, allowExist bool) { ) } -func testLoginNoPrompt(t *testing.T, configFilePath string) { - // Test logging in w/o args and w/o prompt - username, password, domain := exportBasicEnvVariables() - clientId, clientSecret, tokenUrl := exportOAuthEnvVariables() - envUsername, envPassword, envDomain := exportBasicEnvVariables() - envClientId, envClientSecret, envTokenUrl := exportOAuthEnvVariables() - os.Setenv(auth_providers.EnvKeyfactorSkipVerify, "true") - if (envUsername == "" || envPassword == "" || envDomain == "") && (envClientId == "" || envClientSecret == "" || envTokenUrl == "") { - t.Errorf("Environment variables are not set") - t.FailNow() - } - if configFilePath == "" { - homeDir, _ := os.UserHomeDir() - configFilePath = path.Join(homeDir, auth_providers.DefaultConfigFilePath) - } - existingConfig, exErr := auth_providers.ReadConfigFromJSON(configFilePath) - if exErr != nil { - t.Errorf("Error reading existing config: %s", exErr) - t.FailNow() - } - defer func() { - //restore config file - if existingConfig != nil { - wErr := auth_providers.WriteConfigToJSON(configFilePath, existingConfig) - if wErr != nil { - t.Errorf("Error writing existing config: %s", wErr) - t.FailNow() - } - } - }() - t.Run( - fmt.Sprintf("login no prompt from file"), func(t *testing.T) { - unsetOAuthEnvVariables() - unsetBasicEnvVariables() - defer setOAuthEnvVariables(clientId, clientSecret, tokenUrl) - defer setBasicEnvVariables(username, password, domain) - - npfCmd := RootCmd - npfCmd.SetArgs([]string{"login", "--no-prompt"}) - - output := captureOutput( - func() { - noPromptErr := npfCmd.Execute() - if noPromptErr != nil { - t.Errorf("RootCmd() = %v, should pass %v", noPromptErr, true) - t.FailNow() - } - }, - ) - t.Logf("output: %s", output) - assert.Contains(t, output, "Login successful to") - testConfigExists(t, configFilePath, true) - testConfigValid(t) - //testLogout(t) - }, - ) - t.Run( - fmt.Sprintf("login no prompt from env"), func(t *testing.T) { - testLogout(t, configFilePath, false) - - setOAuthEnvVariables(clientId, clientSecret, tokenUrl) - setBasicEnvVariables(username, password, domain) - npeCmd := RootCmd - npeCmd.SetArgs([]string{"login", " --no-prompt"}) - output := captureOutput( - func() { - noPromptErr := npeCmd.Execute() - if noPromptErr != nil { - t.Errorf("RootCmd() = %v, should pass %v", noPromptErr, true) - t.FailNow() - } - }, - ) - t.Logf("output: %s", output) - assert.Contains(t, output, "Login successful via environment variables") - testConfigExists(t, configFilePath, true) - testConfigValid(t) - //testLogout(t) - }, - ) -} - // setOAuthEnvVariables sets the oAuth environment variables func setOAuthEnvVariables(clientId, clientSecret, tokenUrl string) { os.Setenv(auth_providers.EnvKeyfactorClientID, clientId)