From 299d1319aa61a69bd73e9a2bf48235ee442da63d Mon Sep 17 00:00:00 2001 From: Sean <1661003+spbsoluble@users.noreply.github.com> Date: Thu, 7 Nov 2024 09:00:44 -0800 Subject: [PATCH 01/49] feat(auth): Add support for OAuth2 client credentials (#224) --- .github/config/.terraform.lock.hcl | 25 + .github/config/MODULE.MD | 57 + .github/config/Makefile | 26 + .github/config/README.md | 107 + .github/config/environments.tf | 96 + .github/config/int1230c_ad.tf | 16 + .github/config/int1230c_oauth.tf | 33 + .github/config/providers.tf | 20 + .github/config/repo.tf | 3 + .github/config/variables.tf | 85 + .github/workflows/container.yml | 332 +-- .../keyfactor-bootstrap-workflow.yml | 420 +-- .github/workflows/tests.yml | 634 ++-- .github/workflows/update-stores.yml | 394 +-- CHANGELOG.md | 6 + README.md | 114 +- cmd/certificates.go | 11 +- cmd/containers.go | 12 +- cmd/export.go | 41 +- cmd/helm_uo.go | 27 +- cmd/helpers.go | 3 + cmd/import.go | 140 +- cmd/inventory.go | 337 ++- cmd/login.go | 723 +++-- cmd/login_test.go | 437 ++- cmd/orchs.go | 59 +- cmd/pam.go | 76 +- cmd/root.go | 710 +++-- cmd/rot.go | 2593 +++++++++-------- cmd/storeTypes.go | 19 +- cmd/storeTypes_get.go | 49 +- cmd/stores.go | 9 +- cmd/storesBulkOperations.go | 162 +- 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 | 6 +- 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 | 16 +- go.sum | 38 +- integration-manifest.json | 3 +- pkg/version/version.go | 2 +- readme_source.md | 92 +- 89 files changed, 5292 insertions(+), 2903 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/int1230c_ad.tf create mode 100644 .github/config/int1230c_oauth.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..4e1d569 --- /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` | `"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 | + +## 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..3a92963 --- /dev/null +++ b/.github/config/README.md @@ -0,0 +1,107 @@ +# 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` | `"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 | + +## 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..52b5bf3 --- /dev/null +++ b/.github/config/environments.tf @@ -0,0 +1,96 @@ +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_CLEAN + 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_CLEAN + 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" { + 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")) +} + + 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/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..3d557a2 --- /dev/null +++ b/.github/config/variables.tf @@ -0,0 +1,85 @@ +// 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" +} + + +// 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/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/tests.yml b/.github/workflows/tests.yml index fddeab9..100807c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -15,24 +15,29 @@ on: 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.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/" + 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 + runs-on: kfutil-runner-set needs: - build steps: @@ -43,19 +48,36 @@ jobs: ### Store Type Tests Test_StoreTypes_KFC_10_5_0: - runs-on: ubuntu-latest + runs-on: kfutil-runner-set needs: - build - kf_10_x_x + environment: "KFC_10_5_0_CLEAN" 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}} + 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 + - 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 @@ -63,232 +85,460 @@ jobs: ### Store Tests Test_Stores_KFC_10_5_0: - runs-on: ubuntu-latest + runs-on: kfutil-runner-set needs: - build - kf_10_x_x - Test_StoreTypes_KFC_10_5_0 + environment: "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}} + 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 + - 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_*" ### PAM Tests Test_PAM_KFC_10_5_0: - runs-on: ubuntu-latest + runs-on: kfutil-runner-set needs: - build - kf_10_x_x - Test_StoreTypes_KFC_10_5_0 + environment: "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}} + 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 + - 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*" - ### 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 + - name: Check out code uses: actions/checkout@v4 + - name: Set up Go uses: actions/setup-go@v5 with: - go-version: "1.21" + 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*" + + # ## 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 11.x.x - kf_11_x_x: - runs-on: ubuntu-latest + ## KFC 12.x.x + kf_12_x_x: + runs-on: kfutil-runner-set needs: - build steps: - - name: Checkout code + - name: Check out 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 }} - steps: - - name: Checkout code - uses: actions/checkout@v4 - - name: Run tests - run: | - unset KFUTIL_DEBUG - go test -v ./cmd -run "^Test_StoreTypes*" + - 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 - ### 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 }} - steps: - - name: Checkout code - uses: actions/checkout@v4 - - name: Run tests - run: go test -v ./cmd -run "^Test_Stores_*" + - 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/" - ### 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 }} - steps: - - name: Checkout code - uses: actions/checkout@v4 - name: Run tests - run: | - unset KFUTIL_DEBUG - go test -v ./cmd -run "^Test_PAM*" + 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*" - ### PAM Tests AKV Auth Provider - Test_AKV_PAM_KFC_11_1_2: - runs-on: self-hosted + Test_StoreTypes_KFC_12_3_0_OAUTH: + runs-on: kfutil-runner-set needs: - - Test_PAM_KFC_11_1_2 + - build + - kf_12_x_x + environment: "KFC_12_3_0_OAUTH_CLEAN" env: - SECRET_NAME: "command-config-1112-az" + 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 + - name: Check out code uses: actions/checkout@v4 + - name: Set up Go uses: actions/setup-go@v5 with: - go-version: "1.21" - - 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*" + 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/" - ## KFC 12.x.x - ### Store Type Tests - Test_StoreTypes_KFC_12_2_0: - runs-on: ubuntu-latest - needs: - - build - - kf_11_x_x - env: - SECRET_NAME: "command-config-1220-clean" - KEYFACTOR_HOSTNAME: "int1220-test-clean.kfdelivery.com" - KEYFACTOR_DOMAIN: "command" - KEYFACTOR_USERNAME: ${{ secrets.LAB_USERNAME }} - KEYFACTOR_PASSWORD: ${{ secrets.LAB_PASSWORD }} - 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_12_2_0: - runs-on: ubuntu-latest + # 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: - build - - kf_11_x_x - - Test_StoreTypes_KFC_12_2_0 + - kf_12_x_x + - Test_StoreTypes_KFC_12_3_0_OAUTH + environment: "KFC_12_3_0_OAUTH" 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}} + 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 + - 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_*" ### PAM Tests - Test_PAM_KFC_12_2_0: - runs-on: ubuntu-latest + # 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 needs: - build - - kf_11_x_x - - Test_StoreTypes_KFC_12_2_0 + - kf_12_x_x + - Test_StoreTypes_KFC_12_3_0_OAUTH + environment: "KFC_12_3_0_OAUTH" 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}} + 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 + - 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 @@ -296,37 +546,86 @@ jobs: ### PAM Tests AKV Auth Provider - Test_AKV_PAM_KFC_12_2_0: + # 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_2_0 + - Test_PAM_KFC_12_3_0_OAUTH + environment: "KFC_12_3_0_OAUTH" env: - SECRET_NAME: "command-config-1220-az" + 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.21" + 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*" - - # Tester Install Script Test_Install_Script: - runs-on: ubuntu-latest + runs-on: kfutil-runner-set steps: - name: Test Quick Install Script run: | @@ -341,28 +640,29 @@ jobs: # Package Tests Test_Kfutil_pkg: - runs-on: ubuntu-latest + 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 + - 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 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 }} 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/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/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..d177845 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(false) agents, aErr := kfClient.GetStoreContainer(id) if aErr != nil { @@ -95,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") @@ -119,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 @@ -144,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 07d0431..e0145c5 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 @@ -136,21 +137,13 @@ var exportCmd = &cobra.Command{ SecurityRoles: []api.CreateSecurityRoleArg{}, } - log.Debug().Msgf("%s: createAuthConfigFromParams", DebugFuncCall) - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) - - 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() @@ -371,8 +364,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 +570,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 +586,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/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/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/import.go b/cmd/import.go index 5004a2e..e9a3bf7 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 { @@ -68,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") @@ -106,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() @@ -194,7 +189,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 +207,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 +226,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 +245,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 +259,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 +327,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 +341,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 +358,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 +390,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 +459,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 +480,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 +498,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 +532,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..28d4404 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 @@ -50,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) @@ -71,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") @@ -133,7 +132,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 +148,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 +167,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, + ) } } @@ -203,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) @@ -237,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") @@ -264,9 +277,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 +289,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 +301,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 +342,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 +360,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 +376,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, + ) } } @@ -370,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) @@ -403,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") @@ -430,9 +466,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 +478,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 +490,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 +532,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 +550,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 +565,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, + ) } } @@ -552,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) @@ -569,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]") @@ -669,42 +724,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..578990e 100644 --- a/cmd/login.go +++ b/cmd/login.go @@ -15,18 +15,21 @@ package cmd import ( + "bufio" "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" + "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/term" ) var loginCmd = &cobra.Command{ @@ -35,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. + +For more information on the environment variables review the docs: https://github.com/Keyfactor/kfutil/tree/main?tab=readme-ov-file#environmental-variables -WARNING: The 'username'' and 'password' will be stored in the config file in plain text at: +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: "", @@ -60,114 +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, @@ -191,27 +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 { @@ -223,7 +329,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 +351,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) @@ -284,16 +375,39 @@ 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 + if len(password) > 0 { + password = password[:len(password)-1] + } + if password == "" { return defaultValue } - password := string(bytePassword) - fmt.Println("") return password } @@ -329,40 +443,102 @@ 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) { - if hostname == "" || forcePrompt { - hostname = promptForInteractiveParameter("Keyfactor Command kfcHostName", hostname) - } - if username == "" || forcePrompt { - username = promptForInteractiveParameter("Keyfactor Command kfcUsername", username) - } - if password == "" || forcePrompt { - password = promptForInteractivePassword("Keyfactor Command kfcPassword", password) +func authInteractive( + serverConf *auth_providers.Server, + profileName string, + forcePrompt bool, + saveConfig bool, + configPath string, +) (auth_providers.Config, error) { + if serverConf == nil { + serverConf = &auth_providers.Server{} + } + + if serverConf.Host == "" || forcePrompt { + serverConf.Host = promptForInteractiveParameter("Keyfactor Command HostName", serverConf.Host) + } + 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 } @@ -397,7 +573,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 +681,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_providers.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 +749,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 +789,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 +799,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,13 +835,17 @@ 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 { 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 { @@ -752,7 +857,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 +904,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 +948,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 +1037,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 +1080,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 +1138,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 +1321,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)) @@ -1202,14 +1344,3 @@ 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, - } - return &output -} diff --git a/cmd/login_test.go b/cmd/login_test.go index 6fda933..c9dad5d 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) { @@ -49,30 +52,87 @@ 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 +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) + +} + +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) - // 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) + 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"}) - output := captureOutput(func() { - err := testCmd.Execute() - assert.NoError(t, err) - }) + testCmd.SetArgs( + []string{ + "stores", "list", "--exp", "--config", "$HOME/.keyfactor/extra_config.json", "--profile", + "oauth", + }, + ) + output := captureOutput( + func() { + err := testCmd.Execute() + assert.NoError(t, err) + }, + ) 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) } @@ -81,35 +141,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 +193,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) + + 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") - }) + // 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 +232,173 @@ 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) - 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 + 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)) } - 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)) - } - }) + }, + ) } -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) - }) +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 loading .env file") - } - testLogout(t) - testConfigExists(t, filePath, false) - testConfigValid(t) - }) + 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, filePath, false) + testConfigExists(t, filePath, false) + testConfigValid(t) + }, + ) } -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) +// 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 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 } - testConfigExists(t, filePath, true) - os.Unsetenv("KEYFACTOR_USERNAME") - os.Unsetenv("KEYFACTOR_PASSWORD") - testConfigValid(t) - //testLogout(t) - }) + } + return result +} + +// 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/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 a356d55..c5d7e53 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -20,9 +20,11 @@ import ( "io" stdlog "log" "os" + "strings" + "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 +37,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,242 +71,508 @@ 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_providers.Server, error) { + var commandConfig *auth_providers.Config + var serverConfig auth_providers.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" + } + 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_providers.ReadConfigFromYAML()") + //commandConfig, cfgReadErr = auth_providers.ReadConfigFromYAML(configFile) + commandConfig, cfgReadErr = auth_providers.ReadConfigFromJSON(configFile) + } else { + log.Debug().Msg("call: auth_providers.ReadConfigFromJSON()") + commandConfig, cfgReadErr = auth_providers.ReadConfigFromJSON(configFile) } - 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 cfgReadErr != nil { + log.Error().Err(cfgReadErr).Msg("unable to read config file") + return nil, fmt.Errorf("unable to read config file: %s", cfgReadErr) + } + + // 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_providers.Server, error) { + log.Debug().Msg("Enter getServerConfigFromEnv()") + + oAuthNoParamsConfig := &auth_providers.CommandConfigOauth{} + basicAuthNoParamsConfig := &auth_providers.CommandAuthConfigBasic{} + + 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()") + basicAuthNoParamsConfig.WithCommandHostName(hostname). + WithCommandAPIPath(apiPath). + WithSkipVerify(skipVerifyBool) + + bErr := basicAuthNoParamsConfig. + WithUsername(username). + WithPassword(password). + WithDomain(domain). + Authenticate() + log.Debug().Msg("complete: basicAuthNoParamsConfig.Authenticate()") + if bErr != nil { + log.Error().Err(bErr).Msg("unable to authenticate with provided credentials") + return nil, bErr } - } 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("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 } + + log.Debug().Msg("return: getServerConfigFromEnv()") + return oAuthNoParamsConfig.GetServerConfig(), nil + } - log.Debug().Str("flagProfile", flagProfile).Send() - if flagProfile == "" { - flagProfile = "default" + log.Error().Msg("unable to authenticate with provided credentials") + return nil, fmt.Errorf("incomplete environment variable configuration") + +} + +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 + } + log.Debug().Msg("call: c.AuthClient.Authenticate()") + authErr := c.AuthClient.Authenticate() + log.Debug().Msg("complete: c.AuthClient.Authenticate()") + if authErr == nil { + return c, nil + } - //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 + } + 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 } - 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 + + } + 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 ( + 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 } - 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 + 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 } - 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 - } + 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 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 } - 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 { + log.Error().Err(authErr).Msg("unable to authenticate via environment variables") + return nil, authErr } - log.Debug().Str("flagProfile", flagProfile).Msg("Setting configEntry") - commandConfig.Servers[flagProfile] = configEntry + 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") +} - 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 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 + ) + + 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 } } - 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") + 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.Debug().Msg("call: api.NewKeyfactorClient()") - c, err := api.NewKeyfactorClient(&clientAuth) - log.Debug().Msg("complete: api.NewKeyfactorClient()") + 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 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.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 *api.AuthConfig, saveConfig bool, ) (*keyfactor.APIClient, error) { - var commandConfig ConfigurationFile + 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()") + + var ( + authenticated bool + c *keyfactor.APIClient + cErr error + ) if providerType != "" { - return authViaProviderGenClient() - } - - commandConfig, _ = authEnvVars(flagConfig, "", saveConfig) - - if flagConfig != "" || !validConfigFileEntry(commandConfig, flagProfile) { - commandConfig, _ = authConfigFile(flagConfig, flagProfile, "", noPrompt, saveConfig) - } - - if flagProfile == "" { - flagProfile = "default" + log.Debug(). + Str("providerType", providerType). + Msg("call: authViaProvider()") + //return authViaProvider() + return nil, fmt.Errorf("provider auth not supported using Keyfactor Command SDK") } - - //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 + log.Debug(). + Msg("providerType is empty attempting to authenticate via params") + + 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 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) + 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 } } - 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) + log.Info().Msg("Keyfactor Command client created") return c, 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", @@ -407,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/rot.go b/cmd/rot.go index 897e65f..2a7478c 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") +// +// +// +// debugModeEnabled := checkDebug(debugFlag) +// log.Println("Debug mode enabled: ", debugModeEnabled) +// var lookupFailures []string +// kfClient, _ := initClient(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") +// +// +// +// debugModeEnabled := checkDebug(debugFlag) +// +// log.Println("Debug mode enabled: ", debugModeEnabled) +// +// var lookupFailures []string +// kfClient, _ := initClient(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") +// +// +// +// 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(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..068e7ca 100644 --- a/cmd/storeTypes.go +++ b/cmd/storeTypes.go @@ -25,8 +25,10 @@ import ( "strings" "time" + stdlog "log" + "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" ) @@ -52,13 +54,18 @@ var storesTypesListCmd = &cobra.Command{ if debugErr != nil { return debugErr } + stdlog.SetOutput(io.Discard) informDebug(debugFlag) // Authenticate - authConfig := createAuthConfigFromParams(kfcHostName, kfcUsername, kfcPassword, kfcDomain, kfcAPIPath) - kfClient, _ := initClient(configFile, profile, providerType, providerProfile, noPrompt, authConfig, false) + kfClient, cErr := initClient(false) + if cErr != nil { + log.Error().Err(cErr).Msg("unable to authenticate") + return cErr + } // CLI Logic + storeTypes, err := kfClient.ListCertificateStoreTypes() if err != nil { @@ -99,8 +106,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 +250,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 74f8c85..e630d11 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 { @@ -98,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") @@ -107,7 +125,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 +159,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 +284,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/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 216ed45..ada8184 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.", @@ -82,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") @@ -107,7 +156,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 +261,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 +283,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 +344,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 ", @@ -319,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 @@ -421,7 +476,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 }, } @@ -456,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(). @@ -504,7 +562,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 +1050,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/docs/kfutil.md b/docs/kfutil.md index c784705..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 8-Sep-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_completion.md b/docs/kfutil_completion.md index 14d566b..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 8-Sep-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 f961da7..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 8-Sep-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 a0d386f..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 8-Sep-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 e96bc99..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 8-Sep-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 98b4917..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 8-Sep-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_containers.md b/docs/kfutil_containers.md index 625c7e5..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 8-Sep-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 fa8c3e0..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 8-Sep-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 465cc19..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 8-Sep-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_export.md b/docs/kfutil_export.md index fb69f13..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 8-Sep-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_helm.md b/docs/kfutil_helm.md index a7c8bf5..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 8-Sep-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 eca60b9..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 8-Sep-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 580fcd5..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 8-Sep-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 5873538..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 8-Sep-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 f65cea8..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 8-Sep-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 b7c5d7e..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 8-Sep-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_pam.md b/docs/kfutil_pam.md index 45a5a4f..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 8-Sep-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 f2446b6..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 8-Sep-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 133f103..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 8-Sep-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 03c66a0..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 8-Sep-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 2e11dfb..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 8-Sep-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 7002cbe..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 8-Sep-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 6354470..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 8-Sep-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 abb7db5..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 8-Sep-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_status.md b/docs/kfutil_status.md index 8c30015..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 8-Sep-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 239320a..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 8-Sep-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 9b071b5..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 8-Sep-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 ff64309..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 8-Sep-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 2cddccc..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 8-Sep-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 feefa24..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 8-Sep-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 558db74..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 8-Sep-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_stores.md b/docs/kfutil_stores.md index 11cd523..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. ``` @@ -41,6 +44,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 6-Nov-2024 diff --git a/docs/kfutil_stores_delete.md b/docs/kfutil_stores_delete.md index 18a6b60..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 8-Sep-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 bcd5fdf..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 8-Sep-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 97a0f40..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 8-Sep-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 fc7b75e..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 8-Sep-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 67d1239..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 8-Sep-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 ee55cfc..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 8-Sep-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 be3e5d9..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 8-Sep-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 706058f..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 8-Sep-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 25948fb..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 8-Sep-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 cedc3b2..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 8-Sep-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/docs/kfutil_version.md b/docs/kfutil_version.md index 383c1de..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 8-Sep-2024 +###### Auto generated by spf13/cobra on 6-Nov-2024 diff --git a/go.mod b/go.mod index d839dc2..092f499 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 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 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..99162bc 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 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= +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= @@ -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/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" } diff --git a/pkg/version/version.go b/pkg/version/version.go index 354b351..3294bc0 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.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: Thu, 7 Nov 2024 09:38:37 -0800 Subject: [PATCH 02/49] fix(ci): Bump tests timeout to 20m Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- .github/workflows/tests.yml | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 100807c..42eb0c3 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -81,7 +81,7 @@ jobs: - name: Run tests run: | export KFUTIL_DEBUG=1 - go test -v ./cmd -run "^Test_StoreTypes*" + go test -timeout 20m -v ./cmd -run "^Test_StoreTypes*" ### Store Tests Test_Stores_KFC_10_5_0: @@ -116,7 +116,7 @@ jobs: 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_*" + run: go test -timeout 20m -v ./cmd -run "^Test_Stores_*" ### PAM Tests Test_PAM_KFC_10_5_0: @@ -153,7 +153,7 @@ jobs: - name: Run tests run: | unset KFUTIL_DEBUG - go test -v ./cmd -run "^Test_PAM*" + go test -timeout 20m -v ./cmd -run "^Test_PAM*" ### PAM Tests AKV Auth Provider Test_AKV_PAM_KFC_10_5_0: @@ -193,7 +193,7 @@ jobs: - name: Run tests run: | - go test -v ./cmd -run "^Test_PAM*" + go test -timeout 20m -v ./cmd -run "^Test_PAM*" # ## KFC 11.x.x @@ -226,7 +226,7 @@ jobs: # - name: Run tests # run: | # unset KFUTIL_DEBUG - # go test -v ./cmd -run "^Test_StoreTypes*" + # go test -timeout 20m -v ./cmd -run "^Test_StoreTypes*" # # # ### Store Tests @@ -250,7 +250,7 @@ jobs: # 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_*" + # run: go test -timeout 20m -v ./cmd -run "^Test_Stores_*" # # ### PAM Tests # Test_PAM_KFC_11_1_2: @@ -275,7 +275,7 @@ jobs: # - name: Run tests # run: | # unset KFUTIL_DEBUG - # go test -v ./cmd -run "^Test_PAM*" + # go test -timeout 20m -v ./cmd -run "^Test_PAM*" # # # ### PAM Tests AKV Auth Provider @@ -306,7 +306,7 @@ jobs: # make install # - name: Run tests # run: | - # go test -v ./cmd -run "^Test_PAM*" + # go test -timeout 20m -v ./cmd -run "^Test_PAM*" ## KFC 12.x.x kf_12_x_x: @@ -365,7 +365,7 @@ jobs: # - name: Run tests # run: | # unset KFUTIL_DEBUG - # go test -v ./cmd -run "^Test_StoreTypes*" + # go test -timeout 20m -v ./cmd -run "^Test_StoreTypes*" Test_StoreTypes_KFC_12_3_0_OAUTH: runs-on: kfutil-runner-set @@ -401,7 +401,7 @@ jobs: - name: Run tests run: | unset KFUTIL_DEBUG - go test -v ./cmd -run "^Test_StoreTypes*" + go test -timeout 20m -v ./cmd -run "^Test_StoreTypes*" ### Store Tests # Test_Stores_KFC_12_3_0: @@ -435,7 +435,7 @@ jobs: # 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_*" + # run: go test -timeout 20m -v ./cmd -run "^Test_Stores_*" Test_Stores_KFC_12_3_0_OAUTH: runs-on: kfutil-runner-set needs: @@ -469,7 +469,7 @@ jobs: 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_*" + run: go test -timeout 20m -v ./cmd -run "^Test_Stores_*" ### PAM Tests # Test_PAM_KFC_12_3_0: @@ -505,7 +505,7 @@ jobs: # - name: Run tests # run: | # unset KFUTIL_DEBUG - # go test -v ./cmd -run "^Test_PAM*" + # go test -timeout 20m -v ./cmd -run "^Test_PAM*" Test_PAM_KFC_12_3_0_OAUTH: runs-on: self-hosted @@ -542,7 +542,7 @@ jobs: - name: Run tests run: | unset KFUTIL_DEBUG - go test -v ./cmd -run "^Test_PAM*" + go test -timeout 20m -v ./cmd -run "^Test_PAM*" ### PAM Tests AKV Auth Provider @@ -582,7 +582,7 @@ jobs: # make install # - name: Run tests # run: | - # go test -v ./cmd -run "^Test_PAM*" + # go test -timeout 20m -v ./cmd -run "^Test_PAM*" Test_AKV_PAM_KFC_12_3_0_OAUTH: runs-on: self-hosted @@ -621,7 +621,7 @@ jobs: - name: Run tests run: | - go test -v ./cmd -run "^Test_PAM*" + go test -timeout 20m -v ./cmd -run "^Test_PAM*" # Tester Install Script Test_Install_Script: @@ -666,4 +666,4 @@ jobs: # Run the tests with coverage found in the pkg directory - name: Run tests - run: go test -v -cover ./pkg/... + run: go test -timeout 20m -v -cover ./pkg/... From 82533c9a2659b8c469d6845a1c6305b4d586026b Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Mon, 11 Nov 2024 10:06:26 -0800 Subject: [PATCH 03/49] fix(ci): Update starter workflow Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- .../keyfactor-bootstrap-workflow.yml | 421 +++++++++--------- 1 file changed, 211 insertions(+), 210 deletions(-) diff --git a/.github/workflows/keyfactor-bootstrap-workflow.yml b/.github/workflows/keyfactor-bootstrap-workflow.yml index 78f5d45..5d3b5f0 100644 --- a/.github/workflows/keyfactor-bootstrap-workflow.yml +++ b/.github/workflows/keyfactor-bootstrap-workflow.yml @@ -1,226 +1,227 @@ -#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 +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: -# 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 }} -# + # 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: -# token: ${{ secrets.V2BUILDTOKEN}} -# -# - name: Display base.ref from Pull Request -# if: github.event_name == 'pull_request' -# id: display-from-pr + # 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 "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 + # 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: Display base_ref from Push Event -# if: github.event_name == 'push' -# id: display-from-push + # - name: Get Package Version + # id: get-pkg-version # 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 + # 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: | -# 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" + # 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 "No tags exist in this repo" -# echo "LATEST_TAG=" | tee -a "$GITHUB_ENV" + # 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 "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" + # 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" # -## 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 + # update-pkg-version: + # needs: + # - check-package-version + # runs-on: ubuntu-latest # -# 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 + # 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@go_build_private_repo_access + 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 }} + GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN }} \ No newline at end of file From 57e125018b186ba5a2f0794981b0cd0d17777b2a Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Mon, 11 Nov 2024 10:06:26 -0800 Subject: [PATCH 04/49] fix(ci): Update starter workflow Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- .../keyfactor-bootstrap-workflow.yml | 421 +++++++++--------- .goreleaser.yml | 4 +- 2 files changed, 213 insertions(+), 212 deletions(-) diff --git a/.github/workflows/keyfactor-bootstrap-workflow.yml b/.github/workflows/keyfactor-bootstrap-workflow.yml index 78f5d45..5d3b5f0 100644 --- a/.github/workflows/keyfactor-bootstrap-workflow.yml +++ b/.github/workflows/keyfactor-bootstrap-workflow.yml @@ -1,226 +1,227 @@ -#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 +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: -# 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 }} -# + # 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: -# token: ${{ secrets.V2BUILDTOKEN}} -# -# - name: Display base.ref from Pull Request -# if: github.event_name == 'pull_request' -# id: display-from-pr + # 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 "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 + # 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: Display base_ref from Push Event -# if: github.event_name == 'push' -# id: display-from-push + # - name: Get Package Version + # id: get-pkg-version # 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 + # 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: | -# 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" + # 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 "No tags exist in this repo" -# echo "LATEST_TAG=" | tee -a "$GITHUB_ENV" + # 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 "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" + # 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" # -## 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 + # update-pkg-version: + # needs: + # - check-package-version + # runs-on: ubuntu-latest # -# 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 + # 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@go_build_private_repo_access + 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 }} + GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN }} \ No newline at end of file diff --git a/.goreleaser.yml b/.goreleaser.yml index ba8a4fd..df5f4b3 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -12,9 +12,9 @@ builds: - CGO_ENABLED=0 mod_timestamp: '{{ .CommitTimestamp }}' flags: - - -trimpath + - '-trimpath' ldflags: - - '-s -w -X main.version={{.Version}} -X main.commit={{.Commit}}' + - '-s -w -X version.VERSION={{.Version}} -X main.commit={{.Commit}}' goos: - freebsd - windows From 50088740d855a4ce91c93be0813ee892c4ecbba6 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Tue, 12 Nov 2024 10:06:12 -0800 Subject: [PATCH 05/49] fix(ci): AKV auth provider test pass GH token. Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- .github/workflows/tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 42eb0c3..e4812d9 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -163,6 +163,7 @@ jobs: environment: "KFC_10_5_0" env: SECRET_NAME: "command-config-1050-az" + GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} steps: - name: Check out code uses: actions/checkout@v4 From f08667db52028f92bde8608578fa62eba71c89da Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Tue, 12 Nov 2024 11:56:57 -0800 Subject: [PATCH 06/49] fix(cli): Handle and report SDK client errors. Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- cmd/export.go | 2 +- cmd/import.go | 2 +- cmd/pam.go | 32 ++++++++++--- cmd/root.go | 129 +++++++++++++++++++++++++++++--------------------- go.mod | 8 ++-- go.sum | 12 ++--- 6 files changed, 111 insertions(+), 74 deletions(-) diff --git a/cmd/export.go b/cmd/export.go index e0145c5..a4b5737 100644 --- a/cmd/export.go +++ b/cmd/export.go @@ -21,7 +21,7 @@ import ( "os" "strconv" - "github.com/Keyfactor/keyfactor-go-client-sdk/api/keyfactor" + "github.com/Keyfactor/keyfactor-go-client-sdk/v2/api/keyfactor" "github.com/Keyfactor/keyfactor-go-client/v3/api" "github.com/rs/zerolog/log" "github.com/spf13/cobra" diff --git a/cmd/import.go b/cmd/import.go index e9a3bf7..0a1374a 100644 --- a/cmd/import.go +++ b/cmd/import.go @@ -21,7 +21,7 @@ import ( "io" "os" - "github.com/Keyfactor/keyfactor-go-client-sdk/api/keyfactor" + "github.com/Keyfactor/keyfactor-go-client-sdk/v2/api/keyfactor" "github.com/Keyfactor/keyfactor-go-client/v3/api" "github.com/rs/zerolog/log" "github.com/spf13/cobra" diff --git a/cmd/pam.go b/cmd/pam.go index 1893081..8606a37 100644 --- a/cmd/pam.go +++ b/cmd/pam.go @@ -22,7 +22,7 @@ import ( "net/http" "os" - "github.com/Keyfactor/keyfactor-go-client-sdk/api/keyfactor" + "github.com/Keyfactor/keyfactor-go-client-sdk/v2/api/keyfactor" "github.com/rs/zerolog/log" "github.com/spf13/cobra" ) @@ -136,7 +136,10 @@ https://github.com/Keyfactor/hashicorp-vault-pam/blob/main/integration-manifest. // Authenticate //kfClient, _ := initClient(configFile, profile, providerType, providerProfile, noPrompt, authConfig, false) - sdkClient, _ := initGenClient(false) + sdkClient, cErr := initGenClient(false) + if cErr != nil { + return cErr + } // Check required flags if pamConfigFile == "" && repoName == "" { @@ -229,7 +232,10 @@ var pamProvidersListCmd = &cobra.Command{ // Authenticate //kfClient, _ := initClient(configFile, profile, providerType, providerProfile, noPrompt, authConfig, false) - sdkClient, _ := initGenClient(false) + sdkClient, cErr := initGenClient(false) + if cErr != nil { + return cErr + } // CLI Logic log.Debug().Msg("call: PAMProviderGetPamProviders()") @@ -280,7 +286,10 @@ var pamProvidersGetCmd = &cobra.Command{ // Authenticate //kfClient, _ := initClient(configFile, profile, providerType, providerProfile, noPrompt, authConfig, false) - sdkClient, _ := initGenClient(false) + sdkClient, cErr := initGenClient(false) + if cErr != nil { + return cErr + } // CLI Logic log.Debug().Msg("call: PAMProviderGetPamProvider()") @@ -335,7 +344,10 @@ var pamProvidersCreateCmd = &cobra.Command{ // Authenticate // kfClient, _ := initClient(configFile, profile, providerType, providerProfile, noPrompt, authConfig, false) - sdkClient, _ := initGenClient(false) + sdkClient, cErr := initGenClient(false) + if cErr != nil { + return cErr + } // CLI Logic var pamProvider *keyfactor.CSSCMSDataModelModelsProvider @@ -398,7 +410,10 @@ var pamProvidersUpdateCmd = &cobra.Command{ // Authenticate //kfClient, _ := initClient(configFile, profile, providerType, providerProfile, noPrompt, authConfig, false) - sdkClient, _ := initGenClient(false) + sdkClient, cErr := initGenClient(false) + if cErr != nil { + return cErr + } // CLI Logic var pamProvider *keyfactor.CSSCMSDataModelModelsProvider @@ -464,7 +479,10 @@ var pamProvidersDeleteCmd = &cobra.Command{ // Authenticate //kfClient, _ := initClient(configFile, profile, providerType, providerProfile, noPrompt, authConfig, false) - sdkClient, _ := initGenClient(false) + sdkClient, cErr := initGenClient(false) + if cErr != nil { + return cErr + } // CLI Logic log.Debug(). diff --git a/cmd/root.go b/cmd/root.go index c5d7e53..7f21fc9 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -23,7 +23,7 @@ import ( "strings" "github.com/Keyfactor/keyfactor-auth-client-go/auth_providers" - "github.com/Keyfactor/keyfactor-go-client-sdk/api/keyfactor" + "github.com/Keyfactor/keyfactor-go-client-sdk/v2/api/keyfactor" "github.com/Keyfactor/keyfactor-go-client/v3/api" "github.com/rs/zerolog/log" "github.com/spf13/cobra" @@ -253,7 +253,7 @@ func authSdkViaConfigFile(cfgFile string, cfgProfile string) (*keyfactor.APIClie } if conf != nil { log.Debug().Msg("call: keyfactor.NewAPIClient()") - c = keyfactor.NewAPIClient(conf) + c, cErr = keyfactor.NewAPIClient(conf) log.Debug().Msg("complete: keyfactor.NewAPIClient()") if cErr != nil { log.Error(). @@ -326,7 +326,7 @@ func authSdkViaEnvVars() (*keyfactor.APIClient, error) { } if conf != nil { log.Debug().Msg("call: api.NewKeyfactorClient()") - c = keyfactor.NewAPIClient(conf) + c, cErr = keyfactor.NewAPIClient(conf) log.Debug().Msg("complete: api.NewKeyfactorClient()") if cErr != nil { log.Error().Err(cErr).Msg("unable to create Keyfactor client") @@ -367,9 +367,9 @@ func initClient(saveConfig bool) (*api.Client, error) { Str("providerProfile", providerProfile). Msg("enter: initClient()") var ( - authenticated bool - c *api.Client - cErr error + c *api.Client + envCfgErr error + cfgErr error ) if providerType != "" { @@ -382,50 +382,49 @@ func initClient(saveConfig bool) (*api.Client, error) { 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). + Msg("authenticating via config file") + c, cfgErr = authViaConfigFile(configFile, profile) + if cfgErr == 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.Debug().Msg("call: authViaEnvVars()") - c, cErr = authViaEnvVars() - log.Debug().Msg("returned: authViaEnvVars()") - if cErr == nil { - log.Info().Msg("Authenticated via environment variables") - authenticated = true + return c, nil } } - 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 - } + log.Info().Msg("authenticating via environment variables") + log.Debug().Msg("call: authViaEnvVars()") + c, envCfgErr = authViaEnvVars() + log.Debug().Msg("returned: authViaEnvVars()") + if envCfgErr == nil { + log.Info().Msg("Authenticated via environment variables") + return c, nil } - 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(). + Str("configFile", DefaultConfigFileName). + Str("profile", "default"). + Msg("implicit authenticating via config file using default profile") + log.Debug().Msg("call: authViaConfigFile()") + c, cfgErr = authViaConfigFile("", "") + if cfgErr == nil { + log.Info(). + Str("configFile", DefaultConfigFileName). + Str("profile", "default"). + Msgf("authenticated implictly via config file '%s' using 'default' profile", DefaultConfigFileName) + return c, nil } - log.Info().Msg("Keyfactor Command client created") - return c, nil + log.Error(). + Err(cfgErr). + Err(envCfgErr). + Msg("unable to authenticate to Keyfactor Command") + log.Debug().Msg("return: initClient()") + return nil, fmt.Errorf("unable to authenticate to Keyfactor Command") } func initGenClient( @@ -450,9 +449,9 @@ func initGenClient( Msg("enter: initGenClient()") var ( - authenticated bool - c *keyfactor.APIClient - cErr error + c *keyfactor.APIClient + envCErr error + cfErr error ) if providerType != "" { @@ -466,28 +465,48 @@ func initGenClient( Msg("providerType is empty attempting to authenticate via params") if configFile != "" || profile != "" { - c, cErr = authSdkViaConfigFile(configFile, profile) - if cErr == nil { + log.Info(). + Str("configFile", configFile). + Str("profile", profile). + Msg("authenticating via config file") + c, cfErr = authSdkViaConfigFile(configFile, profile) + if cfErr == nil { log.Info(). Str("configFile", configFile). Str("profile", profile). Msgf("Authenticated via config file %s using profile %s", configFile, profile) - authenticated = true + return c, nil } } - 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 - } + log.Info().Msg("authenticating via environment variables") + log.Debug().Msg("call: authViaEnvVars()") + c, envCErr = authSdkViaEnvVars() + log.Debug().Msg("returned: authViaEnvVars()") + if envCErr == nil { + log.Info().Msg("authenticated via environment variables") + return c, nil + } + + log.Info(). + Str("configFile", DefaultConfigFileName). + Str("profile", "default"). + Msg("implicit authenticating via config file using default profile") + log.Debug().Msg("call: authViaConfigFile()") + c, cfErr = authSdkViaConfigFile("", "") + if cfErr == nil { + log.Info(). + Str("configFile", DefaultConfigFileName). + Str("profile", "default"). + Msgf("authenticated implictly via config file '%s' using 'default' profile", DefaultConfigFileName) + return c, nil } - log.Info().Msg("Keyfactor Command client created") - return c, nil + log.Error(). + Err(cfErr). + Err(envCErr). + Msg("unable to authenticate") + return nil, fmt.Errorf("unable to authenticate to Keyfactor Command with provided credentials, please check your configuration") } //func initGenClientV1( diff --git a/go.mod b/go.mod index 092f499..292b121 100644 --- a/go.mod +++ b/go.mod @@ -9,8 +9,8 @@ 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.6 - github.com/Keyfactor/keyfactor-go-client-sdk v1.1.0-rc.0 + github.com/Keyfactor/keyfactor-auth-client-go v1.0.0-rc.7 + github.com/Keyfactor/keyfactor-go-client-sdk/v2 v2.0.0-rc.1 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 @@ -23,6 +23,7 @@ require ( github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.9.0 golang.org/x/crypto v0.25.0 + golang.org/x/term v0.22.0 gopkg.in/yaml.v3 v3.0.1 //github.com/google/go-cmp/cmp v0.5.9 ) @@ -48,9 +49,8 @@ require ( github.com/spbsoluble/go-pkcs12 v0.3.3 // 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/oauth2 v0.24.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 99162bc..ded8191 100644 --- a/go.sum +++ b/go.sum @@ -10,10 +10,10 @@ 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.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-auth-client-go v1.0.0-rc.7 h1:s97WeaaqeU2ULJIQtOReHHoC9k+VYQFK6to/SPZI850= +github.com/Keyfactor/keyfactor-auth-client-go v1.0.0-rc.7/go.mod h1:UTPLARTONwfc+j1y2SjEa54gbFFCObQucHf3ubQVyDk= +github.com/Keyfactor/keyfactor-go-client-sdk/v2 v2.0.0-rc.1 h1:/SzbHi0isBr6c7FgxBYBAtAwe9daHevSqcGKaYXDyjw= +github.com/Keyfactor/keyfactor-go-client-sdk/v2 v2.0.0-rc.1/go.mod h1:HXfgEAR2Ebg7j5em5vVZp2hnmprPjHqDUEYe0UqdZIM= 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= @@ -106,8 +106,8 @@ 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/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= +golang.org/x/oauth2 v0.24.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= From 38c9500ffdf4834305b19a927bddf336c0e515d9 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Tue, 12 Nov 2024 12:34:43 -0800 Subject: [PATCH 07/49] chore(deps): Bump `Keyfactor/keyfactor-auth-client-go` to `v1.0.0-rc.8` 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 292b121..7a2641c 100644 --- a/go.mod +++ b/go.mod @@ -9,8 +9,8 @@ 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.7 - github.com/Keyfactor/keyfactor-go-client-sdk/v2 v2.0.0-rc.1 + github.com/Keyfactor/keyfactor-auth-client-go v1.0.0-rc.8 + github.com/Keyfactor/keyfactor-go-client-sdk/v2 v2.0.0-rc.2 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 diff --git a/go.sum b/go.sum index ded8191..d6d4f26 100644 --- a/go.sum +++ b/go.sum @@ -10,10 +10,10 @@ 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.7 h1:s97WeaaqeU2ULJIQtOReHHoC9k+VYQFK6to/SPZI850= -github.com/Keyfactor/keyfactor-auth-client-go v1.0.0-rc.7/go.mod h1:UTPLARTONwfc+j1y2SjEa54gbFFCObQucHf3ubQVyDk= -github.com/Keyfactor/keyfactor-go-client-sdk/v2 v2.0.0-rc.1 h1:/SzbHi0isBr6c7FgxBYBAtAwe9daHevSqcGKaYXDyjw= -github.com/Keyfactor/keyfactor-go-client-sdk/v2 v2.0.0-rc.1/go.mod h1:HXfgEAR2Ebg7j5em5vVZp2hnmprPjHqDUEYe0UqdZIM= +github.com/Keyfactor/keyfactor-auth-client-go v1.0.0-rc.8 h1:IMbXP9P8lWJn5uFKLC8Jkp2lP/IdZ+LYPDGRt6YvSPk= +github.com/Keyfactor/keyfactor-auth-client-go v1.0.0-rc.8/go.mod h1:00PVslvswI2+6Uln50XKymEiEafmxfrcOxsNEz3bOME= +github.com/Keyfactor/keyfactor-go-client-sdk/v2 v2.0.0-rc.2 h1:RNrfgrC+mPvqOc1wPsFjB4thuw7qJbP3gOycRDcRwxI= +github.com/Keyfactor/keyfactor-go-client-sdk/v2 v2.0.0-rc.2/go.mod h1:11WXGG9VVKSV0EPku1IswjHbGGpzHDKqD4pe2vD7vas= 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= From 96fbc769a79383976ccfc7f7b0b92bdde7feb84c Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Wed, 13 Nov 2024 12:20:35 -0800 Subject: [PATCH 08/49] fix(core): Don't log `bcrypt`ed strings. chore(ci): update Github environment configs. Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- .github/config/MODULE.MD | 42 ++++++++++++++++++++------------- .github/config/README.md | 42 ++++++++++++++++++++------------- .github/config/environments.tf | 13 ---------- .github/config/int1230_oauth.tf | 35 +++++++++++++++++++++++++++ cmd/root.go | 18 +++++++------- 5 files changed, 95 insertions(+), 55 deletions(-) create mode 100644 .github/config/int1230_oauth.tf diff --git a/.github/config/MODULE.MD b/.github/config/MODULE.MD index 4e1d569..b5afcef 100644 --- a/.github/config/MODULE.MD +++ b/.github/config/MODULE.MD @@ -34,23 +34,31 @@ ## 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` | `"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 | +| 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\_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 | +| [kfc1230\_client\_id](#input\_kfc1230\_client\_id) | The client ID to authenticate with the Keyfactor instance using oauth2 client credentials | `string` | n/a | yes | +| [kfc1230\_client\_secret](#input\_kfc1230\_client\_secret) | The client secret to authenticate with the Keyfactor instance using oauth2 client credentials | `string` | n/a | yes | +| [kfc1230\_oauth\_hostname](#input\_kfc1230\_oauth\_hostname) | The hostname of the Keyfactor instance | `string` | `"int1230c-oauth.eastus2.cloudapp.azure.com"` | no | +| [kfc1230\_oauth\_token\_url](#input\_kfc1230\_oauth\_token\_url) | The hostname of the Keyfactor instance | `string` | `"https://int1230c-oauth.eastus2.cloudapp.azure.com:8444/realms/Keyfactor/protocol/openid-connect/token"` | no | +| [kfc1230c\_ad\_hostname](#input\_kfc1230c\_ad\_hostname) | The hostname of the Keyfactor instance | `string` | `"int1230c-ad.eastus2.cloudapp.azure.com"` | no | +| [kfc1230c\_client\_id](#input\_kfc1230c\_client\_id) | The client ID to authenticate with the Keyfactor instance using oauth2 client credentials | `string` | n/a | yes | +| [kfc1230c\_client\_secret](#input\_kfc1230c\_client\_secret) | The client secret to authenticate with the Keyfactor instance using oauth2 client credentials | `string` | n/a | yes | +| [kfc1230c\_oauth\_hostname](#input\_kfc1230c\_oauth\_hostname) | The hostname of the Keyfactor instance | `string` | `"int1230c-oauth.eastus2.cloudapp.azure.com"` | no | +| [kfc1230c\_oauth\_token\_url](#input\_kfc1230c\_oauth\_token\_url) | The hostname of the Keyfactor instance | `string` | `"https://int1230c-oauth.eastus2.cloudapp.azure.com:8444/realms/Keyfactor/protocol/openid-connect/token"` | no | ## Outputs diff --git a/.github/config/README.md b/.github/config/README.md index 3a92963..2149532 100644 --- a/.github/config/README.md +++ b/.github/config/README.md @@ -83,23 +83,31 @@ module "keyfactor_github_test_environment_12_3_0_kc" { ## 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` | `"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 | +| 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\_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 | +| [kfc1230\_client\_id](#input\_kfc1230\_client\_id) | The client ID to authenticate with the Keyfactor instance using oauth2 client credentials | `string` | n/a | yes | +| [kfc1230\_client\_secret](#input\_kfc1230\_client\_secret) | The client secret to authenticate with the Keyfactor instance using oauth2 client credentials | `string` | n/a | yes | +| [kfc1230\_oauth\_hostname](#input\_kfc1230\_oauth\_hostname) | The hostname of the Keyfactor instance | `string` | `"int1230c-oauth.eastus2.cloudapp.azure.com"` | no | +| [kfc1230\_oauth\_token\_url](#input\_kfc1230\_oauth\_token\_url) | The hostname of the Keyfactor instance | `string` | `"https://int1230c-oauth.eastus2.cloudapp.azure.com:8444/realms/Keyfactor/protocol/openid-connect/token"` | no | +| [kfc1230c\_ad\_hostname](#input\_kfc1230c\_ad\_hostname) | The hostname of the Keyfactor instance | `string` | `"int1230c-ad.eastus2.cloudapp.azure.com"` | no | +| [kfc1230c\_client\_id](#input\_kfc1230c\_client\_id) | The client ID to authenticate with the Keyfactor instance using oauth2 client credentials | `string` | n/a | yes | +| [kfc1230c\_client\_secret](#input\_kfc1230c\_client\_secret) | The client secret to authenticate with the Keyfactor instance using oauth2 client credentials | `string` | n/a | yes | +| [kfc1230c\_oauth\_hostname](#input\_kfc1230c\_oauth\_hostname) | The hostname of the Keyfactor instance | `string` | `"int1230c-oauth.eastus2.cloudapp.azure.com"` | no | +| [kfc1230c\_oauth\_token\_url](#input\_kfc1230c\_oauth\_token\_url) | The hostname of the Keyfactor instance | `string` | `"https://int1230c-oauth.eastus2.cloudapp.azure.com:8444/realms/Keyfactor/protocol/openid-connect/token"` | no | ## Outputs diff --git a/.github/config/environments.tf b/.github/config/environments.tf index 52b5bf3..fb16940 100644 --- a/.github/config/environments.tf +++ b/.github/config/environments.tf @@ -80,17 +80,4 @@ module "keyfactor_github_test_environment_12_3_0_AD" { } -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")) -} - diff --git a/.github/config/int1230_oauth.tf b/.github/config/int1230_oauth.tf new file mode 100644 index 0000000..3d8ff20 --- /dev/null +++ b/.github/config/int1230_oauth.tf @@ -0,0 +1,35 @@ +variable "kfc1230_oauth_hostname" { + description = "The hostname of the Keyfactor instance" + type = string + default = "int1230-oauth.eastus2.cloudapp.azure.com" +} + +variable "kfc1230_oauth_token_url" { + description = "The hostname of the Keyfactor instance" + type = string + default = "https://int1230-oauth.eastus2.cloudapp.azure.com:8444/realms/Keyfactor/protocol/openid-connect/token" +} + + +variable "kfc1230_client_id" { + description = "The client ID to authenticate with the Keyfactor instance using oauth2 client credentials" + type = string + +} +variable "kfc1230_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" { + 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.kfc1230_oauth_hostname + keyfactor_auth_token_url = var.kfc1230_oauth_token_url + keyfactor_client_id = var.kfc1230_client_id + keyfactor_client_secret = var.kfc1230_client_secret + keyfactor_tls_skip_verify = true + keyfactor_config_file = base64encode(file("${path.module}/int1230_oauth_command_config.json")) +} \ No newline at end of file diff --git a/cmd/root.go b/cmd/root.go index 7f21fc9..85dcbfa 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -55,10 +55,12 @@ var ( func hashSecretValue(secretValue string) string { log.Debug().Msg("Enter hashSecretValue()") - if logInsecure { + if secretValue == "" { return secretValue } - log.Trace().Str("secretValue", secretValue).Send() + if !logInsecure { + return "*****************************" + } cost := 12 log.Debug().Int("cost", cost).Msg("call: bcrypt.GenerateFromPassword()") hashedPassword, err := bcrypt.GenerateFromPassword([]byte(secretValue), cost) @@ -659,12 +661,12 @@ func init() { "Will not attempt to connect to GitHub for latest release information and resources.", ) RootCmd.PersistentFlags().BoolVar(&debugFlag, "debug", false, "Enable debugFlag logging.") - RootCmd.PersistentFlags().BoolVar( - &logInsecure, - "log-insecure", - false, - "Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.)", - ) + //RootCmd.PersistentFlags().BoolVar( + // &logInsecure, + // "log-insecure", + // false, + // "Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.)", + //) RootCmd.PersistentFlags().StringVarP( &profile, "profile", From 449e1eeaa9352984a0e496c7c845ad7663cc46fa Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Wed, 13 Nov 2024 14:44:39 -0800 Subject: [PATCH 09/49] fix(ci): `Test_AKV_PAM_KFC_12_3_0_OAUTH` run on k8s runners Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e4812d9..062d325 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -509,7 +509,7 @@ jobs: # go test -timeout 20m -v ./cmd -run "^Test_PAM*" Test_PAM_KFC_12_3_0_OAUTH: - runs-on: self-hosted + runs-on: kfutil-runner-set needs: - build - kf_12_x_x From 4d56067e39fd04a65ae7fe954270bbb90a2000ae Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Thu, 14 Nov 2024 10:49:26 -0800 Subject: [PATCH 10/49] chore(deps): Bump `keyfactor-auth-client-go` to `v1.0.0-rc.18` 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 7a2641c..50efeb3 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.8 + github.com/Keyfactor/keyfactor-auth-client-go v1.0.0-rc.18 github.com/Keyfactor/keyfactor-go-client-sdk/v2 v2.0.0-rc.2 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 d6d4f26..cc8b5dd 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.8 h1:IMbXP9P8lWJn5uFKLC8Jkp2lP/IdZ+LYPDGRt6YvSPk= -github.com/Keyfactor/keyfactor-auth-client-go v1.0.0-rc.8/go.mod h1:00PVslvswI2+6Uln50XKymEiEafmxfrcOxsNEz3bOME= +github.com/Keyfactor/keyfactor-auth-client-go v1.0.0-rc.18 h1:PMH/pST30UEQ1dz6YcxYCaoA14iGS3BoL+e3M9m3eyw= +github.com/Keyfactor/keyfactor-auth-client-go v1.0.0-rc.18/go.mod h1:00PVslvswI2+6Uln50XKymEiEafmxfrcOxsNEz3bOME= github.com/Keyfactor/keyfactor-go-client-sdk/v2 v2.0.0-rc.2 h1:RNrfgrC+mPvqOc1wPsFjB4thuw7qJbP3gOycRDcRwxI= github.com/Keyfactor/keyfactor-go-client-sdk/v2 v2.0.0-rc.2/go.mod h1:11WXGG9VVKSV0EPku1IswjHbGGpzHDKqD4pe2vD7vas= github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.11 h1:nYc7fEidu26ZKGwEByQNr2EWPCsCs0zxnHUKnRT6/rY= From 7d415b68e0e96e13f0a5aa0c6eefed8197240fe2 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Thu, 14 Nov 2024 13:43:51 -0800 Subject: [PATCH 11/49] fix(tests): PAM tests accomodate for bug `63171` Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- cmd/pam.go | 49 ++++++++++++++++++++++++++++++++++- cmd/pam_test.go | 69 +++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 103 insertions(+), 15 deletions(-) diff --git a/cmd/pam.go b/cmd/pam.go index 8606a37..a15400f 100644 --- a/cmd/pam.go +++ b/cmd/pam.go @@ -21,6 +21,8 @@ import ( "io" "net/http" "os" + "strconv" + "strings" "github.com/Keyfactor/keyfactor-go-client-sdk/v2/api/keyfactor" "github.com/rs/zerolog/log" @@ -320,6 +322,30 @@ var pamProvidersGetCmd = &cobra.Command{ }, } +func checkBug63171(cmdResp *http.Response, operation string) error { + if cmdResp != nil && cmdResp.StatusCode == 200 { + defer cmdResp.Body.Close() + // .\Admin + productVersion := cmdResp.Header.Get("X-Keyfactor-Product-Version") + log.Debug().Str("productVersion", productVersion).Msg("Keyfactor Command Version") + majorVersionStr := strings.Split(productVersion, ".")[0] + // Try to convert to int + majorVersion, err := strconv.Atoi(majorVersionStr) + if err == nil && majorVersion >= 12 { + // TODO: Pending resolution of this bug: https://dev.azure.com/Keyfactor/Engineering/_workitems/edit/63171 + errMsg := fmt.Sprintf( + "PAM Provider %s is not supported in Keyfactor Command version 12 and later, "+ + "please use the Keyfactor Command UI to create PAM Providers", operation, + ) + oErr := fmt.Errorf(errMsg) + log.Error().Err(oErr).Send() + outputError(oErr, true, outputFormat) + return oErr + } + } + return nil +} + var pamProvidersCreateCmd = &cobra.Command{ Use: "create", Short: "Create a new PAM Provider, currently only supported from file.", @@ -345,6 +371,17 @@ var pamProvidersCreateCmd = &cobra.Command{ // Authenticate // kfClient, _ := initClient(configFile, profile, providerType, providerProfile, noPrompt, authConfig, false) sdkClient, cErr := initGenClient(false) + + _, cmdResp, sErr := sdkClient.StatusApi.StatusGetEndpoints(context.Background()).Execute() + if sErr != nil { + log.Error().Err(sErr).Msg("failed to get Keyfactor Command version") + } else { + bug63171 := checkBug63171(cmdResp, "CREATE") + if bug63171 != nil { + return bug63171 + } + } + if cErr != nil { return cErr } @@ -415,6 +452,16 @@ var pamProvidersUpdateCmd = &cobra.Command{ return cErr } + _, cmdResp, sErr := sdkClient.StatusApi.StatusGetEndpoints(context.Background()).Execute() + if sErr != nil { + log.Error().Err(sErr).Msg("failed to get Keyfactor Command version") + } else { + bug63171 := checkBug63171(cmdResp, "UPDATE") + if bug63171 != nil { + return bug63171 + } + } + // CLI Logic var pamProvider *keyfactor.CSSCMSDataModelModelsProvider log.Debug().Str("file", pamConfigFile). @@ -435,7 +482,7 @@ var pamProvidersUpdateCmd = &cobra.Command{ log.Debug().Msg("returned: PAMProviderUpdatePamProvider()") log.Trace().Interface("httpResponse", httpResponse).Msg("PAMProviderUpdatePamProvider") if err != nil { - returnHttpErr(httpResponse, err) + return returnHttpErr(httpResponse, err) } log.Debug().Msg(convertResponseMsg) diff --git a/cmd/pam_test.go b/cmd/pam_test.go index d196b0e..57b29cc 100644 --- a/cmd/pam_test.go +++ b/cmd/pam_test.go @@ -19,7 +19,6 @@ import ( "fmt" "os" "path" - "path/filepath" "strconv" "strings" "testing" @@ -210,14 +209,17 @@ func Test_PAMCreateCmd(t *testing.T) { // test // get current working dir - cwd, _ := os.Getwd() + cwd, wdErr := os.Getwd() + if wdErr != nil { + cwd = "./" + } t.Logf("cwd: %s", cwd) providerName := "Delinea-SecretServer-test" t.Logf("providerName: %s", providerName) - inputFileName := path.Join(filepath.Dir(cwd), "artifacts/pam/pam-create-template.json") + inputFileName := path.Join(cwd, "artifacts/pam/pam-create-template.json") t.Logf("inputFileName: %s", inputFileName) - invalidInputFileName := path.Join(filepath.Dir(cwd), "artifacts/pam/pam-create-invalid.json") + invalidInputFileName := path.Join(cwd, "artifacts/pam/pam-create-invalid.json") t.Logf("invalidInputFileName: %s", invalidInputFileName) updatedFileName, fErr := testFormatPamCreateConfig(t, inputFileName, "", false) @@ -230,6 +232,9 @@ func Test_PAMCreateCmd(t *testing.T) { // Test valid config file createResponse, err := testCreatePamProvider(t, updatedFileName, providerName, false) + if err != nil && testCheckBug63171(err) { + t.Skip("PAM Provider creation is not supported in Keyfactor Command version 12 and later") + } assert.NoError(t, err) assert.NotNil(t, createResponse) if err != nil { @@ -268,14 +273,17 @@ func Test_PAMCreateCmd(t *testing.T) { func Test_PAMUpdateCmd(t *testing.T) { // test // get current working dir - cwd, _ := os.Getwd() + cwd, wdErr := os.Getwd() + if wdErr != nil { + cwd = "./" + } t.Logf("cwd: %s", cwd) providerName := "Delinea-SecretServer-test" t.Logf("providerName: %s", providerName) - inputFileName := path.Join(filepath.Dir(cwd), "artifacts/pam/pam-create-template.json") + inputFileName := path.Join(cwd, "artifacts/pam/pam-create-template.json") t.Logf("inputFileName: %s", inputFileName) - invalidInputFileName := path.Join(filepath.Dir(cwd), "artifacts/pam/pam-create-invalid.json") + invalidInputFileName := path.Join(cwd, "artifacts/pam/pam-create-invalid.json") t.Logf("invalidInputFileName: %s", invalidInputFileName) // read input file into a map[string]interface{} @@ -301,6 +309,12 @@ func Test_PAMUpdateCmd(t *testing.T) { output := captureOutput( func() { err := testCmd.Execute() + if err != nil && testCheckBug63171(err) { + t.Skip("Updating PAM Providers is not supported in Keyfactor Command version 12 and later") + } else if err != nil { + t.Errorf("failed to update a PAM provider: %v", err) + t.FailNow() + } assert.NoError(t, err) }, ) @@ -337,14 +351,17 @@ func Test_PAMUpdateCmd(t *testing.T) { func Test_PAMDeleteCmd(t *testing.T) { // test // get current working dir - cwd, _ := os.Getwd() + cwd, wdErr := os.Getwd() + if wdErr != nil { + cwd = "./" + } t.Logf("cwd: %s", cwd) providerName := "Delinea-SecretServer-test" t.Logf("providerName: %s", providerName) - inputFileName := path.Join(filepath.Dir(cwd), "artifacts/pam/pam-create-template.json") + inputFileName := path.Join(cwd, "artifacts/pam/pam-create-template.json") t.Logf("inputFileName: %s", inputFileName) - invalidInputFileName := path.Join(filepath.Dir(cwd), "artifacts/pam/pam-create-invalid.json") + invalidInputFileName := path.Join(cwd, "artifacts/pam/pam-create-invalid.json") t.Logf("invalidInputFileName: %s", invalidInputFileName) //cProviderTypeName := "Delinea-SecretServer" @@ -357,7 +374,10 @@ func Test_PAMDeleteCmd(t *testing.T) { return } // Create a provider to delete, doesn't matter if it fails, assume it exists then delete it - testCreatePamProvider(t, updatedFileName, providerName, true) + _, cErr := testCreatePamProvider(t, updatedFileName, providerName, true) + if cErr != nil && testCheckBug63171(cErr) { + t.Skip("PAM Provider creation is not supported in Keyfactor Command version 12 and later") + } // list providers providersList, err := testListPamProviders(t) @@ -464,6 +484,7 @@ func testCreatePamProvider(t *testing.T, fileName string, providerName string, a } else { testName = fmt.Sprintf("Create PAM provider '%s'", providerName) } + var bug63171 error t.Run( testName, func(t *testing.T) { testCmd := RootCmd @@ -473,19 +494,28 @@ func testCreatePamProvider(t *testing.T, fileName string, providerName string, a t.Logf("args: %s", args) testCmd.SetArgs(args) t.Logf("fileName: %s", fileName) + output := captureOutput( func() { err = testCmd.Execute() if !allowFail { + if err != nil && testCheckBug63171(err) { + bug63171 = err + t.Skip("PAM Provider creation is not supported in Keyfactor Command version 12 and later") + } assert.NoError(t, err) + } else if err != nil && !testCheckBug63171(err) { + bug63171 = err } }, ) - if err = json.Unmarshal([]byte(output), &createResponse); err != nil { + + if jErr := json.Unmarshal([]byte(output), &createResponse); jErr != nil { if allowFail { - t.Logf("Error unmarshalling JSON: %v", err) + t.Logf("Error unmarshalling JSON: %v", jErr) } else { - t.Errorf("failed to create a PAM provider: %v", err) + t.Errorf("failed to create a PAM provider: %v", jErr) + t.FailNow() } return } @@ -499,6 +529,10 @@ func testCreatePamProvider(t *testing.T, fileName string, providerName string, a }, ) + if bug63171 != nil { + return createResponse, bug63171 + } + return createResponse, err } @@ -722,3 +756,10 @@ func testFormatPamCreateConfig(t *testing.T, inputFileName string, providerName } return updatedFileName, nil } + +func testCheckBug63171(err error) bool { + if err != nil && strings.Contains(err.Error(), "not supported in Keyfactor Command version 12 and later") { + return true + } + return false +} From 9457be1d517dd1c1b0d8876bc0ef4ae52dd5dcd1 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Thu, 14 Nov 2024 14:56:57 -0800 Subject: [PATCH 12/49] fix(ci): display working dir info Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- .github/workflows/tests.yml | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 062d325..2b8e097 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -124,7 +124,7 @@ jobs: needs: - build - kf_10_x_x - - Test_StoreTypes_KFC_10_5_0 + # - Test_StoreTypes_KFC_10_5_0 environment: "KFC_10_5_0" env: GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} @@ -150,6 +150,13 @@ jobs: run: | git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + + - name: Display working directory + run: | + pwd + ls -ltr + ls -ltr ./artifacts/pam + - name: Run tests run: | unset KFUTIL_DEBUG @@ -513,7 +520,7 @@ jobs: needs: - build - kf_12_x_x - - Test_StoreTypes_KFC_12_3_0_OAUTH + # - Test_StoreTypes_KFC_12_3_0_OAUTH environment: "KFC_12_3_0_OAUTH" env: GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} @@ -540,6 +547,12 @@ jobs: run: | git config --global url."https://$GITHUB_TOKEN:x-oauth-basic@github.com/".insteadOf "https://github.com/" + - name: Display working directory + run: | + pwd + ls -ltr + ls -ltr ./artifacts/pam + - name: Run tests run: | unset KFUTIL_DEBUG From de029a377c069c3e118e3fc6b5a3b1eb73bb2029 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Thu, 14 Nov 2024 15:03:34 -0800 Subject: [PATCH 13/49] fix(ci): revert pathing Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- .github/workflows/tests.yml | 4 ++-- cmd/pam_test.go | 13 +++++++------ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2b8e097..6676247 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -89,7 +89,7 @@ jobs: needs: - build - kf_10_x_x - - Test_StoreTypes_KFC_10_5_0 + # - Test_StoreTypes_KFC_10_5_0 environment: "KFC_10_5_0" env: GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} @@ -449,7 +449,7 @@ jobs: needs: - build - kf_12_x_x - - Test_StoreTypes_KFC_12_3_0_OAUTH + # - Test_StoreTypes_KFC_12_3_0_OAUTH environment: "KFC_12_3_0_OAUTH" env: GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN}} diff --git a/cmd/pam_test.go b/cmd/pam_test.go index 57b29cc..8df914b 100644 --- a/cmd/pam_test.go +++ b/cmd/pam_test.go @@ -19,6 +19,7 @@ import ( "fmt" "os" "path" + "path/filepath" "strconv" "strings" "testing" @@ -217,9 +218,9 @@ func Test_PAMCreateCmd(t *testing.T) { providerName := "Delinea-SecretServer-test" t.Logf("providerName: %s", providerName) - inputFileName := path.Join(cwd, "artifacts/pam/pam-create-template.json") + inputFileName := path.Join(filepath.Dir(cwd), "artifacts/pam/pam-create-template.json") t.Logf("inputFileName: %s", inputFileName) - invalidInputFileName := path.Join(cwd, "artifacts/pam/pam-create-invalid.json") + invalidInputFileName := path.Join(filepath.Dir(cwd), "artifacts/pam/pam-create-invalid.json") t.Logf("invalidInputFileName: %s", invalidInputFileName) updatedFileName, fErr := testFormatPamCreateConfig(t, inputFileName, "", false) @@ -281,9 +282,9 @@ func Test_PAMUpdateCmd(t *testing.T) { providerName := "Delinea-SecretServer-test" t.Logf("providerName: %s", providerName) - inputFileName := path.Join(cwd, "artifacts/pam/pam-create-template.json") + inputFileName := path.Join(filepath.Dir(cwd), "artifacts/pam/pam-create-template.json") t.Logf("inputFileName: %s", inputFileName) - invalidInputFileName := path.Join(cwd, "artifacts/pam/pam-create-invalid.json") + invalidInputFileName := path.Join(filepath.Dir(cwd), "artifacts/pam/pam-create-invalid.json") t.Logf("invalidInputFileName: %s", invalidInputFileName) // read input file into a map[string]interface{} @@ -359,9 +360,9 @@ func Test_PAMDeleteCmd(t *testing.T) { providerName := "Delinea-SecretServer-test" t.Logf("providerName: %s", providerName) - inputFileName := path.Join(cwd, "artifacts/pam/pam-create-template.json") + inputFileName := path.Join(filepath.Dir(cwd), "artifacts/pam/pam-create-template.json") t.Logf("inputFileName: %s", inputFileName) - invalidInputFileName := path.Join(cwd, "artifacts/pam/pam-create-invalid.json") + invalidInputFileName := path.Join(filepath.Dir(cwd), "artifacts/pam/pam-create-invalid.json") t.Logf("invalidInputFileName: %s", invalidInputFileName) //cProviderTypeName := "Delinea-SecretServer" From 668f372d2407f60b1903d310f4b9d73e2b7deff6 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Thu, 14 Nov 2024 15:33:43 -0800 Subject: [PATCH 14/49] feat(scripts): Enhance akv_auth script to detect run environment. Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- .github/workflows/tests.yml | 4 +- examples/auth/akv/akv_auth_v2.sh | 83 ++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 examples/auth/akv/akv_auth_v2.sh diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6676247..4ecf368 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -187,16 +187,18 @@ jobs: 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 + . ./examples/auth/akv/akv_auth_v2.sh cat $HOME/.keyfactor/command_config.json - name: Install kfutil run: | + echo "Installing kfutil on self-hosted runner" make install - name: Run tests diff --git a/examples/auth/akv/akv_auth_v2.sh b/examples/auth/akv/akv_auth_v2.sh new file mode 100644 index 0000000..0399c74 --- /dev/null +++ b/examples/auth/akv/akv_auth_v2.sh @@ -0,0 +1,83 @@ +#!/usr/bin/env bash +set -e -o pipefail + +# Define the default values using environment variables +default_vault_name="${VAULT_NAME:-kfutil}" +default_secret_name="${SECRET_NAME:-integration-labs}" +echo "Default vault name: $default_vault_name" +echo "Default secret name: $default_secret_name" + +export METADATA_URL="http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://vault.azure.net" + +read_keyvault_secret_azure() { + local vault_name="$1" + local secret_name="$2" + + echo "Vault Name: $vault_name" + echo "Secret Name: $secret_name" + + # Make a request to the metadata endpoint + echo "Querying metadata endpoint for access token..." + echo "Metadata URL: $METADATA_URL" + token_json=$(curl -H "Metadata: true" $METADATA_URL) + + echo "Exporting access token to access_token variable..." + # Parse the access token from the response JSON + access_token=$(echo $token_json | jq -r .access_token) + + # Now you can use the $access_token to authenticate and access Azure Key Vault + echo "Access Token: $access_token" + + secret_url="https://${vault_name}.vault.azure.net/secrets/${secret_name}?api-version=7.0" + echo "Secret URL: $secret_url" + + # Get the secret value from Azure Key Vault + echo "Querying Azure Key Vault for secret value..." + secret_value=$(curl -H "Authorization: Bearer ${access_token}" "$secret_url" | jq -r .value) + + mkdir -p ~/.keyfactor + echo "${secret_value}" | jq -r . > "${secret_name}.json" + rm -f "${HOME}/.keyfactor/command_config.json" || true + echo "${secret_value}" | jq -r . > "${HOME}/.keyfactor/command_config.json" +} + +read_keyvault_secret_cli() { + local vault_name="$1" + local secret_name="$2" + + echo "Vault Name: $vault_name" + echo "Secret Name: $secret_name" + + # Check if the user is logged in to Azure CLI + if ! az account show &> /dev/null; then + echo "You are not logged in to Azure CLI. Please run 'az login' to continue." + exit 1 + fi + + # Get the secret value from Azure Key Vault using Azure CLI + echo "Querying Azure Key Vault for secret value using Azure CLI..." + secret_value=$(az keyvault secret show --vault-name "$vault_name" --name "$secret_name" --query value -o tsv) + + mkdir -p ~/.keyfactor + echo "${secret_value}" | jq -r . > "${secret_name}.json" + rm -f "${HOME}/.keyfactor/command_config.json" || true + echo "${secret_value}" | jq -r . > "${HOME}/.keyfactor/command_config.json" +} + +# Main script logic +if curl -H "Metadata: true" --max-time 5 $METADATA_URL &> /dev/null; then + # Running in Azure Cloud + read_keyvault_secret_azure "$default_vault_name" "$default_secret_name" +else + # Running on a workstation + if [[ $# -eq 0 ]]; then + # No arguments provided, use default values from environment variables + read_keyvault_secret_cli "$default_vault_name" "$default_secret_name" + elif [[ $# -eq 2 ]]; then + # Two arguments provided: vault_name and secret_name + read_keyvault_secret_cli "$1" "$2" + else + echo "Usage: $0 [vault_name secret_name]" + exit 1 + fi +fi \ No newline at end of file From bc6d4b1e022523eaf950098ab883247b31e982bb Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Mon, 18 Nov 2024 09:09:13 -0800 Subject: [PATCH 15/49] fix(auth): Auth via AKV config using `keyfactor-auth-client-go` Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- .../keyfactor-bootstrap-workflow.yml | 3 +- cmd/helm_uo.go | 7 +- cmd/login.go | 816 ------------------ cmd/root.go | 266 ++++-- go.mod | 16 +- go.sum | 44 +- 6 files changed, 223 insertions(+), 929 deletions(-) diff --git a/.github/workflows/keyfactor-bootstrap-workflow.yml b/.github/workflows/keyfactor-bootstrap-workflow.yml index 5d3b5f0..4a58139 100644 --- a/.github/workflows/keyfactor-bootstrap-workflow.yml +++ b/.github/workflows/keyfactor-bootstrap-workflow.yml @@ -223,5 +223,4 @@ jobs: token: ${{ secrets.V2BUILDTOKEN}} APPROVE_README_PUSH: ${{ secrets.APPROVE_README_PUSH}} gpg_key: ${{ secrets.KF_GPG_PRIVATE_KEY }} - gpg_pass: ${{ secrets.KF_GPG_PASSPHRASE }} - GITHUB_TOKEN: ${{ secrets.V2BUILDTOKEN }} \ No newline at end of file + gpg_pass: ${{ secrets.KF_GPG_PASSPHRASE }} \ No newline at end of file diff --git a/cmd/helm_uo.go b/cmd/helm_uo.go index 2060926..ceeee6e 100644 --- a/cmd/helm_uo.go +++ b/cmd/helm_uo.go @@ -20,6 +20,7 @@ import ( "fmt" "log" + "github.com/Keyfactor/keyfactor-auth-client-go/auth_providers" "github.com/spf13/cobra" "github.com/spf13/pflag" "kfutil/pkg/cmdutil" @@ -171,13 +172,13 @@ func (f *HelmUoFlags) ToOptions(cmd *cobra.Command, args []string) (*HelmUoOptio } // Get the command config entry from global flags - commandConfig, _ := authConfigFile(configFile, profile, "", noPrompt, false) + commandConfig, _ := auth_providers.ReadConfigFromJSON(configFile) // Get the hostname from the command config entry, ok := commandConfig.Servers[profile] if ok { - if entry.Hostname != "" { - options.CommandHostname = commandConfig.Servers[profile].Hostname + if entry.Host != "" { + options.CommandHostname = commandConfig.Servers[profile].Host } } diff --git a/cmd/login.go b/cmd/login.go index 578990e..6e34772 100644 --- a/cmd/login.go +++ b/cmd/login.go @@ -16,7 +16,6 @@ package cmd import ( "bufio" - "encoding/json" "fmt" "io" stdlog "log" @@ -25,7 +24,6 @@ import ( "strings" "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" @@ -329,28 +327,6 @@ func getDomainFromUsername(username string) string { return "" } -func createConfigFile( - hostname string, - username string, - password string, - domain string, - apiPath string, - profileName string, -) ConfigurationFile { - output := ConfigurationFile{ - Servers: map[string]ConfigurationFileEntry{ - profileName: { - Hostname: hostname, - Username: username, - Password: password, - Domain: domain, - APIPath: apiPath, - }, - }, - } - return output -} - func promptForInteractiveParameter(parameterName string, defaultValue string) string { var input string fmt.Printf("Enter %s [%s]: \n", parameterName, defaultValue) @@ -423,26 +399,6 @@ func handleInteractiveError(err error, parameterName string) error { return nil } -func saveConfigFile(configFile ConfigurationFile, configPath string, profileName string) (ConfigurationFile, error) { - if profileName == "" { - profileName = "default" - } - - configurationErr := createOrUpdateConfigurationFile(configFile.Servers[profileName], profileName, configPath) - if configurationErr != nil { - //log.Fatal("[ERROR] Unable to save configuration file to disk: ", configurationErr) - log.Error().Err(configurationErr) - return configFile, configurationErr - } - loadedConfig, loadErr := loadConfigurationFile(configPath, true) - if loadErr != nil { - //log.Fatal("[ERROR] Unable to load configuration file after save: ", loadErr) - log.Error().Err(loadErr) - return configFile, loadErr - } - return loadedConfig, nil -} - func authInteractive( serverConf *auth_providers.Server, profileName string, @@ -572,775 +528,3 @@ func prepHomeDir() (string, error) { } return userHomeDir, hErr } - -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). - Msg("loadConfigFileData() called") - - log.Debug().Msg("calling authEnvVars()") - envConfig, _ := authEnvVars(configPath, profileName, false) //Load env vars first - log.Debug().Msg("authEnvVars() returned") - - // Check if profileName exists in config file - log.Debug().Str("profileName", profileName).Msg("checking if profileName exists in config file") - configProfile, profileExists := configurationFile.Servers[profileName] - if !profileExists { - log.Error(). - Str("profileName", profileName). - Msg("profileName does not exist in config file") - if noPrompt { // TODO: If profile doesn't exist how does this work? - log.Error().Msg("noPrompt is set, unable to prompt for missing profileName") - return envConfig.Servers[profileName].Hostname, envConfig.Servers[profileName].Username, envConfig.Servers[profileName].Password, envConfig.Servers[profileName].Domain, envConfig.Servers[profileName].APIPath - } - } else { - //log.Println("[INFO] Using kfutil config profileName: ", profileName) - log.Info().Str("profileName", profileName).Msg("Using kfutil config profileName") - hostName := configProfile.Hostname - userName := configProfile.Username - password := configProfile.Password - domain := configProfile.Domain - apiPath := configProfile.APIPath - authProvider := configProfile.AuthProvider - log.Debug().Str("hostName", hostName). - Str("userName", userName). - Str("password", hashSecretValue(password)). - Str("domain", domain). - Str("apiPath", apiPath). - Str("authProvider", fmt.Sprintf("%+v", authProvider)). - Msg("configProfile values") - - if authProvider.Type != "" && authProvider.Parameters != nil { - // cALL authViaProviderParams - log.Info().Str("authProvider.Type", authProvider.Type). - Msg("Authenticating via authProvider") - log.Debug().Msg("calling authViaProviderParams()") - authConfig, authErr := authViaProviderParams(&authProvider) - if authErr != nil { - //log.Println("[ERROR] Unable to authenticate via provider: ", authErr) - log.Error().Err(authErr).Msg("Unable to authenticate via provider") - return "", "", "", "", "" - } - - // Check if authProvider profile is set - if authProvider.Profile == "" { - authProvider.Profile = "default" - log.Info().Msg("Using default authProvider profile") - } - - hostName = authConfig.Servers[authProvider.Profile].Hostname - userName = authConfig.Servers[authProvider.Profile].Username - password = authConfig.Servers[authProvider.Profile].Password - domain = authConfig.Servers[authProvider.Profile].Domain - apiPath = authConfig.Servers[authProvider.Profile].APIPath - - log.Debug().Str("hostName", hostName). - Str("userName", userName). - Str("password", hashSecretValue(password)). - Str("domain", domain). - Str("apiPath", apiPath). - Msg("authConfig values") - - return hostName, userName, password, domain, apiPath - } - - if hostName == "" && envConfig.Servers[profileName].Hostname != "" { - hostName = envConfig.Servers[profileName].Hostname - } - if userName == "" && envConfig.Servers[profileName].Username != "" { - userName = envConfig.Servers[profileName].Username - } - if password == "" && envConfig.Servers[profileName].Password != "" { - password = envConfig.Servers[profileName].Password - } - if domain == "" && envConfig.Servers[profileName].Domain != "" { - domain = envConfig.Servers[profileName].Domain - } - if apiPath == "" && envConfig.Servers[profileName].APIPath != "" { - apiPath = envConfig.Servers[profileName].APIPath - } - - log.Debug().Str("hostName", hostName). - Str("userName", userName). - Str("password", hashSecretValue(password)). - Str("domain", domain). - Str("apiPath", apiPath). - Msg("configProfile values") - - return hostName, userName, password, domain, apiPath - } - log.Error().Msg("Unable to load config file data") - return "", "", "", "", "" -} - -func authViaProvider() (*api.Client, error) { - var clientAuth api.AuthConfig - var commandConfig auth_providers.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'") - 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 //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(clientConfig, nil) - log.Debug().Msg("complete: api.NewKeyfactorClient()") - - 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) - } - 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 - // First check if provider type and provider config are not empty - if pt == "" || providerConfig == nil { - return ConfigurationFile{}, fmt.Errorf("provider type and provider config cannot be empty") - } - - // 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, - ) - } - - // Check if provider type matches requested provider type - switch pt { - case "azure-id", "azid", "az-id", "azureid": - //load provider config params into AuthProviderAzureIdParams struct - log.Debug().Msg("authenticating via azure-id provider") - var providerParams AuthProviderAzureIDParams - log.Debug().Msg("marshalling providerConfig.Parameters") - paramsJson, _ := json.Marshal(providerConfig.Parameters) - log.Debug().Msg("unmarshalling providerParams") - jsonErr := json.Unmarshal(paramsJson, &providerParams) - if jsonErr != nil { - log.Error().Err(jsonErr).Msg("unable to unmarshal providerParams") - return ConfigurationFile{}, jsonErr - } - - // Check if required params are set - if providerParams.SecretName == "" || providerParams.AzureVaultName == "" { - return ConfigurationFile{}, fmt.Errorf("provider params secret_name and vault_name are required") - } - log.Debug().Msgf("providerParams: %+v", providerParams) - return providerParams.authenticate() - case "az-cli", "azcli", "azure-cli", "azurecli": - log.Debug().Msg("authenticating via azure-cli provider") - break - default: - //log.Println("[ERROR] invalid auth provider type") - log.Error().Msg("invalid auth provider type") - break - } - return ConfigurationFile{}, fmt.Errorf( - "invalid auth provider type '%s'. Valid auth providers are: %v", - pt, - ValidAuthProviders, - ) -} - -func validAuthProvider(providerType string) bool { - log.Debug().Str("providerType", providerType).Msg("validAuthProvider() called") - if providerType == "" { - return true // default to Username/Password - } - for _, validProvider := range ValidAuthProviders { - if validProvider == providerType { - log.Debug().Str("providerType", providerType).Msg("is valid auth provider type") - return true - } - } - log.Error().Str("providerType", providerType).Msg("is not valid auth provider type") - return false -} - -func authConfigFile( - configPath string, - profileName string, - authProviderProfile string, - noPrompt bool, - saveConfig bool, -) (ConfigurationFile, []error) { - var configurationFile ConfigurationFile - var ( - hostName string - userName string - password string - domain string - apiPath string - - //hostSet bool - //userSet bool - //passSet bool - //domainSet bool - //apiPathSet bool - //profileSet bool - ) - - //log.Println("[DEBUG] Using profileName: ", profileName) - log.Debug().Str("profileName", profileName). - Msg("Using profileName") - - if configPath == "" { - log.Debug().Msg("configPath is empty, setting to default") - log.Debug().Msg("calling prepHomeDir()") - userHomeDir, _ := prepHomeDir() - log.Debug().Msg("prepHomeDir() returned") - - configPath = fmt.Sprintf("%s/%s", userHomeDir, DefaultConfigFileName) - log.Debug().Str("configPath", configPath).Msg("configPath set") - } - configurationFile, _ = loadConfigurationFile(configPath, noPrompt) - - if configurationFile.Servers == nil { - configurationFile.Servers = make(map[string]ConfigurationFileEntry) - } - if profileName == "" { - log.Debug().Msg("profileName is empty, setting to default") - profileName = "default" - } - - log.Debug().Msg("calling loadConfigFileData()") - hostName, userName, password, domain, apiPath = loadConfigFileData( - profileName, - configPath, - noPrompt, - configurationFile, - ) - log.Debug().Msg("loadConfigFileData() returned") - - log.Debug().Str("hostName", hostName). - Str("userName", userName). - Str("password", hashSecretValue(password)). - Str("domain", domain). - Str("apiPath", apiPath). - Msg("loadConfigFileData() values") - - log.Debug().Msg("calling createConfigFile()") - confFile := createConfigFile(hostName, userName, password, domain, apiPath, profileName) - log.Debug().Msg("createConfigFile() returned") - - if saveConfig { - log.Info().Str("configPath", configPath). - Str("profileName", profileName). - Msg("Saving configuration file") - log.Debug().Msg("calling saveConfigFile()") - savedConfigFile, saveErr := saveConfigFile(confFile, configPath, profileName) - log.Debug().Msg("saveConfigFile() returned") - if saveErr != nil { - log.Error().Err(saveErr) - return confFile, []error{saveErr} - } - log.Info().Str("configPath", configPath). - Str("profileName", profileName). - Msg("Configuration file saved") - - log.Debug().Msg("returning savedConfigFile") - return savedConfigFile, nil - } - - configurationFile.Servers[profileName] = confFile.Servers[profileName] - return configurationFile, nil -} - -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") - - if configProfile == "" { - log.Debug().Msg("configProfile is empty, setting to default") - configProfile = "default" - } - // attempt to cast authProvider.Parameters to string - authProviderParams, ok := authProvider.Parameters.(string) - if !ok { - //log.Println("[ERROR] unable to cast authProvider.Parameters to string") - log.Error().Msg("unable to cast authProvider.Parameters to string") - return ConfigurationFile{}, []error{fmt.Errorf("invalid configuration, unable to cast authProvider.Parameters to string")} - } - - if strings.HasPrefix(authProviderParams, "{") && strings.HasSuffix(authProviderParams, "}") { - // authProviderParams is a json string - //log.Println("[DEBUG] authProviderParams is a json string") - log.Debug().Msg("authProviderParams is a json string") - var providerParams interface{} - //log.Println("[DEBUG] converting authProviderParams to unescaped json") - log.Debug().Msg("converting authProviderParams to unescaped json") - jsonErr := json.Unmarshal([]byte(authProviderParams), &providerParams) - if jsonErr != nil { - //log.Println("[ERROR] unable to unmarshal authProviderParams: ", jsonErr) - log.Error().Err(jsonErr).Msg("unable to unmarshal authProviderParams") - return ConfigurationFile{}, []error{jsonErr} - } - authProvider.Parameters = providerParams - } else { - // attempt to read as json file path - //log.Println("[DEBUG] authProviderParams is a json file path") - log.Debug().Msg("authProviderParams is a json file path") - var providerParams interface{} - var providerConfigFile ConfigurationFile - var authProviderConfig AuthProvider - //log.Println("[DEBUG] opening authProviderParams file ", authProviderParams) - log.Debug().Str("authProviderParams", authProviderParams).Msg("opening authProviderParams file") - - jsonFile, jsonFileErr := os.Open(authProviderParams) - if jsonFileErr != nil { - //log.Println("[ERROR] unable to open authProviderParams file: ", jsonFileErr) - log.Error().Err(jsonFileErr).Msg("unable to open authProviderParams file") - return ConfigurationFile{}, []error{jsonFileErr} - } - defer jsonFile.Close() - //log.Println(fmt.Sprintf("[DEBUG] reading authProviderParams file %s as bytes", authProviderParams)) - log.Debug().Str("authProviderParams", authProviderParams).Msg("reading authProviderParams file as bytes") - jsonBytes, jsonBytesErr := os.ReadFile(authProviderParams) - if jsonBytesErr != nil { - //log.Println("[ERROR] unable to read authProviderParams file: ", jsonBytesErr) - log.Error().Err(jsonBytesErr).Msg("unable to read authProviderParams file") - return ConfigurationFile{}, []error{jsonBytesErr} - } - //log.Println("[DEBUG] converting authProviderParams to unescaped json") - log.Debug().Msg("converting authProviderParams to unescaped json") - jsonErr := json.Unmarshal(jsonBytes, &providerParams) - if jsonErr != nil { - //log.Println("[ERROR] unable to unmarshal authProviderParams: ", jsonErr) - log.Error().Err(jsonErr).Msg("unable to unmarshal authProviderParams") - return ConfigurationFile{}, []error{jsonErr} - } - - //Check if provider params is a configuration file - //log.Println("[DEBUG] checking if authProviderParams is a configuration file") - log.Debug().Msg("checking if authProviderParams is a configuration file") - jsonErr = json.Unmarshal(jsonBytes, &providerConfigFile) - if jsonErr == nil && providerConfigFile.Servers != nil { - // lookup params based on configProfile - //log.Println("[DEBUG] authProviderParams is a configuration file") - log.Debug().Msg("authProviderParams is a configuration file") - // check to see if profile exists in config file - if _, isConfigFile := providerConfigFile.Servers[configProfile]; isConfigFile { - //log.Println(fmt.Sprintf("[DEBUG] profile '%s' found in authProviderParams file", configProfile)) - log.Debug().Str("configProfile", configProfile).Msg("profile found in authProviderParams file") - providerParams = providerConfigFile.Servers[configProfile] - // check if providerParams is a ConfigurationFileEntry - if _, isConfigFileEntry := providerParams.(ConfigurationFileEntry); !isConfigFileEntry { - //log.Println("[ERROR] unable to cast providerParams to ConfigurationFileEntry") - log.Error().Msg("unable to cast providerParams to ConfigurationFileEntry") - return ConfigurationFile{}, []error{fmt.Errorf("invalid configuration, unable to cast providerParams to ConfigurationFileEntry")} - } - // set providerParams to ConfigurationFileEntry.AuthProvider.Parameters - providerParams = providerConfigFile.Servers[configProfile].AuthProvider.Parameters - } 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, - ), - } - } - } else { - //check if provider params is an AuthProvider - //log.Println("[DEBUG] checking if authProviderParams is an AuthProvider") - log.Debug().Msg("checking if authProviderParams is an AuthProvider") - - //log.Println("[DEBUG] converting authProviderParams to unescaped json") - log.Debug().Msg("converting authProviderParams to unescaped json") - - //check if providerParams is a map[string]interface{} - if _, isMap := providerParams.(map[string]interface{}); isMap { - //check if 'auth_provider' key exists and if it does convert to json bytes - log.Debug().Msg("authProviderParams is a map") - if _, isAuthProvider := providerParams.(map[string]interface{})["auth_provider"]; isAuthProvider { - //log.Println("[DEBUG] authProviderParams is a map[string]interface{}") - //log.Println("[DEBUG] converting authProviderParams to unescaped json") - log.Debug().Msg("authProviderParams is a map[string]interface{}") - log.Debug().Msg("converting authProviderParams to unescaped json") - jsonBytes, jsonBytesErr = json.Marshal(providerParams.(map[string]interface{})["auth_provider"]) - if jsonBytesErr != nil { - //log.Println("[ERROR] unable to marshal authProviderParams: ", jsonBytesErr) - log.Error().Err(jsonBytesErr).Msg("unable to marshal authProviderParams") - return ConfigurationFile{}, []error{jsonBytesErr} - } - } - } - - jsonErr = json.Unmarshal(jsonBytes, &authProviderConfig) - if jsonErr == nil && authProviderConfig.Type != "" && authProviderConfig.Parameters != nil { - //log.Println("[DEBUG] authProviderParams is an AuthProvider") - log.Debug().Msg("authProviderParams is an AuthProvider") - providerParams = authProviderConfig.Parameters - } - } - 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") - configFile, authErr := authViaProviderParams(authProvider) - if authErr != nil { - //log.Println("[ERROR] Unable to authenticate via provider: ", authErr) - log.Error().Err(authErr).Msg("Unable to authenticate via provider") - return ConfigurationFile{}, []error{authErr} - } - //log.Println("[INFO] Successfully retrieved kfutil creds via auth provider") - log.Info().Msg("Successfully retrieved kfutil creds via auth provider") - return configFile, nil -} - -func authEnvVars(configPath string, profileName string, saveConfig bool) (ConfigurationFile, []error) { - hostname, hostSet := os.LookupEnv("KEYFACTOR_HOSTNAME") - username, userSet := os.LookupEnv("KEYFACTOR_USERNAME") - password, passSet := os.LookupEnv("KEYFACTOR_PASSWORD") - domain, domainSet := os.LookupEnv("KEYFACTOR_DOMAIN") - apiPath, apiPathSet := os.LookupEnv("KEYFACTOR_API_PATH") - envProfileName, _ := os.LookupEnv("KFUTIL_PROFILE") - authProviderType, _ := os.LookupEnv("KFUTIL_AUTH_PROVIDER_TYPE") - authProviderProfile, _ := os.LookupEnv("KUTIL_AUTH_PROVIDER_PROFILE") - authProviderParams, _ := os.LookupEnv("KFUTIL_AUTH_PROVIDER_PARAMS") // this is a json string or a json file path - - if authProviderType != "" || authProviderParams != "" { - if authProviderParams == "" { - authProviderParams = fmt.Sprintf("%s/.keyfactor/%s", os.Getenv("HOME"), DefaultConfigFileName) - } - if authProviderProfile == "" { - authProviderProfile = "default" - } - authProvider := AuthProvider{ - Type: authProviderType, - Profile: authProviderProfile, - Parameters: authProviderParams, - } - //check if authProviderParams is a json string or a json file path - return authEnvProvider(&authProvider, profileName) - } - - if profileName == "" && envProfileName != "" { - profileName = envProfileName - } else if profileName == "" { - profileName = "default" - } - - log.Printf("KEYFACTOR_HOSTNAME: %s\n", hostname) - log.Printf("KEYFACTOR_USERNAME: %s\n", username) - log.Printf("KEYFACTOR_DOMAIN: %s\n", domain) - - if domain == "" && username != "" { - domain = getDomainFromUsername(username) - } - - var outputErr []error - if !hostSet { - 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"), - ) - } - if !passSet { - 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"), - ) - } - if !apiPathSet { - apiPath = DefaultAPIPath - apiPathSet = true - } - - if !hostSet && !userSet && !passSet && !domainSet { - return ConfigurationFile{}, outputErr - } - - confFile := createConfigFile(hostname, username, password, domain, apiPath, profileName) - - if len(outputErr) > 0 { - return confFile, outputErr - } - - if saveConfig { - savedConfigFile, saveErr := saveConfigFile(confFile, configPath, profileName) - if saveErr != nil { - return confFile, []error{saveErr} - } - return savedConfigFile, nil - } - return confFile, nil -} - -func createOrUpdateConfigurationFile(cfgFile ConfigurationFileEntry, profile string, configPath string) error { - //log.Println("[INFO] Creating or updating configuration file") - log.Info().Str("configPath", configPath). - Str("profile", profile). - Msg("Creating or updating configuration file") - //log.Println("[DEBUG] configuration file path: ", configPath) - - if len(profile) == 0 { - log.Debug().Msg("profile is empty, setting to default") - profile = "default" - } - //check if configPath exists - if configPath == "" { - defaultDir, _ := os.UserHomeDir() - configPath = path.Join(defaultDir, ".keyfactor", DefaultConfigFileName) - //log.Println("[WARN] no config path provided. Using '" + configPath + "'.") - log.Debug().Str("configPath", configPath).Msg("no config path provided using default") - } - confFileExists, fileErr := os.Stat(configPath) - if fileErr != nil { - //log.Println("[WARN] ", fileErr) - log.Error().Err(fileErr).Msg("error checking if config file exists") - } - - existingConfig, _ := loadConfigurationFile(configPath, true) - if len(existingConfig.Servers) > 0 { - // check if the config name already exists - if _, ok := existingConfig.Servers[profile]; ok { - //log.Println(fmt.Sprintf("[WARN] config name '%s' already exists. Overwriting existing config.", profile)) - log.Info(). - Str("profile", profile). - Msg("config profile already exists, overwriting existing config") - //log.Println(fmt.Sprintf("[DEBUG] existing config: %v", existingConfig.Servers[profile])) - log.Debug().Str("profile", profile). - Str("existingConfig", fmt.Sprintf("%+v", existingConfig.Servers[profile])). - Msg("existing config") - //log.Println(fmt.Sprintf("[DEBUG] new config: %v", cfgFile)) - // print out the diff between the two configs - diff := cmp.Diff(existingConfig.Servers[profile], cfgFile) - if len(diff) == 0 && confFileExists != nil { - //log.Println("[DEBUG] no configuration changes detected") - log.Debug().Msg("no configuration changes detected") - return nil - } - //log.Println(fmt.Sprintf("[DEBUG] diff: %s", diff)) - log.Debug().Str("diff", diff).Msg("config diff") - } - existingConfig.Servers[profile] = cfgFile - } else { - //log.Println(fmt.Sprintf("[INFO] adding new config name '%s'", profile)) - log.Info().Str("profile", profile).Msg("adding new profile") - existingConfig.Servers = make(map[string]ConfigurationFileEntry) - existingConfig.Servers[profile] = cfgFile - } - - //log.Println("[DEBUG] kfcfg entry: ", cfgFile) - log.Debug().Str("cfgFile", fmt.Sprintf("%+v", cfgFile)).Msg("kfcfg entry") - - f, fErr := os.OpenFile(fmt.Sprintf("%s", configPath), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0600) - defer f.Close() - if fErr != nil { - msg := fmt.Errorf("unable to create command configuration file %s: %s", configPath, fErr) - outputError(msg, false, outputFormat) - log.Error().Err(fErr).Msg("unable to create command configuration file") - return fErr - } - - // convert existingConfig to json - jsonData, jsErr := json.MarshalIndent(existingConfig, "", " ") - if jsErr != nil { - //fmt.Println("Unable to read kfcfg file due to invalid format. ", jsErr) - outputError(jsErr, false, outputFormat) - //log.Println("[ERROR] marshalling kfcfg file: ", jsErr) - log.Error().Err(jsErr).Msg("marshalling command config file") - return jsErr - } - _, enErr := f.Write(jsonData) - if enErr != nil { - //fmt.Println("Unable to read kfcfg file due to invalid format. ", enErr) - outputError(enErr, false, outputFormat) - //log.Println("[ERROR] encoding kfcfg file: ", enErr) - log.Error().Err(enErr).Msg("encoding command config file") - return enErr - } - return nil -} - -func loadConfigurationFile(filePath string, silent bool) (ConfigurationFile, error) { - log.Debug().Str("filePath", filePath).Msg("loadConfigurationFile() called") - //data := ConfigurationFile{Servers: make(map[string]ConfigurationFileEntry)} - data := ConfigurationFile{} - if filePath == "" { - log.Debug().Msg("filePath is empty, setting to default") - defaultDir, _ := os.UserHomeDir() - filePath = path.Join(defaultDir, ".keyfactor", DefaultConfigFileName) - } - log.Debug().Str("filePath", filePath).Msg("filePath set") - - // attempt to make the directory if it doesn't exist - dirPath := path.Dir(filePath) - if _, dirErr := os.Stat(dirPath); os.IsNotExist(dirErr) { - //log.Println("[DEBUG] config directory does not exist, creating: ", dirPath) - log.Debug().Str("dirPath", dirPath).Msg("config directory does not exist, creating") - err := os.MkdirAll(dirPath, 0700) - if err != nil { - //log.Println("[ERROR] creating config directory: ", err) - log.Error().Err(err).Msg("creating config directory") - return data, err - } - return data, nil // return empty data since the directory didn't exist the file won't exist - } - - // check if file exists - if _, fileErr := os.Stat(filePath); os.IsNotExist(fileErr) { - //log.Println("[DEBUG] config file does not exist: ", filePath) - log.Debug().Str("filePath", filePath).Msg("config file does not exist") - return data, nil // return empty data since the file doesn't exist - } - - f, rFErr := os.ReadFile(filePath) - if rFErr != nil { - if !silent { - //fmt.Println(fmt.Sprintf("Unable to read config file '%s'.", rFErr)) - outputError(rFErr, true, outputFormat) - //log.Fatal("[FATAL] Error reading config file: ", rFErr) - log.Error().Err(rFErr).Msg("error reading config file") - } - return data, rFErr - } - - // Try to unmarshal as a single entry first - var singleEntry ConfigurationFileEntry - 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") - } 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)) - log.Debug().Str("filePath", filePath).Msg("config file is a single entry, adding to map") - data.Servers = make(map[string]ConfigurationFileEntry) - data.Servers["default"] = singleEntry - return data, nil - } - - jErr := json.Unmarshal(f, &data) - if jErr != nil { - //fmt.Println("Unable to read config file due to invalid format. ", jErr) - //log.Println("[ERROR] decoding config file: ", jErr) - log.Error().Err(jErr).Msg("decoding config file") - return data, jErr - } - - return data, nil -} diff --git a/cmd/root.go b/cmd/root.go index 85dcbfa..18e1daf 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -53,6 +53,7 @@ var ( offline bool ) +// hashSecretValue hashes the secret value using bcrypt func hashSecretValue(secretValue string) string { log.Debug().Msg("Enter hashSecretValue()") if secretValue == "" { @@ -73,6 +74,7 @@ func hashSecretValue(secretValue string) string { return string(hashedPassword) } +// getServerConfigFromFile reads the configuration file and returns the server configuration func getServerConfigFromFile(configFile string, profile string) (*auth_providers.Server, error) { var commandConfig *auth_providers.Config var serverConfig auth_providers.Server @@ -114,6 +116,7 @@ func getServerConfigFromFile(configFile string, profile string) (*auth_providers return &serverConfig, nil } +// getServerConfigFromEnv reads the environment variables and returns the server configuration func getServerConfigFromEnv() (*auth_providers.Server, error) { log.Debug().Msg("Enter getServerConfigFromEnv()") @@ -204,6 +207,7 @@ func getServerConfigFromEnv() (*auth_providers.Server, error) { } +// authViaConfigFile authenticates using the configuration file func authViaConfigFile(cfgFile string, cfgProfile string) (*api.Client, error) { var ( c *api.Client @@ -219,6 +223,12 @@ func authViaConfigFile(cfgFile string, cfgProfile string) (*api.Client, error) { return nil, err } if conf != nil { + if conf.AuthProvider.Type != "" { + switch conf.AuthProvider.Type { + case "azid", "azure", "az", "akv": + return authViaProvider(cfgFile, cfgProfile) + } + } log.Debug().Msg("call: api.NewKeyfactorClient()") c, cErr = api.NewKeyfactorClient(conf, nil) log.Debug().Msg("complete: api.NewKeyfactorClient()") @@ -239,6 +249,8 @@ 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) } + +// authSdkViaConfigFile authenticates using the configuration file func authSdkViaConfigFile(cfgFile string, cfgProfile string) (*keyfactor.APIClient, error) { var ( c *keyfactor.APIClient @@ -254,6 +266,18 @@ func authSdkViaConfigFile(cfgFile string, cfgProfile string) (*keyfactor.APIClie return nil, err } if conf != nil { + if conf.AuthProvider.Type != "" { + switch conf.AuthProvider.Type { + case "azid", "azure", "az", "akv": + log.Debug(). + Str("providerType", conf.AuthProvider.Type). + Str("providerProfile", conf.AuthProvider.Profile). + Str("cfgFile", cfgFile). + Str("cfgProfile", cfgProfile). + Msg("call: authSdkViaProvider()") + return authSdkViaProvider(cfgFile, cfgProfile) + } + } log.Debug().Msg("call: keyfactor.NewAPIClient()") c, cErr = keyfactor.NewAPIClient(conf) log.Debug().Msg("complete: keyfactor.NewAPIClient()") @@ -275,6 +299,7 @@ func authSdkViaConfigFile(cfgFile string, cfgProfile string) (*keyfactor.APIClie return nil, fmt.Errorf("unable to authenticate via config file '%s' using profile '%s'", cfgFile, cfgProfile) } +// authViaEnvVars authenticates using the environment variables func authViaEnvVars() (*api.Client, error) { var ( c *api.Client @@ -312,6 +337,8 @@ func authViaEnvVars() (*api.Client, error) { log.Debug().Msg("return: authViaEnvVars()") return nil, fmt.Errorf("unable to authenticate via environment variables") } + +// authSdkViaEnvVars authenticates using the environment variables func authSdkViaEnvVars() (*keyfactor.APIClient, error) { var ( c *keyfactor.APIClient @@ -350,6 +377,154 @@ func authSdkViaEnvVars() (*keyfactor.APIClient, error) { return nil, fmt.Errorf("unable to authenticate via environment variables") } +// authViaProvider authenticates using the provider +func authViaProvider(cfgFile string, cfgProfile string) (*api.Client, error) { + log.Debug(). + Str("providerType", providerType). + Str("providerProfile", providerProfile). + Str("cfgFile", cfgFile). + Str("cfgProfile", cfgProfile). + Msg("enter: authViaProvider()") + 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 authenticate via provider") + return nil, err + } + + if providerType == "" { + providerType = conf.AuthProvider.Type + } + + if providerType == "azid" || providerType == "azure" { + azConfig := &auth_providers.ConfigProviderAzureKeyVault{} + secretName, sOk := os.LookupEnv(auth_providers.EnvAzureSecretName) + vaultName, vOk := os.LookupEnv(auth_providers.EnvAzureVaultName) + if !sOk { + secretName, sOk = conf.AuthProvider.Parameters["secret_name"].(string) + } + if !vOk { + vaultName, vOk = conf.AuthProvider.Parameters["vault_name"].(string) + } + aErr := azConfig. + WithSecretName(secretName). + WithVaultName(vaultName). + Authenticate() + if aErr != nil { + log.Error().Err(aErr).Msg("unable to authenticate via provider") + return nil, aErr + } + cfg, cfgErr := azConfig.LoadConfigFromAzureKeyVault() + if cfgErr != nil { + log.Error().Err(cfgErr).Msg("unable to load config from Azure Key Vault") + return nil, cfgErr + } + log.Debug().Msg("call: api.NewKeyfactorClient()") + serverConfig, serOk := cfg.Servers[providerProfile] + if !serOk { + log.Error().Str("profile", providerProfile).Msg("invalid profile") + return nil, fmt.Errorf("invalid profile: %s", providerProfile) + } + c, cErr = api.NewKeyfactorClient(&serverConfig, nil) + log.Debug().Msg("complete: api.NewKeyfactorClient()") + 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 { + log.Error().Err(authErr).Msg("unable to authenticate via provider") + return nil, authErr + } + return c, nil + } + log.Error().Str("providerType", providerType).Msg("unsupported provider type") + return nil, fmt.Errorf("unsupported provider type: %s", providerType) +} + +// authSdkViaProvider authenticates using the provider +func authSdkViaProvider(cfgFile string, cfgProfile string) (*keyfactor.APIClient, error) { + log.Debug(). + Str("providerType", providerType). + Str("providerProfile", providerProfile). + Str("cfgFile", cfgFile). + Str("cfgProfile", cfgProfile). + Msg("enter: authViaProvider()") + 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 authenticate via provider") + return nil, err + } + + if providerType == "" { + providerType = conf.AuthProvider.Type + } + + if providerType == "azid" || providerType == "azure" { + azConfig := &auth_providers.ConfigProviderAzureKeyVault{} + secretName, sOk := os.LookupEnv(auth_providers.EnvAzureSecretName) + vaultName, vOk := os.LookupEnv(auth_providers.EnvAzureVaultName) + if !sOk { + secretName, sOk = conf.AuthProvider.Parameters["secret_name"].(string) + } + if !vOk { + vaultName, vOk = conf.AuthProvider.Parameters["vault_name"].(string) + } + aErr := azConfig. + WithSecretName(secretName). + WithVaultName(vaultName). + Authenticate() + if aErr != nil { + log.Error().Err(aErr).Msg("unable to authenticate via provider") + return nil, aErr + } + cfg, cfgErr := azConfig.LoadConfigFromAzureKeyVault() + if cfgErr != nil { + log.Error().Err(cfgErr).Msg("unable to load config from Azure Key Vault") + return nil, cfgErr + } + + serverConfig, serOk := cfg.Servers[providerProfile] + if !serOk { + log.Error().Str("profile", providerProfile).Msg("invalid profile") + return nil, fmt.Errorf("invalid profile: %s", providerProfile) + } + log.Debug().Msg("call: keyfactor.NewAPIClient()") + c, cErr = keyfactor.NewAPIClient(&serverConfig) + 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 { + log.Error().Err(authErr).Msg("unable to authenticate via provider") + return nil, authErr + } + return c, nil + } + log.Error().Str("providerType", providerType).Msg("unsupported provider type") + return nil, fmt.Errorf("unsupported provider type: %s", providerType) +} + +// initClient initializes the legacy Command API client func initClient(saveConfig bool) (*api.Client, error) { log.Debug(). Str("configFile", configFile). @@ -378,7 +553,7 @@ func initClient(saveConfig bool) (*api.Client, error) { log.Debug(). Str("providerType", providerType). Msg("call: authViaProvider()") - return authViaProvider() + return authViaProvider("", "") } log.Debug(). Msg("providerType is empty attempting to authenticate via params") @@ -429,6 +604,7 @@ func initClient(saveConfig bool) (*api.Client, error) { return nil, fmt.Errorf("unable to authenticate to Keyfactor Command") } +// initGenClient initializes the SDK Command API client func initGenClient( saveConfig bool, ) (*keyfactor.APIClient, error) { @@ -459,9 +635,8 @@ func initGenClient( if providerType != "" { log.Debug(). Str("providerType", providerType). - Msg("call: authViaProvider()") - //return authViaProvider() - return nil, fmt.Errorf("provider auth not supported using Keyfactor Command SDK") + Msg("call: authSdkViaProvider()") + return authSdkViaProvider("", "") } log.Debug(). Msg("providerType is empty attempting to authenticate via params") @@ -511,89 +686,6 @@ func initGenClient( return nil, fmt.Errorf("unable to authenticate to Keyfactor Command with provided credentials, please check your configuration") } -//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/go.mod b/go.mod index 50efeb3..984670a 100644 --- a/go.mod +++ b/go.mod @@ -7,9 +7,9 @@ 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/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 github.com/Jeffail/gabs v1.4.0 - github.com/Keyfactor/keyfactor-auth-client-go v1.0.0-rc.18 + github.com/Keyfactor/keyfactor-auth-client-go v1.1.0-rc.3 github.com/Keyfactor/keyfactor-go-client-sdk/v2 v2.0.0-rc.2 github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.11 github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 @@ -22,14 +22,16 @@ require ( github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.9.0 - golang.org/x/crypto v0.25.0 - golang.org/x/term v0.22.0 + golang.org/x/crypto v0.27.0 + golang.org/x/term v0.24.0 gopkg.in/yaml.v3 v3.0.1 //github.com/google/go-cmp/cmp v0.5.9 ) require ( github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.12.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 // indirect 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 @@ -48,9 +50,9 @@ require ( github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/spbsoluble/go-pkcs12 v0.3.3 // indirect go.mozilla.org/pkcs7 v0.9.0 // indirect - golang.org/x/net v0.27.0 // indirect + golang.org/x/net v0.29.0 // indirect golang.org/x/oauth2 v0.24.0 // indirect - golang.org/x/sys v0.22.0 // indirect - golang.org/x/text v0.16.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/text v0.18.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index cc8b5dd..602a011 100644 --- a/go.sum +++ b/go.sum @@ -2,22 +2,32 @@ github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkk github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 h1:nyQWyZvwGTvunIMxi1Y9uXkcyr+I7TeNrr/foo4Kpk8= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0/go.mod h1:l38EPgmsp71HHLq9j7De57JcKOWPyhrsW1Awm1JS6K0= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 h1:tfLQ34V6F7tVSwoTf/4lH5sE0o6eCJuNDTmH09nDpbc= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 h1:B/dfvscEQtew9dVuoxqxrUKKv8Ih2f55PydknDamU+g= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0/go.mod h1:fiPSssYvltE08HJchL04dOy+RD4hgrjph0cwGGMntdI= +github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0 h1:+m0M/LFxN43KvULkDNfdXOgrjtg6UYJPFBJyuEcRCAw= +github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0/go.mod h1:PwOyop78lveYMRs6oCxjiVyBdyCgIYH6XHIVZO9/SFQ= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY= +github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.12.0 h1:xnO4sFyG8UH2fElBkcqLTOZsAajvKfnSlgBBW8dXYjw= +github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.12.0/go.mod h1:XD3DIOOVgBCO03OleB1fHjgktVRFxlT++KwKgIOewdM= +github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 h1:FbH3BbSb4bvGluTesZZ+ttN/MDsnMmQP36OSnDuSXqw= +github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1/go.mod h1:9V2j0jn9jDEkCkv8w/bKTNppX/d0FVA1ud77xCIP4KA= +github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM= +github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU= 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.18 h1:PMH/pST30UEQ1dz6YcxYCaoA14iGS3BoL+e3M9m3eyw= -github.com/Keyfactor/keyfactor-auth-client-go v1.0.0-rc.18/go.mod h1:00PVslvswI2+6Uln50XKymEiEafmxfrcOxsNEz3bOME= +github.com/Keyfactor/keyfactor-auth-client-go v1.1.0-rc.3 h1:pQvbBM3DmSDdGMLh9s648Md+fHOoZtL7tjmVnHNDeVc= +github.com/Keyfactor/keyfactor-auth-client-go v1.1.0-rc.3/go.mod h1:Ia3VmXsumFrr01BMc1Rp5OpDWmfXWjdeMituda14T4I= github.com/Keyfactor/keyfactor-go-client-sdk/v2 v2.0.0-rc.2 h1:RNrfgrC+mPvqOc1wPsFjB4thuw7qJbP3gOycRDcRwxI= github.com/Keyfactor/keyfactor-go-client-sdk/v2 v2.0.0-rc.2/go.mod h1:11WXGG9VVKSV0EPku1IswjHbGGpzHDKqD4pe2vD7vas= 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/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= @@ -27,6 +37,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/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= 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= @@ -49,6 +61,8 @@ github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs= +github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -75,6 +89,8 @@ github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjL github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/redis/go-redis/v9 v9.6.1 h1:HHDteefn6ZkTtY5fGUE8tj8uy85AHk6zP7CpzIAM0y4= +github.com/redis/go-redis/v9 v9.6.1/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJCQLgE9+RA= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= @@ -98,14 +114,14 @@ 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= -golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 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/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -125,18 +141,18 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= -golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= -golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= +golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= +golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= From edf6f7d6a2874a28bfadc59dbe95e466e7870878 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Mon, 18 Nov 2024 09:23:45 -0800 Subject: [PATCH 16/49] fix(ci): Revert starter workflow to `v3` Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- .../keyfactor-bootstrap-workflow.yml | 105 +----------------- 1 file changed, 1 insertion(+), 104 deletions(-) diff --git a/.github/workflows/keyfactor-bootstrap-workflow.yml b/.github/workflows/keyfactor-bootstrap-workflow.yml index 4a58139..744d769 100644 --- a/.github/workflows/keyfactor-bootstrap-workflow.yml +++ b/.github/workflows/keyfactor-bootstrap-workflow.yml @@ -113,111 +113,8 @@ jobs: 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 }} - # 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 - call-starter-workflow: - uses: keyfactor/actions/.github/workflows/starter.yml@go_build_private_repo_access + uses: keyfactor/actions/.github/workflows/starter.yml@v3 needs: get-versions secrets: token: ${{ secrets.V2BUILDTOKEN}} From 0bc61c5a16cabe86f9abd3267fda0c44d9c5a8b7 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Mon, 18 Nov 2024 09:46:43 -0800 Subject: [PATCH 17/49] chore(docs): Update `Basic` auth verbiage and add `audidence` to oauth config vars Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- README.md | 6 ++++-- readme_source.md | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c4214ef..adc0f94 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ Invoke-WebRequest -Uri "https://raw.githubusercontent.com/Keyfactor/kfutil/main/ ### Basic Auth -Currently, only Active Directory `Basic` authentication is supported. +Currently `Basic Authentication` via `Active Directory` is the *ONLY* supported method of `Basic Authentication`. | Name | Description | Default | |--------------------|---------------------------------------------------------------------------------------------|---------| @@ -87,8 +87,10 @@ Currently, only Active Directory `Basic` authentication is supported. | 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_SCOPES | Scopes to request when authenticating to Keyfactor Command API. Each scope MUST be separated by `,` | `openid` | +| KEYFACTOR_AUTH_AUDIENCE | Audience to request when authenticating to Keyfactor Command API | | | KEYFACTOR_AUTH_ACCESS_TOKEN | Access token to use to authenticate to Keyfactor Command API. This can be supplied directly or generated via client credentials | | +| KEYFACTOR_AUTH_CA_CERT | Either a file path or PEM encoded string to a CA certificate to use when connecting to Keyfactor Auth | | ### kfutil specific diff --git a/readme_source.md b/readme_source.md index 0f6cd9f..4260625 100644 --- a/readme_source.md +++ b/readme_source.md @@ -50,7 +50,7 @@ Invoke-WebRequest -Uri "https://raw.githubusercontent.com/Keyfactor/kfutil/main/ ### Basic Auth -Currently, only Active Directory `Basic` authentication is supported. +Currently `Basic Authentication` via `Active Directory` is the *ONLY* supported method of `Basic Authentication`. | Name | Description | Default | |--------------------|---------------------------------------------------------------------------------------------|---------| @@ -65,8 +65,10 @@ Currently, only Active Directory `Basic` authentication is supported. | 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_SCOPES | Scopes to request when authenticating to Keyfactor Command API. Each scope MUST be separated by `,` | `openid` | +| KEYFACTOR_AUTH_AUDIENCE | Audience to request when authenticating to Keyfactor Command API | | | KEYFACTOR_AUTH_ACCESS_TOKEN | Access token to use to authenticate to Keyfactor Command API. This can be supplied directly or generated via client credentials | | +| KEYFACTOR_AUTH_CA_CERT | Either a file path or PEM encoded string to a CA certificate to use when connecting to Keyfactor Auth | | ### kfutil specific From 04d3fc0437b705a69719ccb98488df7c4d5a3676 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Mon, 18 Nov 2024 10:03:31 -0800 Subject: [PATCH 18/49] chore(docs): Update CHANGELOG.md Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fea864b..a90dc84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# v1.6.0 + +## Features + +- Auth: Added support for authenticating to Keyfactor Command using a oAuth Client Credentials grant type. + # v1.5.1 ## Fixes From 020c30b703b33436dcfedd1ab4fbc3de7d29a940 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Mon, 18 Nov 2024 10:51:04 -0800 Subject: [PATCH 19/49] chore(store-types): Update store-type definitions with latest releases. Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- store_types.json | 445 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 388 insertions(+), 57 deletions(-) diff --git a/store_types.json b/store_types.json index cf7471a..359e05d 100644 --- a/store_types.json +++ b/store_types.json @@ -122,16 +122,16 @@ "Required": false }, { - "Name": "IamAccountId", - "DisplayName": "IAM AWS Account ID", + "Name": "IAMAssumeRole", + "DisplayName": "AWS Role to Assume (IAM)", "Type": "String", "DependsOn": "UseIAM", "DefaultValue": null, "Required": false }, { - "Name": "OAuthAccountId", - "DisplayName": "OAuth AWS Account ID", + "Name": "OAuthAssumeRole", + "DisplayName": "AWS Role to Assume (OAuth)", "Type": "String", "DependsOn": "UseOAuth", "DefaultValue": null, @@ -186,6 +186,34 @@ "BlueprintAllowed": true, "CustomAliasAllowed": "Optional" }, + { + "Name": "Airlock Application Firewall Certificate", + "ShortName": "AirlockWAF", + "Capability": "AirlockWAF", + "LocalStore": false, + "SupportedOperations": { + "Add": false, + "Create": false, + "Discovery": true, + "Enrollment": false, + "Remove": false + }, + "Properties": [], + "EntryParameters": [], + "PasswordOptions": { + "EntrySupported": false, + "StoreRequired": true, + "Style": "Default" + }, + "StorePathType": "", + "StorePathValue": "", + "PrivateKeyAllowed": "Required", + "JobProperties": [], + "ServerRequired": true, + "PowerShell": false, + "BlueprintAllowed": false, + "CustomAliasAllowed": "Allowed" + }, { "Name": "Akamai Certificate Provisioning Service", "ShortName": "Akamai", @@ -776,20 +804,20 @@ "DisplayName": "Server Username", "Type": "Secret", "Description": "The Application ID of the Service Principal used to authenticate with Microsoft Graph for managing Application/Service Principal certificates.", - "Required": false + "Required": true }, { "Name": "ServerPassword", "DisplayName": "Server Password", "Type": "Secret", - "Description": "A Client Secret that the extension will use to authenticate with Microsoft Graph for managing Application/Service Principal certificates, OR the password that encrypts the private key in ClientCertificate", + "Description": "A Client Secret that the extension will use to authenticate with Microsoft Graph for managing Application/Service Principal certificates, OR the password that encrypts the private key in ClientCertificate. If Client Cert Auth is used _and_ the Client Certificate's private key is not encrypted, you **must** select 'No Value' for this field.", "Required": false }, { "Name": "ClientCertificate", "DisplayName": "Client Certificate", "Type": "Secret", - "Description": "The client certificate used to authenticate with Microsoft Graph for managing Application/Service Principal certificates. See the [requirements](#client-certificate-or-client-secret) for more information.", + "Description": "The client certificate used to authenticate with Microsoft Graph for managing Application/Service Principal certificates. See the [requirements](#client-certificate-or-client-secret) for more information. If Client Certificate Auth is not used, you **must** select 'No Value' for this field.", "Required": false }, { @@ -814,7 +842,73 @@ "StoreRequired": false, "Style": "Default" }, - "PrivateKeyAllowed": "Required", + "PrivateKeyAllowed": "Forbidden", + "ServerRequired": true, + "PowerShell": false, + "BlueprintAllowed": false, + "CustomAliasAllowed": "Required" + }, + { + "Name": "Azure App Registration 2 (Application)", + "ShortName": "AzureApp2", + "Capability": "AzureApp2", + "LocalStore": false, + "ClientMachineDescription": "The Azure Tenant (directory) ID where the Application is instantiated", + "StorePathDescription": "The Object ID of the target Application/App Registration that will be managed by the Azure App Registration and Enterprise Application Orchestrator extension.", + "SupportedOperations": { + "Add": true, + "Remove": true, + "Enrollment": false, + "Discovery": true, + "Inventory": true + }, + "Properties": [ + { + "Name": "ServerUsername", + "DisplayName": "Server Username", + "Type": "Secret", + "Description": "The Application ID of the Service Principal used to authenticate with Microsoft Graph for managing Application/App Registration certificates.", + "Required": true + }, + { + "Name": "ServerPassword", + "DisplayName": "Server Password", + "DependsOn": "ServerUsername", + "Type": "Secret", + "Description": "A Client Secret that the extension will use to authenticate with Microsoft Graph for managing Application/App Registration certificates. If Client Certificate Auth is used, you **must** select 'No Value'.", + "Required": false + }, + { + "Name": "ClientCertificate", + "DisplayName": "Client Certificate", + "DependsOn": "ServerUsername", + "Type": "Secret", + "Description": "The client certificate used to authenticate with Microsoft Graph for managing Application/App Registrations certificates. See the [requirements](#client-certificate-or-client-secret) for more information. If Client Certificate Auth is not used, you **must** check 'No Value'.", + "Required": false + }, + { + "Name": "ClientCertificatePassword", + "DisplayName": "Client Certificate Password", + "DependsOn": "ClientCertificate", + "Type": "Secret", + "Description": "The (optional) password that encrypts the private key in ClientCertificate. If Client Certificate Auth is not used, you **must** check 'No Value'.", + "Required": false + }, + { + "Name": "AzureCloud", + "DisplayName": "Azure Global Cloud Authority Host", + "Type": "MultipleChoice", + "DefaultValue": "public,china,germany,government", + "Description": "Specifies the Azure Cloud instance used by the organization.", + "Required": false + } + ], + "PasswordOptions": { + "EntrySupported": false, + "StoreRequired": false, + "Style": "Default" + }, + "PrivateKeyAllowed": "Forbidden", "ServerRequired": true, "PowerShell": false, "BlueprintAllowed": false, @@ -904,20 +998,20 @@ "DisplayName": "Server Username", "Type": "Secret", "Description": "The Application ID of the Service Principal used to authenticate with Microsoft Graph for managing Application/Service Principal certificates.", - "Required": false + "Required": true }, { "Name": "ServerPassword", "DisplayName": "Server Password", "Type": "Secret", - "Description": "A Client Secret that the extension will use to authenticate with Microsoft Graph for managing Application/Service Principal certificates, OR the password that encrypts the private key in ClientCertificate", + "Description": "A Client Secret that the extension will use to authenticate with Microsoft Graph for managing Application/Service Principal certificates, OR the password that encrypts the private key in ClientCertificate. If Client Cert Auth is used _and_ the Client Certificate's private key is not encrypted, you **must** select 'No Value' for this field.", "Required": false }, { "Name": "ClientCertificate", "DisplayName": "Client Certificate", "Type": "Secret", - "Description": "The client certificate used to authenticate with Microsoft Graph for managing Application/Service Principal certificates. See the [requirements](#client-certificate-or-client-secret) for more information.", + "Description": "The client certificate used to authenticate with Microsoft Graph for managing Application/Service Principal certificates. See the [requirements](#client-certificate-or-client-secret) for more information. If Client Certificate Auth is not used, you **must** select 'No Value' for this field.", "Required": false }, { @@ -948,6 +1042,72 @@ "BlueprintAllowed": false, "CustomAliasAllowed": "Required" }, + { + "Name": "Azure Enterprise Application 2 (Service Principal)", + "ShortName": "AzureSP2", + "Capability": "AzureSP2", + "LocalStore": false, + "ClientMachineDescription": "The Azure Tenant (directory) ID where the Service Principal is instantiated", + "StorePathDescription": "The Object ID of the target Service Principal/Enterprise Application that will be managed by the Azure App Registration and Enterprise Application Orchestrator extension.", + "SupportedOperations": { + "Add": true, + "Remove": true, + "Enrollment": false, + "Discovery": true, + "Inventory": true + }, + "Properties": [ + { + "Name": "ServerUsername", + "DisplayName": "Server Username", + "Type": "Secret", + "Description": "The Application ID of the Service Principal used to authenticate with Microsoft Graph for managing Service Principal/Enterprise Application certificates.", + "Required": true + }, + { + "Name": "ServerPassword", + "DisplayName": "Server Password", + "DependsOn": "ServerUsername", + "Type": "Secret", + "Description": "A Client Secret that the extension will use to authenticate with Microsoft Graph for managing Service Principal/Enterprise Application certificates. If Client Certificate Auth is used, you **must** check 'No Value'.", + "Required": false + }, + { + "Name": "ClientCertificate", + "DisplayName": "Client Certificate", + "DependsOn": "ServerUsername", + "Type": "Secret", + "Description": "The client certificate used to authenticate with Microsoft Graph for managing Service Principal/Enterprise Application certificates. See the [requirements](#client-certificate-or-client-secret) for more information. If Client Certificate Auth is not used, you **must** check 'No Value'.", + "Required": false + }, + { + "Name": "ClientCertificatePassword", + "DisplayName": "Client Certificate Password", + "DependsOn": "ClientCertificate", + "Type": "Secret", + "Description": "The (optional) password that encrypts the private key in ClientCertificate. If Client Certificate Auth is not used or the certificate's private key is not encrypted, you **must** check 'No Value'.", + "Required": false + }, + { + "Name": "AzureCloud", + "DisplayName": "Azure Global Cloud Authority Host", + "Type": "MultipleChoice", + "DefaultValue": "public,china,germany,government", + "Description": "Specifies the Azure Cloud instance used by the organization.", + "Required": false + } + ], + "PasswordOptions": { + "EntrySupported": false, + "StoreRequired": false, + "Style": "Default" + }, + "PrivateKeyAllowed": "Required", + "ServerRequired": true, + "PowerShell": false, + "BlueprintAllowed": false, + "CustomAliasAllowed": "Required" + }, { "Name": "Bosch IP Camera", "ShortName": "BIPCamera", @@ -1283,7 +1443,6 @@ "Style": "Default" }, "PrivateKeyAllowed": "Required", - "JobProperties": [], "ServerRequired": true, "PowerShell": false, "BlueprintAllowed": true, @@ -1491,7 +1650,7 @@ "EntryParameters": [], "PasswordOptions": { "EntrySupported": false, - "StoreRequired": false, + "StoreRequired": true, "Style": "Default" }, "PrivateKeyAllowed": "Optional", @@ -2948,16 +3107,41 @@ "PasswordOptions": { "Style": "Default", "EntrySupported": false, - "StoreRequired": true + "StoreRequired": true, + "StorePassword": { + "Description": "Password used to secure the Certificate Store", + "IsPAMEligible": true + } }, "Properties": [ + { + "Name": "ServerUsername", + "DisplayName": "Server Username", + "Type": "Secret", + "DependsOn": "", + "DefaultValue": "", + "Required": false, + "IsPAMEligible": true, + "Description": "A username (or valid PAM key if the username is stored in a KF Command configured PAM integration). If acting as an *agent* using local file access, just check *No Value*" + }, + { + "Name": "ServerPassword", + "DisplayName": "Server Password", + "Type": "Secret", + "DependsOn": "", + "DefaultValue": "", + "Required": false, + "IsPAMEligible": true, + "Description": "A password (or valid PAM key if the password is stored in a KF Command configured PAM integration). The password can also be an SSH private key if connecting via SSH to a server using SSH private key authentication. If acting as an *agent* using local file access, just check *No Value*" + }, { "Name": "LinuxFilePermissionsOnStoreCreation", "DisplayName": "Linux File Permissions on Store Creation", "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The LinuxFilePermissionsOnStoreCreation field should contain a three-digit value between 000 and 777 representing the Linux file permissions to be set for the certificate store upon creation. Example: '600' or '755'." }, { "Name": "LinuxFileOwnerOnStoreCreation", @@ -2965,7 +3149,8 @@ "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The LinuxFileOwnerOnStoreCreation field should contain a valid user ID recognized by the destination Linux server, optionally followed by a colon and a group ID if the group owner differs. Example: 'userID' or 'userID:groupID'." }, { "Name": "SudoImpersonatingUser", @@ -2973,7 +3158,8 @@ "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The SudoImpersonatingUser field should contain a valid user ID to impersonate using sudo on the destination Linux server. Example: 'impersonatedUserID'." }, { "Name": "SeparatePrivateKeyFilePath", @@ -2981,10 +3167,13 @@ "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The SeparatePrivateKeyFilePath field should contain the full path and file name where the separate private key file will be stored if it is to be kept outside the main certificate file. Example: '/path/to/privatekey.der'." } ], - "EntryParameters": [] + "EntryParameters": [], + "ClientMachineDescription": "The Client Machine field should contain the DNS name or IP address of the remote orchestrated server for Linux orchestrated servers, formatted as a URL (protocol://dns-or-ip:port) for Windows orchestrated servers, or '1.1.1.1|LocalMachine' for local agents. Example: 'https://myserver.mydomain.com:5986' or '1.1.1.1|LocalMachine' for local access.", + "StorePathDescription": "The Store Path field should contain the full path and file name, including file extension if applicable, beginning with a forward slash (/) for Linux orchestrated servers or a drive letter (i.e., c:\\folder\\path\\storename.der) for Windows orchestrated servers. Example: '/folder/path/storename.der' or 'c:\\folder\\path\\storename.der'." }, { "Name": "RFJKS", @@ -3005,16 +3194,41 @@ "PasswordOptions": { "Style": "Default", "EntrySupported": false, - "StoreRequired": true + "StoreRequired": true, + "StorePassword": { + "Description": "Password used to secure the Certificate Store", + "IsPAMEligible": true + } }, "Properties": [ + { + "Name": "ServerUsername", + "DisplayName": "Server Username", + "Type": "Secret", + "DependsOn": "", + "DefaultValue": "", + "Required": false, + "IsPAMEligible": true, + "Description": "A username (or valid PAM key if the username is stored in a KF Command configured PAM integration). If acting as an *agent* using local file access, just check *No Value*" + }, + { + "Name": "ServerPassword", + "DisplayName": "Server Password", + "Type": "Secret", + "DependsOn": "", + "DefaultValue": "", + "Required": false, + "IsPAMEligible": true, + "Description": "A password (or valid PAM key if the password is stored in a KF Command configured PAM integration). The password can also be an SSH private key if connecting via SSH to a server using SSH private key authentication. If acting as an *agent* using local file access, just check *No Value*" + }, { "Name": "LinuxFilePermissionsOnStoreCreation", "DisplayName": "Linux File Permissions on Store Creation", "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The LinuxFilePermissionsOnStoreCreation field should contain a three-digit value between 000 and 777 representing the Linux file permissions to be set for the certificate store upon creation. Example: '600' or '755'." }, { "Name": "LinuxFileOwnerOnStoreCreation", @@ -3022,7 +3236,8 @@ "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The LinuxFileOwnerOnStoreCreation field should contain a valid user ID recognized by the destination Linux server, optionally followed by a colon and a group ID if the group owner differs. Example: 'userID' or 'userID:groupID'." }, { "Name": "SudoImpersonatingUser", @@ -3030,10 +3245,13 @@ "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The SudoImpersonatingUser field should contain a valid user ID to impersonate using sudo on the destination Linux server. Example: 'impersonatedUserID'." } ], - "EntryParameters": [] + "EntryParameters": [], + "ClientMachineDescription": "The IP address or DNS of the server hosting the certificate store. For more information, see [Client Machine ](#client-machine-instructions)", + "StorePathDescription": "The full path and file name, including file extension if one exists where the certificate store file is located. For Linux orchestrated servers, StorePath will begin with a forward slash (i.e. /folder/path/storename.ext). For Windows orchestrated servers, it should begin with a drive letter (i.e. c:\\folder\\path\\storename.ext)." }, { "Name": "RFKDB", @@ -3054,16 +3272,41 @@ "PasswordOptions": { "Style": "Default", "EntrySupported": false, - "StoreRequired": true + "StoreRequired": true, + "StorePassword": { + "Description": "Password used to secure the Certificate Store", + "IsPAMEligible": true + } }, "Properties": [ + { + "Name": "ServerUsername", + "DisplayName": "Server Username", + "Type": "Secret", + "DependsOn": "", + "DefaultValue": "", + "Required": false, + "IsPAMEligible": true, + "Description": "A username (or valid PAM key if the username is stored in a KF Command configured PAM integration). If acting as an *agent* using local file access, just check *No Value*" + }, + { + "Name": "ServerPassword", + "DisplayName": "Server Password", + "Type": "Secret", + "DependsOn": "", + "DefaultValue": "", + "Required": false, + "IsPAMEligible": true, + "Description": "A password (or valid PAM key if the password is stored in a KF Command configured PAM integration). The password can also be an SSH private key if connecting via SSH to a server using SSH private key authentication. If acting as an *agent* using local file access, just check *No Value*" + }, { "Name": "LinuxFilePermissionsOnStoreCreation", "DisplayName": "Linux File Permissions on Store Creation", "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The LinuxFilePermissionsOnStoreCreation field should contain a three-digit value between 000 and 777 representing the Linux file permissions to be set for the certificate store upon creation. Example: '600' or '755'." }, { "Name": "LinuxFileOwnerOnStoreCreation", @@ -3071,7 +3314,8 @@ "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The LinuxFileOwnerOnStoreCreation field should contain a valid user ID recognized by the destination Linux server, optionally followed by a colon and a group ID if the group owner differs. Example: 'userID' or 'userID:groupID'." }, { "Name": "SudoImpersonatingUser", @@ -3079,10 +3323,13 @@ "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The SudoImpersonatingUser field should contain a valid user ID to impersonate using sudo on the destination Linux server. Example: 'impersonatedUserID'." } ], - "EntryParameters": [] + "EntryParameters": [], + "ClientMachineDescription": "The Client Machine field should contain the DNS name or IP address of the remote orchestrated server for Linux orchestrated servers, formatted as a URL (protocol://dns-or-ip:port) for Windows orchestrated servers, or '1.1.1.1|LocalMachine' for local agents. Example: 'https://myserver.mydomain.com:5986' or '1.1.1.1|LocalMachine' for local access.", + "StorePathDescription": "The Store Path field should contain the full path and file name, including file extension if applicable, beginning with a forward slash (/) for Linux orchestrated servers or a drive letter (i.e., c:\\folder\\path\\storename.kdb) for Windows orchestrated servers. Example: '/folder/path/storename.kdb' or 'c:\\folder\\path\\storename.kdb'." }, { "Name": "RFORA", @@ -3103,16 +3350,41 @@ "PasswordOptions": { "Style": "Default", "EntrySupported": false, - "StoreRequired": true + "StoreRequired": true, + "StorePassword": { + "Description": "Password used to secure the Certificate Store", + "IsPAMEligible": true + } }, "Properties": [ + { + "Name": "ServerUsername", + "DisplayName": "Server Username", + "Type": "Secret", + "DependsOn": "", + "DefaultValue": "", + "Required": false, + "IsPAMEligible": true, + "Description": "A username (or valid PAM key if the username is stored in a KF Command configured PAM integration). If acting as an *agent* using local file access, just check *No Value*" + }, + { + "Name": "ServerPassword", + "DisplayName": "Server Password", + "Type": "Secret", + "DependsOn": "", + "DefaultValue": "", + "Required": false, + "IsPAMEligible": true, + "Description": "A password (or valid PAM key if the password is stored in a KF Command configured PAM integration). The password can also be an SSH private key if connecting via SSH to a server using SSH private key authentication. If acting as an *agent* using local file access, just check *No Value*" + }, { "Name": "LinuxFilePermissionsOnStoreCreation", "DisplayName": "Linux File Permissions on Store Creation", "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The LinuxFilePermissionsOnStoreCreation field should contain a three-digit value between 000 and 777 representing the Linux file permissions to be set for the certificate store upon creation. Example: '600' or '755'." }, { "Name": "LinuxFileOwnerOnStoreCreation", @@ -3120,7 +3392,8 @@ "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The LinuxFileOwnerOnStoreCreation field should contain a valid user ID recognized by the destination Linux server, optionally followed by a colon and a group ID if the group owner differs. Example: 'userID' or 'userID:groupID'." }, { "Name": "SudoImpersonatingUser", @@ -3128,7 +3401,8 @@ "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The SudoImpersonatingUser field should contain a valid user ID to impersonate using sudo on the destination Linux server. Example: 'impersonatedUserID'." }, { "Name": "WorkFolder", @@ -3136,10 +3410,13 @@ "Required": true, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The WorkFolder field should contain the path on the managed server where temporary work files can be created, modified, and deleted during Inventory and Management jobs. Example: '/path/to/workfolder'." } ], - "EntryParameters": [] + "EntryParameters": [], + "ClientMachineDescription": "The Client Machine field should contain the DNS name or IP address of the remote orchestrated server for Linux orchestrated servers, formatted as a URL (protocol://dns-or-ip:port) for Windows orchestrated servers, or '1.1.1.1|LocalMachine' for local agents. Example: 'https://myserver.mydomain.com:5986' or '1.1.1.1|LocalMachine' for local access.", + "StorePathDescription": "The Store Path field should contain the full path and file name of the Oracle Wallet, including the 'eWallet.p12' file name by convention. Example: '/path/to/eWallet.p12' or 'c:\\path\\to\\eWallet.p12'." }, { "Name": "RFPEM", @@ -3160,16 +3437,41 @@ "PasswordOptions": { "Style": "Default", "EntrySupported": false, - "StoreRequired": true + "StoreRequired": true, + "StorePassword": { + "Description": "Password used to secure the Certificate Store. For stores with PKCS#8 private keys, set the password for encrypted private keys (BEGIN ENCRYPTED PRIVATE KEY) or 'No Value' for unencrypted private keys (BEGIN PRIVATE KEY). If managing a store with a PKCS#1 private key (BEGIN RSA PRIVATE KEY), this value MUST be set to 'No Value'", + "IsPAMEligible": true + } }, "Properties": [ + { + "Name": "ServerUsername", + "DisplayName": "Server Username", + "Type": "Secret", + "DependsOn": "", + "DefaultValue": "", + "Required": false, + "IsPAMEligible": true, + "Description": "A username (or valid PAM key if the username is stored in a KF Command configured PAM integration). If acting as an *agent* using local file access, just check *No Value*" + }, + { + "Name": "ServerPassword", + "DisplayName": "Server Password", + "Type": "Secret", + "DependsOn": "", + "DefaultValue": "", + "Required": false, + "IsPAMEligible": true, + "Description": "A password (or valid PAM key if the password is stored in a KF Command configured PAM integration). The password can also be an SSH private key if connecting via SSH to a server using SSH private key authentication. If acting as an *agent* using local file access, just check *No Value*" + }, { "Name": "LinuxFilePermissionsOnStoreCreation", "DisplayName": "Linux File Permissions on Store Creation", "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The LinuxFilePermissionsOnStoreCreation field should contain a three-digit value between 000 and 777 representing the Linux file permissions to be set for the certificate store upon creation. Example: '600' or '755'." }, { "Name": "LinuxFileOwnerOnStoreCreation", @@ -3177,7 +3479,8 @@ "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The LinuxFileOwnerOnStoreCreation field should contain a valid user ID recognized by the destination Linux server, optionally followed by a colon and a group ID if the group owner differs. Example: 'userID' or 'userID:groupID'." }, { "Name": "SudoImpersonatingUser", @@ -3185,7 +3488,8 @@ "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The SudoImpersonatingUser field should contain a valid user ID to impersonate using sudo on the destination Linux server. Example: 'impersonatedUserID'." }, { "Name": "IsTrustStore", @@ -3193,7 +3497,8 @@ "Required": false, "DependsOn": "", "Type": "Bool", - "DefaultValue": false + "DefaultValue": "false", + "Description": "The IsTrustStore field should contain a boolean value ('true' or 'false') indicating whether the store will be identified as a trust store, which can hold multiple certificates without private keys. Example: 'true' for a trust store or 'false' for a store with a single certificate and private key." }, { "Name": "IncludesChain", @@ -3201,7 +3506,8 @@ "Required": false, "DependsOn": "", "Type": "Bool", - "DefaultValue": false + "DefaultValue": "false", + "Description": "The IncludesChain field should contain a boolean value ('true' or 'false') indicating whether the certificate store includes the full certificate chain along with the end entity certificate. Example: 'true' to include the full chain or 'false' to exclude it." }, { "Name": "SeparatePrivateKeyFilePath", @@ -3209,15 +3515,8 @@ "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" - }, - { - "Name": "IsRSAPrivateKey", - "DisplayName": "Is RSA Private Key", - "Required": false, - "DependsOn": "", - "Type": "Bool", - "DefaultValue": false + "DefaultValue": "", + "Description": "The SeparatePrivateKeyFilePath field should contain the full path and file name where the separate private key file will be stored if it is to be kept outside the main certificate file. Example: '/path/to/privatekey.pem'." }, { "Name": "IgnorePrivateKeyOnInventory", @@ -3225,10 +3524,13 @@ "Required": false, "DependsOn": "", "Type": "Bool", - "DefaultValue": false + "DefaultValue": "false", + "Description": "The IgnorePrivateKeyOnInventory field should contain a boolean value ('true' or 'false') indicating whether to ignore the private key during inventory, which will make the store inventory-only and return all certificates without private key entries. Example: 'true' to ignore the private key or 'false' to include it." } ], - "EntryParameters": [] + "EntryParameters": [], + "ClientMachineDescription": "The Client Machine field should contain the DNS name or IP address of the remote orchestrated server for Linux orchestrated servers, formatted as a URL (protocol://dns-or-ip:port) for Windows orchestrated servers, or '1.1.1.1|LocalMachine' for local agents. Example: 'https://myserver.mydomain.com:5986' or '1.1.1.1|LocalMachine' for local access.", + "StorePathDescription": "The Store Path field should contain the full path and file name, including file extension if applicable, beginning with a forward slash (/) for Linux orchestrated servers or a drive letter (i.e., c:\\folder\\path\\storename.ext) for Windows orchestrated servers. Example: '/folder/path/storename.pem' or 'c:\\folder\\path\\storename.pem'." }, { "Name": "RFPkcs12", @@ -3249,16 +3551,41 @@ "PasswordOptions": { "Style": "Default", "EntrySupported": false, - "StoreRequired": true + "StoreRequired": true, + "StorePassword": { + "Description": "Password used to secure the Certificate Store", + "IsPAMEligible": true + } }, "Properties": [ + { + "Name": "ServerUsername", + "DisplayName": "Server Username", + "Type": "Secret", + "DependsOn": "", + "DefaultValue": "", + "Required": false, + "IsPAMEligible": true, + "Description": "A username (or valid PAM key if the username is stored in a KF Command configured PAM integration). If acting as an *agent* using local file access, just check *No Value*" + }, + { + "Name": "ServerPassword", + "DisplayName": "Server Password", + "Type": "Secret", + "DependsOn": "", + "DefaultValue": "", + "Required": false, + "IsPAMEligible": true, + "Description": "A password (or valid PAM key if the password is stored in a KF Command configured PAM integration). The password can also be an SSH private key if connecting via SSH to a server using SSH private key authentication. If acting as an *agent* using local file access, just check *No Value*" + }, { "Name": "LinuxFilePermissionsOnStoreCreation", "DisplayName": "Linux File Permissions on Store Creation", "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The LinuxFilePermissionsOnStoreCreation field should contain a three-digit value between 000 and 777 representing the Linux file permissions to be set for the certificate store upon creation. Example: '600' or '755'." }, { "Name": "LinuxFileOwnerOnStoreCreation", @@ -3266,7 +3593,8 @@ "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The LinuxFileOwnerOnStoreCreation field should contain a valid user ID recognized by the destination Linux server, optionally followed by a colon and a group ID if the group owner differs. Example: 'userID' or 'userID:groupID'." }, { "Name": "SudoImpersonatingUser", @@ -3274,10 +3602,13 @@ "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The SudoImpersonatingUser field should contain a valid user ID to impersonate using sudo on the destination Linux server. Example: 'impersonatedUserID'." } ], - "EntryParameters": [] + "EntryParameters": [], + "ClientMachineDescription": "The Client Machine field should contain the DNS name or IP address of the remote orchestrated server for Linux orchestrated servers, formatted as a URL (protocol://dns-or-ip:port) for Windows orchestrated servers, or '1.1.1.1|LocalMachine' for local agents. Example: 'https://myserver.mydomain.com:5986' or '1.1.1.1|LocalMachine' for local access.", + "StorePathDescription": "The Store Path field should contain the full path and file name, including file extension if applicable, beginning with a forward slash (/) for Linux orchestrated servers or a drive letter (i.e., c:\\folder\\path\\storename.p12) for Windows orchestrated servers. Example: '/folder/path/storename.p12' or 'c:\\folder\\path\\storename.p12'." }, { "Name": "SampleStoreType", From 91376ae007161e73cc8799ec43d66f3d05aab3ec Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Mon, 18 Nov 2024 11:43:04 -0800 Subject: [PATCH 20/49] fix(auth): Interactive auth prompt for `audience` and `scopes` for `oauth` interactive. Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- cmd/login.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/cmd/login.go b/cmd/login.go index 6e34772..9856f7e 100644 --- a/cmd/login.go +++ b/cmd/login.go @@ -460,6 +460,19 @@ func authInteractive( serverConf.OAuthTokenUrl, ) } + if len(serverConf.Scopes) == 0 || forcePrompt { + scopesCsv := promptForInteractiveParameter( + "OAuth Scopes", + strings.Join(serverConf.Scopes, ","), + ) + serverConf.Scopes = strings.Split(scopesCsv, ",") + } + if serverConf.Audience == "" || forcePrompt { + serverConf.Audience = promptForInteractiveParameter( + "OAuth Audience", + serverConf.Audience, + ) + } } if serverConf.APIPath == "" || forcePrompt { From 4bdd1663fa9fffea4503d6a787f643a4343f0cb4 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Mon, 18 Nov 2024 14:48:41 -0800 Subject: [PATCH 21/49] fix(auth): Add prompt for providing oauth access token directly rather than force `client id` and `client secret`. fix(auth): For interactive passwords trim leading and/or trailing `\n` characters. Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- cmd/login.go | 104 ++++++++++++++++++++++++++++++++++++--------------- go.mod | 2 +- go.sum | 4 +- 3 files changed, 77 insertions(+), 33 deletions(-) diff --git a/cmd/login.go b/cmd/login.go index 9856f7e..36c0f85 100644 --- a/cmd/login.go +++ b/cmd/login.go @@ -379,7 +379,7 @@ func promptForInteractivePassword(parameterName string, defaultValue string) str // Trim newline and check if password is empty; if so, return default if len(password) > 0 { - password = password[:len(password)-1] + password = strings.Trim(password, "\n") } if password == "" { return defaultValue @@ -442,51 +442,93 @@ func authInteractive( } } } else if serverConf.AuthType == "oauth" { - if serverConf.ClientID == "" || forcePrompt { - serverConf.ClientID = promptForInteractiveParameter( - "Keyfactor Command OAuth Client ID", - serverConf.ClientID, + if serverConf.AccessToken == "" || forcePrompt { + log.Debug().Msg("prompting for OAuth access token") + serverConf.AccessToken = promptForInteractiveParameter( + "Keyfactor Command OAuth Access Token (to use client ID and secret, leave blank)", + serverConf.AccessToken, ) } - 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 len(serverConf.Scopes) == 0 || forcePrompt { - scopesCsv := promptForInteractiveParameter( - "OAuth Scopes", - strings.Join(serverConf.Scopes, ","), - ) - serverConf.Scopes = strings.Split(scopesCsv, ",") - } - if serverConf.Audience == "" || forcePrompt { - serverConf.Audience = promptForInteractiveParameter( - "OAuth Audience", - serverConf.Audience, - ) + if serverConf.AccessToken == "" { + log.Debug().Msg("no oauth access token provided") + if serverConf.ClientID == "" || forcePrompt { + log.Debug(). + Str("serverConf.ClientID", serverConf.ClientID). + Msg("prompting for OAuth client ID") + serverConf.ClientID = promptForInteractiveParameter( + "Keyfactor Command OAuth Client ID", + serverConf.ClientID, + ) + } + if serverConf.ClientSecret == "" || forcePrompt { + log.Debug().Msg("prompting for OAuth client secret") + serverConf.ClientSecret = promptForInteractivePassword( + "Keyfactor Command OAuth Client Secret", + serverConf.ClientSecret, + ) + } + + if serverConf.OAuthTokenUrl == "" || forcePrompt { + log.Debug(). + Str("serverConf.OAuthTokenUrl", serverConf.OAuthTokenUrl). + Msg("prompting for OAuth token URL") + serverConf.OAuthTokenUrl = promptForInteractiveParameter( + "Keyfactor Command OAuth Token URL", + serverConf.OAuthTokenUrl, + ) + } + if len(serverConf.Scopes) == 0 || forcePrompt { + log.Debug(). + Strs("serverConf.Scopes", serverConf.Scopes). + Msg("prompting for OAuth scopes") + scopesCsv := promptForInteractiveParameter( + "OAuth Scopes", + strings.Join(serverConf.Scopes, ","), + ) + serverConf.Scopes = strings.Split(scopesCsv, ",") + } + if serverConf.Audience == "" || forcePrompt { + log.Debug().Msg("prompting for OAuth audience") + serverConf.Audience = promptForInteractiveParameter( + "OAuth Audience", + serverConf.Audience, + ) + } + } else { + log.Debug(). + Str("serverConf.AccessToken", hashSecretValue(serverConf.AccessToken)). + Msg("using provided OAuth access token") } } if serverConf.APIPath == "" || forcePrompt { + log.Debug(). + Str("serverConf.APIPath", serverConf.APIPath). + Msg("prompting for API path") serverConf.APIPath = promptForInteractiveParameter("Keyfactor Command API path", serverConf.APIPath) } if serverConf.CACertPath == "" || forcePrompt { + log.Debug(). + Str("serverConf.CACertPath", serverConf.CACertPath). + Msg("prompting for CA cert path") serverConf.CACertPath = promptForInteractiveParameter("Keyfactor Command CA Cert Path", serverConf.CACertPath) } + if !serverConf.SkipTLSVerify || forcePrompt { + log.Debug(). + Bool("serverConf.SkipTLSVerify", serverConf.SkipTLSVerify). + Msg("prompting for Skip TLS Verify") + serverConf.SkipTLSVerify = promptForInteractiveParameter( + "Keyfactor Command Skip TLS Verify [true,false]", + fmt.Sprintf("%t", serverConf.SkipTLSVerify), + ) == "true" + } if profileName == "" { - profileName = "default" + profileName = auth_providers.DefaultConfigProfile } if configPath == "" { + log.Debug().Msg("configPath is empty, calling prepHomeDir()") userHomeDir, hErr := prepHomeDir() if hErr != nil { //log.Println("[ERROR] Unable to create home directory: ", hErr) @@ -502,6 +544,7 @@ func authInteractive( confFile.Servers[profileName] = *serverConf if saveConfig { + log.Debug().Bool("saveConfig", saveConfig).Msg("calling writeConfigFile()") saveErr := writeConfigFile(&confFile, configPath) if saveErr != nil { //log.Println("[ERROR] Unable to save configuration file to disk: ", saveErr) @@ -509,6 +552,7 @@ func authInteractive( return confFile, saveErr } } + log.Debug().Msg("authInteractive() returning") return confFile, nil } diff --git a/go.mod b/go.mod index 984670a..5393c5b 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.8.0 github.com/Jeffail/gabs v1.4.0 - github.com/Keyfactor/keyfactor-auth-client-go v1.1.0-rc.3 + github.com/Keyfactor/keyfactor-auth-client-go v1.1.0-rc.4 github.com/Keyfactor/keyfactor-go-client-sdk/v2 v2.0.0-rc.2 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 602a011..ead21a3 100644 --- a/go.sum +++ b/go.sum @@ -18,8 +18,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.1.0-rc.3 h1:pQvbBM3DmSDdGMLh9s648Md+fHOoZtL7tjmVnHNDeVc= -github.com/Keyfactor/keyfactor-auth-client-go v1.1.0-rc.3/go.mod h1:Ia3VmXsumFrr01BMc1Rp5OpDWmfXWjdeMituda14T4I= +github.com/Keyfactor/keyfactor-auth-client-go v1.1.0-rc.4 h1:2TTlhVjPvPV6UrKN/VEqdcNGb4mgwAcsLcGuoQofg28= +github.com/Keyfactor/keyfactor-auth-client-go v1.1.0-rc.4/go.mod h1:Ia3VmXsumFrr01BMc1Rp5OpDWmfXWjdeMituda14T4I= github.com/Keyfactor/keyfactor-go-client-sdk/v2 v2.0.0-rc.2 h1:RNrfgrC+mPvqOc1wPsFjB4thuw7qJbP3gOycRDcRwxI= github.com/Keyfactor/keyfactor-go-client-sdk/v2 v2.0.0-rc.2/go.mod h1:11WXGG9VVKSV0EPku1IswjHbGGpzHDKqD4pe2vD7vas= github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.11 h1:nYc7fEidu26ZKGwEByQNr2EWPCsCs0zxnHUKnRT6/rY= From 973ccd75166b254ebdebbf432171dbf9cf95c07e Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Mon, 18 Nov 2024 14:55:25 -0800 Subject: [PATCH 22/49] fix(auth): Interactive auth if no scopes are passed then don't pass array of empty string. Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- cmd/login.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmd/login.go b/cmd/login.go index 36c0f85..b59a6ee 100644 --- a/cmd/login.go +++ b/cmd/login.go @@ -485,7 +485,9 @@ func authInteractive( "OAuth Scopes", strings.Join(serverConf.Scopes, ","), ) - serverConf.Scopes = strings.Split(scopesCsv, ",") + if scopesCsv != "" && scopesCsv != "," { + serverConf.Scopes = strings.Split(scopesCsv, ",") + } } if serverConf.Audience == "" || forcePrompt { log.Debug().Msg("prompting for OAuth audience") From 44a9da635a81af50a50175151dcdc2b39f6c2f45 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Mon, 18 Nov 2024 15:07:26 -0800 Subject: [PATCH 23/49] chore(docs): Update auth related docs with example `access_token` oAuth configs. Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- README.md | 38 +++++++++++++++++++++++++++++++++++--- readme_source.md | 38 +++++++++++++++++++++++++++++++++++--- 2 files changed, 70 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index adc0f94..f7f7d47 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ Currently `Basic Authentication` via `Active Directory` is the *ONLY* supported | 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 +### oAuth Credentials | Name | Description | Default | |------------------------------|---------------------------------------------------------------------------------------------------------------------------------|----------| @@ -104,8 +104,12 @@ and use them if they are set. ### Linux/MacOS: +Below are examples of setting the environment variables in Linux/MacOS to be used with `kfutil`. + #### Active Directory Basic Authentication +This is the minimum required configuration to authenticate to Keyfactor Command using Active Directory username, +password auth. ```bash export KEYFACTOR_HOSTNAME="" export KEYFACTOR_USERNAME="" @@ -115,6 +119,7 @@ export KEYFACTOR_DOMAIN="" # Optional if username contains do #### oAuth Client Credentials +This is the minimum required configuration to authenticate to Keyfactor Command using oAuth client credentials. ```bash export KEYFACTOR_HOSTNAME="" export KEYFACTOR_AUTH_CLIENT_ID=" Date: Tue, 19 Nov 2024 07:28:31 -0800 Subject: [PATCH 24/49] chore(docs): Update CHANGELOG.md with dep upgrades. Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- CHANGELOG.md | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a90dc84..680b81c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,21 @@ ## Features -- Auth: Added support for authenticating to Keyfactor Command using a oAuth Client Credentials grant type. +- `auth`: Added support for authenticating to Keyfactor Command using a oAuth2 client credentials or access token. + +## Fixes + +- `cli`: Fixed an issue where the CLI would sometimes terminate with no error messages when calling the + `keyfactor-go-client-sdk` + +## Chores + +- `deps`: Bump `go` version to `1.23`. +- `deps`: Bump `azure-sdk-for-go/sdk/azidentity` version to `v1.8.0`. +- `deps`: Bump `keyfactor-go-client-sdk` version to `v2.0.0`. +- `deps`: Bump `keyfactor-go-client` version to `v3.0.0`. +- `deps`: Bump `golang.org/x/crypto` version to `v0.27.0`. +- `deps`: Bump `golang.org/x/term` version to `v0.24.0`. # v1.5.1 @@ -31,31 +45,39 @@ - No longer log before the `--debug` flag is evaluated. # v1.4.0 + ## Features ### Stores -- `stores import generate-template`: New sub CLI to generate a CSV template for bulk importing stores. [See docs](docs/kfutil_stores_import_generate-template.md)`. + +- `stores import generate-template`: New sub CLI to generate a CSV template for bulk importing + stores. [See docs](docs/kfutil_stores_import_generate-template.md)`. - `stores delete`: Support for user interactive mode. - `stores delete`: Support of delete from CSV file. - `stores export`: Supports `--all` flag and user interactive mode ## Fixes + - Various null pointer references when nothing and/or empty inputs/responses are received. - Installer script checksum check now validates properly. #119 - `stores import` sub CLI is now listed and documented #71 ### Store Types -- Empty `storepath` values are no longer passed to the API. #56 + +- Empty `storepath` values are no longer passed to the API. #56 ### PAM Types + - Handle duplicate provider type that is already created without crashing. #139 ## Docs + - [Examples for certificate store bulk operations](https://github.com/Keyfactor/kfutil/tree/epic_54795/examples/cert_stores/bulk_operations#readme) # v1.3.2 ### Package + - Bump deps `cobra` version to `v1.8.0`, `azcore` version to `v1.9.0`, `pty` version to `v1.1.21` # v1.3.1 @@ -63,17 +85,23 @@ ## Bug Fixes ### Package + - Bump package version to `1.3.1` to fix an issue with the `1.3.0` release. ### Installer + - Remove `v` prefix from installer URL path to accommodate for the new build process. # v1.3.0 + ## Features ### StoreTypes -- Added `--output-to-integration-manifest` flag to `kfutil store-types get` to download a remote certificate store type definition into an `integration-manifest.json` file locally. -- Updated usage: `kfutil store-types get [-i | -n ] [-b ] [-g | --output-to-integration-manifest]` + +- Added `--output-to-integration-manifest` flag to `kfutil store-types get` to download a remote certificate store type + definition into an `integration-manifest.json` file locally. +- Updated usage: + `kfutil store-types get [-i | -n ] [-b ] [-g | --output-to-integration-manifest]` # v1.2.1 @@ -93,7 +121,7 @@ # v1.2.0 ## Features - + ### Auth - Added support for sourcing credentials from [Azure Key Vault using Azure ID](docs/auth_providers.md#azure-key-vault) From d69e361c26b04ca8eb1efe8fbd64a28badc196e6 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Tue, 19 Nov 2024 09:38:57 -0800 Subject: [PATCH 25/49] chore(store-types): Remove airlock cert store type. Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- store_types.json | 30 +----------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/store_types.json b/store_types.json index 359e05d..caeb3df 100644 --- a/store_types.json +++ b/store_types.json @@ -1,12 +1,12 @@ [ { + "Name": "Azure Keyvault", "BlueprintAllowed": false, "Capability": "AKV", "CustomAliasAllowed": "Optional", "EntryParameters": null, "JobProperties": [], "LocalStore": false, - "Name": "Azure Keyvault", "PasswordOptions": { "EntrySupported": false, "StoreRequired": false, @@ -186,34 +186,6 @@ "BlueprintAllowed": true, "CustomAliasAllowed": "Optional" }, - { - "Name": "Airlock Application Firewall Certificate", - "ShortName": "AirlockWAF", - "Capability": "AirlockWAF", - "LocalStore": false, - "SupportedOperations": { - "Add": false, - "Create": false, - "Discovery": true, - "Enrollment": false, - "Remove": false - }, - "Properties": [], - "EntryParameters": [], - "PasswordOptions": { - "EntrySupported": false, - "StoreRequired": true, - "Style": "Default" - }, - "StorePathType": "", - "StorePathValue": "", - "PrivateKeyAllowed": "Required", - "JobProperties": [], - "ServerRequired": true, - "PowerShell": false, - "BlueprintAllowed": false, - "CustomAliasAllowed": "Allowed" - }, { "Name": "Akamai Certificate Provisioning Service", "ShortName": "Akamai", From 5303edfb5c5d024f8cec996f231e04fae218d63e Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Tue, 19 Nov 2024 11:49:07 -0800 Subject: [PATCH 26/49] fix(tests): Remove debug output from tests Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- .github/workflows/tests.yml | 2 +- cmd/storeTypes_get_test.go | 189 +++++++++++++++++++----------------- 2 files changed, 103 insertions(+), 88 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 4ecf368..98231c8 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -80,7 +80,7 @@ jobs: - name: Run tests run: | - export KFUTIL_DEBUG=1 + unset KFUTIL_DEBUG go test -timeout 20m -v ./cmd -run "^Test_StoreTypes*" ### Store Tests diff --git a/cmd/storeTypes_get_test.go b/cmd/storeTypes_get_test.go index 517aee9..baf8c3f 100644 --- a/cmd/storeTypes_get_test.go +++ b/cmd/storeTypes_get_test.go @@ -18,97 +18,112 @@ package cmd import ( "encoding/json" + "os" + "testing" + "github.com/stretchr/testify/assert" "kfutil/pkg/cmdtest" manifestv1 "kfutil/pkg/keyfactor/v1" - "os" - "testing" ) func Test_StoreTypesGet(t *testing.T) { - t.Run("WithName", func(t *testing.T) { - testCmd := RootCmd - - output, err := cmdtest.TestExecuteCommand(t, testCmd, []string{"store-types", "get", "--name", "PEM", "--debug"}...) - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } - var storeType map[string]interface{} - if err := json.Unmarshal([]byte(output), &storeType); err != nil { - t.Fatalf("Error unmarshalling JSON: %v", err) - } - - assert.NotNil(t, storeType["Name"], "Expected store type to have a name") - assert.NotNil(t, storeType["ShortName"], "Expected store type to have short name") - assert.NotNil(t, storeType["StoreType"], "Expected store type to have a store type") - - // verify that the store type is an integer - _, ok := storeType["StoreType"].(float64) - assert.True(t, ok, "Expected store type to be an integer") - // verify short name is a string - _, ok = storeType["ShortName"].(string) - assert.True(t, ok, "Expected short name to be a string") - // verify name is a string - _, ok = storeType["Name"].(string) - assert.True(t, ok, "Expected name to be a string") - // check that shortname == AWS - assert.Equal(t, storeType["ShortName"], "PEM", "Expected short name to be PEM") - }) - - t.Run("GenericOutput", func(t *testing.T) { - testCmd := RootCmd - output, err := cmdtest.TestExecuteCommand(t, testCmd, []string{"store-types", "get", "--name", "PEM", "-g", "--debug"}...) - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } - var storeType map[string]interface{} - if err := json.Unmarshal(output, &storeType); err != nil { - t.Fatalf("Error unmarshalling JSON: %v", err) - } - - assert.NotNil(t, storeType["Name"], "Expected store type to have a Name") - assert.NotNil(t, storeType["ShortName"], "Expected store type to have ShortName") - - assert.Nil(t, storeType["StoreType"], "Expected StoreType to to be nil") - assert.Nil(t, storeType["InventoryJobType"], "Expected InventoryJobType to be nil") - assert.Nil(t, storeType["InventoryEndpoint"], "Expected InventoryEndpoint to be nil") - assert.Nil(t, storeType["ManagementJobType"], "Expected ManagementJobType to be nil") - assert.Nil(t, storeType["DiscoveryJobType"], "Expected DiscoveryJobType to be nil") - assert.Nil(t, storeType["EnrollmentJobType"], "Expected EnrollmentJobType to be nil") - assert.Nil(t, storeType["ImportType"], "Expected ImportType to be nil") - - // verify short name is a string - _, ok := storeType["ShortName"].(string) - assert.True(t, ok, "Expected short name to be a string") - // verify name is a string - _, ok = storeType["Name"].(string) - assert.True(t, ok, "Expected name to be a string") - // check that shortname == PEM - assert.Equal(t, storeType["ShortName"], "PEM", "Expected short name to be PEM") - }) - - t.Run("OutputToManifest", func(t *testing.T) { - testCmd := RootCmd - _, err := cmdtest.TestExecuteCommand(t, testCmd, []string{"store-types", "get", "--name", "PEM", "--output-to-integration-manifest", "--debug"}...) - if err != nil { - t.Fatalf("Unexpected error: %v", err) - } - - // Verify that integration-manifest.json was created - manifest := manifestv1.IntegrationManifest{} - err = manifest.LoadFromFilesystem() - if err != nil { - t.Fatalf("Error loading integration manifest: %v", err) - } - - if len(manifest.About.Orchestrator.StoreTypes) != 1 { - t.Fatalf("Expected 1 store type, got %d", len(manifest.About.Orchestrator.StoreTypes)) - } - - // Clean up - err = os.Remove("integration-manifest.json") - if err != nil { - t.Errorf("Error removing integration-manifest.json: %v", err) - } - }) + t.Run( + "WithName", func(t *testing.T) { + testCmd := RootCmd + + output, err := cmdtest.TestExecuteCommand(t, testCmd, []string{"store-types", "get", "--name", "PEM"}...) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + var storeType map[string]interface{} + if err := json.Unmarshal([]byte(output), &storeType); err != nil { + t.Fatalf("Error unmarshalling JSON: %v", err) + } + + assert.NotNil(t, storeType["Name"], "Expected store type to have a name") + assert.NotNil(t, storeType["ShortName"], "Expected store type to have short name") + assert.NotNil(t, storeType["StoreType"], "Expected store type to have a store type") + + // verify that the store type is an integer + _, ok := storeType["StoreType"].(float64) + assert.True(t, ok, "Expected store type to be an integer") + // verify short name is a string + _, ok = storeType["ShortName"].(string) + assert.True(t, ok, "Expected short name to be a string") + // verify name is a string + _, ok = storeType["Name"].(string) + assert.True(t, ok, "Expected name to be a string") + // check that shortname == AWS + assert.Equal(t, storeType["ShortName"], "PEM", "Expected short name to be PEM") + }, + ) + + t.Run( + "GenericOutput", func(t *testing.T) { + testCmd := RootCmd + output, err := cmdtest.TestExecuteCommand( + t, + testCmd, + []string{"store-types", "get", "--name", "PEM", "-g"}..., + ) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + var storeType map[string]interface{} + if err := json.Unmarshal(output, &storeType); err != nil { + t.Fatalf("Error unmarshalling JSON: %v", err) + } + + assert.NotNil(t, storeType["Name"], "Expected store type to have a Name") + assert.NotNil(t, storeType["ShortName"], "Expected store type to have ShortName") + + assert.Nil(t, storeType["StoreType"], "Expected StoreType to to be nil") + assert.Nil(t, storeType["InventoryJobType"], "Expected InventoryJobType to be nil") + assert.Nil(t, storeType["InventoryEndpoint"], "Expected InventoryEndpoint to be nil") + assert.Nil(t, storeType["ManagementJobType"], "Expected ManagementJobType to be nil") + assert.Nil(t, storeType["DiscoveryJobType"], "Expected DiscoveryJobType to be nil") + assert.Nil(t, storeType["EnrollmentJobType"], "Expected EnrollmentJobType to be nil") + assert.Nil(t, storeType["ImportType"], "Expected ImportType to be nil") + + // verify short name is a string + _, ok := storeType["ShortName"].(string) + assert.True(t, ok, "Expected short name to be a string") + // verify name is a string + _, ok = storeType["Name"].(string) + assert.True(t, ok, "Expected name to be a string") + // check that shortname == PEM + assert.Equal(t, storeType["ShortName"], "PEM", "Expected short name to be PEM") + }, + ) + + t.Run( + "OutputToManifest", func(t *testing.T) { + testCmd := RootCmd + _, err := cmdtest.TestExecuteCommand( + t, + testCmd, + []string{"store-types", "get", "--name", "PEM", "--output-to-integration-manifest"}..., + ) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + // Verify that integration-manifest.json was created + manifest := manifestv1.IntegrationManifest{} + err = manifest.LoadFromFilesystem() + if err != nil { + t.Fatalf("Error loading integration manifest: %v", err) + } + + if len(manifest.About.Orchestrator.StoreTypes) != 1 { + t.Fatalf("Expected 1 store type, got %d", len(manifest.About.Orchestrator.StoreTypes)) + } + + // Clean up + err = os.Remove("integration-manifest.json") + if err != nil { + t.Errorf("Error removing integration-manifest.json: %v", err) + } + }, + ) } From da3a6a497399c65e0c9dd381bca4e8c763cbabd6 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Tue, 19 Nov 2024 12:15:41 -0800 Subject: [PATCH 27/49] chore(store-types): Update embedded definitions. Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- cmd/store_types.json | 447 +++++++++++++++++++++++++++++++++++++------ store_types.json | 28 +++ 2 files changed, 417 insertions(+), 58 deletions(-) diff --git a/cmd/store_types.json b/cmd/store_types.json index cf7471a..324a97f 100644 --- a/cmd/store_types.json +++ b/cmd/store_types.json @@ -1,12 +1,12 @@ [ { + "Name": "Azure Keyvault", "BlueprintAllowed": false, "Capability": "AKV", "CustomAliasAllowed": "Optional", "EntryParameters": null, "JobProperties": [], "LocalStore": false, - "Name": "Azure Keyvault", "PasswordOptions": { "EntrySupported": false, "StoreRequired": false, @@ -122,16 +122,16 @@ "Required": false }, { - "Name": "IamAccountId", - "DisplayName": "IAM AWS Account ID", + "Name": "IAMAssumeRole", + "DisplayName": "AWS Role to Assume (IAM)", "Type": "String", "DependsOn": "UseIAM", "DefaultValue": null, "Required": false }, { - "Name": "OAuthAccountId", - "DisplayName": "OAuth AWS Account ID", + "Name": "OAuthAssumeRole", + "DisplayName": "AWS Role to Assume (OAuth)", "Type": "String", "DependsOn": "UseOAuth", "DefaultValue": null, @@ -186,6 +186,34 @@ "BlueprintAllowed": true, "CustomAliasAllowed": "Optional" }, + { + "Name": "Airlock Application Firewall Certificate", + "ShortName": "AirlockWAF", + "Capability": "AirlockWAF", + "LocalStore": false, + "SupportedOperations": { + "Add": true, + "Create": false, + "Discovery": true, + "Enrollment": false, + "Remove": true + }, + "Properties": [], + "EntryParameters": [], + "PasswordOptions": { + "EntrySupported": false, + "StoreRequired": true, + "Style": "Default" + }, + "StorePathType": "", + "StorePathValue": "", + "PrivateKeyAllowed": "Required", + "JobProperties": [], + "ServerRequired": true, + "PowerShell": false, + "BlueprintAllowed": false, + "CustomAliasAllowed": "Allowed" + }, { "Name": "Akamai Certificate Provisioning Service", "ShortName": "Akamai", @@ -776,20 +804,20 @@ "DisplayName": "Server Username", "Type": "Secret", "Description": "The Application ID of the Service Principal used to authenticate with Microsoft Graph for managing Application/Service Principal certificates.", - "Required": false + "Required": true }, { "Name": "ServerPassword", "DisplayName": "Server Password", "Type": "Secret", - "Description": "A Client Secret that the extension will use to authenticate with Microsoft Graph for managing Application/Service Principal certificates, OR the password that encrypts the private key in ClientCertificate", + "Description": "A Client Secret that the extension will use to authenticate with Microsoft Graph for managing Application/Service Principal certificates, OR the password that encrypts the private key in ClientCertificate. If Client Cert Auth is used _and_ the Client Certificate's private key is not encrypted, you **must** select 'No Value' for this field.", "Required": false }, { "Name": "ClientCertificate", "DisplayName": "Client Certificate", "Type": "Secret", - "Description": "The client certificate used to authenticate with Microsoft Graph for managing Application/Service Principal certificates. See the [requirements](#client-certificate-or-client-secret) for more information.", + "Description": "The client certificate used to authenticate with Microsoft Graph for managing Application/Service Principal certificates. See the [requirements](#client-certificate-or-client-secret) for more information. If Client Certificate Auth is not used, you **must** select 'No Value' for this field.", "Required": false }, { @@ -814,7 +842,73 @@ "StoreRequired": false, "Style": "Default" }, - "PrivateKeyAllowed": "Required", + "PrivateKeyAllowed": "Forbidden", + "ServerRequired": true, + "PowerShell": false, + "BlueprintAllowed": false, + "CustomAliasAllowed": "Required" + }, + { + "Name": "Azure App Registration 2 (Application)", + "ShortName": "AzureApp2", + "Capability": "AzureApp2", + "LocalStore": false, + "ClientMachineDescription": "The Azure Tenant (directory) ID where the Application is instantiated", + "StorePathDescription": "The Object ID of the target Application/App Registration that will be managed by the Azure App Registration and Enterprise Application Orchestrator extension.", + "SupportedOperations": { + "Add": true, + "Remove": true, + "Enrollment": false, + "Discovery": true, + "Inventory": true + }, + "Properties": [ + { + "Name": "ServerUsername", + "DisplayName": "Server Username", + "Type": "Secret", + "Description": "The Application ID of the Service Principal used to authenticate with Microsoft Graph for managing Application/App Registration certificates.", + "Required": true + }, + { + "Name": "ServerPassword", + "DisplayName": "Server Password", + "DependsOn": "ServerUsername", + "Type": "Secret", + "Description": "A Client Secret that the extension will use to authenticate with Microsoft Graph for managing Application/App Registration certificates. If Client Certificate Auth is used, you **must** select 'No Value'.", + "Required": false + }, + { + "Name": "ClientCertificate", + "DisplayName": "Client Certificate", + "DependsOn": "ServerUsername", + "Type": "Secret", + "Description": "The client certificate used to authenticate with Microsoft Graph for managing Application/App Registrations certificates. See the [requirements](#client-certificate-or-client-secret) for more information. If Client Certificate Auth is not used, you **must** check 'No Value'.", + "Required": false + }, + { + "Name": "ClientCertificatePassword", + "DisplayName": "Client Certificate Password", + "DependsOn": "ClientCertificate", + "Type": "Secret", + "Description": "The (optional) password that encrypts the private key in ClientCertificate. If Client Certificate Auth is not used, you **must** check 'No Value'.", + "Required": false + }, + { + "Name": "AzureCloud", + "DisplayName": "Azure Global Cloud Authority Host", + "Type": "MultipleChoice", + "DefaultValue": "public,china,germany,government", + "Description": "Specifies the Azure Cloud instance used by the organization.", + "Required": false + } + ], + "PasswordOptions": { + "EntrySupported": false, + "StoreRequired": false, + "Style": "Default" + }, + "PrivateKeyAllowed": "Forbidden", "ServerRequired": true, "PowerShell": false, "BlueprintAllowed": false, @@ -904,20 +998,20 @@ "DisplayName": "Server Username", "Type": "Secret", "Description": "The Application ID of the Service Principal used to authenticate with Microsoft Graph for managing Application/Service Principal certificates.", - "Required": false + "Required": true }, { "Name": "ServerPassword", "DisplayName": "Server Password", "Type": "Secret", - "Description": "A Client Secret that the extension will use to authenticate with Microsoft Graph for managing Application/Service Principal certificates, OR the password that encrypts the private key in ClientCertificate", + "Description": "A Client Secret that the extension will use to authenticate with Microsoft Graph for managing Application/Service Principal certificates, OR the password that encrypts the private key in ClientCertificate. If Client Cert Auth is used _and_ the Client Certificate's private key is not encrypted, you **must** select 'No Value' for this field.", "Required": false }, { "Name": "ClientCertificate", "DisplayName": "Client Certificate", "Type": "Secret", - "Description": "The client certificate used to authenticate with Microsoft Graph for managing Application/Service Principal certificates. See the [requirements](#client-certificate-or-client-secret) for more information.", + "Description": "The client certificate used to authenticate with Microsoft Graph for managing Application/Service Principal certificates. See the [requirements](#client-certificate-or-client-secret) for more information. If Client Certificate Auth is not used, you **must** select 'No Value' for this field.", "Required": false }, { @@ -948,6 +1042,72 @@ "BlueprintAllowed": false, "CustomAliasAllowed": "Required" }, + { + "Name": "Azure Enterprise Application 2 (Service Principal)", + "ShortName": "AzureSP2", + "Capability": "AzureSP2", + "LocalStore": false, + "ClientMachineDescription": "The Azure Tenant (directory) ID where the Service Principal is instantiated", + "StorePathDescription": "The Object ID of the target Service Principal/Enterprise Application that will be managed by the Azure App Registration and Enterprise Application Orchestrator extension.", + "SupportedOperations": { + "Add": true, + "Remove": true, + "Enrollment": false, + "Discovery": true, + "Inventory": true + }, + "Properties": [ + { + "Name": "ServerUsername", + "DisplayName": "Server Username", + "Type": "Secret", + "Description": "The Application ID of the Service Principal used to authenticate with Microsoft Graph for managing Service Principal/Enterprise Application certificates.", + "Required": true + }, + { + "Name": "ServerPassword", + "DisplayName": "Server Password", + "DependsOn": "ServerUsername", + "Type": "Secret", + "Description": "A Client Secret that the extension will use to authenticate with Microsoft Graph for managing Service Principal/Enterprise Application certificates. If Client Certificate Auth is used, you **must** check 'No Value'.", + "Required": false + }, + { + "Name": "ClientCertificate", + "DisplayName": "Client Certificate", + "DependsOn": "ServerUsername", + "Type": "Secret", + "Description": "The client certificate used to authenticate with Microsoft Graph for managing Service Principal/Enterprise Application certificates. See the [requirements](#client-certificate-or-client-secret) for more information. If Client Certificate Auth is not used, you **must** check 'No Value'.", + "Required": false + }, + { + "Name": "ClientCertificatePassword", + "DisplayName": "Client Certificate Password", + "DependsOn": "ClientCertificate", + "Type": "Secret", + "Description": "The (optional) password that encrypts the private key in ClientCertificate. If Client Certificate Auth is not used or the certificate's private key is not encrypted, you **must** check 'No Value'.", + "Required": false + }, + { + "Name": "AzureCloud", + "DisplayName": "Azure Global Cloud Authority Host", + "Type": "MultipleChoice", + "DefaultValue": "public,china,germany,government", + "Description": "Specifies the Azure Cloud instance used by the organization.", + "Required": false + } + ], + "PasswordOptions": { + "EntrySupported": false, + "StoreRequired": false, + "Style": "Default" + }, + "PrivateKeyAllowed": "Required", + "ServerRequired": true, + "PowerShell": false, + "BlueprintAllowed": false, + "CustomAliasAllowed": "Required" + }, { "Name": "Bosch IP Camera", "ShortName": "BIPCamera", @@ -1283,7 +1443,6 @@ "Style": "Default" }, "PrivateKeyAllowed": "Required", - "JobProperties": [], "ServerRequired": true, "PowerShell": false, "BlueprintAllowed": true, @@ -1491,7 +1650,7 @@ "EntryParameters": [], "PasswordOptions": { "EntrySupported": false, - "StoreRequired": false, + "StoreRequired": true, "Style": "Default" }, "PrivateKeyAllowed": "Optional", @@ -2948,16 +3107,41 @@ "PasswordOptions": { "Style": "Default", "EntrySupported": false, - "StoreRequired": true + "StoreRequired": true, + "StorePassword": { + "Description": "Password used to secure the Certificate Store", + "IsPAMEligible": true + } }, "Properties": [ + { + "Name": "ServerUsername", + "DisplayName": "Server Username", + "Type": "Secret", + "DependsOn": "", + "DefaultValue": "", + "Required": false, + "IsPAMEligible": true, + "Description": "A username (or valid PAM key if the username is stored in a KF Command configured PAM integration). If acting as an *agent* using local file access, just check *No Value*" + }, + { + "Name": "ServerPassword", + "DisplayName": "Server Password", + "Type": "Secret", + "DependsOn": "", + "DefaultValue": "", + "Required": false, + "IsPAMEligible": true, + "Description": "A password (or valid PAM key if the password is stored in a KF Command configured PAM integration). The password can also be an SSH private key if connecting via SSH to a server using SSH private key authentication. If acting as an *agent* using local file access, just check *No Value*" + }, { "Name": "LinuxFilePermissionsOnStoreCreation", "DisplayName": "Linux File Permissions on Store Creation", "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The LinuxFilePermissionsOnStoreCreation field should contain a three-digit value between 000 and 777 representing the Linux file permissions to be set for the certificate store upon creation. Example: '600' or '755'." }, { "Name": "LinuxFileOwnerOnStoreCreation", @@ -2965,7 +3149,8 @@ "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The LinuxFileOwnerOnStoreCreation field should contain a valid user ID recognized by the destination Linux server, optionally followed by a colon and a group ID if the group owner differs. Example: 'userID' or 'userID:groupID'." }, { "Name": "SudoImpersonatingUser", @@ -2973,7 +3158,8 @@ "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The SudoImpersonatingUser field should contain a valid user ID to impersonate using sudo on the destination Linux server. Example: 'impersonatedUserID'." }, { "Name": "SeparatePrivateKeyFilePath", @@ -2981,10 +3167,13 @@ "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The SeparatePrivateKeyFilePath field should contain the full path and file name where the separate private key file will be stored if it is to be kept outside the main certificate file. Example: '/path/to/privatekey.der'." } ], - "EntryParameters": [] + "EntryParameters": [], + "ClientMachineDescription": "The Client Machine field should contain the DNS name or IP address of the remote orchestrated server for Linux orchestrated servers, formatted as a URL (protocol://dns-or-ip:port) for Windows orchestrated servers, or '1.1.1.1|LocalMachine' for local agents. Example: 'https://myserver.mydomain.com:5986' or '1.1.1.1|LocalMachine' for local access.", + "StorePathDescription": "The Store Path field should contain the full path and file name, including file extension if applicable, beginning with a forward slash (/) for Linux orchestrated servers or a drive letter (i.e., c:\\folder\\path\\storename.der) for Windows orchestrated servers. Example: '/folder/path/storename.der' or 'c:\\folder\\path\\storename.der'." }, { "Name": "RFJKS", @@ -3005,16 +3194,41 @@ "PasswordOptions": { "Style": "Default", "EntrySupported": false, - "StoreRequired": true + "StoreRequired": true, + "StorePassword": { + "Description": "Password used to secure the Certificate Store", + "IsPAMEligible": true + } }, "Properties": [ + { + "Name": "ServerUsername", + "DisplayName": "Server Username", + "Type": "Secret", + "DependsOn": "", + "DefaultValue": "", + "Required": false, + "IsPAMEligible": true, + "Description": "A username (or valid PAM key if the username is stored in a KF Command configured PAM integration). If acting as an *agent* using local file access, just check *No Value*" + }, + { + "Name": "ServerPassword", + "DisplayName": "Server Password", + "Type": "Secret", + "DependsOn": "", + "DefaultValue": "", + "Required": false, + "IsPAMEligible": true, + "Description": "A password (or valid PAM key if the password is stored in a KF Command configured PAM integration). The password can also be an SSH private key if connecting via SSH to a server using SSH private key authentication. If acting as an *agent* using local file access, just check *No Value*" + }, { "Name": "LinuxFilePermissionsOnStoreCreation", "DisplayName": "Linux File Permissions on Store Creation", "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The LinuxFilePermissionsOnStoreCreation field should contain a three-digit value between 000 and 777 representing the Linux file permissions to be set for the certificate store upon creation. Example: '600' or '755'." }, { "Name": "LinuxFileOwnerOnStoreCreation", @@ -3022,7 +3236,8 @@ "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The LinuxFileOwnerOnStoreCreation field should contain a valid user ID recognized by the destination Linux server, optionally followed by a colon and a group ID if the group owner differs. Example: 'userID' or 'userID:groupID'." }, { "Name": "SudoImpersonatingUser", @@ -3030,10 +3245,13 @@ "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The SudoImpersonatingUser field should contain a valid user ID to impersonate using sudo on the destination Linux server. Example: 'impersonatedUserID'." } ], - "EntryParameters": [] + "EntryParameters": [], + "ClientMachineDescription": "The IP address or DNS of the server hosting the certificate store. For more information, see [Client Machine ](#client-machine-instructions)", + "StorePathDescription": "The full path and file name, including file extension if one exists where the certificate store file is located. For Linux orchestrated servers, StorePath will begin with a forward slash (i.e. /folder/path/storename.ext). For Windows orchestrated servers, it should begin with a drive letter (i.e. c:\\folder\\path\\storename.ext)." }, { "Name": "RFKDB", @@ -3054,16 +3272,41 @@ "PasswordOptions": { "Style": "Default", "EntrySupported": false, - "StoreRequired": true + "StoreRequired": true, + "StorePassword": { + "Description": "Password used to secure the Certificate Store", + "IsPAMEligible": true + } }, "Properties": [ + { + "Name": "ServerUsername", + "DisplayName": "Server Username", + "Type": "Secret", + "DependsOn": "", + "DefaultValue": "", + "Required": false, + "IsPAMEligible": true, + "Description": "A username (or valid PAM key if the username is stored in a KF Command configured PAM integration). If acting as an *agent* using local file access, just check *No Value*" + }, + { + "Name": "ServerPassword", + "DisplayName": "Server Password", + "Type": "Secret", + "DependsOn": "", + "DefaultValue": "", + "Required": false, + "IsPAMEligible": true, + "Description": "A password (or valid PAM key if the password is stored in a KF Command configured PAM integration). The password can also be an SSH private key if connecting via SSH to a server using SSH private key authentication. If acting as an *agent* using local file access, just check *No Value*" + }, { "Name": "LinuxFilePermissionsOnStoreCreation", "DisplayName": "Linux File Permissions on Store Creation", "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The LinuxFilePermissionsOnStoreCreation field should contain a three-digit value between 000 and 777 representing the Linux file permissions to be set for the certificate store upon creation. Example: '600' or '755'." }, { "Name": "LinuxFileOwnerOnStoreCreation", @@ -3071,7 +3314,8 @@ "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The LinuxFileOwnerOnStoreCreation field should contain a valid user ID recognized by the destination Linux server, optionally followed by a colon and a group ID if the group owner differs. Example: 'userID' or 'userID:groupID'." }, { "Name": "SudoImpersonatingUser", @@ -3079,10 +3323,13 @@ "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The SudoImpersonatingUser field should contain a valid user ID to impersonate using sudo on the destination Linux server. Example: 'impersonatedUserID'." } ], - "EntryParameters": [] + "EntryParameters": [], + "ClientMachineDescription": "The Client Machine field should contain the DNS name or IP address of the remote orchestrated server for Linux orchestrated servers, formatted as a URL (protocol://dns-or-ip:port) for Windows orchestrated servers, or '1.1.1.1|LocalMachine' for local agents. Example: 'https://myserver.mydomain.com:5986' or '1.1.1.1|LocalMachine' for local access.", + "StorePathDescription": "The Store Path field should contain the full path and file name, including file extension if applicable, beginning with a forward slash (/) for Linux orchestrated servers or a drive letter (i.e., c:\\folder\\path\\storename.kdb) for Windows orchestrated servers. Example: '/folder/path/storename.kdb' or 'c:\\folder\\path\\storename.kdb'." }, { "Name": "RFORA", @@ -3103,16 +3350,41 @@ "PasswordOptions": { "Style": "Default", "EntrySupported": false, - "StoreRequired": true + "StoreRequired": true, + "StorePassword": { + "Description": "Password used to secure the Certificate Store", + "IsPAMEligible": true + } }, "Properties": [ + { + "Name": "ServerUsername", + "DisplayName": "Server Username", + "Type": "Secret", + "DependsOn": "", + "DefaultValue": "", + "Required": false, + "IsPAMEligible": true, + "Description": "A username (or valid PAM key if the username is stored in a KF Command configured PAM integration). If acting as an *agent* using local file access, just check *No Value*" + }, + { + "Name": "ServerPassword", + "DisplayName": "Server Password", + "Type": "Secret", + "DependsOn": "", + "DefaultValue": "", + "Required": false, + "IsPAMEligible": true, + "Description": "A password (or valid PAM key if the password is stored in a KF Command configured PAM integration). The password can also be an SSH private key if connecting via SSH to a server using SSH private key authentication. If acting as an *agent* using local file access, just check *No Value*" + }, { "Name": "LinuxFilePermissionsOnStoreCreation", "DisplayName": "Linux File Permissions on Store Creation", "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The LinuxFilePermissionsOnStoreCreation field should contain a three-digit value between 000 and 777 representing the Linux file permissions to be set for the certificate store upon creation. Example: '600' or '755'." }, { "Name": "LinuxFileOwnerOnStoreCreation", @@ -3120,7 +3392,8 @@ "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The LinuxFileOwnerOnStoreCreation field should contain a valid user ID recognized by the destination Linux server, optionally followed by a colon and a group ID if the group owner differs. Example: 'userID' or 'userID:groupID'." }, { "Name": "SudoImpersonatingUser", @@ -3128,7 +3401,8 @@ "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The SudoImpersonatingUser field should contain a valid user ID to impersonate using sudo on the destination Linux server. Example: 'impersonatedUserID'." }, { "Name": "WorkFolder", @@ -3136,10 +3410,13 @@ "Required": true, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The WorkFolder field should contain the path on the managed server where temporary work files can be created, modified, and deleted during Inventory and Management jobs. Example: '/path/to/workfolder'." } ], - "EntryParameters": [] + "EntryParameters": [], + "ClientMachineDescription": "The Client Machine field should contain the DNS name or IP address of the remote orchestrated server for Linux orchestrated servers, formatted as a URL (protocol://dns-or-ip:port) for Windows orchestrated servers, or '1.1.1.1|LocalMachine' for local agents. Example: 'https://myserver.mydomain.com:5986' or '1.1.1.1|LocalMachine' for local access.", + "StorePathDescription": "The Store Path field should contain the full path and file name of the Oracle Wallet, including the 'eWallet.p12' file name by convention. Example: '/path/to/eWallet.p12' or 'c:\\path\\to\\eWallet.p12'." }, { "Name": "RFPEM", @@ -3160,16 +3437,41 @@ "PasswordOptions": { "Style": "Default", "EntrySupported": false, - "StoreRequired": true + "StoreRequired": true, + "StorePassword": { + "Description": "Password used to secure the Certificate Store. For stores with PKCS#8 private keys, set the password for encrypted private keys (BEGIN ENCRYPTED PRIVATE KEY) or 'No Value' for unencrypted private keys (BEGIN PRIVATE KEY). If managing a store with a PKCS#1 private key (BEGIN RSA PRIVATE KEY), this value MUST be set to 'No Value'", + "IsPAMEligible": true + } }, "Properties": [ + { + "Name": "ServerUsername", + "DisplayName": "Server Username", + "Type": "Secret", + "DependsOn": "", + "DefaultValue": "", + "Required": false, + "IsPAMEligible": true, + "Description": "A username (or valid PAM key if the username is stored in a KF Command configured PAM integration). If acting as an *agent* using local file access, just check *No Value*" + }, + { + "Name": "ServerPassword", + "DisplayName": "Server Password", + "Type": "Secret", + "DependsOn": "", + "DefaultValue": "", + "Required": false, + "IsPAMEligible": true, + "Description": "A password (or valid PAM key if the password is stored in a KF Command configured PAM integration). The password can also be an SSH private key if connecting via SSH to a server using SSH private key authentication. If acting as an *agent* using local file access, just check *No Value*" + }, { "Name": "LinuxFilePermissionsOnStoreCreation", "DisplayName": "Linux File Permissions on Store Creation", "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The LinuxFilePermissionsOnStoreCreation field should contain a three-digit value between 000 and 777 representing the Linux file permissions to be set for the certificate store upon creation. Example: '600' or '755'." }, { "Name": "LinuxFileOwnerOnStoreCreation", @@ -3177,7 +3479,8 @@ "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The LinuxFileOwnerOnStoreCreation field should contain a valid user ID recognized by the destination Linux server, optionally followed by a colon and a group ID if the group owner differs. Example: 'userID' or 'userID:groupID'." }, { "Name": "SudoImpersonatingUser", @@ -3185,7 +3488,8 @@ "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The SudoImpersonatingUser field should contain a valid user ID to impersonate using sudo on the destination Linux server. Example: 'impersonatedUserID'." }, { "Name": "IsTrustStore", @@ -3193,7 +3497,8 @@ "Required": false, "DependsOn": "", "Type": "Bool", - "DefaultValue": false + "DefaultValue": "false", + "Description": "The IsTrustStore field should contain a boolean value ('true' or 'false') indicating whether the store will be identified as a trust store, which can hold multiple certificates without private keys. Example: 'true' for a trust store or 'false' for a store with a single certificate and private key." }, { "Name": "IncludesChain", @@ -3201,7 +3506,8 @@ "Required": false, "DependsOn": "", "Type": "Bool", - "DefaultValue": false + "DefaultValue": "false", + "Description": "The IncludesChain field should contain a boolean value ('true' or 'false') indicating whether the certificate store includes the full certificate chain along with the end entity certificate. Example: 'true' to include the full chain or 'false' to exclude it." }, { "Name": "SeparatePrivateKeyFilePath", @@ -3209,15 +3515,8 @@ "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" - }, - { - "Name": "IsRSAPrivateKey", - "DisplayName": "Is RSA Private Key", - "Required": false, - "DependsOn": "", - "Type": "Bool", - "DefaultValue": false + "DefaultValue": "", + "Description": "The SeparatePrivateKeyFilePath field should contain the full path and file name where the separate private key file will be stored if it is to be kept outside the main certificate file. Example: '/path/to/privatekey.pem'." }, { "Name": "IgnorePrivateKeyOnInventory", @@ -3225,10 +3524,13 @@ "Required": false, "DependsOn": "", "Type": "Bool", - "DefaultValue": false + "DefaultValue": "false", + "Description": "The IgnorePrivateKeyOnInventory field should contain a boolean value ('true' or 'false') indicating whether to ignore the private key during inventory, which will make the store inventory-only and return all certificates without private key entries. Example: 'true' to ignore the private key or 'false' to include it." } ], - "EntryParameters": [] + "EntryParameters": [], + "ClientMachineDescription": "The Client Machine field should contain the DNS name or IP address of the remote orchestrated server for Linux orchestrated servers, formatted as a URL (protocol://dns-or-ip:port) for Windows orchestrated servers, or '1.1.1.1|LocalMachine' for local agents. Example: 'https://myserver.mydomain.com:5986' or '1.1.1.1|LocalMachine' for local access.", + "StorePathDescription": "The Store Path field should contain the full path and file name, including file extension if applicable, beginning with a forward slash (/) for Linux orchestrated servers or a drive letter (i.e., c:\\folder\\path\\storename.ext) for Windows orchestrated servers. Example: '/folder/path/storename.pem' or 'c:\\folder\\path\\storename.pem'." }, { "Name": "RFPkcs12", @@ -3249,16 +3551,41 @@ "PasswordOptions": { "Style": "Default", "EntrySupported": false, - "StoreRequired": true + "StoreRequired": true, + "StorePassword": { + "Description": "Password used to secure the Certificate Store", + "IsPAMEligible": true + } }, "Properties": [ + { + "Name": "ServerUsername", + "DisplayName": "Server Username", + "Type": "Secret", + "DependsOn": "", + "DefaultValue": "", + "Required": false, + "IsPAMEligible": true, + "Description": "A username (or valid PAM key if the username is stored in a KF Command configured PAM integration). If acting as an *agent* using local file access, just check *No Value*" + }, + { + "Name": "ServerPassword", + "DisplayName": "Server Password", + "Type": "Secret", + "DependsOn": "", + "DefaultValue": "", + "Required": false, + "IsPAMEligible": true, + "Description": "A password (or valid PAM key if the password is stored in a KF Command configured PAM integration). The password can also be an SSH private key if connecting via SSH to a server using SSH private key authentication. If acting as an *agent* using local file access, just check *No Value*" + }, { "Name": "LinuxFilePermissionsOnStoreCreation", "DisplayName": "Linux File Permissions on Store Creation", "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The LinuxFilePermissionsOnStoreCreation field should contain a three-digit value between 000 and 777 representing the Linux file permissions to be set for the certificate store upon creation. Example: '600' or '755'." }, { "Name": "LinuxFileOwnerOnStoreCreation", @@ -3266,7 +3593,8 @@ "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The LinuxFileOwnerOnStoreCreation field should contain a valid user ID recognized by the destination Linux server, optionally followed by a colon and a group ID if the group owner differs. Example: 'userID' or 'userID:groupID'." }, { "Name": "SudoImpersonatingUser", @@ -3274,10 +3602,13 @@ "Required": false, "DependsOn": "", "Type": "String", - "DefaultValue": "" + "DefaultValue": "", + "Description": "The SudoImpersonatingUser field should contain a valid user ID to impersonate using sudo on the destination Linux server. Example: 'impersonatedUserID'." } ], - "EntryParameters": [] + "EntryParameters": [], + "ClientMachineDescription": "The Client Machine field should contain the DNS name or IP address of the remote orchestrated server for Linux orchestrated servers, formatted as a URL (protocol://dns-or-ip:port) for Windows orchestrated servers, or '1.1.1.1|LocalMachine' for local agents. Example: 'https://myserver.mydomain.com:5986' or '1.1.1.1|LocalMachine' for local access.", + "StorePathDescription": "The Store Path field should contain the full path and file name, including file extension if applicable, beginning with a forward slash (/) for Linux orchestrated servers or a drive letter (i.e., c:\\folder\\path\\storename.p12) for Windows orchestrated servers. Example: '/folder/path/storename.p12' or 'c:\\folder\\path\\storename.p12'." }, { "Name": "SampleStoreType", diff --git a/store_types.json b/store_types.json index caeb3df..324a97f 100644 --- a/store_types.json +++ b/store_types.json @@ -186,6 +186,34 @@ "BlueprintAllowed": true, "CustomAliasAllowed": "Optional" }, + { + "Name": "Airlock Application Firewall Certificate", + "ShortName": "AirlockWAF", + "Capability": "AirlockWAF", + "LocalStore": false, + "SupportedOperations": { + "Add": true, + "Create": false, + "Discovery": true, + "Enrollment": false, + "Remove": true + }, + "Properties": [], + "EntryParameters": [], + "PasswordOptions": { + "EntrySupported": false, + "StoreRequired": true, + "Style": "Default" + }, + "StorePathType": "", + "StorePathValue": "", + "PrivateKeyAllowed": "Required", + "JobProperties": [], + "ServerRequired": true, + "PowerShell": false, + "BlueprintAllowed": false, + "CustomAliasAllowed": "Allowed" + }, { "Name": "Akamai Certificate Provisioning Service", "ShortName": "Akamai", From 76c4a6ceab25e8be8047cbcc7d9866a347cc4ea7 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Tue, 19 Nov 2024 12:24:28 -0800 Subject: [PATCH 28/49] chore(store-types): Remove `AirlockWAF` Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- cmd/store_types.json | 28 ---------------------------- store_types.json | 28 ---------------------------- 2 files changed, 56 deletions(-) diff --git a/cmd/store_types.json b/cmd/store_types.json index 324a97f..caeb3df 100644 --- a/cmd/store_types.json +++ b/cmd/store_types.json @@ -186,34 +186,6 @@ "BlueprintAllowed": true, "CustomAliasAllowed": "Optional" }, - { - "Name": "Airlock Application Firewall Certificate", - "ShortName": "AirlockWAF", - "Capability": "AirlockWAF", - "LocalStore": false, - "SupportedOperations": { - "Add": true, - "Create": false, - "Discovery": true, - "Enrollment": false, - "Remove": true - }, - "Properties": [], - "EntryParameters": [], - "PasswordOptions": { - "EntrySupported": false, - "StoreRequired": true, - "Style": "Default" - }, - "StorePathType": "", - "StorePathValue": "", - "PrivateKeyAllowed": "Required", - "JobProperties": [], - "ServerRequired": true, - "PowerShell": false, - "BlueprintAllowed": false, - "CustomAliasAllowed": "Allowed" - }, { "Name": "Akamai Certificate Provisioning Service", "ShortName": "Akamai", diff --git a/store_types.json b/store_types.json index 324a97f..caeb3df 100644 --- a/store_types.json +++ b/store_types.json @@ -186,34 +186,6 @@ "BlueprintAllowed": true, "CustomAliasAllowed": "Optional" }, - { - "Name": "Airlock Application Firewall Certificate", - "ShortName": "AirlockWAF", - "Capability": "AirlockWAF", - "LocalStore": false, - "SupportedOperations": { - "Add": true, - "Create": false, - "Discovery": true, - "Enrollment": false, - "Remove": true - }, - "Properties": [], - "EntryParameters": [], - "PasswordOptions": { - "EntrySupported": false, - "StoreRequired": true, - "Style": "Default" - }, - "StorePathType": "", - "StorePathValue": "", - "PrivateKeyAllowed": "Required", - "JobProperties": [], - "ServerRequired": true, - "PowerShell": false, - "BlueprintAllowed": false, - "CustomAliasAllowed": "Allowed" - }, { "Name": "Akamai Certificate Provisioning Service", "ShortName": "Akamai", From e415a683b49da40524b0c652548e96f66e8a5dac Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Tue, 19 Nov 2024 13:10:19 -0800 Subject: [PATCH 29/49] fix(ci): Add `SAST_TOKEN` Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- .github/workflows/keyfactor-bootstrap-workflow.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/keyfactor-bootstrap-workflow.yml b/.github/workflows/keyfactor-bootstrap-workflow.yml index 744d769..580c4a6 100644 --- a/.github/workflows/keyfactor-bootstrap-workflow.yml +++ b/.github/workflows/keyfactor-bootstrap-workflow.yml @@ -120,4 +120,5 @@ jobs: 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 + gpg_pass: ${{ secrets.KF_GPG_PASSPHRASE }} + scan_token: ${{ secrets.SAST_TOKEN }} \ No newline at end of file From 0bbd7fc2483596136b2dedd2a59c34dc9c775d29 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Tue, 19 Nov 2024 13:27:29 -0800 Subject: [PATCH 30/49] fix(ci): Move install script test to run after bootstrap workflow builds release. Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- .../keyfactor-bootstrap-workflow.yml | 24 ++++++++++++++++++- .github/workflows/tests.yml | 15 ------------ 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/.github/workflows/keyfactor-bootstrap-workflow.yml b/.github/workflows/keyfactor-bootstrap-workflow.yml index 580c4a6..dfaf288 100644 --- a/.github/workflows/keyfactor-bootstrap-workflow.yml +++ b/.github/workflows/keyfactor-bootstrap-workflow.yml @@ -121,4 +121,26 @@ jobs: APPROVE_README_PUSH: ${{ secrets.APPROVE_README_PUSH}} gpg_key: ${{ secrets.KF_GPG_PRIVATE_KEY }} gpg_pass: ${{ secrets.KF_GPG_PASSPHRASE }} - scan_token: ${{ secrets.SAST_TOKEN }} \ No newline at end of file + scan_token: ${{ secrets.SAST_TOKEN }} + + # Tester Install Script + Test_Install_Script: + runs-on: kfutil-runner-set + if: startsWith(github.ref, 'refs/tags/') + needs: + - get-versions + # - call-starter-workflow + steps: + - name: Test Quick Install Script + env: + VERSION: ${{ needs.get-versions.outputs.NEXT_VERSION }} + run: | + echo "Testing Install Script for version: $VERSION" + 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) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 98231c8..54f2ca1 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -639,21 +639,6 @@ jobs: run: | go test -timeout 20m -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 From 92da929a74cfcfd2c15fdbae411abb69d2b4187a Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Tue, 19 Nov 2024 13:28:12 -0800 Subject: [PATCH 31/49] fix(ci): Remove tag condition on install script test Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- .github/workflows/keyfactor-bootstrap-workflow.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/keyfactor-bootstrap-workflow.yml b/.github/workflows/keyfactor-bootstrap-workflow.yml index dfaf288..bd970a9 100644 --- a/.github/workflows/keyfactor-bootstrap-workflow.yml +++ b/.github/workflows/keyfactor-bootstrap-workflow.yml @@ -126,7 +126,6 @@ jobs: # Tester Install Script Test_Install_Script: runs-on: kfutil-runner-set - if: startsWith(github.ref, 'refs/tags/') needs: - get-versions # - call-starter-workflow From 131b7beaf2ac08ec977462a8d0197fef1640800e Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Wed, 20 Nov 2024 09:23:51 -0800 Subject: [PATCH 32/49] chore(deps): Bump `github.com/Keyfactor/keyfactor-auth-client-go` to `v1.1.0-rc.8` Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- go.mod | 22 +++++++++++----------- go.sum | 44 ++++++++++++++++++++++---------------------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/go.mod b/go.mod index 5393c5b..8a35b6a 100644 --- a/go.mod +++ b/go.mod @@ -6,11 +6,11 @@ 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/azcore v1.16.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 github.com/Jeffail/gabs v1.4.0 - github.com/Keyfactor/keyfactor-auth-client-go v1.1.0-rc.4 - github.com/Keyfactor/keyfactor-go-client-sdk/v2 v2.0.0-rc.2 + github.com/Keyfactor/keyfactor-auth-client-go v1.1.0-rc.8 + github.com/Keyfactor/keyfactor-go-client-sdk/v2 v2.0.0-rc.3 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 @@ -22,17 +22,17 @@ require ( github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.9.0 - golang.org/x/crypto v0.27.0 - golang.org/x/term v0.24.0 + golang.org/x/crypto v0.28.0 + golang.org/x/term v0.25.0 gopkg.in/yaml.v3 v3.0.1 //github.com/google/go-cmp/cmp v0.5.9 ) require ( github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.12.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 // indirect - github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect + github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.3.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.0 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.3.1 // 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 @@ -50,9 +50,9 @@ require ( github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/spbsoluble/go-pkcs12 v0.3.3 // indirect go.mozilla.org/pkcs7 v0.9.0 // indirect - golang.org/x/net v0.29.0 // indirect + golang.org/x/net v0.30.0 // indirect golang.org/x/oauth2 v0.24.0 // indirect - golang.org/x/sys v0.25.0 // indirect - golang.org/x/text v0.18.0 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/text v0.19.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index ead21a3..6f831b4 100644 --- a/go.sum +++ b/go.sum @@ -1,27 +1,27 @@ github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ= github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 h1:nyQWyZvwGTvunIMxi1Y9uXkcyr+I7TeNrr/foo4Kpk8= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0/go.mod h1:l38EPgmsp71HHLq9j7De57JcKOWPyhrsW1Awm1JS6K0= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 h1:JZg6HRh6W6U4OLl6lk7BZ7BLisIzM9dG1R50zUk9C/M= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0/go.mod h1:YL1xnZ6QejvQHWJrX/AvhFl4WW4rqHVoKspWNVwFk0M= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 h1:B/dfvscEQtew9dVuoxqxrUKKv8Ih2f55PydknDamU+g= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0/go.mod h1:fiPSssYvltE08HJchL04dOy+RD4hgrjph0cwGGMntdI= github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0 h1:+m0M/LFxN43KvULkDNfdXOgrjtg6UYJPFBJyuEcRCAw= github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0/go.mod h1:PwOyop78lveYMRs6oCxjiVyBdyCgIYH6XHIVZO9/SFQ= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY= -github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.12.0 h1:xnO4sFyG8UH2fElBkcqLTOZsAajvKfnSlgBBW8dXYjw= -github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.12.0/go.mod h1:XD3DIOOVgBCO03OleB1fHjgktVRFxlT++KwKgIOewdM= -github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 h1:FbH3BbSb4bvGluTesZZ+ttN/MDsnMmQP36OSnDuSXqw= -github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1/go.mod h1:9V2j0jn9jDEkCkv8w/bKTNppX/d0FVA1ud77xCIP4KA= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.3.0 h1:WLUIpeyv04H0RCcQHaA4TNoyrQ39Ox7V+re+iaqzTe0= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.3.0/go.mod h1:hd8hTTIY3VmUVPRHNH7GVCHO3SHgXkJKZHReby/bnUQ= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.0 h1:eXnN9kaS8TiDwXjoie3hMRLuwdUBUMW9KRgOqB3mCaw= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.0/go.mod h1:XIpam8wumeZ5rVMuhdDQLMfIPDf1WO3IzrCRO3e3e3o= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= -github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU= -github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/AzureAD/microsoft-authentication-library-for-go v1.3.1 h1:gUDtaZk8heteyfdmv+pcfHvhR9llnh7c7GMwZ8RVG04= +github.com/AzureAD/microsoft-authentication-library-for-go v1.3.1/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.1.0-rc.4 h1:2TTlhVjPvPV6UrKN/VEqdcNGb4mgwAcsLcGuoQofg28= -github.com/Keyfactor/keyfactor-auth-client-go v1.1.0-rc.4/go.mod h1:Ia3VmXsumFrr01BMc1Rp5OpDWmfXWjdeMituda14T4I= -github.com/Keyfactor/keyfactor-go-client-sdk/v2 v2.0.0-rc.2 h1:RNrfgrC+mPvqOc1wPsFjB4thuw7qJbP3gOycRDcRwxI= -github.com/Keyfactor/keyfactor-go-client-sdk/v2 v2.0.0-rc.2/go.mod h1:11WXGG9VVKSV0EPku1IswjHbGGpzHDKqD4pe2vD7vas= +github.com/Keyfactor/keyfactor-auth-client-go v1.1.0-rc.8 h1:JtA7UwqCSsqBUc0shlEBk+g2xNMorxwQHtknCY7hcUg= +github.com/Keyfactor/keyfactor-auth-client-go v1.1.0-rc.8/go.mod h1:dUIVnqWpPiYkGqKMYQi6Z98fqzQdkZ1KHvJpCoSLQ2s= +github.com/Keyfactor/keyfactor-go-client-sdk/v2 v2.0.0-rc.3 h1:5qeMOqWFKMefxVXIVoQuWcDYP5vhlCSdIwDey2PBAd8= +github.com/Keyfactor/keyfactor-go-client-sdk/v2 v2.0.0-rc.3/go.mod h1:11WXGG9VVKSV0EPku1IswjHbGGpzHDKqD4pe2vD7vas= 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= @@ -114,14 +114,14 @@ 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.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= -golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -141,18 +141,18 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= -golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= +golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= +golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= From 70f3d6848cae40c43de4839f22b89a1a40305116 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Wed, 20 Nov 2024 09:25:49 -0800 Subject: [PATCH 33/49] chore(docs): Update autogen CLI docs. Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- docs/kfutil.md | 3 +-- docs/kfutil_completion.md | 3 +-- docs/kfutil_completion_bash.md | 3 +-- docs/kfutil_completion_fish.md | 3 +-- docs/kfutil_completion_powershell.md | 3 +-- docs/kfutil_completion_zsh.md | 3 +-- docs/kfutil_containers.md | 3 +-- docs/kfutil_containers_get.md | 3 +-- docs/kfutil_containers_list.md | 3 +-- docs/kfutil_export.md | 3 +-- docs/kfutil_helm.md | 3 +-- docs/kfutil_helm_uo.md | 3 +-- docs/kfutil_import.md | 3 +-- docs/kfutil_login.md | 3 +-- docs/kfutil_logout.md | 3 +-- docs/kfutil_orchs.md | 3 +-- docs/kfutil_orchs_approve.md | 3 +-- docs/kfutil_orchs_disapprove.md | 3 +-- docs/kfutil_orchs_ext.md | 3 +-- docs/kfutil_orchs_get.md | 3 +-- docs/kfutil_orchs_list.md | 3 +-- docs/kfutil_orchs_logs.md | 3 +-- docs/kfutil_orchs_reset.md | 3 +-- docs/kfutil_pam.md | 3 +-- docs/kfutil_pam_create.md | 3 +-- docs/kfutil_pam_delete.md | 3 +-- docs/kfutil_pam_get.md | 3 +-- docs/kfutil_pam_list.md | 3 +-- docs/kfutil_pam_types-create.md | 3 +-- docs/kfutil_pam_types-list.md | 3 +-- docs/kfutil_pam_update.md | 3 +-- docs/kfutil_status.md | 3 +-- docs/kfutil_store-types.md | 3 +-- docs/kfutil_store-types_create.md | 5 ++--- docs/kfutil_store-types_delete.md | 3 +-- docs/kfutil_store-types_get.md | 3 +-- docs/kfutil_store-types_list.md | 3 +-- docs/kfutil_store-types_templates-fetch.md | 3 +-- docs/kfutil_stores.md | 3 +-- docs/kfutil_stores_delete.md | 3 +-- docs/kfutil_stores_export.md | 3 +-- docs/kfutil_stores_get.md | 3 +-- docs/kfutil_stores_import.md | 3 +-- docs/kfutil_stores_import_csv.md | 3 +-- docs/kfutil_stores_import_generate-template.md | 3 +-- docs/kfutil_stores_inventory.md | 3 +-- docs/kfutil_stores_inventory_add.md | 3 +-- docs/kfutil_stores_inventory_remove.md | 3 +-- docs/kfutil_stores_inventory_show.md | 3 +-- docs/kfutil_stores_list.md | 3 +-- docs/kfutil_version.md | 3 +-- 51 files changed, 52 insertions(+), 103 deletions(-) diff --git a/docs/kfutil.md b/docs/kfutil.md index 1644a76..ed50166 100644 --- a/docs/kfutil.md +++ b/docs/kfutil.md @@ -21,7 +21,6 @@ A CLI wrapper around the Keyfactor Platform API. --format text How to format the CLI output. Currently only text is supported. (default "text") -h, --help help for kfutil --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -46,4 +45,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 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_completion.md b/docs/kfutil_completion.md index 8121f78..580e5cd 100644 --- a/docs/kfutil_completion.md +++ b/docs/kfutil_completion.md @@ -28,7 +28,6 @@ See each sub-command's help for details on how to use the generated script. --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -45,4 +44,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 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_completion_bash.md b/docs/kfutil_completion_bash.md index 7f3da87..c9c719e 100644 --- a/docs/kfutil_completion_bash.md +++ b/docs/kfutil_completion_bash.md @@ -51,7 +51,6 @@ kfutil completion bash --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -64,4 +63,4 @@ kfutil completion bash * [kfutil completion](kfutil_completion.md) - Generate the autocompletion script for the specified shell -###### Auto generated by spf13/cobra on 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_completion_fish.md b/docs/kfutil_completion_fish.md index bd17588..2860cc5 100644 --- a/docs/kfutil_completion_fish.md +++ b/docs/kfutil_completion_fish.md @@ -42,7 +42,6 @@ kfutil completion fish [flags] --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -55,4 +54,4 @@ kfutil completion fish [flags] * [kfutil completion](kfutil_completion.md) - Generate the autocompletion script for the specified shell -###### Auto generated by spf13/cobra on 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_completion_powershell.md b/docs/kfutil_completion_powershell.md index e9d0fe2..93e007a 100644 --- a/docs/kfutil_completion_powershell.md +++ b/docs/kfutil_completion_powershell.md @@ -39,7 +39,6 @@ kfutil completion powershell [flags] --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -52,4 +51,4 @@ kfutil completion powershell [flags] * [kfutil completion](kfutil_completion.md) - Generate the autocompletion script for the specified shell -###### Auto generated by spf13/cobra on 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_completion_zsh.md b/docs/kfutil_completion_zsh.md index 503bbd5..c2faf3a 100644 --- a/docs/kfutil_completion_zsh.md +++ b/docs/kfutil_completion_zsh.md @@ -53,7 +53,6 @@ kfutil completion zsh [flags] --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -66,4 +65,4 @@ kfutil completion zsh [flags] * [kfutil completion](kfutil_completion.md) - Generate the autocompletion script for the specified shell -###### Auto generated by spf13/cobra on 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_containers.md b/docs/kfutil_containers.md index 2252311..2964e48 100644 --- a/docs/kfutil_containers.md +++ b/docs/kfutil_containers.md @@ -26,7 +26,6 @@ A collections of APIs and utilities for interacting with Keyfactor certificate s --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -41,4 +40,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 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_containers_get.md b/docs/kfutil_containers_get.md index 80f5b79..042be2c 100644 --- a/docs/kfutil_containers_get.md +++ b/docs/kfutil_containers_get.md @@ -31,7 +31,6 @@ kfutil containers get [flags] --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -44,4 +43,4 @@ kfutil containers get [flags] * [kfutil containers](kfutil_containers.md) - Keyfactor certificate store container API and utilities. -###### Auto generated by spf13/cobra on 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_containers_list.md b/docs/kfutil_containers_list.md index 97c27e1..e19825c 100644 --- a/docs/kfutil_containers_list.md +++ b/docs/kfutil_containers_list.md @@ -30,7 +30,6 @@ kfutil containers list [flags] --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -43,4 +42,4 @@ kfutil containers list [flags] * [kfutil containers](kfutil_containers.md) - Keyfactor certificate store container API and utilities. -###### Auto generated by spf13/cobra on 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_export.md b/docs/kfutil_export.md index c7fe906..726264e 100644 --- a/docs/kfutil_export.md +++ b/docs/kfutil_export.md @@ -42,7 +42,6 @@ kfutil export [flags] --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -55,4 +54,4 @@ kfutil export [flags] * [kfutil](kfutil.md) - Keyfactor CLI utilities -###### Auto generated by spf13/cobra on 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_helm.md b/docs/kfutil_helm.md index 45ea1c9..180c93b 100644 --- a/docs/kfutil_helm.md +++ b/docs/kfutil_helm.md @@ -32,7 +32,6 @@ kubectl helm uo | helm install -f - keyfactor-universal-orchestrator keyfactor/k --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -46,4 +45,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 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_helm_uo.md b/docs/kfutil_helm_uo.md index a4e2326..35a8634 100644 --- a/docs/kfutil_helm_uo.md +++ b/docs/kfutil_helm_uo.md @@ -37,7 +37,6 @@ kfutil helm uo [-t ] [-o ] [-f ] [-e ] [-o ] [-f ] [-e -e @,@ -o ./app/extension --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -60,4 +59,4 @@ ext -t -e @,@ -o ./app/extension * [kfutil orchs](kfutil_orchs.md) - Keyfactor agents/orchestrators APIs and utilities. -###### Auto generated by spf13/cobra on 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_orchs_get.md b/docs/kfutil_orchs_get.md index b8147aa..7c80400 100644 --- a/docs/kfutil_orchs_get.md +++ b/docs/kfutil_orchs_get.md @@ -31,7 +31,6 @@ kfutil orchs get [flags] --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -44,4 +43,4 @@ kfutil orchs get [flags] * [kfutil orchs](kfutil_orchs.md) - Keyfactor agents/orchestrators APIs and utilities. -###### Auto generated by spf13/cobra on 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_orchs_list.md b/docs/kfutil_orchs_list.md index 2d1df65..76a8639 100644 --- a/docs/kfutil_orchs_list.md +++ b/docs/kfutil_orchs_list.md @@ -30,7 +30,6 @@ kfutil orchs list [flags] --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -43,4 +42,4 @@ kfutil orchs list [flags] * [kfutil orchs](kfutil_orchs.md) - Keyfactor agents/orchestrators APIs and utilities. -###### Auto generated by spf13/cobra on 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_orchs_logs.md b/docs/kfutil_orchs_logs.md index 122a01e..9fa34cd 100644 --- a/docs/kfutil_orchs_logs.md +++ b/docs/kfutil_orchs_logs.md @@ -31,7 +31,6 @@ kfutil orchs logs [flags] --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -44,4 +43,4 @@ kfutil orchs logs [flags] * [kfutil orchs](kfutil_orchs.md) - Keyfactor agents/orchestrators APIs and utilities. -###### Auto generated by spf13/cobra on 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_orchs_reset.md b/docs/kfutil_orchs_reset.md index bfd668b..81bf2d7 100644 --- a/docs/kfutil_orchs_reset.md +++ b/docs/kfutil_orchs_reset.md @@ -31,7 +31,6 @@ kfutil orchs reset [flags] --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -44,4 +43,4 @@ kfutil orchs reset [flags] * [kfutil orchs](kfutil_orchs.md) - Keyfactor agents/orchestrators APIs and utilities. -###### Auto generated by spf13/cobra on 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_pam.md b/docs/kfutil_pam.md index 37b2039..e4bd665 100644 --- a/docs/kfutil_pam.md +++ b/docs/kfutil_pam.md @@ -28,7 +28,6 @@ programmatically create, delete, edit, and list PAM Providers. --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -48,4 +47,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 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_pam_create.md b/docs/kfutil_pam_create.md index 8d883ff..8a737f0 100644 --- a/docs/kfutil_pam_create.md +++ b/docs/kfutil_pam_create.md @@ -31,7 +31,6 @@ kfutil pam create [flags] --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -44,4 +43,4 @@ kfutil pam create [flags] * [kfutil pam](kfutil_pam.md) - Keyfactor PAM Provider APIs. -###### Auto generated by spf13/cobra on 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_pam_delete.md b/docs/kfutil_pam_delete.md index 409740f..47589bc 100644 --- a/docs/kfutil_pam_delete.md +++ b/docs/kfutil_pam_delete.md @@ -31,7 +31,6 @@ kfutil pam delete [flags] --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -44,4 +43,4 @@ kfutil pam delete [flags] * [kfutil pam](kfutil_pam.md) - Keyfactor PAM Provider APIs. -###### Auto generated by spf13/cobra on 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_pam_get.md b/docs/kfutil_pam_get.md index 1607c36..d483dc1 100644 --- a/docs/kfutil_pam_get.md +++ b/docs/kfutil_pam_get.md @@ -31,7 +31,6 @@ kfutil pam get [flags] --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -44,4 +43,4 @@ kfutil pam get [flags] * [kfutil pam](kfutil_pam.md) - Keyfactor PAM Provider APIs. -###### Auto generated by spf13/cobra on 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_pam_list.md b/docs/kfutil_pam_list.md index d7118c2..6d8f60e 100644 --- a/docs/kfutil_pam_list.md +++ b/docs/kfutil_pam_list.md @@ -30,7 +30,6 @@ kfutil pam list [flags] --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -43,4 +42,4 @@ kfutil pam list [flags] * [kfutil pam](kfutil_pam.md) - Keyfactor PAM Provider APIs. -###### Auto generated by spf13/cobra on 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_pam_types-create.md b/docs/kfutil_pam_types-create.md index 246aa13..b819765 100644 --- a/docs/kfutil_pam_types-create.md +++ b/docs/kfutil_pam_types-create.md @@ -38,7 +38,6 @@ kfutil pam types-create [flags] --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -51,4 +50,4 @@ kfutil pam types-create [flags] * [kfutil pam](kfutil_pam.md) - Keyfactor PAM Provider APIs. -###### Auto generated by spf13/cobra on 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_pam_types-list.md b/docs/kfutil_pam_types-list.md index 4e71281..a16cc21 100644 --- a/docs/kfutil_pam_types-list.md +++ b/docs/kfutil_pam_types-list.md @@ -30,7 +30,6 @@ kfutil pam types-list [flags] --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -43,4 +42,4 @@ kfutil pam types-list [flags] * [kfutil pam](kfutil_pam.md) - Keyfactor PAM Provider APIs. -###### Auto generated by spf13/cobra on 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_pam_update.md b/docs/kfutil_pam_update.md index fb76e01..7f45450 100644 --- a/docs/kfutil_pam_update.md +++ b/docs/kfutil_pam_update.md @@ -31,7 +31,6 @@ kfutil pam update [flags] --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -44,4 +43,4 @@ kfutil pam update [flags] * [kfutil pam](kfutil_pam.md) - Keyfactor PAM Provider APIs. -###### Auto generated by spf13/cobra on 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_status.md b/docs/kfutil_status.md index ce08c15..913a017 100644 --- a/docs/kfutil_status.md +++ b/docs/kfutil_status.md @@ -30,7 +30,6 @@ kfutil status [flags] --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -43,4 +42,4 @@ kfutil status [flags] * [kfutil](kfutil.md) - Keyfactor CLI utilities -###### Auto generated by spf13/cobra on 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_store-types.md b/docs/kfutil_store-types.md index 04756e8..69ce108 100644 --- a/docs/kfutil_store-types.md +++ b/docs/kfutil_store-types.md @@ -26,7 +26,6 @@ A collections of APIs and utilities for interacting with Keyfactor certificate s --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -44,4 +43,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 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_store-types_create.md b/docs/kfutil_store-types_create.md index 9f2f511..ebd5e9d 100644 --- a/docs/kfutil_store-types_create.md +++ b/docs/kfutil_store-types_create.md @@ -18,7 +18,7 @@ kfutil store-types create [flags] -b, --git-ref string The git branch or tag to reference when pulling store-types from the internet. (default "main") -h, --help help for create -l, --list List valid store types. - -n, --name string Short name of the certificate store type to get. Valid choices are: AKV, AWS-ACM, Akamai, AppGwBin, AzureApp, AzureAppGw, AzureSP, BIPCamera, CiscoAsa, CitrixAdc, F5-BigIQ, F5-CA-REST, F5-SL-REST, F5-WS-REST, Fortigate, GCPLoadBal, GcpCertMgr, HCVKV, HCVKVJKS, HCVKVP12, HCVKVPEM, HCVKVPFX, HCVPKI, IISU, Imperva, K8SCert, K8SCluster, K8SJKS, K8SNS, K8SPKCS12, K8SSecret, K8STLSSecr, MOST, Nmap, PaloAlto, RFDER, RFJKS, RFKDB, RFORA, RFPEM, RFPkcs12, SAMPLETYPE, Signum, VMware-NSX, WinCerMgmt, WinCert, WinSql + -n, --name string Short name of the certificate store type to get. Valid choices are: AKV, AWS-ACM, Akamai, AppGwBin, AzureApp, AzureApp2, AzureAppGw, AzureSP, AzureSP2, BIPCamera, CiscoAsa, CitrixAdc, F5-BigIQ, F5-CA-REST, F5-SL-REST, F5-WS-REST, Fortigate, GCPLoadBal, GcpCertMgr, HCVKV, HCVKVJKS, HCVKVP12, HCVKVPEM, HCVKVPFX, HCVPKI, IISU, Imperva, K8SCert, K8SCluster, K8SJKS, K8SNS, K8SPKCS12, K8SSecret, K8STLSSecr, MOST, Nmap, PaloAlto, RFDER, RFJKS, RFKDB, RFORA, RFPEM, RFPkcs12, SAMPLETYPE, Signum, VMware-NSX, WinCerMgmt, WinCert, WinSql ``` ### Options inherited from parent commands @@ -35,7 +35,6 @@ kfutil store-types create [flags] --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -48,4 +47,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 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_store-types_delete.md b/docs/kfutil_store-types_delete.md index 8a6016d..e035dda 100644 --- a/docs/kfutil_store-types_delete.md +++ b/docs/kfutil_store-types_delete.md @@ -34,7 +34,6 @@ kfutil store-types delete [flags] --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -47,4 +46,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 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_store-types_get.md b/docs/kfutil_store-types_get.md index 1347b28..ad937b7 100644 --- a/docs/kfutil_store-types_get.md +++ b/docs/kfutil_store-types_get.md @@ -35,7 +35,6 @@ kfutil store-types get [-i | -n ] [-b --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -48,4 +47,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 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_store-types_list.md b/docs/kfutil_store-types_list.md index 07eed0a..0cece34 100644 --- a/docs/kfutil_store-types_list.md +++ b/docs/kfutil_store-types_list.md @@ -30,7 +30,6 @@ kfutil store-types list [flags] --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -43,4 +42,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 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_store-types_templates-fetch.md b/docs/kfutil_store-types_templates-fetch.md index 4beaadd..e252262 100644 --- a/docs/kfutil_store-types_templates-fetch.md +++ b/docs/kfutil_store-types_templates-fetch.md @@ -31,7 +31,6 @@ kfutil store-types templates-fetch [flags] --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -44,4 +43,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 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_stores.md b/docs/kfutil_stores.md index 1f2e2cf..c9f2478 100644 --- a/docs/kfutil_stores.md +++ b/docs/kfutil_stores.md @@ -26,7 +26,6 @@ A collections of APIs and utilities for interacting with Keyfactor certificate s --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -45,4 +44,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 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_stores_delete.md b/docs/kfutil_stores_delete.md index 7c17a1b..c3d1924 100644 --- a/docs/kfutil_stores_delete.md +++ b/docs/kfutil_stores_delete.md @@ -33,7 +33,6 @@ kfutil stores delete [flags] --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -46,4 +45,4 @@ kfutil stores delete [flags] * [kfutil stores](kfutil_stores.md) - Keyfactor certificate stores APIs and utilities. -###### Auto generated by spf13/cobra on 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_stores_export.md b/docs/kfutil_stores_export.md index 75d2b05..5b52f32 100644 --- a/docs/kfutil_stores_export.md +++ b/docs/kfutil_stores_export.md @@ -34,7 +34,6 @@ kfutil stores export [flags] --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -47,4 +46,4 @@ kfutil stores export [flags] * [kfutil stores](kfutil_stores.md) - Keyfactor certificate stores APIs and utilities. -###### Auto generated by spf13/cobra on 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_stores_get.md b/docs/kfutil_stores_get.md index 96cea90..7277fa3 100644 --- a/docs/kfutil_stores_get.md +++ b/docs/kfutil_stores_get.md @@ -31,7 +31,6 @@ kfutil stores get [flags] --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -44,4 +43,4 @@ kfutil stores get [flags] * [kfutil stores](kfutil_stores.md) - Keyfactor certificate stores APIs and utilities. -###### Auto generated by spf13/cobra on 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_stores_import.md b/docs/kfutil_stores_import.md index 6858875..4317133 100644 --- a/docs/kfutil_stores_import.md +++ b/docs/kfutil_stores_import.md @@ -26,7 +26,6 @@ Tools for generating import templates and importing certificate stores --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -41,4 +40,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 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_stores_import_csv.md b/docs/kfutil_stores_import_csv.md index c6e2a02..6cf3532 100644 --- a/docs/kfutil_stores_import_csv.md +++ b/docs/kfutil_stores_import_csv.md @@ -38,7 +38,6 @@ kfutil stores import csv --file --store-type-id --store-type-id --store-t --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -49,4 +48,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 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_stores_inventory.md b/docs/kfutil_stores_inventory.md index b57dd0e..395a43b 100644 --- a/docs/kfutil_stores_inventory.md +++ b/docs/kfutil_stores_inventory.md @@ -26,7 +26,6 @@ Commands related to certificate store inventory management --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -42,4 +41,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 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_stores_inventory_add.md b/docs/kfutil_stores_inventory_add.md index eed7bb6..f8dd194 100644 --- a/docs/kfutil_stores_inventory_add.md +++ b/docs/kfutil_stores_inventory_add.md @@ -44,7 +44,6 @@ kfutil stores inventory add [flags] --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -57,4 +56,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 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_stores_inventory_remove.md b/docs/kfutil_stores_inventory_remove.md index ba4a0fa..b1ebf34 100644 --- a/docs/kfutil_stores_inventory_remove.md +++ b/docs/kfutil_stores_inventory_remove.md @@ -40,7 +40,6 @@ kfutil stores inventory remove [flags] --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -53,4 +52,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 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_stores_inventory_show.md b/docs/kfutil_stores_inventory_show.md index 1dbdd3d..25eb963 100644 --- a/docs/kfutil_stores_inventory_show.md +++ b/docs/kfutil_stores_inventory_show.md @@ -34,7 +34,6 @@ kfutil stores inventory show [flags] --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -47,4 +46,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 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_stores_list.md b/docs/kfutil_stores_list.md index 57fe589..84bf4f1 100644 --- a/docs/kfutil_stores_list.md +++ b/docs/kfutil_stores_list.md @@ -30,7 +30,6 @@ kfutil stores list [flags] --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -43,4 +42,4 @@ kfutil stores list [flags] * [kfutil stores](kfutil_stores.md) - Keyfactor certificate stores APIs and utilities. -###### Auto generated by spf13/cobra on 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 diff --git a/docs/kfutil_version.md b/docs/kfutil_version.md index e50f95a..a6ae00b 100644 --- a/docs/kfutil_version.md +++ b/docs/kfutil_version.md @@ -30,7 +30,6 @@ kfutil version [flags] --exp Enable expEnabled features. (USE AT YOUR OWN RISK, these features are not supported and may change or be removed at any time.) --format text How to format the CLI output. Currently only text is supported. (default "text") --hostname string Hostname to use for authenticating to Keyfactor Command. - --log-insecure Log insecure API requests. (USE AT YOUR OWN RISK, this WILL log sensitive information to the console.) --no-prompt Do not prompt for any user input and assume defaults or environmental variables are set. --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. @@ -43,4 +42,4 @@ kfutil version [flags] * [kfutil](kfutil.md) - Keyfactor CLI utilities -###### Auto generated by spf13/cobra on 6-Nov-2024 +###### Auto generated by spf13/cobra on 20-Nov-2024 From 4b1ca6065b82934345325d886d37575a88322184 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Wed, 20 Nov 2024 09:29:30 -0800 Subject: [PATCH 34/49] chore(ci): Add back commented out workflows Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- .github/workflows/container.yml | 332 +++++++++++------------ .github/workflows/update-stores.yml | 394 ++++++++++++++-------------- 2 files changed, 363 insertions(+), 363 deletions(-) diff --git a/.github/workflows/container.yml b/.github/workflows/container.yml index e429892..3b64e9d 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/update-stores.yml b/.github/workflows/update-stores.yml index e15a993..0e42dfc 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 9e407afe5f375ca14572374370f08ce81e3ab92c Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Mon, 9 Dec 2024 07:31:22 -0800 Subject: [PATCH 35/49] feat(store-types): Add ability to create store-types from `integration-manifest.json` Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- cmd/integration_manifest.go | 30 +++++++++++++++++++ cmd/storeTypes.go | 57 +++++++++++++++++++++++++++++-------- 2 files changed, 75 insertions(+), 12 deletions(-) create mode 100644 cmd/integration_manifest.go diff --git a/cmd/integration_manifest.go b/cmd/integration_manifest.go new file mode 100644 index 0000000..409c37f --- /dev/null +++ b/cmd/integration_manifest.go @@ -0,0 +1,30 @@ +package cmd + +import ( + "github.com/Keyfactor/keyfactor-go-client/v3/api" +) + +type IntegrationManifest struct { + Schema string `json:"$schema"` + IntegrationType string `json:"integration_type"` + Name string `json:"name"` + Status string `json:"status"` + LinkGithub bool `json:"link_github"` + UpdateCatalog bool `json:"update_catalog"` + SupportLevel string `json:"support_level"` + ReleaseDir string `json:"release_dir"` + ReleaseProject string `json:"release_project"` + Description string `json:"description"` + About About `json:"about"` +} + +type About struct { + Orchestrator Orchestrator `json:"orchestrator"` +} + +type Orchestrator struct { + UOFramework string `json:"UOFramework"` + PAMSupport bool `json:"pam_support"` + KeyfactorPlatformVersion string `json:"keyfactor_platform_version"` + StoreTypes []api.CertificateStoreType `json:"store_types"` +} diff --git a/cmd/storeTypes.go b/cmd/storeTypes.go index 068e7ca..9e1ccf1 100644 --- a/cmd/storeTypes.go +++ b/cmd/storeTypes.go @@ -133,13 +133,15 @@ var storesTypeCreateCmd = &cobra.Command{ } if storeTypeConfigFile != "" { - createdStore, err := createStoreFromFile(storeTypeConfigFile, kfClient) + createdStoreTypes, err := createStoreTypeFromFile(storeTypeConfigFile, kfClient) if err != nil { fmt.Printf("Failed to create store type from file \"%s\"", err) return err } - fmt.Printf("Created store type called \"%s\"\n", createdStore.Name) + for _, v := range createdStoreTypes { + fmt.Printf("Created store type \"%s\"\n", v.Name) + } return nil } @@ -409,27 +411,58 @@ var fetchStoreTypesCmd = &cobra.Command{ // return nil // }, // } -func createStoreFromFile(filename string, kfClient *api.Client) (*api.CertificateStoreType, error) { +func createStoreTypeFromFile(filename string, kfClient *api.Client) ([]api.CertificateStoreType, error) { // Read the file + log.Debug().Str("filename", filename).Msg("Reading store type from file") file, err := os.Open(filename) + defer file.Close() if err != nil { + log.Error(). + Str("filename", filename). + Err(err).Msg("unable to open file") return nil, err } // Compile JSON contents to a api.CertificateStoreType struct - var storeType api.CertificateStoreType + var sType api.CertificateStoreType + var sTypes []api.CertificateStoreType + + log.Debug().Msg("Decoding JSON file as single store type") decoder := json.NewDecoder(file) - err = decoder.Decode(&storeType) - if err != nil { - return nil, err + err = decoder.Decode(&sType) + if err != nil || (sType.ShortName == "" && sType.Capability == "") { + log.Warn().Err(err).Msg("Unable to decode JSON file, attempting to parse an integration manifest") + // Attempt to parse as an integration manifest + var manifest IntegrationManifest + log.Debug().Msg("Decoding JSON file as integration manifest") + // Reset the file pointer + _, err = file.Seek(0, 0) + decoder = json.NewDecoder(file) + mErr := decoder.Decode(&manifest) + if mErr != nil { + return nil, err + } + log.Debug().Msg("Decoded JSON file as integration manifest") + sTypes = manifest.About.Orchestrator.StoreTypes + } else { + log.Debug().Msg("Decoded JSON file as single store type") + sTypes = []api.CertificateStoreType{sType} } - // Use the Keyfactor client to create the store type - createResp, err := kfClient.CreateStoreType(&storeType) - if err != nil { - return nil, err + for _, st := range sTypes { + log.Debug().Msgf("Creating certificate store type %s", st.Name) + createResp, cErr := kfClient.CreateStoreType(&st) + if cErr != nil { + log.Error(). + Str("storeType", st.Name). + Err(cErr).Msg("unable to create certificate store type") + return nil, cErr + } + log.Info().Msgf("Certificate store type %s created with ID: %d", st.Name, createResp.StoreType) } - return createResp, nil + // Use the Keyfactor client to create the store type + log.Debug().Msg("Store type created") + return sTypes, nil } func formatStoreTypes(sTypesList *[]interface{}) (map[string]interface{}, error) { From 05966321bdad009d1b48f4f49998faee7d23e603 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Mon, 9 Dec 2024 08:23:59 -0800 Subject: [PATCH 36/49] feat(store-types): Add ability to use `integration-manifest.json` from custom `Keyfactor` git repo, default to `kfutil` repo. Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- cmd/constants.go | 3 + cmd/storeTypes.go | 83 +++++++++++++++---- cmd/storeTypes_get.go | 3 +- cmd/storesBulkOperations.go | 4 +- 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 | 3 +- 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 | 3 +- docs/kfutil_stores.md | 2 +- 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 +- 55 files changed, 127 insertions(+), 70 deletions(-) diff --git a/cmd/constants.go b/cmd/constants.go index ee900c3..55779dd 100644 --- a/cmd/constants.go +++ b/cmd/constants.go @@ -21,11 +21,14 @@ const ( DefaultAPIPath = "KeyfactorAPI" DefaultConfigFileName = "command_config.json" DefaultStoreTypesFileName = "store_types.json" + DefaultGitRepo = "kfutil" + DefaultGitRef = "main" FailedAuthMsg = "Login failed!" SuccessfulAuthMsg = "Login successful!" XKeyfactorRequestedWith = "APIClient" XKeyfactorApiVersion = "1" FlagGitRef = "git-ref" + FlagGitRepo = "repo" FlagFromFile = "from-file" DebugFuncEnter = "entered: %s" DebugFuncExit = "exiting: %s" diff --git a/cmd/storeTypes.go b/cmd/storeTypes.go index 9e1ccf1..20e43f0 100644 --- a/cmd/storeTypes.go +++ b/cmd/storeTypes.go @@ -91,8 +91,9 @@ var storesTypeCreateCmd = &cobra.Command{ cmd.SilenceUsage = true // Specific flags gitRef, _ := cmd.Flags().GetString(FlagGitRef) + gitRepo, _ := cmd.Flags().GetString(FlagGitRepo) creatAll, _ := cmd.Flags().GetBool("all") - validStoreTypes := getValidStoreTypes("", gitRef) + validStoreTypes := getValidStoreTypes("", gitRef, gitRepo) storeType, _ := cmd.Flags().GetString("name") listTypes, _ := cmd.Flags().GetBool("list") storeTypeConfigFile, _ := cmd.Flags().GetString("from-file") @@ -110,7 +111,10 @@ var storesTypeCreateCmd = &cobra.Command{ // CLI Logic if gitRef == "" { - gitRef = "main" + gitRef = DefaultGitRef + } + if gitRepo == "" { + gitRepo = DefaultGitRepo } storeTypeIsValid := false @@ -119,6 +123,7 @@ var storesTypeCreateCmd = &cobra.Command{ Str("storeTypeConfigFile", storeTypeConfigFile). Bool("creatAll", creatAll). Str("gitRef", gitRef). + Str("gitRepo", gitRepo). Strs("validStoreTypes", validStoreTypes). Msg("create command flags") @@ -183,7 +188,7 @@ var storesTypeCreateCmd = &cobra.Command{ } else { typesToCreate = validStoreTypes } - storeTypeConfig, stErr := readStoreTypesConfig("", gitRef, offline) + storeTypeConfig, stErr := readStoreTypesConfig("", gitRef, gitRepo, offline) if stErr != nil { log.Error().Err(stErr).Send() return stErr @@ -263,7 +268,7 @@ var storesTypeDeleteCmd = &cobra.Command{ validStoreTypesResp, vstErr := kfClient.ListCertificateStoreTypes() if vstErr != nil { log.Error().Err(vstErr).Msg("unable to list certificate store types") - validStoreTypes = getValidStoreTypes("", gitRef) + validStoreTypes = getValidStoreTypes("", gitRef, DefaultGitRepo) } else { for _, v := range *validStoreTypesResp { validStoreTypes = append(validStoreTypes, v.ShortName) @@ -360,6 +365,7 @@ var fetchStoreTypesCmd = &cobra.Command{ cmd.SilenceUsage = true // Specific flags gitRef, _ := cmd.Flags().GetString(FlagGitRef) + gitRepo, _ := cmd.Flags().GetString(FlagGitRepo) // Debug + expEnabled checks isExperimental := false @@ -372,7 +378,7 @@ var fetchStoreTypesCmd = &cobra.Command{ if gitRef == "" { gitRef = "main" } - templates, err := readStoreTypesConfig("", gitRef, offline) + templates, err := readStoreTypesConfig("", gitRef, gitRepo, offline) if err != nil { log.Error().Err(err).Send() return err @@ -480,15 +486,26 @@ func formatStoreTypes(sTypesList *[]interface{}) (map[string]interface{}, error) return output, nil } -func getStoreTypesInternet(gitRef string) (map[string]interface{}, error) { +func getStoreTypesInternet(gitRef string, repo string) (map[string]interface{}, error) { //resp, err := http.Get("https://raw.githubusercontent.com/keyfactor/kfutil/main/store_types.json") //resp, err := http.Get("https://raw.githubusercontent.com/keyfactor/kfctl/master/storetypes/storetypes.json") - baseUrl := "https://raw.githubusercontent.com/Keyfactor/kfutil/%s/store_types.json" + baseUrl := "https://raw.githubusercontent.com/Keyfactor/%s/%s/%s" if gitRef == "" { - gitRef = "main" + gitRef = DefaultGitRef + } + if repo == "" { + repo = DefaultGitRepo + } + + var fileName string + if repo == "kfutil" { + fileName = "store_types.json" + } else { + fileName = "integration-manifest.json" } - url := fmt.Sprintf(baseUrl, gitRef) + + url := fmt.Sprintf(baseUrl, repo, gitRef, fileName) log.Debug(). Str("url", url). Msg("Getting store types from internet") @@ -513,7 +530,23 @@ func getStoreTypesInternet(gitRef string) (map[string]interface{}, error) { var result []interface{} jErr := json.Unmarshal(body, &result) if jErr != nil { - return nil, jErr + log.Warn().Err(jErr).Msg("Unable to decode JSON file, attempting to parse an integration manifest") + // Attempt to parse as an integration manifest + var manifest IntegrationManifest + log.Debug().Msg("Decoding JSON file as integration manifest") + // Reset the file pointer + + mErr := json.Unmarshal(body, &manifest) + if mErr != nil { + return nil, jErr + } + log.Debug().Msg("Decoded JSON file as integration manifest") + sTypes := manifest.About.Orchestrator.StoreTypes + output := make(map[string]interface{}) + for _, st := range sTypes { + output[st.ShortName] = st + } + return output, nil } output, sErr := formatStoreTypes(&result) if sErr != nil { @@ -525,18 +558,20 @@ func getStoreTypesInternet(gitRef string) (map[string]interface{}, error) { } -func getValidStoreTypes(fp string, gitRef string) []string { +func getValidStoreTypes(fp string, gitRef string, gitRepo string) []string { log.Debug(). Str("file", fp). Str("gitRef", gitRef). + Str("gitRepo", gitRepo). Bool("offline", offline). Msg(DebugFuncEnter) log.Debug(). Str("file", fp). Str("gitRef", gitRef). + Str("gitRepo", gitRepo). Msg("Reading store types config.") - validStoreTypes, rErr := readStoreTypesConfig(fp, gitRef, offline) + validStoreTypes, rErr := readStoreTypesConfig(fp, gitRef, gitRepo, offline) if rErr != nil { log.Error().Err(rErr).Msg("unable to read store types") return nil @@ -549,7 +584,7 @@ func getValidStoreTypes(fp string, gitRef string) []string { return validStoreTypesList } -func readStoreTypesConfig(fp, gitRef string, offline bool) (map[string]interface{}, error) { +func readStoreTypesConfig(fp, gitRef string, gitRepo string, offline bool) (map[string]interface{}, error) { log.Debug().Str("file", fp).Str("gitRef", gitRef).Msg("Entering readStoreTypesConfig") var ( @@ -560,7 +595,7 @@ func readStoreTypesConfig(fp, gitRef string, offline bool) (map[string]interface log.Debug().Msg("Reading store types config from file") } else { log.Debug().Msg("Reading store types config from internet") - sTypes, stErr = getStoreTypesInternet(gitRef) + sTypes, stErr = getStoreTypesInternet(gitRef, gitRepo) } if stErr != nil || sTypes == nil || len(sTypes) == 0 { @@ -600,11 +635,11 @@ func readStoreTypesConfig(fp, gitRef string, offline bool) (map[string]interface } func init() { - defaultGitRef := "main" offline = true // temporarily set to true as it runs before the flag is set debugFlag = false // temporarily set to false as it runs before the flag is set var gitRef string - validTypesString := strings.Join(getValidStoreTypes("", defaultGitRef), ", ") + var gitRepo string + validTypesString := strings.Join(getValidStoreTypes("", DefaultGitRef, DefaultGitRepo), ", ") offline = false //revert this so that flag is not set to true by default RootCmd.AddCommand(storeTypesCmd) @@ -618,6 +653,14 @@ func init() { "The git branch or tag to reference when pulling store-types from the internet.", ) + fetchStoreTypesCmd.Flags().StringVarP( + &gitRepo, + FlagGitRepo, + "r", + DefaultGitRepo, + "The repository to pull store-type definitions from.", + ) + // LIST command storeTypesCmd.AddCommand(storesTypesListCmd) @@ -653,6 +696,14 @@ func init() { "main", "The git branch or tag to reference when pulling store-types from the internet.", ) + storesTypeCreateCmd.Flags().StringVarP( + &gitRepo, + FlagGitRepo, + "r", + DefaultGitRepo, + "The repository to pull store-types definitions from.", + ) + storesTypeCreateCmd.Flags().BoolVarP(&createAll, "all", "a", false, "Create all store types.") // UPDATE command diff --git a/cmd/storeTypes_get.go b/cmd/storeTypes_get.go index e630d11..8635ea3 100644 --- a/cmd/storeTypes_get.go +++ b/cmd/storeTypes_get.go @@ -187,6 +187,7 @@ type StoreTypesGetOptions struct { storeTypeName string genericFormat bool gitRef string + gitRepo string storeTypeInterface interface{} outputType string outputToIntegrationManifest bool @@ -243,7 +244,7 @@ func (f *StoreTypesGetOptions) Validate() error { // Check inputs and prompt if necessary // The f.storeTypeInterface is used to pass the store type to the API if f.storeTypeID < 0 && f.storeTypeName == "" { - validStoreTypes := getValidStoreTypes("", f.gitRef) + validStoreTypes := getValidStoreTypes("", f.gitRef, DefaultGitRepo) prompt := &survey.Select{ Message: "Choose a store type:", Options: validStoreTypes, diff --git a/cmd/storesBulkOperations.go b/cmd/storesBulkOperations.go index ada8184..aa24793 100644 --- a/cmd/storesBulkOperations.go +++ b/cmd/storesBulkOperations.go @@ -77,7 +77,7 @@ func formatProperties(json *gabs.Container, reqPropertiesForStoreType []string) func serializeStoreFromTypeDef(storeTypeName string, input string) (string, error) { // check if storetypename is an integer - storeTypes, _ := readStoreTypesConfig("", "", offline) + storeTypes, _ := readStoreTypesConfig("", DefaultGitRef, DefaultGitRepo, offline) log.Debug(). Str("storeTypeName", storeTypeName). Msg("checking if storeTypeName is an integer") @@ -399,7 +399,7 @@ Store type IDs can be found by running the "store-types" command.`, validStoreTypesResp, vstErr := kfClient.ListCertificateStoreTypes() if vstErr != nil { log.Error().Err(vstErr).Msg("unable to list certificate store types") - validStoreTypes = getValidStoreTypes("", "main") + validStoreTypes = getValidStoreTypes("", DefaultGitRef, DefaultGitRepo) } else { for _, v := range *validStoreTypesResp { validStoreTypes = append(validStoreTypes, v.ShortName) diff --git a/docs/kfutil.md b/docs/kfutil.md index ed50166..f3c47a3 100644 --- a/docs/kfutil.md +++ b/docs/kfutil.md @@ -45,4 +45,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 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_completion.md b/docs/kfutil_completion.md index 580e5cd..0b6c7a8 100644 --- a/docs/kfutil_completion.md +++ b/docs/kfutil_completion.md @@ -44,4 +44,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 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_completion_bash.md b/docs/kfutil_completion_bash.md index c9c719e..deb9347 100644 --- a/docs/kfutil_completion_bash.md +++ b/docs/kfutil_completion_bash.md @@ -63,4 +63,4 @@ kfutil completion bash * [kfutil completion](kfutil_completion.md) - Generate the autocompletion script for the specified shell -###### Auto generated by spf13/cobra on 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_completion_fish.md b/docs/kfutil_completion_fish.md index 2860cc5..d61446d 100644 --- a/docs/kfutil_completion_fish.md +++ b/docs/kfutil_completion_fish.md @@ -54,4 +54,4 @@ kfutil completion fish [flags] * [kfutil completion](kfutil_completion.md) - Generate the autocompletion script for the specified shell -###### Auto generated by spf13/cobra on 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_completion_powershell.md b/docs/kfutil_completion_powershell.md index 93e007a..fd4d1cd 100644 --- a/docs/kfutil_completion_powershell.md +++ b/docs/kfutil_completion_powershell.md @@ -51,4 +51,4 @@ kfutil completion powershell [flags] * [kfutil completion](kfutil_completion.md) - Generate the autocompletion script for the specified shell -###### Auto generated by spf13/cobra on 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_completion_zsh.md b/docs/kfutil_completion_zsh.md index c2faf3a..b8a0c62 100644 --- a/docs/kfutil_completion_zsh.md +++ b/docs/kfutil_completion_zsh.md @@ -65,4 +65,4 @@ kfutil completion zsh [flags] * [kfutil completion](kfutil_completion.md) - Generate the autocompletion script for the specified shell -###### Auto generated by spf13/cobra on 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_containers.md b/docs/kfutil_containers.md index 2964e48..e86ce53 100644 --- a/docs/kfutil_containers.md +++ b/docs/kfutil_containers.md @@ -40,4 +40,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 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_containers_get.md b/docs/kfutil_containers_get.md index 042be2c..88f94f6 100644 --- a/docs/kfutil_containers_get.md +++ b/docs/kfutil_containers_get.md @@ -43,4 +43,4 @@ kfutil containers get [flags] * [kfutil containers](kfutil_containers.md) - Keyfactor certificate store container API and utilities. -###### Auto generated by spf13/cobra on 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_containers_list.md b/docs/kfutil_containers_list.md index e19825c..d00b2df 100644 --- a/docs/kfutil_containers_list.md +++ b/docs/kfutil_containers_list.md @@ -42,4 +42,4 @@ kfutil containers list [flags] * [kfutil containers](kfutil_containers.md) - Keyfactor certificate store container API and utilities. -###### Auto generated by spf13/cobra on 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_export.md b/docs/kfutil_export.md index 726264e..8407861 100644 --- a/docs/kfutil_export.md +++ b/docs/kfutil_export.md @@ -54,4 +54,4 @@ kfutil export [flags] * [kfutil](kfutil.md) - Keyfactor CLI utilities -###### Auto generated by spf13/cobra on 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_helm.md b/docs/kfutil_helm.md index 180c93b..d79a1ed 100644 --- a/docs/kfutil_helm.md +++ b/docs/kfutil_helm.md @@ -45,4 +45,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 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_helm_uo.md b/docs/kfutil_helm_uo.md index 35a8634..59eb497 100644 --- a/docs/kfutil_helm_uo.md +++ b/docs/kfutil_helm_uo.md @@ -49,4 +49,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 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_orchs_get.md b/docs/kfutil_orchs_get.md index 7c80400..72ec459 100644 --- a/docs/kfutil_orchs_get.md +++ b/docs/kfutil_orchs_get.md @@ -43,4 +43,4 @@ kfutil orchs get [flags] * [kfutil orchs](kfutil_orchs.md) - Keyfactor agents/orchestrators APIs and utilities. -###### Auto generated by spf13/cobra on 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_orchs_list.md b/docs/kfutil_orchs_list.md index 76a8639..978b1ae 100644 --- a/docs/kfutil_orchs_list.md +++ b/docs/kfutil_orchs_list.md @@ -42,4 +42,4 @@ kfutil orchs list [flags] * [kfutil orchs](kfutil_orchs.md) - Keyfactor agents/orchestrators APIs and utilities. -###### Auto generated by spf13/cobra on 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_orchs_logs.md b/docs/kfutil_orchs_logs.md index 9fa34cd..1686c2e 100644 --- a/docs/kfutil_orchs_logs.md +++ b/docs/kfutil_orchs_logs.md @@ -43,4 +43,4 @@ kfutil orchs logs [flags] * [kfutil orchs](kfutil_orchs.md) - Keyfactor agents/orchestrators APIs and utilities. -###### Auto generated by spf13/cobra on 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_orchs_reset.md b/docs/kfutil_orchs_reset.md index 81bf2d7..d4f3ffa 100644 --- a/docs/kfutil_orchs_reset.md +++ b/docs/kfutil_orchs_reset.md @@ -43,4 +43,4 @@ kfutil orchs reset [flags] * [kfutil orchs](kfutil_orchs.md) - Keyfactor agents/orchestrators APIs and utilities. -###### Auto generated by spf13/cobra on 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_pam.md b/docs/kfutil_pam.md index e4bd665..8c16fb8 100644 --- a/docs/kfutil_pam.md +++ b/docs/kfutil_pam.md @@ -47,4 +47,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 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_pam_create.md b/docs/kfutil_pam_create.md index 8a737f0..c773937 100644 --- a/docs/kfutil_pam_create.md +++ b/docs/kfutil_pam_create.md @@ -43,4 +43,4 @@ kfutil pam create [flags] * [kfutil pam](kfutil_pam.md) - Keyfactor PAM Provider APIs. -###### Auto generated by spf13/cobra on 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_pam_delete.md b/docs/kfutil_pam_delete.md index 47589bc..6e7d014 100644 --- a/docs/kfutil_pam_delete.md +++ b/docs/kfutil_pam_delete.md @@ -43,4 +43,4 @@ kfutil pam delete [flags] * [kfutil pam](kfutil_pam.md) - Keyfactor PAM Provider APIs. -###### Auto generated by spf13/cobra on 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_pam_get.md b/docs/kfutil_pam_get.md index d483dc1..a8140e7 100644 --- a/docs/kfutil_pam_get.md +++ b/docs/kfutil_pam_get.md @@ -43,4 +43,4 @@ kfutil pam get [flags] * [kfutil pam](kfutil_pam.md) - Keyfactor PAM Provider APIs. -###### Auto generated by spf13/cobra on 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_pam_list.md b/docs/kfutil_pam_list.md index 6d8f60e..ad133fd 100644 --- a/docs/kfutil_pam_list.md +++ b/docs/kfutil_pam_list.md @@ -42,4 +42,4 @@ kfutil pam list [flags] * [kfutil pam](kfutil_pam.md) - Keyfactor PAM Provider APIs. -###### Auto generated by spf13/cobra on 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_pam_types-create.md b/docs/kfutil_pam_types-create.md index b819765..4294459 100644 --- a/docs/kfutil_pam_types-create.md +++ b/docs/kfutil_pam_types-create.md @@ -50,4 +50,4 @@ kfutil pam types-create [flags] * [kfutil pam](kfutil_pam.md) - Keyfactor PAM Provider APIs. -###### Auto generated by spf13/cobra on 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_pam_types-list.md b/docs/kfutil_pam_types-list.md index a16cc21..fd3b7c8 100644 --- a/docs/kfutil_pam_types-list.md +++ b/docs/kfutil_pam_types-list.md @@ -42,4 +42,4 @@ kfutil pam types-list [flags] * [kfutil pam](kfutil_pam.md) - Keyfactor PAM Provider APIs. -###### Auto generated by spf13/cobra on 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_pam_update.md b/docs/kfutil_pam_update.md index 7f45450..fd13a7a 100644 --- a/docs/kfutil_pam_update.md +++ b/docs/kfutil_pam_update.md @@ -43,4 +43,4 @@ kfutil pam update [flags] * [kfutil pam](kfutil_pam.md) - Keyfactor PAM Provider APIs. -###### Auto generated by spf13/cobra on 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_status.md b/docs/kfutil_status.md index 913a017..697ad95 100644 --- a/docs/kfutil_status.md +++ b/docs/kfutil_status.md @@ -42,4 +42,4 @@ kfutil status [flags] * [kfutil](kfutil.md) - Keyfactor CLI utilities -###### Auto generated by spf13/cobra on 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_store-types.md b/docs/kfutil_store-types.md index 69ce108..43296ac 100644 --- a/docs/kfutil_store-types.md +++ b/docs/kfutil_store-types.md @@ -43,4 +43,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 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_store-types_create.md b/docs/kfutil_store-types_create.md index ebd5e9d..3e78704 100644 --- a/docs/kfutil_store-types_create.md +++ b/docs/kfutil_store-types_create.md @@ -19,6 +19,7 @@ kfutil store-types create [flags] -h, --help help for create -l, --list List valid store types. -n, --name string Short name of the certificate store type to get. Valid choices are: AKV, AWS-ACM, Akamai, AppGwBin, AzureApp, AzureApp2, AzureAppGw, AzureSP, AzureSP2, BIPCamera, CiscoAsa, CitrixAdc, F5-BigIQ, F5-CA-REST, F5-SL-REST, F5-WS-REST, Fortigate, GCPLoadBal, GcpCertMgr, HCVKV, HCVKVJKS, HCVKVP12, HCVKVPEM, HCVKVPFX, HCVPKI, IISU, Imperva, K8SCert, K8SCluster, K8SJKS, K8SNS, K8SPKCS12, K8SSecret, K8STLSSecr, MOST, Nmap, PaloAlto, RFDER, RFJKS, RFKDB, RFORA, RFPEM, RFPkcs12, SAMPLETYPE, Signum, VMware-NSX, WinCerMgmt, WinCert, WinSql + -r, --repo string The repository to pull store-types definitions from. (default "kfutil") ``` ### Options inherited from parent commands @@ -47,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 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_store-types_delete.md b/docs/kfutil_store-types_delete.md index e035dda..9cc5b01 100644 --- a/docs/kfutil_store-types_delete.md +++ b/docs/kfutil_store-types_delete.md @@ -46,4 +46,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 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_store-types_get.md b/docs/kfutil_store-types_get.md index ad937b7..77f68ca 100644 --- a/docs/kfutil_store-types_get.md +++ b/docs/kfutil_store-types_get.md @@ -47,4 +47,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 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_store-types_list.md b/docs/kfutil_store-types_list.md index 0cece34..d28e11a 100644 --- a/docs/kfutil_store-types_list.md +++ b/docs/kfutil_store-types_list.md @@ -42,4 +42,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 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_store-types_templates-fetch.md b/docs/kfutil_store-types_templates-fetch.md index e252262..3e81a65 100644 --- a/docs/kfutil_store-types_templates-fetch.md +++ b/docs/kfutil_store-types_templates-fetch.md @@ -15,6 +15,7 @@ kfutil store-types templates-fetch [flags] ``` -b, --git-ref string The git branch or tag to reference when pulling store-types from the internet. (default "main") -h, --help help for templates-fetch + -r, --repo string The repository to pull store-type definitions from. (default "kfutil") ``` ### Options inherited from parent commands @@ -43,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 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_stores.md b/docs/kfutil_stores.md index c9f2478..77ac0ec 100644 --- a/docs/kfutil_stores.md +++ b/docs/kfutil_stores.md @@ -44,4 +44,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 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_stores_delete.md b/docs/kfutil_stores_delete.md index c3d1924..1182516 100644 --- a/docs/kfutil_stores_delete.md +++ b/docs/kfutil_stores_delete.md @@ -45,4 +45,4 @@ kfutil stores delete [flags] * [kfutil stores](kfutil_stores.md) - Keyfactor certificate stores APIs and utilities. -###### Auto generated by spf13/cobra on 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_stores_export.md b/docs/kfutil_stores_export.md index 5b52f32..1409d25 100644 --- a/docs/kfutil_stores_export.md +++ b/docs/kfutil_stores_export.md @@ -46,4 +46,4 @@ kfutil stores export [flags] * [kfutil stores](kfutil_stores.md) - Keyfactor certificate stores APIs and utilities. -###### Auto generated by spf13/cobra on 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_stores_get.md b/docs/kfutil_stores_get.md index 7277fa3..b83e0f5 100644 --- a/docs/kfutil_stores_get.md +++ b/docs/kfutil_stores_get.md @@ -43,4 +43,4 @@ kfutil stores get [flags] * [kfutil stores](kfutil_stores.md) - Keyfactor certificate stores APIs and utilities. -###### Auto generated by spf13/cobra on 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_stores_import.md b/docs/kfutil_stores_import.md index 4317133..a4d0d4f 100644 --- a/docs/kfutil_stores_import.md +++ b/docs/kfutil_stores_import.md @@ -40,4 +40,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 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_stores_import_csv.md b/docs/kfutil_stores_import_csv.md index 6cf3532..7884fe5 100644 --- a/docs/kfutil_stores_import_csv.md +++ b/docs/kfutil_stores_import_csv.md @@ -50,4 +50,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 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_stores_inventory.md b/docs/kfutil_stores_inventory.md index 395a43b..03221b0 100644 --- a/docs/kfutil_stores_inventory.md +++ b/docs/kfutil_stores_inventory.md @@ -41,4 +41,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 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_stores_inventory_add.md b/docs/kfutil_stores_inventory_add.md index f8dd194..1d673c8 100644 --- a/docs/kfutil_stores_inventory_add.md +++ b/docs/kfutil_stores_inventory_add.md @@ -56,4 +56,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 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_stores_inventory_remove.md b/docs/kfutil_stores_inventory_remove.md index b1ebf34..2a35110 100644 --- a/docs/kfutil_stores_inventory_remove.md +++ b/docs/kfutil_stores_inventory_remove.md @@ -52,4 +52,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 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_stores_inventory_show.md b/docs/kfutil_stores_inventory_show.md index 25eb963..0aceca7 100644 --- a/docs/kfutil_stores_inventory_show.md +++ b/docs/kfutil_stores_inventory_show.md @@ -46,4 +46,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 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_stores_list.md b/docs/kfutil_stores_list.md index 84bf4f1..199cd04 100644 --- a/docs/kfutil_stores_list.md +++ b/docs/kfutil_stores_list.md @@ -42,4 +42,4 @@ kfutil stores list [flags] * [kfutil stores](kfutil_stores.md) - Keyfactor certificate stores APIs and utilities. -###### Auto generated by spf13/cobra on 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 diff --git a/docs/kfutil_version.md b/docs/kfutil_version.md index a6ae00b..b118dbe 100644 --- a/docs/kfutil_version.md +++ b/docs/kfutil_version.md @@ -42,4 +42,4 @@ kfutil version [flags] * [kfutil](kfutil.md) - Keyfactor CLI utilities -###### Auto generated by spf13/cobra on 20-Nov-2024 +###### Auto generated by spf13/cobra on 9-Dec-2024 From 4db328749d1b6e7143761946ca1a7e9446aa182b Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Mon, 9 Dec 2024 08:27:14 -0800 Subject: [PATCH 37/49] chore(docs): Update `CHANGELOG.md` Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 680b81c..7e2ca3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,15 @@ ## Features +### CLI - `auth`: Added support for authenticating to Keyfactor Command using a oAuth2 client credentials or access token. +### Store Types + +- `store-types create`: Added support for creating store types from a local file in `integration-manifest.json` format. +- `store-types create`: Added support for creating store types specified by a Keyfactor repo name and optional branch + ref. + ## Fixes - `cli`: Fixed an issue where the CLI would sometimes terminate with no error messages when calling the From d5f40ff1467a62fde2483cb7240e7c3adfbbc636 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Mon, 9 Dec 2024 10:06:32 -0800 Subject: [PATCH 38/49] fix(stores): `import csv` converts all integer properties to string as there is no int type in Command for properties. Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- cmd/storesBulkOperations.go | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/cmd/storesBulkOperations.go b/cmd/storesBulkOperations.go index aa24793..4ef6543 100644 --- a/cmd/storesBulkOperations.go +++ b/cmd/storesBulkOperations.go @@ -50,26 +50,27 @@ 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 + // 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) + json.Set("", "Properties", reqProp) // Correctly add the required property } - // iterate through properties and convert any "int" values to strings + // 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 { + if intValue, 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) + asStr := strconv.Itoa(intValue) + // Use gabs' Set method to update the property value + json.Set(asStr, "Properties", name) } } return json @@ -132,7 +133,11 @@ var storesCreateFromCSVCmd = &cobra.Command{ informDebug(debugFlag) // Authenticate - kfClient, _ := initClient(false) + kfClient, cErr := initClient(false) + if cErr != nil { + log.Error().Err(cErr).Msg("Error initializing client") + return cErr + } // CLI Logic log.Info().Msg("Importing certificate stores") @@ -683,6 +688,10 @@ var storesExportCmd = &cobra.Command{ log.Debug().Str("name", name). Interface("prop", prop). Msg("adding to properties CSV data") + //check if property is an int + if _, isInt := prop.(int); isInt { + prop = strconv.Itoa(prop.(int)) + } if name != "ServerUsername" && name != "ServerPassword" { // Don't add ServerUsername and ServerPassword to properties as they can't be exported via API csvData[store.Id]["Properties."+name] = prop } @@ -899,6 +908,13 @@ func unmarshalPropertiesString(properties string) map[string]interface{} { // Then, iterate through each key:value pair and serialize into map[string]string newMap := make(map[string]interface{}) for key, value := range tempInterface.(map[string]interface{}) { + // check if value is an int + if _, isInt := value.(int); isInt { + log.Debug(). + Str("key", key). + Int("value", value.(int)).Msg("converting int to string as Command does not accept int") + value = strconv.Itoa(value.(int)) + } newMap[key] = value } return newMap From 9eeb2389935bc8b6ec71742ef454296121dc5774 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Mon, 9 Dec 2024 10:08:35 -0800 Subject: [PATCH 39/49] chore(docs): Update `CHANGELOG.md` Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e2ca3a..7a632b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,9 +13,15 @@ ## Fixes -- `cli`: Fixed an issue where the CLI would sometimes terminate with no error messages when calling the +### CLI + +- Fixed an issue where the CLI would sometimes terminate with no error messages when calling the `keyfactor-go-client-sdk` +### Stores + +- `import csv`: Converts all `int` properties to `string` since Keyfactor Command does not support `int` properties. + ## Chores - `deps`: Bump `go` version to `1.23`. From 20fcdf5ccfd1c6bad4b58e06948813ddb12269e2 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Mon, 9 Dec 2024 10:23:52 -0800 Subject: [PATCH 40/49] fix(stores): `import csv` return useful error message when invalid store-type name or ID are passed rather than panic. Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- cmd/storesBulkOperations.go | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/cmd/storesBulkOperations.go b/cmd/storesBulkOperations.go index 4ef6543..54a7d43 100644 --- a/cmd/storesBulkOperations.go +++ b/cmd/storesBulkOperations.go @@ -213,7 +213,10 @@ var storesCreateFromCSVCmd = &cobra.Command{ // check for minimum necessary required fields for creating certificate stores log.Info().Msgf("Checking for minimum required fields for creating certificate stores") - intID, reqPropertiesForStoreType := getRequiredProperties(st, *kfClient) + intID, reqPropertiesForStoreType, pErr := getRequiredProperties(st, *kfClient) + if pErr != nil { + return pErr + } // if not present in header, throw error. headerRow := inFile[0] @@ -863,13 +866,17 @@ func getHeadersForStoreType(id interface{}, kfClient api.Client) (int64, string, return intId, shortName, csvHeaders } -func getRequiredProperties(id interface{}, kfClient api.Client) (int64, []string) { +func getRequiredProperties(id interface{}, kfClient api.Client) (int64, []string, error) { storeType, err := kfClient.GetCertificateStoreType(id) if err != nil { - log.Printf("Error: %s", err) - fmt.Printf("Error: %s\n", err) - panic("error retrieving store type") + log.Error(). + Interface("id", id). + Err(err).Msg("Error retrieving store type from Keyfactor Command") + return 0, nil, fmt.Errorf( + "error retrieving store type '%s' from Keyfactor Command, please ensure you're using `ShortName` or `Id`", + id, + ) } output, jErr := json.Marshal(storeType) @@ -895,7 +902,7 @@ func getRequiredProperties(id interface{}, kfClient api.Client) (int64, []string } intId, _ := jsonParsedObj.S("StoreType").Data().(json.Number).Int64() - return intId, reqProps + return intId, reqProps, nil } func unmarshalPropertiesString(properties string) map[string]interface{} { From 1300d27876ef9d8a83028e4e1082e4e0ec6c89f0 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Mon, 9 Dec 2024 10:24:54 -0800 Subject: [PATCH 41/49] chore(docs): Update `CHANGELOG.md` Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a632b2..707cf29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Features ### CLI + - `auth`: Added support for authenticating to Keyfactor Command using a oAuth2 client credentials or access token. ### Store Types @@ -21,6 +22,8 @@ ### Stores - `import csv`: Converts all `int` properties to `string` since Keyfactor Command does not support `int` properties. +- `import csv`: Returns useful error message when invalid `store-type-name` or `store-type-id` are passed rather than + panic. ## Chores From 66eb370f21525609e1428bd6e1f4813d9feb7df5 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Mon, 9 Dec 2024 10:29:06 -0800 Subject: [PATCH 42/49] chore: silence usage on getRequiredProperties errors Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- cmd/storesBulkOperations.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/storesBulkOperations.go b/cmd/storesBulkOperations.go index 54a7d43..45d61fa 100644 --- a/cmd/storesBulkOperations.go +++ b/cmd/storesBulkOperations.go @@ -215,6 +215,7 @@ var storesCreateFromCSVCmd = &cobra.Command{ log.Info().Msgf("Checking for minimum required fields for creating certificate stores") intID, reqPropertiesForStoreType, pErr := getRequiredProperties(st, *kfClient) if pErr != nil { + cmd.SilenceUsage = true return pErr } From d944f373eb22b5d3753fd3d640f2097ed8fc9dd3 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Tue, 10 Dec 2024 12:34:00 -0800 Subject: [PATCH 43/49] fix(auth): `oauth2` client now correctly sets `scopes` and `audience` fields. chore(deps): Bump `Keyfactor/keyfactor-auth-client-go` to `v1.1.1-rc.0`. chore(deps): Bump `Keyfactor/keyfactor-go-client-sdk/v2` to `v2.0.0`. chore(deps): Bump `Keyfactor/keyfactor-go-client/v3` to `v3.0.0`. chore(deps): Bump `creack/pty` to `v1.1.24`. chore(deps): Bump `stretchr/testify` to `v1.10.0`. chore(deps): Bump `x/crypto` to `v0.30.0`. chore(deps): Bump `x/term` to `v0.27.0`. chore(deps): Bump `x/sys` to `v0.28.0`. chore(deps): Bump `x/term` to `v0.27.0`. chore(deps): Bump `x/text` to `v0.21.0`. chore(deps): Bump `AzureAD/microsoft-authentication-library-for-go` to `v1.3.2`. Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- CHANGELOG.md | 9 +++++++-- go.mod | 22 +++++++++++----------- go.sum | 44 ++++++++++++++++++++++---------------------- 3 files changed, 40 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 707cf29..8d15cf5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,10 +29,15 @@ - `deps`: Bump `go` version to `1.23`. - `deps`: Bump `azure-sdk-for-go/sdk/azidentity` version to `v1.8.0`. +- `deps`: Bump `AzureAD/microsoft-authentication-library-for-go` to `v1.3.2`. - `deps`: Bump `keyfactor-go-client-sdk` version to `v2.0.0`. - `deps`: Bump `keyfactor-go-client` version to `v3.0.0`. -- `deps`: Bump `golang.org/x/crypto` version to `v0.27.0`. -- `deps`: Bump `golang.org/x/term` version to `v0.24.0`. +- `deps`: Bump `creack/pty` to `v1.1.24`. +- `deps`: Bump `stretchr/testify` to `v1.10.0`. +- `deps`: Bump `x/crypto` to `v0.30.0`. +- `deps`: Bump `x/term` to `v0.27.0`. +- `deps`: Bump `x/sys` to `v0.28.0`. +- `deps`: Bump `x/text` to `v0.21.0`. # v1.5.1 diff --git a/go.mod b/go.mod index 8a35b6a..e0f9465 100644 --- a/go.mod +++ b/go.mod @@ -9,11 +9,11 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 github.com/Jeffail/gabs v1.4.0 - github.com/Keyfactor/keyfactor-auth-client-go v1.1.0-rc.8 - github.com/Keyfactor/keyfactor-go-client-sdk/v2 v2.0.0-rc.3 - github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0-rc.11 + github.com/Keyfactor/keyfactor-auth-client-go v1.1.1-rc.0 + github.com/Keyfactor/keyfactor-go-client-sdk/v2 v2.0.0 + github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0 github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 - github.com/creack/pty v1.1.23 + github.com/creack/pty v1.1.24 github.com/google/go-cmp v0.6.0 github.com/google/uuid v1.6.0 github.com/hinshun/vt10x v0.0.0-20220301184237-5011da428d02 @@ -21,9 +21,9 @@ require ( github.com/rs/zerolog v1.33.0 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 - github.com/stretchr/testify v1.9.0 - golang.org/x/crypto v0.28.0 - golang.org/x/term v0.25.0 + github.com/stretchr/testify v1.10.0 + golang.org/x/crypto v0.30.0 + golang.org/x/term v0.27.0 gopkg.in/yaml.v3 v3.0.1 //github.com/google/go-cmp/cmp v0.5.9 ) @@ -32,7 +32,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.3.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.0 // indirect - github.com/AzureAD/microsoft-authentication-library-for-go v1.3.1 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.3.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 @@ -50,9 +50,9 @@ require ( github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/spbsoluble/go-pkcs12 v0.3.3 // indirect go.mozilla.org/pkcs7 v0.9.0 // indirect - golang.org/x/net v0.30.0 // indirect + golang.org/x/net v0.32.0 // indirect golang.org/x/oauth2 v0.24.0 // indirect - golang.org/x/sys v0.26.0 // indirect - golang.org/x/text v0.19.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index 6f831b4..8de6d9d 100644 --- a/go.sum +++ b/go.sum @@ -14,16 +14,16 @@ github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.0 h1:eXnN9 github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.0/go.mod h1:XIpam8wumeZ5rVMuhdDQLMfIPDf1WO3IzrCRO3e3e3o= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= -github.com/AzureAD/microsoft-authentication-library-for-go v1.3.1 h1:gUDtaZk8heteyfdmv+pcfHvhR9llnh7c7GMwZ8RVG04= -github.com/AzureAD/microsoft-authentication-library-for-go v1.3.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2 h1:kYRSnvJju5gYVyhkij+RTJ/VR6QIUaCfWeaFm2ycsjQ= +github.com/AzureAD/microsoft-authentication-library-for-go v1.3.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.1.0-rc.8 h1:JtA7UwqCSsqBUc0shlEBk+g2xNMorxwQHtknCY7hcUg= -github.com/Keyfactor/keyfactor-auth-client-go v1.1.0-rc.8/go.mod h1:dUIVnqWpPiYkGqKMYQi6Z98fqzQdkZ1KHvJpCoSLQ2s= -github.com/Keyfactor/keyfactor-go-client-sdk/v2 v2.0.0-rc.3 h1:5qeMOqWFKMefxVXIVoQuWcDYP5vhlCSdIwDey2PBAd8= -github.com/Keyfactor/keyfactor-go-client-sdk/v2 v2.0.0-rc.3/go.mod h1:11WXGG9VVKSV0EPku1IswjHbGGpzHDKqD4pe2vD7vas= -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/Keyfactor/keyfactor-auth-client-go v1.1.1-rc.0 h1:/N/7pBj/oTUM1cYga2NvKyA4q6nfE0acciJHZqKC9Ug= +github.com/Keyfactor/keyfactor-auth-client-go v1.1.1-rc.0/go.mod h1:yw92P9gSYVEyWkiUAJFsb7hjhXa8slN1+yTQgjSgovM= +github.com/Keyfactor/keyfactor-go-client-sdk/v2 v2.0.0 h1:ehk5crxEGVBwkC8yXsoQXcyITTDlgbxMEkANrl1dA2Q= +github.com/Keyfactor/keyfactor-go-client-sdk/v2 v2.0.0/go.mod h1:11WXGG9VVKSV0EPku1IswjHbGGpzHDKqD4pe2vD7vas= +github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0 h1:yMChWRnnxmcgLt6kEQ3FZfteps05v/qot5KXLXxa6so= +github.com/Keyfactor/keyfactor-go-client/v3 v3.0.0/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/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -32,8 +32,8 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= -github.com/creack/pty v1.1.23 h1:4M6+isWdcStXEf15G/RbrMPOQj1dZ7HPZCGwE4kOeP0= -github.com/creack/pty v1.1.23/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= +github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= +github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= 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= @@ -107,21 +107,21 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An 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/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.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.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.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= -golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= +golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY= +golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= -golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= +golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= +golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -141,18 +141,18 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= -golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= -golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= +golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= -golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= From ee1b63e5e88608fa6b985279b2d9d45af54c89a2 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Tue, 10 Dec 2024 14:56:58 -0800 Subject: [PATCH 44/49] feat(logout): Add verbose logging for `logout` sub cli. Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- cmd/logout.go | 144 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 129 insertions(+), 15 deletions(-) diff --git a/cmd/logout.go b/cmd/logout.go index 21c9ec3..ff56259 100644 --- a/cmd/logout.go +++ b/cmd/logout.go @@ -16,9 +16,12 @@ package cmd import ( "fmt" - "log" + "io" + stdlog "log" "os" + "github.com/Keyfactor/keyfactor-auth-client-go/auth_providers" + "github.com/rs/zerolog/log" "github.com/spf13/cobra" ) @@ -27,29 +30,140 @@ var logoutCmd = &cobra.Command{ Use: "logout", Short: "Removes the credentials file '$HOME/.keyfactor/command_config.json'.", Long: `Removes the credentials file '$HOME/.keyfactor/command_config.json'.`, - 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") - - debugModeEnabled := checkDebug(debugFlag) - log.Println("Debug mode enabled: ", debugModeEnabled) - err := os.Remove(fmt.Sprintf("%s/.keyfactor/%s", os.Getenv("HOME"), DefaultConfigFileName)) + RunE: func(cmd *cobra.Command, args []string) error { + log.Info().Msg("Running logout command") + cmd.SilenceUsage = true + // expEnabled checks + isExperimental := false + debugErr := warnExperimentalFeature(expEnabled, isExperimental) + if debugErr != nil { + return debugErr + } + stdlog.SetOutput(io.Discard) + informDebug(debugFlag) + + logGlobals() + + var configFilePath string + if configFile == "" { + // check if environment variables for config file is set + if os.Getenv(auth_providers.EnvKeyfactorConfigFile) != "" { + configFilePath = os.Getenv(auth_providers.EnvKeyfactorConfigFile) + } else { + userHomeDir, err := os.UserHomeDir() + if err != nil { + userHomeDir, err = os.Getwd() + if err != nil { + userHomeDir = "." + } + } + configFilePath = fmt.Sprintf("%s/%s", userHomeDir, auth_providers.DefaultConfigFilePath) + } + } else { + configFilePath = configFile + } + + // Remove environment variables + log.Info().Msg("Running logout command for environment variables") + envLogout() + + log.Info(). + Str("configFilePath", configFilePath). + Msg("Attempting to removing config file") + err := os.Remove(configFilePath) if err != nil { if os.IsNotExist(err) { - fmt.Println("Config file does not exist.") - fmt.Println("Logged out successfully!") - return + log.Error(). + Err(err). + Msg("Config file does not exist, unable to logout.") + fmt.Println("Config file does not exist, unable to logout.") + return err } + log.Error(). + Err(err). + Msg("unable to remove config file, logout failed") fmt.Println("Error removing config file: ", err) - //log.Fatal("[ERROR] removing config file: ", err) + return err } + log.Info(). + Str("configFilePath", configFilePath). + Msg("Config file removed successfully") fmt.Println("Logged out successfully!") + return nil }, } +func envLogout() { + log.Debug().Msg("Running logout command for environment variables") + + log.Debug().Msg("Unsetting base environment variables") + + log.Trace().Str("EnvKeyfactorHostName", auth_providers.EnvKeyfactorHostName).Msg("Unsetting") + os.Unsetenv(auth_providers.EnvKeyfactorHostName) + + log.Trace().Str("EnvKeyfactorPort", auth_providers.EnvKeyfactorPort).Msg("Unsetting") + os.Unsetenv(auth_providers.EnvKeyfactorPort) + + log.Trace().Str("EnvKeyfactorAPIPath", auth_providers.EnvKeyfactorAPIPath).Msg("Unsetting") + os.Unsetenv(auth_providers.EnvKeyfactorAPIPath) + + log.Trace().Str("EnvAuthCACert", auth_providers.EnvAuthCACert).Msg("Unsetting") + os.Unsetenv(auth_providers.EnvAuthCACert) + + log.Trace().Str("EnvKeyfactorSkipVerify", auth_providers.EnvKeyfactorSkipVerify).Msg("Unsetting") + os.Unsetenv(auth_providers.EnvKeyfactorSkipVerify) + + log.Trace().Str("EnvKeyfactorClientTimeout", auth_providers.EnvKeyfactorClientTimeout).Msg("Unsetting") + os.Unsetenv(auth_providers.EnvKeyfactorClientTimeout) + + log.Debug().Msg("Unsetting kfutil environment variables") + log.Trace().Str("EnvKeyfactorAuthProfile", auth_providers.EnvKeyfactorAuthProfile).Msg("Unsetting") + os.Unsetenv(auth_providers.EnvKeyfactorAuthProfile) + + log.Trace().Str("EnvKeyfactorConfigFile", auth_providers.EnvKeyfactorConfigFile).Msg("Unsetting") + os.Unsetenv(auth_providers.EnvKeyfactorConfigFile) + + log.Debug().Msg("Unsetting command basic auth environment variables") + log.Trace().Str("EnvKeyfactorUsername", auth_providers.EnvKeyfactorUsername).Msg("Unsetting") + os.Unsetenv(auth_providers.EnvKeyfactorUsername) + + log.Trace().Str("EnvKeyfactorPassword", auth_providers.EnvKeyfactorPassword).Msg("Unsetting") + os.Unsetenv(auth_providers.EnvKeyfactorPassword) + + log.Trace().Str("EnvKeyfactorDomain", auth_providers.EnvKeyfactorDomain).Msg("Unsetting") + os.Unsetenv(auth_providers.EnvKeyfactorDomain) + + log.Debug().Msg("Unsetting command oauth2 environment variables") + log.Trace().Str("EnvKeyfactorClientID", auth_providers.EnvKeyfactorClientID).Msg("Unsetting") + os.Unsetenv(auth_providers.EnvKeyfactorClientID) + + log.Trace().Str("EnvKeyfactorClientSecret", auth_providers.EnvKeyfactorClientSecret).Msg("Unsetting") + os.Unsetenv(auth_providers.EnvKeyfactorClientSecret) + + log.Trace().Str("EnvKeyfactorAccessToken", auth_providers.EnvKeyfactorAccessToken).Msg("Unsetting") + os.Unsetenv(auth_providers.EnvKeyfactorAccessToken) + + log.Trace().Str("EnvKeyfactorAuthTokenURL", auth_providers.EnvKeyfactorAuthTokenURL).Msg("Unsetting") + os.Unsetenv(auth_providers.EnvKeyfactorAuthTokenURL) + + log.Trace().Str("EnvKeyfactorAuthScopes", auth_providers.EnvKeyfactorAuthScopes).Msg("Unsetting") + os.Unsetenv(auth_providers.EnvKeyfactorAuthScopes) + + log.Trace().Str("EnvKeyfactorAuthAudience", auth_providers.EnvKeyfactorAuthAudience).Msg("Unsetting") + os.Unsetenv(auth_providers.EnvKeyfactorAuthAudience) + + log.Debug().Msg("Unsetting command azure environment variables") + log.Trace().Str("EnvKeyfactorAuthProvider", auth_providers.EnvKeyfactorAuthProvider).Msg("Unsetting") + os.Unsetenv(auth_providers.EnvKeyfactorAuthProvider) + + log.Trace().Str("EnvAzureSecretName", auth_providers.EnvAzureSecretName).Msg("Unsetting") + os.Unsetenv(auth_providers.EnvAzureSecretName) + + log.Trace().Str("EnvAzureVaultName", auth_providers.EnvAzureVaultName).Msg("Unsetting") + os.Unsetenv(auth_providers.EnvAzureVaultName) + +} + func init() { RootCmd.AddCommand(logoutCmd) } From 282f69a3d669db46534813d42f67176f01068b1f Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Tue, 10 Dec 2024 14:59:53 -0800 Subject: [PATCH 45/49] chore(logout): Update CLI docs verbiage to call out env unset behavior. Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- cmd/logout.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/logout.go b/cmd/logout.go index ff56259..ef7b24c 100644 --- a/cmd/logout.go +++ b/cmd/logout.go @@ -28,8 +28,8 @@ import ( // logoutCmd represents the logout command var logoutCmd = &cobra.Command{ Use: "logout", - Short: "Removes the credentials file '$HOME/.keyfactor/command_config.json'.", - Long: `Removes the credentials file '$HOME/.keyfactor/command_config.json'.`, + Short: "Unsets environment variables and removes the stored credentials file.", + Long: `Unsets environment variables and removes the stored credentials file.`, RunE: func(cmd *cobra.Command, args []string) error { log.Info().Msg("Running logout command") cmd.SilenceUsage = true @@ -75,7 +75,7 @@ var logoutCmd = &cobra.Command{ if os.IsNotExist(err) { log.Error(). Err(err). - Msg("Config file does not exist, unable to logout.") + Msg("config file does not exist, unable to logout") fmt.Println("Config file does not exist, unable to logout.") return err } From f2afc79b50bb697e5b1fca754a5626cfa5da0d09 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Wed, 11 Dec 2024 11:02:12 -0800 Subject: [PATCH 46/49] feat(logout): Add logout support for `profile` and `config-file` flags. feat(logout): Add `are you sure` prompts to `logout`. Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- CHANGELOG.md | 2 + cmd/login.go | 23 ++++++-- cmd/logout.go | 160 ++++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 162 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d15cf5..d74b894 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ ### CLI - `auth`: Added support for authenticating to Keyfactor Command using a oAuth2 client credentials or access token. +- `logout`: Added support for logging out of specific `profile` and `config-file`. +- `logout`: Added `yes|no` prompt for logout actions, which can be skipped by using the `--no-prompt` flag. ### Store Types diff --git a/cmd/login.go b/cmd/login.go index b59a6ee..eea4638 100644 --- a/cmd/login.go +++ b/cmd/login.go @@ -327,6 +327,17 @@ func getDomainFromUsername(username string) string { return "" } +func promptForInteractiveYesNo(parameterName string) bool { + var input string + fmt.Printf("%s [y/n]: \n", parameterName) + _, err := fmt.Scanln(&input) + _ = handleInteractiveError(err, parameterName) + if strings.ToLower(input) == "y" || strings.ToLower(input) == "yes" { + return true + } + return false +} + func promptForInteractiveParameter(parameterName string, defaultValue string) string { var input string fmt.Printf("Enter %s [%s]: \n", parameterName, defaultValue) @@ -559,7 +570,7 @@ func authInteractive( } func prepHomeDir() (string, error) { - log.Debug().Msg("prepHomeDir() called") + log.Debug().Msg(fmt.Sprintf("%s prepHomeDir()", DebugFuncEnter)) // Set up home directory config userHomeDir, hErr := os.UserHomeDir() @@ -573,17 +584,21 @@ func prepHomeDir() (string, error) { } else { userHomeDir = fmt.Sprintf("%s/.keyfactor", userHomeDir) } - //log.Println("[DEBUG] Configuration directory: ", userHomeDir) + log.Debug().Str("userHomeDir", userHomeDir).Msg("Configuration directory") _, err := os.Stat(userHomeDir) if os.IsNotExist(err) { errDir := os.MkdirAll(userHomeDir, 0700) if errDir != nil { - fmt.Println("Unable to create login config file. ", errDir) - log.Printf("[ERROR] creating directory: %s", errDir) + outputError(fmt.Errorf("error creating home directory: %v", errDir), false, outputFormat) + log.Error().Err(errDir) + log.Debug().Msg(fmt.Sprintf("%s prepHomeDir() returning", DebugFuncExit)) return userHomeDir, errDir } } + log.Debug(). + Str("userHomeDir", userHomeDir). + Msg(fmt.Sprintf("%s prepHomeDir() returning", DebugFuncExit)) return userHomeDir, hErr } diff --git a/cmd/logout.go b/cmd/logout.go index ef7b24c..39e8f56 100644 --- a/cmd/logout.go +++ b/cmd/logout.go @@ -63,37 +63,95 @@ var logoutCmd = &cobra.Command{ configFilePath = configFile } - // Remove environment variables log.Info().Msg("Running logout command for environment variables") envLogout() - log.Info(). - Str("configFilePath", configFilePath). - Msg("Attempting to removing config file") - err := os.Remove(configFilePath) - if err != nil { - if os.IsNotExist(err) { + if profile != "" { + pErr := logoutProfile(profile, configFilePath) + if pErr != nil { log.Error(). - Err(err). - Msg("config file does not exist, unable to logout") - fmt.Println("Config file does not exist, unable to logout.") - return err + Err(pErr). + Str("profile", profile). + Msg("unable to logout profile") + return pErr } + fmt.Printf( + "Logged out successfully, removed profile '%s' from config file '%s'.", + profile, + configFilePath, + ) + return nil + } + + logoutFileErr := logoutFile(configFilePath) + if logoutFileErr != nil { log.Error(). - Err(err). - Msg("unable to remove config file, logout failed") - fmt.Println("Error removing config file: ", err) - return err + Err(logoutFileErr). + Str("configFilePath", configFilePath). + Msg("unable to logout") + return logoutFileErr } - log.Info(). - Str("configFilePath", configFilePath). - Msg("Config file removed successfully") - fmt.Println("Logged out successfully!") return nil }, } +// logoutFile removes the config file +func logoutFile(f string) error { + log.Info(). + Str("configFilePath", f). + Msg("Running logout command for config file") + + var performLogout bool + if !noPrompt { + performLogout = promptForInteractiveYesNo( + fmt.Sprintf( + "Are you sure you want to remove the config file '%s'?", + f, + ), + ) + if !performLogout { + log.Info().Msg("Logout file cancelled") + fmt.Println(fmt.Sprintf("Logout file '%s' cancelled.", f)) + return nil + } + } + + log.Debug(). + Str("configFilePath", f). + Msg("Removing config file") + err := os.Remove(f) + + if err != nil { + if os.IsNotExist(err) { + log.Error(). + Err(err). + Msg("config file does not exist, unable to logout") + return err + } + log.Error(). + Err(err). + Msg("unable to remove config file, logout failed") + return err + } + log.Info(). + Str("configFilePath", f). + Msg("Config file removed successfully") + fmt.Println(fmt.Sprintf("Logged out successfully, removed config file '%s'", f)) + return nil +} + +// envLogout unsets environment variables func envLogout() { + + if !noPrompt { + performLogout := promptForInteractiveYesNo("Are you sure you want to unset environment variables?") + if !performLogout { + log.Info().Msg("Logout environment variables cancelled") + fmt.Println("Logout environment variables cancelled.") + return + } + } + log.Debug().Msg("Running logout command for environment variables") log.Debug().Msg("Unsetting base environment variables") @@ -164,6 +222,70 @@ func envLogout() { } +// logoutProfile removes the profile from the config file +func logoutProfile(p string, f string) error { + log.Info(). + Str("profile", p). + Str("configFilePath", f). + Msg("Running logout command for profile") + + var performLogout bool + if !noPrompt { + performLogout = promptForInteractiveYesNo( + fmt.Sprintf( + "Are you sure you want to remove profile '%s' from '%s?", p, f, + ), + ) + if !performLogout { + log.Info().Msg("Logout profile cancelled") + fmt.Println(fmt.Sprintf("Logout profile '%s' in '%s' cancelled.", p, f)) + return nil + } + } + + log.Debug(). + Str("configFilePath", f). + Msg("Reading config file") + config, err := auth_providers.ReadConfigFromJSON(f) + if err != nil { + log.Error(). + Err(err). + Str("configFilePath", f). + Str("profile", p). + Msg("unable to read config file, logout failed") + return err + } else if config == nil { + log.Error(). + Str("configFilePath", f). + Str("profile", p). + Msg("config file is empty, unable to logout") + return fmt.Errorf("config file is empty, unable to logout profile '%s'", p) + } + + // check if profile exists + if _, ok := config.Servers[p]; !ok { + log.Error(). + Str("profile", p). + Msg("profile does not exist, unable to logout") + return fmt.Errorf("profile '%s' does not exist, unable to logout", p) + } + delete(config.Servers, p) + wErr := auth_providers.WriteConfigToJSON(f, config) + if wErr != nil { + log.Error(). + Err(wErr). + Str("configFilePath", f). + Str("profile", p). + Msg("unable to write config file, logout failed") + return wErr + } + log.Info(). + Str("configFilePath", f). + Str("profile", p). + Msg("Profile removed successfully") + return nil +} + func init() { RootCmd.AddCommand(logoutCmd) } From 0c2390430c16528f0da4b08fe527dc7789859505 Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Wed, 11 Dec 2024 11:07:39 -0800 Subject: [PATCH 47/49] fix(logout): Remove `envLogout` as it's ineffective. Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- cmd/logout.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/logout.go b/cmd/logout.go index 39e8f56..f203824 100644 --- a/cmd/logout.go +++ b/cmd/logout.go @@ -63,8 +63,8 @@ var logoutCmd = &cobra.Command{ configFilePath = configFile } - log.Info().Msg("Running logout command for environment variables") - envLogout() + //log.Info().Msg("Running logout command for environment variables") + //envLogout() if profile != "" { pErr := logoutProfile(profile, configFilePath) From b3e18af27cca15d7fe636dbb1fd3482afcc4b18a Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Wed, 11 Dec 2024 13:52:40 -0800 Subject: [PATCH 48/49] fix(stores): Return errors encountered during initClient Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- cmd/root.go | 2 +- cmd/stores.go | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 18e1daf..32d7cc5 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -601,7 +601,7 @@ func initClient(saveConfig bool) (*api.Client, error) { Err(envCfgErr). Msg("unable to authenticate to Keyfactor Command") log.Debug().Msg("return: initClient()") - return nil, fmt.Errorf("unable to authenticate to Keyfactor Command") + return nil, cfgErr } // initGenClient initializes the SDK Command API client diff --git a/cmd/stores.go b/cmd/stores.go index 9a0c19a..c6951ab 100644 --- a/cmd/stores.go +++ b/cmd/stores.go @@ -51,7 +51,11 @@ var storesListCmd = &cobra.Command{ informDebug(debugFlag) // Authenticate - kfClient, _ := initClient(false) + kfClient, cErr := initClient(false) + if cErr != nil { + log.Error().Err(cErr).Send() + return cErr + } // CLI Logic params := make(map[string]interface{}) From 0059b2d9287fd7fb620f06f42a0b9f59da878a0e Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Thu, 12 Dec 2024 06:57:09 -0800 Subject: [PATCH 49/49] feat(cli): Add global flag `--skip-tls-verify` Signed-off-by: spbsoluble <1661003+spbsoluble@users.noreply.github.com> --- cmd/helpers.go | 8 ++++++++ cmd/root.go | 15 ++++++++++++++- cmd/stores.go | 1 + 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/cmd/helpers.go b/cmd/helpers.go index 743eba8..52e0cdb 100644 --- a/cmd/helpers.go +++ b/cmd/helpers.go @@ -333,11 +333,19 @@ func outputError(err error, isFatal bool, format string) { } func outputResult(result interface{}, format string) { + log.Debug(). + Interface("result", result). + Str("format", format). + Msg(fmt.Sprintf("%s outputResult", DebugFuncEnter)) if format == "json" { fmt.Println(result) } else { fmt.Println(fmt.Sprintf("%s", result)) } + log.Debug(). + Interface("result", result). + Str("format", format). + Msg(fmt.Sprintf("%s outputResult", DebugFuncExit)) } func readCSVHeader(filename string) ([]string, error) { diff --git a/cmd/root.go b/cmd/root.go index 32d7cc5..ab6942d 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -40,6 +40,7 @@ var ( noPrompt bool expEnabled bool debugFlag bool + skipVerifyFlag bool kfcUsername string kfcHostName string kfcPassword string @@ -112,6 +113,10 @@ func getServerConfigFromFile(configFile string, profile string) (*auth_providers return nil, fmt.Errorf("invalid profile: %s", profile) } + if skipVerifyFlag { + serverConfig.SkipTLSVerify = true + } + log.Debug().Msg("return: getServerConfigFromFile()") return &serverConfig, nil } @@ -137,7 +142,9 @@ func getServerConfigFromEnv() (*auth_providers.Server, error) { isBasicAuth := uOk && pOk isOAuth := cOk && csOk && tOk - if svOk { + if skipVerifyFlag { + skipVerifyBool = true + } else if svOk { //convert to bool skipVerify = strings.ToLower(skipVerify) skipVerifyBool = skipVerify == "true" || skipVerify == "1" || skipVerify == "yes" || skipVerify == "y" || skipVerify == "t" @@ -533,6 +540,8 @@ func initClient(saveConfig bool) (*api.Client, error) { Str("providerProfile", providerProfile). Bool("noPrompt", noPrompt). Bool("saveConfig", saveConfig). + Bool("logInsecure", logInsecure). + Bool("skipVerifyFlag", skipVerifyFlag). Str("hostname", kfcHostName). Str("username", kfcUsername). Str("password", hashSecretValue(kfcPassword)). @@ -753,6 +762,10 @@ func init() { "Will not attempt to connect to GitHub for latest release information and resources.", ) RootCmd.PersistentFlags().BoolVar(&debugFlag, "debug", false, "Enable debugFlag logging.") + RootCmd.PersistentFlags().BoolVar( + &skipVerifyFlag, "skip-tls-verify", false, + "Disable TLS verification for API requests to Keyfactor Command.", + ) //RootCmd.PersistentFlags().BoolVar( // &logInsecure, // "log-insecure", diff --git a/cmd/stores.go b/cmd/stores.go index c6951ab..0b2b195 100644 --- a/cmd/stores.go +++ b/cmd/stores.go @@ -74,6 +74,7 @@ var storesListCmd = &cobra.Command{ log.Error().Err(jErr).Send() return jErr } + outputResult(output, outputFormat) return nil },