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="