From 5ff3b8803231a0bd53bb5e5f57d648c565335283 Mon Sep 17 00:00:00 2001 From: Luis Presuel Date: Fri, 7 Jun 2024 10:11:36 -0600 Subject: [PATCH 1/2] adds testing for Azure (which includes adding setting native ruby http to delete provisioned certificates to key vault) and refactors code to use certificate name, other adaptions and sets constants properly in Ruby --- aruba/cucumber.sh | 9 +- .../playbook/steps_definitions/my_steps.rb | 26 ++--- .../provision_cloudkeystore.feature | 3 + .../steps_definitions/my_steps.rb | 95 +++++++++++++------ aruba/features/step_definitions/actions.rb | 6 +- aruba/features/step_definitions/endpoints.rb | 8 +- aruba/features/support/aruba.rb | 36 +++---- aruba/features/support/azure_provider.rb | 50 ++++++++++ aruba/features/support/http_utils.rb | 16 ++++ 9 files changed, 185 insertions(+), 64 deletions(-) create mode 100644 aruba/features/support/azure_provider.rb create mode 100644 aruba/features/support/http_utils.rb diff --git a/aruba/cucumber.sh b/aruba/cucumber.sh index 14ff49a6..1d45d745 100755 --- a/aruba/cucumber.sh +++ b/aruba/cucumber.sh @@ -38,7 +38,14 @@ RUN_COMMAND="docker run -t --rm \ -e AWS_SECRET_ACCESS_KEY \ -e AWS_PROVIDER_NAME \ -e AWS_KEYSTORE_NAME \ - -e AWS_KEYSTORE_ID" + -e AWS_KEYSTORE_ID \ + -e AZURE_CLIENT_ID \ + -e AZURE_CLIENT_SECRET \ + -e AZURE_TENANT_ID \ + -e AZURE_KEYVAULT_NAME \ + -e AZURE_PROVIDER_NAME \ + -e AZURE_KEYSTORE_NAME \ + -e AZURE_KEYSTORE_ID" # Use getopts to handle command-line options while getopts "a:b:" opt; do diff --git a/aruba/features/playbook/steps_definitions/my_steps.rb b/aruba/features/playbook/steps_definitions/my_steps.rb index 35b64658..a8fa881c 100644 --- a/aruba/features/playbook/steps_definitions/my_steps.rb +++ b/aruba/features/playbook/steps_definitions/my_steps.rb @@ -8,7 +8,7 @@ } } - if platform == $platform_tpp + if platform == PLATFORM_TPP validate_tpp_envs connection_tpp = { platform: "tpp", @@ -21,7 +21,7 @@ } connection_tpp['credentials'] = credentials @playbook_data[:config][:connection] = connection_tpp - elsif platform == $platform_vaas or platform == $platform_vcp + elsif platform == PLATFORM_VAAS or platform == PLATFORM_VCP validate_vaas_envs connection_vaas = { platform: "vaas" @@ -189,9 +189,9 @@ current_certificate_task = @playbook_data['certificateTasks'].find { |certificate_task| certificate_task.name == task_name } aux_installation = Installation.new aux_installation.format = "PEM" - aux_installation.file = "{{- Env \"PWD\" }}" + $path_separator + $temp_path + $path_separator + cert_name - aux_installation.chainFile = "{{- Env \"PWD\" }}" + $path_separator + $temp_path + $path_separator + chain_name - aux_installation.keyFile = "{{- Env \"PWD\" }}" + $path_separator + $temp_path + $path_separator + + key_name + aux_installation.file = "{{- Env \"PWD\" }}" + PATH_SEPARATOR + TEMP_PATH + PATH_SEPARATOR + cert_name + aux_installation.chainFile = "{{- Env \"PWD\" }}" + PATH_SEPARATOR + TEMP_PATH + PATH_SEPARATOR + chain_name + aux_installation.keyFile = "{{- Env \"PWD\" }}" + PATH_SEPARATOR + TEMP_PATH + PATH_SEPARATOR + + key_name if password aux_installation.keyPassword = "Passcode123!" end @@ -211,7 +211,7 @@ current_certificate_task = @playbook_data['certificateTasks'].find { |certificate_task| certificate_task.name == task_name } aux_installation = Installation.new aux_installation.format = "JKS" - aux_installation.file = "{{- Env \"PWD\" }}" + $path_separator + $temp_path + $path_separator + cert_name + aux_installation.file = "{{- Env \"PWD\" }}" + PATH_SEPARATOR + TEMP_PATH + PATH_SEPARATOR + cert_name aux_installation.jksAlias = jks_alias aux_installation.jksPassword = jks_password if installation @@ -227,7 +227,7 @@ current_certificate_task = @playbook_data['certificateTasks'].find { |certificate_task| certificate_task.name == task_name } aux_installation = Installation.new aux_installation.format = "PKCS12" - aux_installation.file = "{{- Env \"PWD\" }}" + $path_separator + $temp_path + $path_separator + cert_name + aux_installation.file = "{{- Env \"PWD\" }}" + PATH_SEPARATOR + TEMP_PATH + PATH_SEPARATOR + cert_name aux_installation.p12Password = p12_password if installation aux_installation.afterInstallAction = "echo SuccessInstall" @@ -242,7 +242,7 @@ current_certificate_task = @playbook_data['certificateTasks'].find { |certificate_task| certificate_task.name == task_name } aux_installation = Installation.new aux_installation.format = "PKCS12" - aux_installation.file = "{{- Env \"PWD\" }}" + $path_separator + $temp_path + $path_separator + cert_name + aux_installation.file = "{{- Env \"PWD\" }}" + PATH_SEPARATOR + TEMP_PATH + PATH_SEPARATOR + cert_name aux_installation.p12Password = p12_password aux_installation.useLegacyP12 = true if installation @@ -279,15 +279,15 @@ end And(/^I uninstall file named "(.*)"$/) do |file_name| - file_path = Dir.pwd + $path_separator + $temp_path + $path_separator + file_name + file_path = Dir.pwd + PATH_SEPARATOR + TEMP_PATH + PATH_SEPARATOR + file_name steps %{ Then a file named "#{file_path}" does not exist } end When(/^playbook generated private key in "([^"]*)" and certificate in "([^"]*)" should have the same modulus(?: with password |)(.*)?$/) do |key_file, cert_file, password| - cert_path = Dir.pwd + $path_separator + $temp_path + $path_separator + cert_file - key_path = Dir.pwd + $path_separator + $temp_path + $path_separator + key_file + cert_path = Dir.pwd + PATH_SEPARATOR + TEMP_PATH + PATH_SEPARATOR + cert_file + key_path = Dir.pwd + PATH_SEPARATOR + TEMP_PATH + PATH_SEPARATOR + key_file if password != "" steps %{ @@ -305,7 +305,7 @@ end When(/^playbook generated "([^"]*)" should be PKCS#12 archive with password "([^"]*)"$/) do |filename, password| - cert_path = Dir.pwd + $path_separator + $temp_path + $path_separator + filename + cert_path = Dir.pwd + PATH_SEPARATOR + TEMP_PATH + PATH_SEPARATOR + filename steps %{ Then I try to run `openssl pkcs12 -in "#{cert_path}" -passin pass:#{password} -noout` @@ -323,7 +323,7 @@ fail(ArgumentError.new("Unexpected Key Type. Unknown Key Type: #{key_type}")) end - file_path = Dir.pwd + $path_separator + $temp_path + $path_separator + filename + file_path = Dir.pwd + PATH_SEPARATOR + TEMP_PATH + PATH_SEPARATOR + filename lines = File.open(file_path).first(2).map(&:strip) if lines[0] == header then diff --git a/aruba/features/provision/cloudkeystore/provision_cloudkeystore.feature b/aruba/features/provision/cloudkeystore/provision_cloudkeystore.feature index ba1706f9..e6f56871 100644 --- a/aruba/features/provision/cloudkeystore/provision_cloudkeystore.feature +++ b/aruba/features/provision/cloudkeystore/provision_cloudkeystore.feature @@ -18,6 +18,7 @@ Feature: provision to cloud keystore | cloudkeystore | | GOOGLE | | AWS | + | AZURE | Scenario Outline: Enroll certificate and execute provisioning for cloud keystore and get output in JSON Given I enroll a random certificate with defined platform VCP with -csr service -no-prompt @@ -47,3 +48,5 @@ Feature: provision to cloud keystore Examples: | cloudkeystore | | AWS | + | GOOGLE | + | AZURE | diff --git a/aruba/features/provision/cloudkeystore/steps_definitions/my_steps.rb b/aruba/features/provision/cloudkeystore/steps_definitions/my_steps.rb index d6579337..bf6cd87e 100644 --- a/aruba/features/provision/cloudkeystore/steps_definitions/my_steps.rb +++ b/aruba/features/provision/cloudkeystore/steps_definitions/my_steps.rb @@ -15,13 +15,18 @@ And(/^I use previous Pickup ID and cloud ID to provision again$/) do keystore_provider_names = true flags = "" - if @cloudkeystore_type == $keystore_type_aws + case @cloudkeystore_type + when KEYSTORE_TYPE_AWS flags += " -arn #{@cloud_id}" - elsif @cloudkeystore_type == $keystore_type_azure or @cloudkeystore_type == $keystore_type_gcp - flags += " -certificate-name #{@cloud_id}" + when KEYSTORE_TYPE_AZURE + flags += " -certificate-name #{@cloud_name}" + when KEYSTORE_TYPE_GCP + flags += " -certificate-name #{@cloud_id}" + else + fail(ArgumentError.new("Unknown cloud type: #{@cloudkeystore_type}")) end flags += @global_set_provision_flags - cmd = build_provision_cmd($platform_vcp, @cloudkeystore_type, keystore_provider_names, flags) + cmd = build_provision_cmd(PLATFORM_VCP, @cloudkeystore_type, keystore_provider_names, flags) steps %{Then I try to run `#{cmd}`} end @@ -31,27 +36,36 @@ def build_provision_cmd(platform, cloudkeystore_type, keystore_provider_names, f platform_flag = " -platform " + platform - cmd = "vcert provision cloudkeystore #{platform_flag} #{ENDPOINTS[$platform_vcp]} -pickup-id #{@pickup_id}" + cmd = "vcert provision cloudkeystore #{platform_flag} #{ENDPOINTS[PLATFORM_VCP]} -pickup-id #{@pickup_id}" keystore_name = "" provider_name = "" keystore_id = "" case cloudkeystore_type - when $keystore_type_aws + when KEYSTORE_TYPE_AWS + @cloudkeystore_type = KEYSTORE_TYPE_AWS if keystore_provider_names - keystore_name = $aws_keystore_name - provider_name = $aws_provider_name - @cloudkeystore_type = $keystore_type_aws + keystore_name = AWS_KEYSTORE_NAME + provider_name = AWS_PROVIDER_NAME + else - keystore_name = $aws_keystore_id + keystore_id = AWS_KEYSTORE_ID end - when $keystore_type_gcp + when KEYSTORE_TYPE_AZURE + @cloudkeystore_type = KEYSTORE_TYPE_AZURE if keystore_provider_names - keystore_name = $gcp_keystore_name - provider_name = $gcp_provider_name - @cloudkeystore_type = $keystore_type_gcp + keystore_name = AZURE_KEYSTORE_NAME + provider_name = AZURE_PROVIDER_NAME else - keystore_id = $gcp_keystore_id + keystore_id = AZURE_KEYSTORE_ID + end + when KEYSTORE_TYPE_GCP + @cloudkeystore_type = KEYSTORE_TYPE_GCP + if keystore_provider_names + keystore_name = GCP_KEYSTORE_NAME + provider_name = GCP_PROVIDER_NAME + else + keystore_id = GCP_KEYSTORE_ID end else fail(ArgumentError.new("Unexpected : #{cloudkeystore_type}")) @@ -75,32 +89,48 @@ def build_provision_cmd(platform, cloudkeystore_type, keystore_provider_names, f Then(/^I grab cloud ID from( JSON)? output$/) do |json| - @cloud_id = get_cloud_id_from_output(json) - + @cloud_id = get_value_from_output("cloudId",json) + if @cloudkeystore_type == KEYSTORE_TYPE_AZURE + @cloud_name = get_value_from_output("azureName",json) + end end -def get_cloud_id_from_output(json = false) +def get_value_from_output(value, json = false) if @previous_command_output.nil? fail(ArgumentError.new('@previous_command_output is nil')) end Kernel.puts("Checking output:\n"+@previous_command_output) - cloud_id_attr = "cloudId" if json json_string = extract_json_from_output(@previous_command_output) JSON.parse(json_string) - cloud_id = unescape_text(normalize_json(json_string, "#{cloud_id_attr}")).tr('"', '') + extracted_val = unescape_text(normalize_json(json_string, "#{value}")).tr('"', '') else - m = @previous_command_output.match /#{cloud_id_attr}: (.+)$/ - cloud_id = m[1] + m = @previous_command_output.match /#{value}: (.+)$/ + extracted_val = m[1] end - cloud_id + extracted_val end Then(/^the output( in JSON)? should contain the previous cloud ID$/) do |json| + validate_provision_replace(json) +end + +def validate_provision_replace(json) + # for azure case we want to check the name instead + if @cloudkeystore_type == KEYSTORE_TYPE_AZURE + old_cloud_name = @cloud_name + new_cloud_name = get_value_from_output("azureName", json) + if old_cloud_name != new_cloud_name + cleanup_keystore(old_cloud_name) + cleanup_keystore(new_cloud_name) + fail(ArgumentError.new("Expected old Cloud Name: #{old_cloud_name} to be same as new Cloud Name, but got: #{new_cloud_name}")) + end + return + end old_cloud_id = @cloud_id - new_cloud_id = get_cloud_id_from_output(json) + new_cloud_id = get_value_from_output("cloudId", json) if old_cloud_id != new_cloud_id cleanup_keystore(old_cloud_id) cleanup_keystore(new_cloud_id) @@ -114,10 +144,11 @@ def get_cloud_id_from_output(json = false) def cleanup_keystore(cloud_id = "") case @cloudkeystore_type - when $keystore_type_aws + when KEYSTORE_TYPE_AWS cleanup_aws(cloud_id) - when $keystore_type_azure - when $keystore_type_gcp + when KEYSTORE_TYPE_AZURE + cleanup_akv(@cloud_name) + when KEYSTORE_TYPE_GCP cleanup_google(cloud_id) else fail(ArgumentError.new("Unexpected : #{@cloudkeystore_type}")) @@ -145,3 +176,13 @@ def cleanup_aws(cloud_id = "") delete_acm_certificate(client, certificate_arn) end + +def cleanup_akv(cloud_name = "") + if cloud_name != "" + certificate_name = cloud_name + else + certificate_name = @cloud_name + end + + delete_azure_certificate(certificate_name) +end diff --git a/aruba/features/step_definitions/actions.rb b/aruba/features/step_definitions/actions.rb index 49500899..6677d0c0 100644 --- a/aruba/features/step_definitions/actions.rb +++ b/aruba/features/step_definitions/actions.rb @@ -181,16 +181,16 @@ When(/^I enroll(?: a)?( random)? certificate with defined platform (.*) with (.+)?$/) do |random, platform, flags| if random - cn = " -cn " + $prefix_cn + "-" + random_cn + cn = " -cn " + PREFIX_CN + "-" + random_cn end platform_flag = " -platform " + platform trust_bundle_flag = "" case platform - when $platform_tpp + when PLATFORM_TPP trust_bundle_flag = " -trust-bundle '#{ENV["TPP_TRUST_BUNDLE"]}' " - when $platform_firefly + when PLATFORM_FIREFLY trust_bundle_flag = " -trust-bundle '#{ENV["FIREFLY_CA_BUNDLE"]}' " end diff --git a/aruba/features/step_definitions/endpoints.rb b/aruba/features/step_definitions/endpoints.rb index a2e1b3e9..22bff208 100644 --- a/aruba/features/step_definitions/endpoints.rb +++ b/aruba/features/step_definitions/endpoints.rb @@ -20,9 +20,9 @@ "Firefly" => "-u '#{ENV['FIREFLY_URL']}' -t '#{ENV['IDP_ACCESS_TOKEN']}'" } -ENDPOINTS[$platform_vaas] = ENDPOINTS["Cloud"] +ENDPOINTS[PLATFORM_VAAS] = ENDPOINTS["Cloud"] -ENDPOINTS[$platform_vcp] = ENDPOINTS[$platform_vaas] +ENDPOINTS[PLATFORM_VCP] = ENDPOINTS[PLATFORM_VAAS] ZONE = { "test-mode" => "-z Default", @@ -37,9 +37,9 @@ "Firefly" => "-z '#{ENV['FIREFLY_ZONE']}'" } -ZONE[$platform_vaas] = ZONE["Cloud"] +ZONE[PLATFORM_VAAS] = ZONE["Cloud"] -ZONE[$platform_vcp] = ZONE[$platform_vaas] +ZONE[PLATFORM_VCP] = ZONE[PLATFORM_VAAS] ENDPOINT_CONFIGS = { "test-mode" => " diff --git a/aruba/features/support/aruba.rb b/aruba/features/support/aruba.rb index f1864da9..9164381d 100644 --- a/aruba/features/support/aruba.rb +++ b/aruba/features/support/aruba.rb @@ -5,27 +5,31 @@ config.allow_absolute_paths = true end -$prefix_cn = "vcert" +PREFIX_CN = "vcert" -$platform_tpp = "TPP" -$platform_vaas = "VaaS" # places already use it as is -$platform_vcp = "VCP" -$platform_firefly = "Firefly" +PLATFORM_TPP = "TPP" +PLATFORM_VAAS = "VaaS" # places already use it as is +PLATFORM_VCP = "VCP" +PLATFORM_FIREFLY = "Firefly" -$path_separator = "/" -$temp_path = "tmp/aruba" +PATH_SEPARATOR = "/" +TEMP_PATH = "tmp/aruba" -$keystore_type_aws = "AWS" -$keystore_type_azure = "AZURE" -$keystore_type_gcp = "GOOGLE" +KEYSTORE_TYPE_AWS = "AWS" +KEYSTORE_TYPE_AZURE = "AZURE" +KEYSTORE_TYPE_GCP = "GOOGLE" -$gcp_keystore_id = ENV["GCP_KEYSTORE_ID"] -$gcp_keystore_name = ENV["GCP_KEYSTORE_NAME"] -$gcp_provider_name = ENV["GCP_PROVIDER_NAME"] +GCP_KEYSTORE_ID = ENV["GCP_KEYSTORE_ID"] +GCP_KEYSTORE_NAME = ENV["GCP_KEYSTORE_NAME"] +GCP_PROVIDER_NAME = ENV["GCP_PROVIDER_NAME"] -$aws_keystore_id = ENV["AWS_KEYSTORE_ID"] -$aws_keystore_name = ENV["AWS_KEYSTORE_NAME"] -$aws_provider_name = ENV["AWS_PROVIDER_NAME"] +AWS_KEYSTORE_ID = ENV["AWS_KEYSTORE_ID"] +AWS_KEYSTORE_NAME = ENV["AWS_KEYSTORE_NAME"] +AWS_PROVIDER_NAME = ENV["AWS_PROVIDER_NAME"] + +AZURE_KEYSTORE_ID = ENV["AZURE_KEYSTORE_ID"] +AZURE_KEYSTORE_NAME = ENV["AZURE_KEYSTORE_NAME"] +AZURE_PROVIDER_NAME = ENV["AZURE_PROVIDER_NAME"] def last_json last_command_started.stdout.to_s diff --git a/aruba/features/support/azure_provider.rb b/aruba/features/support/azure_provider.rb new file mode 100644 index 00000000..4472d117 --- /dev/null +++ b/aruba/features/support/azure_provider.rb @@ -0,0 +1,50 @@ +# Define the necessary Azure credentials +CLIENT_ID = ENV['AZURE_CLIENT_ID'] +CLIENT_SECRET = ENV['AZURE_CLIENT_SECRET'] +TENANT_ID = ENV['AZURE_TENANT_ID'] +KEYVAULT_NAME = ENV['AZURE_KEYVAULT_NAME'] + +def get_azure_access_token + token_url = URI("https://login.microsoftonline.com/#{TENANT_ID}/oauth2/v2.0/token") + token_request = Net::HTTP::Post.new(token_url) + token_request.set_form_data({ + 'grant_type' => 'client_credentials', + 'client_id' => CLIENT_ID, + 'client_secret' => CLIENT_SECRET, + 'scope' => 'https://vault.azure.net/.default' + }) + + begin + token_response = Net::HTTP.start(token_url.hostname, token_url.port, use_ssl: true) do |http| + http.request(token_request) + end + handle_http_response(token_response) + + rescue BadRequestError, UnauthorizedError, NotFoundError, ServerError => e + puts "Custom Error: #{e.message}" + rescue StandardError => e + puts "An error occurred: #{e.message}" + end + + token_data = JSON.parse(token_response.body) + token_data['access_token'] +end + +def delete_azure_certificate(certificate_name) + vault_url = URI("https://#{KEYVAULT_NAME}.vault.azure.net/certificates/#{certificate_name}?api-version=7.2") + access_token = get_azure_access_token + + delete_request = Net::HTTP::Delete.new(vault_url) + delete_request['Authorization'] = "Bearer #{access_token}" + + begin + delete_response = Net::HTTP.start(vault_url.hostname, vault_url.port, use_ssl: true) do |http| + http.request(delete_request) + end + handle_http_response(delete_response) + rescue BadRequestError, UnauthorizedError, NotFoundError, ServerError => e + puts "Custom Error: #{e.message}" + rescue StandardError => e + puts "An error occurred: #{e.message}" + end +end \ No newline at end of file diff --git a/aruba/features/support/http_utils.rb b/aruba/features/support/http_utils.rb new file mode 100644 index 00000000..39d23cad --- /dev/null +++ b/aruba/features/support/http_utils.rb @@ -0,0 +1,16 @@ +def handle_http_response(response) + case response + when Net::HTTPSuccess + puts "Response body: #{response.body}" + when Net::HTTPBadRequest + raise BadRequestError, "400 Bad Request" + when Net::HTTPUnauthorized + raise UnauthorizedError, "401 Unauthorized" + when Net::HTTPNotFound + raise NotFoundError, "404 Not Found" + when Net::HTTPServerError + raise ServerError, "5xx Server Error" + else + puts "HTTP Error: #{response.message} (#{response.code})" + end +end \ No newline at end of file From dafcb20a706cb5016ed8330c40c250a9c440da3c Mon Sep 17 00:00:00 2001 From: Luis Presuel Date: Fri, 7 Jun 2024 11:49:16 -0600 Subject: [PATCH 2/2] adds EOL missed in some files --- aruba/features/support/azure_provider.rb | 2 +- aruba/features/support/http_utils.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aruba/features/support/azure_provider.rb b/aruba/features/support/azure_provider.rb index 4472d117..51652283 100644 --- a/aruba/features/support/azure_provider.rb +++ b/aruba/features/support/azure_provider.rb @@ -47,4 +47,4 @@ def delete_azure_certificate(certificate_name) rescue StandardError => e puts "An error occurred: #{e.message}" end -end \ No newline at end of file +end diff --git a/aruba/features/support/http_utils.rb b/aruba/features/support/http_utils.rb index 39d23cad..a0a7e2ea 100644 --- a/aruba/features/support/http_utils.rb +++ b/aruba/features/support/http_utils.rb @@ -13,4 +13,4 @@ def handle_http_response(response) else puts "HTTP Error: #{response.message} (#{response.code})" end -end \ No newline at end of file +end