From 76fccfb912c5dfc14b0d614d63cf33501f9025ba Mon Sep 17 00:00:00 2001 From: dillanb-hashi Date: Wed, 6 Aug 2025 09:55:15 -0700 Subject: [PATCH] test(e2e): Created module for windows client (#5942) e2e(test): Created module and scenario for windows client for rdp testing --- enos/enos-modules.hcl | 4 + enos/enos-scenario-e2e-aws-rdp-target.hcl | 2 +- enos/enos-scenario-e2e-aws-windows.hcl | 305 +++++++++++++++++ enos/enos-variables.hcl | 6 + enos/modules/aws_rdp_server/outputs.tf | 2 +- enos/modules/aws_windows_client/main.tf | 317 ++++++++++++++++++ enos/modules/aws_windows_client/outputs.tf | 49 +++ .../aws_windows_client/scripts/setup.ps1 | 31 ++ enos/modules/aws_windows_client/variables.tf | 49 +++ enos/modules/build_local/main.tf | 13 +- enos/modules/build_local/templates/build.sh | 2 +- enos/modules/test_e2e/main.tf | 42 +++ 12 files changed, 817 insertions(+), 5 deletions(-) create mode 100644 enos/enos-scenario-e2e-aws-windows.hcl create mode 100644 enos/modules/aws_windows_client/main.tf create mode 100644 enos/modules/aws_windows_client/outputs.tf create mode 100644 enos/modules/aws_windows_client/scripts/setup.ps1 create mode 100644 enos/modules/aws_windows_client/variables.tf diff --git a/enos/enos-modules.hcl b/enos/enos-modules.hcl index 5e670762d..8cf58d9b2 100644 --- a/enos/enos-modules.hcl +++ b/enos/enos-modules.hcl @@ -119,6 +119,10 @@ module "aws_target" { enos_user = var.enos_user } +module "aws_windows_client" { + source = "./modules/aws_windows_client" +} + module "vault" { source = "./modules/aws_vault" diff --git a/enos/enos-scenario-e2e-aws-rdp-target.hcl b/enos/enos-scenario-e2e-aws-rdp-target.hcl index bc7da037d..166d320ef 100644 --- a/enos/enos-scenario-e2e-aws-rdp-target.hcl +++ b/enos/enos-scenario-e2e-aws-rdp-target.hcl @@ -67,7 +67,7 @@ scenario "e2e_aws_rdp_target" { } output "rdp_target_public_dns_address" { - value = step.create_rdp_server.public-dns-address + value = step.create_rdp_server.public_dns_address } output "rdp_target_public_ip" { diff --git a/enos/enos-scenario-e2e-aws-windows.hcl b/enos/enos-scenario-e2e-aws-windows.hcl new file mode 100644 index 000000000..fb2597636 --- /dev/null +++ b/enos/enos-scenario-e2e-aws-windows.hcl @@ -0,0 +1,305 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: BUSL-1.1 + +scenario "e2e_aws_windows" { + terraform_cli = terraform_cli.default + terraform = terraform.default + providers = [ + provider.aws.default, + provider.enos.default + ] + + matrix { + builder = ["local", "crt"] + client = ["win10", "win11"] + rdp_server = ["2016", "2019", "2022", "2025"] + } + + locals { + aws_ssh_private_key_path = abspath(var.aws_ssh_private_key_path) + boundary_install_dir = abspath(var.boundary_install_dir) + local_boundary_dir = var.local_boundary_dir != null ? abspath(var.local_boundary_dir) : null + local_boundary_src_dir = var.local_boundary_src_dir != null ? abspath(var.local_boundary_src_dir) : null + boundary_license_path = abspath(var.boundary_license_path != null ? var.boundary_license_path : joinpath(path.root, "./support/boundary.hclic")) + + build_path_linux = { + "local" = "/tmp", + "crt" = var.crt_bundle_path == null ? null : abspath(var.crt_bundle_path) + } + + build_path_windows = { + "local" = "/tmp", + "crt" = var.crt_bundle_path_windows == null ? null : abspath(var.crt_bundle_path_windows) + } + + tags = merge({ + "Project Name" : var.project_name + "Project" : "Enos", + "Environment" : "ci" + }, var.tags) + + collocated_tag = "collocated" + } + + step "find_azs" { + module = module.aws_az_finder + + variables { + instance_type = [ + var.worker_instance_type, + var.controller_instance_type + ] + } + } + + step "read_boundary_license" { + module = module.read_license + + variables { + license_path = local.boundary_license_path + } + } + + step "create_db_password" { + module = module.random_stringifier + } + + step "build_boundary_linux" { + module = matrix.builder == "crt" ? module.build_crt : module.build_local + + variables { + path = local.build_path_linux[matrix.builder] + edition = var.boundary_edition + } + } + + step "build_boundary_windows" { + module = matrix.builder == "crt" ? module.build_crt : module.build_local + + depends_on = [ + step.build_boundary_linux + ] + + variables { + path = local.build_path_windows[matrix.builder] + edition = var.boundary_edition + goos = "windows" + build_target = "build" + artifact_name = "boundary_windows" + binary_name = "boundary.exe" + } + } + + step "create_base_infra" { + module = module.aws_vpc_ipv6 + + depends_on = [ + step.find_azs, + ] + + variables { + availability_zones = step.find_azs.availability_zones + common_tags = local.tags + } + } + + step "create_windows_client" { + module = module.aws_windows_client + + depends_on = [ + step.create_base_infra, + step.build_boundary_windows, + ] + + variables { + vpc_id = step.create_base_infra.vpc_id + client_version = matrix.client + boundary_cli_zip_path = step.build_boundary_windows.artifact_path + boundary_src_path = local.local_boundary_src_dir + } + } + + step "create_vault_cluster" { + module = module.vault + depends_on = [ + step.create_base_infra, + ] + + variables { + deploy = true + ami_id = step.create_base_infra.ami_ids["ubuntu"]["amd64"] + instance_type = var.vault_instance_type + instance_count = 1 + kms_key_arn = step.create_base_infra.kms_key_arn + storage_backend = "raft" + unseal_method = "shamir" + ip_version = "dual" + vault_release = { + version = var.vault_version + edition = "oss" + } + vpc_id = step.create_base_infra.vpc_id + } + } + + step "create_boundary_cluster" { + module = module.aws_boundary + depends_on = [ + step.create_base_infra, + step.create_windows_client, + step.create_db_password, + step.build_boundary_linux, + step.create_vault_cluster, + step.read_boundary_license + ] + + variables { + boundary_binary_name = var.boundary_binary_name + boundary_install_dir = local.boundary_install_dir + boundary_license = var.boundary_edition != "oss" ? step.read_boundary_license.license : null + common_tags = local.tags + controller_instance_type = var.controller_instance_type + controller_count = var.controller_count + db_pass = step.create_db_password.string + kms_key_arn = step.create_base_infra.kms_key_arn + local_artifact_path = step.build_boundary_linux.artifact_path + ubuntu_ami_id = step.create_base_infra.ami_ids["ubuntu"]["amd64"] + vpc_id = step.create_base_infra.vpc_id + worker_count = var.worker_count + worker_instance_type = var.worker_instance_type + controller_config_file_path = "templates/controller_bsr.hcl" + worker_config_file_path = "templates/worker_bsr.hcl" + vault_address = step.create_vault_cluster.instance_public_ips[0] + vault_transit_token = step.create_vault_cluster.vault_transit_token + aws_region = var.aws_region + ip_version = "dual" + recording_storage_path = "/recording" + alb_sg_additional_ips = step.create_windows_client.public_ip_list + } + } + + step "create_test_id" { + module = module.random_stringifier + variables { + length = 5 + } + } + + step "iam_setup" { + module = module.aws_iam_setup + depends_on = [ + step.create_base_infra, + step.create_test_id + ] + + variables { + test_id = step.create_test_id.string + test_email = var.test_email + } + } + + step "create_bucket" { + module = module.aws_bucket + depends_on = [ + step.create_boundary_cluster, + ] + variables { + cluster_tag = step.create_boundary_cluster.cluster_tag + user = step.iam_setup.user_name + is_user = true + } + } + + step "create_rdp_server" { + module = module.aws_rdp_server + depends_on = [ + step.create_base_infra, + ] + + variables { + vpc_id = step.create_base_infra.vpc_id + server_version = matrix.rdp_server + } + } + + step "run_e2e_test" { + module = module.test_e2e + depends_on = [ + step.create_boundary_cluster, + step.create_rdp_server, + step.create_bucket + ] + + variables { + test_package = "" + debug_no_run = true + alb_boundary_api_addr = step.create_boundary_cluster.alb_boundary_api_addr + auth_method_id = step.create_boundary_cluster.auth_method_id + auth_login_name = step.create_boundary_cluster.auth_login_name + auth_password = step.create_boundary_cluster.auth_password + local_boundary_dir = local.local_boundary_dir + aws_ssh_private_key_path = local.aws_ssh_private_key_path + target_user = "ubuntu" + target_port = "22" + aws_bucket_name = step.create_bucket.bucket_name + aws_region = var.aws_region + max_page_size = step.create_boundary_cluster.max_page_size + worker_tag_collocated = local.collocated_tag + target_rdp_address = step.create_rdp_server.private_ip + target_rdp_user = step.create_rdp_server.admin_username + target_rdp_password = step.create_rdp_server.password + client_ip_public = step.create_windows_client.public_ip + client_username = step.create_windows_client.test_username + client_password = step.create_windows_client.test_password + client_test_dir = step.create_windows_client.test_dir + } + } + + output "controller_ips" { + value = step.create_boundary_cluster.controller_ips + } + + output "worker_ips" { + value = step.create_boundary_cluster.worker_ips + } + + output "rdp_target_admin_username" { + value = step.create_rdp_server.admin_username + } + + output "rdp_target_admin_password" { + value = step.create_rdp_server.password + } + + output "rdp_target_public_dns_address" { + value = step.create_rdp_server.public_dns_address + } + + output "rdp_target_private_ip" { + value = step.create_rdp_server.private_ip + } + + output "windows_client_public_ip" { + value = step.create_windows_client.public_ip + } + + output "windows_client_private_ip" { + value = step.create_windows_client.private_ip + } + + output "windows_client_password" { + value = step.create_windows_client.admin_password + } + + output "windows_client_test_user" { + value = step.create_windows_client.test_username + } + + output "windows_client_test_password" { + value = step.create_windows_client.test_password + } + + output "windows_client_ssh_key" { + value = step.create_windows_client.ssh_private_key + } +} diff --git a/enos/enos-variables.hcl b/enos/enos-variables.hcl index 074a33c0b..c8e402155 100644 --- a/enos/enos-variables.hcl +++ b/enos/enos-variables.hcl @@ -115,6 +115,12 @@ variable "crt_bundle_path" { default = null } +variable crt_bundle_path_windows { + description = "Path to CRT generated boundary bundle for windows" + type = string + default = null +} + variable "boundary_install_dir" { description = "Path boundary binaries will be installed to on remote instances" type = string diff --git a/enos/modules/aws_rdp_server/outputs.tf b/enos/modules/aws_rdp_server/outputs.tf index 58a669893..ce930bc9f 100644 --- a/enos/modules/aws_rdp_server/outputs.tf +++ b/enos/modules/aws_rdp_server/outputs.tf @@ -1,7 +1,7 @@ # Copyright (c) HashiCorp, Inc. # SPDX-License-Identifier: BUSL-1.1 -output "public-dns-address" { +output "public_dns_address" { value = aws_instance.rdp_target.public_dns } diff --git a/enos/modules/aws_windows_client/main.tf b/enos/modules/aws_windows_client/main.tf new file mode 100644 index 000000000..b264b22ef --- /dev/null +++ b/enos/modules/aws_windows_client/main.tf @@ -0,0 +1,317 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: BUSL-1.1 + +terraform { + required_version = ">= 1.1.2" + + required_providers { + enos = { + source = "registry.terraform.io/hashicorp-forge/enos" + } + + tls = { + source = "hashicorp/tls" + } + + archive = { + source = "hashicorp/archive" + } + } +} + +locals { + client_to_server_version = { + "win10" = "2022" + "win11" = "2025" + } +} + +data "enos_environment" "current" {} + +data "aws_caller_identity" "current" {} + +data "aws_ami" "infra" { + most_recent = true + owners = ["amazon"] + + filter { + name = "name" + values = ["Windows_Server-${local.client_to_server_version[var.client_version]}-English-Full-Base*"] + } +} + +data "aws_vpc" "infra" { + id = var.vpc_id +} + +data "aws_subnets" "infra" { + filter { + name = "vpc-id" + values = [var.vpc_id] + } +} + +locals { + username = split(":", data.aws_caller_identity.current.user_id)[1] +} + +// We need a keypair to obtain the local administrator credentials to an AWS Windows based EC2 instance. So we generate it locally here +resource "tls_private_key" "rsa-4096-key" { + algorithm = "RSA" + rsa_bits = 4096 +} + +// Create an AWS keypair using the keypair we just generated +resource "aws_key_pair" "rdp-key" { + key_name = "${var.prefix}-windows-client-${local.username}-${var.vpc_id}" + public_key = tls_private_key.rsa-4096-key.public_key_openssh +} + +// Create an AWS security group to allow SSH +resource "aws_security_group" "windows_client" { + name = "${var.prefix}-windows-client-${local.username}-${var.vpc_id}" + vpc_id = var.vpc_id + + # Allow SSH from the public IP of the user + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = flatten([ + formatlist("%s/32", data.enos_environment.current.public_ipv4_addresses), + join(",", data.aws_vpc.infra.cidr_block_associations.*.cidr_block), + ]) + } + + # Allow RDP from the public IP of the user. This is useful for manual testing + ingress { + from_port = 3389 + to_port = 3389 + protocol = "tcp" + cidr_blocks = flatten([ + formatlist("%s/32", data.enos_environment.current.public_ipv4_addresses), + join(",", data.aws_vpc.infra.cidr_block_associations.*.cidr_block), + ]) + } + + ingress { + from_port = 3389 + to_port = 3389 + protocol = "udp" + cidr_blocks = flatten([ + formatlist("%s/32", data.enos_environment.current.public_ipv4_addresses), + join(",", data.aws_vpc.infra.cidr_block_associations.*.cidr_block), + ]) + } + + // Allow all traffic originating from the VPC + ingress { + from_port = 0 + to_port = 0 + protocol = "-1" + self = true + } + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } +} + +resource "random_string" "DSRMPassword" { + length = 8 + override_special = "." # I've set this explicitly so as to avoid characters such as "$" and "'" being used and requiring unneccesary complexity to our user_data scripts + min_lower = 1 + min_upper = 1 + min_numeric = 1 + min_special = 1 +} + +locals { + test_username = "autologinuser" + test_password = random_string.DSRMPassword.result +} + +// Deploy a Windows EC2 instance +resource "aws_instance" "client" { + ami = data.aws_ami.infra.id + instance_type = var.instance_type + vpc_security_group_ids = [aws_security_group.windows_client.id] + key_name = aws_key_pair.rdp-key.key_name + subnet_id = data.aws_subnets.infra.ids[0] + ipv6_address_count = 1 + + root_block_device { + volume_type = "gp2" + volume_size = var.root_block_device_size + delete_on_termination = "true" + encrypted = true + } + + user_data_replace_on_change = true + + user_data = < + # Set up SSH so we can remotely manage the instance + ## Install OpenSSH Server and Client + Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0 + Set-Service -Name sshd -StartupType 'Automatic' + Start-Service sshd + + Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0 + Set-Service -Name ssh-agent -StartupType Automatic + Start-Service ssh-agent + + ## Set PowerShell as the default SSH shell + New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value (Get-Command powershell.exe).Path -PropertyType String -Force + + ## Configure SSH server to use private key authentication so that scripts don't have to use passwords + ## Save the private key from instance metadata + $ImdsToken = (Invoke-WebRequest -Uri 'http://169.254.169.254/latest/api/token' -Method 'PUT' -Headers @{'X-aws-ec2-metadata-token-ttl-seconds' = 2160} -UseBasicParsing).Content + $ImdsHeaders = @{'X-aws-ec2-metadata-token' = $ImdsToken} + $AuthorizedKey = (Invoke-WebRequest -Uri 'http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key' -Headers $ImdsHeaders -UseBasicParsing).Content + $AuthorizedKeysPath = 'C:\ProgramData\ssh\administrators_authorized_keys' + New-Item -Path $AuthorizedKeysPath -ItemType File -Value $AuthorizedKey -Force + + ## Ensure the SSH agent pulls in the new key. + Set-Service -Name ssh-agent -StartupType "Automatic" + Restart-Service -Name ssh-agent + + ## Open the firewall for SSH connections + New-NetFirewallRule -Name sshd -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22 + + # Create a non-admin user to be used for RDP connection. This + # is needed since the scheduled task that runs pyautogui + # doesn't work in an Administrator context. + ## Create a local user + $Username = "${local.test_username}" + $Password = ConvertTo-SecureString "${local.test_password}" -AsPlainText -Force + New-LocalUser $Username -Password $Password -FullName "Auto Login User" -Description "User for Auto Login" + Add-LocalGroupMember -Group "Administrators" -Member $Username + + # Set registry keys for auto-login + $regPath = "HKLM:\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon" + Set-ItemProperty -Path $regPath -Name "AutoAdminLogon" -Value "1" -Type String + Set-ItemProperty -Path $regPath -Name "DefaultUsername" -Value $Username -Type String + Set-ItemProperty -Path $regPath -Name "DefaultPassword" -Value "${local.test_password}" -Type String + Set-ItemProperty -Path $regPath -Name "DefaultDomainName" -Value "$env:COMPUTERNAME" -Type String + + EOF + + metadata_options { + http_endpoint = "enabled" + instance_metadata_tags = "enabled" + } + get_password_data = true + + tags = { + Name = "${var.prefix}-windows-client-${local.username}" + } +} + +locals { + admin_password = rsadecrypt(aws_instance.client.password_data, tls_private_key.rsa-4096-key.private_key_pem) + boundary_cli_zip_path = var.boundary_cli_zip_path != "" ? abspath(var.boundary_cli_zip_path) : "" + test_dir = "C:/Test/" # needs to end in a / to ensure it creates the directory +} + +resource "local_sensitive_file" "private_key" { + depends_on = [tls_private_key.rsa-4096-key] + + content = tls_private_key.rsa-4096-key.private_key_pem + filename = "${path.root}/.terraform/tmp/key-client-${timestamp()}" + file_permission = "0400" +} + +# wait for the SSH service to be available on the instance. We specifically use +# BatchMode=Yes to prevent SSH from prompting for a password to ensure that we +# can just SSH using the private key +resource "enos_local_exec" "wait_for_ssh" { + depends_on = [aws_instance.client] + inline = ["timeout 600s bash -c 'until ssh -i ${abspath(local_sensitive_file.private_key.filename)} -o BatchMode=Yes -o IdentitiesOnly=yes -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no Administrator@${aws_instance.client.public_ip} \"echo ready\"; do sleep 10; done'"] +} + +resource "enos_local_exec" "make_dir" { + count = var.boundary_cli_zip_path != "" ? 1 : 0 + depends_on = [ + enos_local_exec.wait_for_ssh, + ] + + inline = ["ssh -i ${abspath(local_sensitive_file.private_key.filename)} -o IdentitiesOnly=yes -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no Administrator@${aws_instance.client.public_ip} mkdir -Force ${local.test_dir}"] +} + +# copy the boundary cli zip file onto the windows client +resource "enos_local_exec" "add_boundary_cli" { + count = var.boundary_cli_zip_path != "" ? 1 : 0 + depends_on = [ + local_sensitive_file.private_key, + enos_local_exec.make_dir, + ] + + inline = ["scp -i ${abspath(local_sensitive_file.private_key.filename)} -o IdentitiesOnly=yes -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no ${local.boundary_cli_zip_path} Administrator@${aws_instance.client.public_ip}:${local.test_dir}"] +} + +resource "archive_file" "boundary_src_zip" { + count = var.boundary_src_path != "" ? 1 : 0 + type = "zip" + source_dir = var.boundary_src_path + output_path = "${path.root}/.terraform/tmp/boundary-src.zip" + excludes = ["**/enos/**", "**/node_modules/**", "bin/**", "**/.git/**", "plugins/**/*.gz", "website/**"] +} + +resource "enos_local_exec" "add_boundary_src" { + count = var.boundary_src_path != "" ? 1 : 0 + depends_on = [ + enos_local_exec.make_dir, + archive_file.boundary_src_zip + ] + + inline = ["scp -i ${abspath(local_sensitive_file.private_key.filename)} -o IdentitiesOnly=yes -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no ${archive_file.boundary_src_zip[0].output_path} Administrator@${aws_instance.client.public_ip}:${local.test_dir}"] +} + +# create a powershell script to unzip the boundary cli zip file and add it to +# the PATH +resource "local_file" "powershell_script" { + count = var.boundary_cli_zip_path != "" ? 1 : 0 + depends_on = [ + archive_file.boundary_src_zip + ] + content = templatefile("${path.module}/scripts/setup.ps1", { + boundary_cli_zip_path = "${local.test_dir}/${basename(local.boundary_cli_zip_path)}" + boundary_src_zip_path = "${local.test_dir}/${basename(archive_file.boundary_src_zip[0].output_path)}" + }) + filename = "${path.root}/.terraform/tmp/setup_boundary.ps1" +} + +# copy the powershell script onto the windows client +resource "enos_local_exec" "add_powershell_script" { + count = var.boundary_cli_zip_path != "" ? 1 : 0 + depends_on = [ + enos_local_exec.add_boundary_cli, + local_file.powershell_script, + ] + + inline = ["scp -i ${abspath(local_sensitive_file.private_key.filename)} -o IdentitiesOnly=yes -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no ${abspath(local_file.powershell_script[0].filename)} Administrator@${aws_instance.client.public_ip}:${local.test_dir}"] +} + +# run the powershell script on the windows client +resource "enos_local_exec" "run_powershell_script" { + count = var.boundary_cli_zip_path != "" ? 1 : 0 + depends_on = [ + enos_local_exec.add_boundary_cli, + enos_local_exec.add_powershell_script, + enos_local_exec.wait_for_ssh, + ] + + inline = ["ssh -i ${abspath(local_sensitive_file.private_key.filename)} -o IdentitiesOnly=yes -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no Administrator@${aws_instance.client.public_ip} ${local.test_dir}/${basename(local_file.powershell_script[0].filename)}"] +} + +# used for debug +resource "local_file" "powershell_script_output" { + depends_on = [enos_local_exec.run_powershell_script] + count = var.boundary_cli_zip_path != "" ? 1 : 0 + content = enos_local_exec.run_powershell_script[0].stdout + filename = "${path.root}/.terraform/tmp/powershell_script_output.txt" +} diff --git a/enos/modules/aws_windows_client/outputs.tf b/enos/modules/aws_windows_client/outputs.tf new file mode 100644 index 000000000..5577e639e --- /dev/null +++ b/enos/modules/aws_windows_client/outputs.tf @@ -0,0 +1,49 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: BUSL-1.1 + +// This is the public DNS address of our instance +output "public_dns_address" { + value = aws_instance.client.public_dns +} + +output "public_ip" { + value = aws_instance.client.public_ip +} + +output "public_ip_list" { + value = [aws_instance.client.public_ip] +} + +output "private_ip" { + value = aws_instance.client.private_ip +} + +output "admin_username" { + description = "The username of the administrator account" + value = "Administrator" +} + +// This is the decrypted administrator password for the EC2 instance +output "admin_password" { + description = "The password for the administrator account" + value = nonsensitive(local.admin_password) +} + +output "test_username" { + description = "The username of the test account" + value = local.test_username +} +output "test_password" { + description = "The password of the test account" + value = nonsensitive(local.test_password) +} + +output "test_dir" { + description = "The directory where the test files are stored" + value = local.test_dir +} + +output "ssh_private_key" { + description = "Private key to ssh into the windows client" + value = abspath(local_sensitive_file.private_key.filename) +} \ No newline at end of file diff --git a/enos/modules/aws_windows_client/scripts/setup.ps1 b/enos/modules/aws_windows_client/scripts/setup.ps1 new file mode 100644 index 000000000..150aef26d --- /dev/null +++ b/enos/modules/aws_windows_client/scripts/setup.ps1 @@ -0,0 +1,31 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: BUSL-1.1 + +# Unzip Boundary CLI to the same directory +$destination = Split-Path -Path ${boundary_cli_zip_path} +Expand-Archive -Path ${boundary_cli_zip_path} -DestinationPath $destination -Force + +# Add Boundary CLI to PATH +$existingPath = [Environment]::GetEnvironmentVariable( + "Path", + [EnvironmentVariableTarget]::Machine +) + +$newPath = $existingPath + ";" + $destination +[Environment]::SetEnvironmentVariable( + "Path", + $newPath, + [EnvironmentVariableTarget]::Machine +) + +# Install chocolatey (package manager) +powershell -c "irm https://community.chocolatey.org/install.ps1|iex" + +# Refreshes env to get choco on path +$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") +$env:ChocolateyInstall = Convert-Path "$((Get-Command choco).Path)\..\.." +Import-Module "$env:ChocolateyInstall/helpers/chocolateyInstaller.psm1" +refreshenv + +# install mremoteng +choco install mremoteng -y \ No newline at end of file diff --git a/enos/modules/aws_windows_client/variables.tf b/enos/modules/aws_windows_client/variables.tf new file mode 100644 index 000000000..08b45df60 --- /dev/null +++ b/enos/modules/aws_windows_client/variables.tf @@ -0,0 +1,49 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: BUSL-1.1 + +variable "vpc_id" { + type = string + description = "Id of VPC to add additional infra resources to." +} + +# ================================================================= +# ec2 instance configuration +# ================================================================= +variable "client_version" { + type = string + description = "Windows version for client, win10 and win11 supported versions" + default = "win10" +} + +variable "instance_type" { + type = string + description = "The AWS instance type to use for servers." + default = "m7i-flex.xlarge" +} + +variable "root_block_device_size" { + type = string + description = "The volume size of the root block device." + default = 128 +} + +variable "prefix" { + type = string + description = "Prefix used to name various infrastructure components. Alphanumeric characters only." + default = "enos" +} + +# ================================================================= +# Paths for source code +# ================================================================= +variable "boundary_cli_zip_path" { + description = "Path to the boundary cli zip file (windows, amd64)" + type = string + default = "" +} + +variable "boundary_src_path" { + description = "Path to the boundary source code" + type = string + default = "" +} \ No newline at end of file diff --git a/enos/modules/build_local/main.tf b/enos/modules/build_local/main.tf index 4b451235e..d8a09c80a 100644 --- a/enos/modules/build_local/main.tf +++ b/enos/modules/build_local/main.tf @@ -21,16 +21,25 @@ variable "binary_name" { default = "boundary" } +variable "artifact_name" { + default = "boundary" +} + variable "edition" { default = "oss" } +variable "goos" { + default = "linux" +} + resource "enos_local_exec" "build" { environment = { - "GOOS" = "linux", + "GOOS" = var.goos, "GOARCH" = "amd64", "CGO_ENABLED" = 0, "ARTIFACT_PATH" = var.path + "ARTIFACT_NAME" = var.artifact_name "BINARY_NAME" = var.binary_name "BUILD_TARGET" = var.build_target "EDITION" = var.edition @@ -39,5 +48,5 @@ resource "enos_local_exec" "build" { } output "artifact_path" { - value = "${var.path}/boundary.zip" + value = "${var.path}/${var.artifact_name}.zip" } diff --git a/enos/modules/build_local/templates/build.sh b/enos/modules/build_local/templates/build.sh index 160bd2f80..cbac7032f 100755 --- a/enos/modules/build_local/templates/build.sh +++ b/enos/modules/build_local/templates/build.sh @@ -14,6 +14,6 @@ root_dir="$(git rev-parse --show-toplevel)" pushd "${root_dir}" > /dev/null make ${BUILD_TARGET} -zip -j ${ARTIFACT_PATH}/boundary.zip bin/${BINARY_NAME} +zip -j ${ARTIFACT_PATH}/${ARTIFACT_NAME}.zip bin/${BINARY_NAME} popd > /dev/null diff --git a/enos/modules/test_e2e/main.tf b/enos/modules/test_e2e/main.tf index 7dac11088..8fea4ece4 100644 --- a/enos/modules/test_e2e/main.tf +++ b/enos/modules/test_e2e/main.tf @@ -156,6 +156,41 @@ variable "boundary_license" { type = string default = "" } +variable "target_rdp_user" { + description = "RDP username for target" + type = string + default = "Administrator" +} +variable "target_rdp_password" { + description = "RDP password for target" + type = string + default = "" +} +variable "target_rdp_address" { + description = "Address of target for RDP" + type = string + default = "" +} +variable "client_ip_public" { + description = "Public IP of the client machine" + type = string + default = "" +} +variable "client_username" { + description = "Username for the client machine" + type = string + default = "" +} +variable "client_password" { + description = "Password for the client machine" + type = string + default = "" +} +variable "client_test_dir" { + description = "Directory on the client machine where tests will be run" + type = string + default = "" +} variable "ip_version" { description = "ip version used to setup boundary instance, should be 4, 6, or dual" @@ -207,6 +242,13 @@ resource "enos_local_exec" "run_e2e_test" { E2E_WORKER_ADDRESS = var.worker_address E2E_MAX_PAGE_SIZE = var.max_page_size E2E_IP_VERSION = var.ip_version + E2E_TARGET_RDP_USER = var.target_rdp_user + E2E_TARGET_RDP_PASSWORD = var.target_rdp_password + E2E_TARGET_RDP_ADDRESS = var.target_rdp_address + E2E_CLIENT_IP_PUBLIC = var.client_ip_public + E2E_CLIENT_USERNAME = var.client_username + E2E_CLIENT_PASSWORD = var.client_password + E2E_CLIENT_TEST_DIR = var.client_test_dir } inline = var.debug_no_run ? [""] : [