diff --git a/enos/enos-modules.hcl b/enos/enos-modules.hcl index 5229ca30b8..d914d4a7a1 100644 --- a/enos/enos-modules.hcl +++ b/enos/enos-modules.hcl @@ -154,6 +154,10 @@ module "docker_openssh_server" { source = "./modules/docker_openssh_server" } +module "docker_openssh_server_ca_key" { + source = "./modules/docker_openssh_server_ca_key" +} + module "docker_network" { source = "./modules/docker_network" } diff --git a/enos/modules/docker_openssh_server_ca_key/custom-cont-init.d/00-trust-user-ca b/enos/modules/docker_openssh_server_ca_key/custom-cont-init.d/00-trust-user-ca new file mode 100644 index 0000000000..1df6e85104 --- /dev/null +++ b/enos/modules/docker_openssh_server_ca_key/custom-cont-init.d/00-trust-user-ca @@ -0,0 +1,14 @@ +#!/usr/bin/with-contenv bash +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +cp /ca/ca-key.pub /etc/ssh/ca-key.pub +chown 1000:1000 /etc/ssh/ca-key.pub +chmod 644 /etc/ssh/ca-key.pub +echo TrustedUserCAKeys /etc/ssh/ca-key.pub >> /etc/ssh/sshd_config +echo PermitTTY yes >> /etc/ssh/sshd_config +sed -i 's/X11Forwarding no/X11Forwarding yes/' /etc/ssh/sshd_config +echo "X11UseLocalhost no" >> /etc/ssh/sshd_config + +apk update +apk add xterm util-linux dbus ttf-freefont xauth firefox diff --git a/enos/modules/docker_openssh_server_ca_key/main.tf b/enos/modules/docker_openssh_server_ca_key/main.tf new file mode 100644 index 0000000000..9c1e2c7197 --- /dev/null +++ b/enos/modules/docker_openssh_server_ca_key/main.tf @@ -0,0 +1,122 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +terraform { + required_providers { + docker = { + source = "kreuzwerker/docker" + version = "3.0.1" + } + + tls = { + source = "hashicorp/tls" + version = "4.0.4" + } + + enos = { + source = "app.terraform.io/hashicorp-qti/enos" + } + } +} + +variable "image_name" { + description = "Name of Docker Image" + type = string + default = "docker.mirror.hashicorp.services/linuxserver/openssh-server:latest" +} +variable "network_name" { + description = "Name of Docker Network" + type = string +} +variable "container_name" { + description = "Name of Docker Container" + type = string + default = "openssh-server" +} +variable "target_user" { + description = "SSH username for target" + type = string + default = "ubuntu" +} +variable "private_key_file_path" { + description = "Local Path to key used to SSH onto created hosts" + type = string +} + +data "tls_public_key" "host_key_openssh" { + private_key_openssh = file(var.private_key_file_path) +} + +resource "tls_private_key" "ca_key" { + algorithm = "RSA" + rsa_bits = 4096 +} + +data "tls_public_key" "ca_key" { + private_key_openssh = tls_private_key.ca_key.private_key_openssh +} + +locals { + ssh_public_key = data.tls_public_key.host_key_openssh.public_key_openssh + ca_public_key = data.tls_public_key.ca_key.public_key_openssh +} + +resource "docker_image" "openssh_server" { + name = var.image_name + keep_locally = true +} + +resource "docker_container" "openssh_server" { + image = docker_image.openssh_server.image_id + name = var.container_name + env = [ + "PUID=1000", + "PGID=1000", + "TZ=US/Eastern", + "USER_NAME=${var.target_user}", + "PUBLIC_KEY=${local.ssh_public_key}", + ] + networks_advanced { + name = var.network_name + } + ports { + internal = 2222 + external = 2222 + } + volumes { + host_path = format("%s/%s", abspath(path.module), "/custom-cont-init.d") + container_path = "/custom-cont-init.d" + } + upload { + content_base64 = base64encode(tls_private_key.ca_key.private_key_openssh) + file = "/ca/ca-key" + } + upload { + content_base64 = base64encode(local.ca_public_key) + file = "/ca/ca-key.pub" + } +} + +resource "enos_local_exec" "wait" { + depends_on = [ + docker_container.openssh_server + ] + + inline = ["timeout 20s bash -c 'until ssh -t -t -i ${var.private_key_file_path} -p 2222 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o IdentitiesOnly=yes ${var.target_user}@localhost hostname; do sleep 2; done'"] +} + +output "user" { + value = var.target_user +} + +output "address" { + value = docker_container.openssh_server.network_data[0].ip_address +} + +output "port" { + value = "2222" +} + +output "ca_key" { + value = base64encode(tls_private_key.ca_key.private_key_openssh) +} diff --git a/enos/modules/test_e2e/main.tf b/enos/modules/test_e2e/main.tf index ab1a04d037..2407771e2c 100644 --- a/enos/modules/test_e2e/main.tf +++ b/enos/modules/test_e2e/main.tf @@ -156,6 +156,7 @@ resource "enos_local_exec" "run_e2e_test" { E2E_SSH_USER = var.target_user, E2E_SSH_PORT = var.target_port, E2E_SSH_KEY_PATH = local.aws_ssh_private_key_path, + E2E_SSH_CA_KEY = "", VAULT_ADDR = local.vault_addr, VAULT_TOKEN = var.vault_root_token, E2E_VAULT_ADDR = local.vault_addr_internal, diff --git a/enos/modules/test_e2e_docker/main.tf b/enos/modules/test_e2e_docker/main.tf index 1ed8467f89..a315619421 100644 --- a/enos/modules/test_e2e_docker/main.tf +++ b/enos/modules/test_e2e_docker/main.tf @@ -90,6 +90,11 @@ variable "target_port" { type = string default = "" } +variable "target_ca_key" { + description = "CA Private Key (base64 encoded)" + type = string + default = "" +} variable "vault_addr" { description = "External network address of Vault. Will be converted to a URL below" type = string @@ -202,6 +207,7 @@ resource "enos_local_exec" "run_e2e_test" { E2E_SSH_USER = var.target_user, E2E_SSH_PORT = var.target_port, E2E_SSH_KEY_PATH = local.aws_ssh_private_key_path, + E2E_SSH_CA_KEY = var.target_ca_key, VAULT_ADDR = local.vault_addr, VAULT_ADDR_INTERNAL = local.vault_addr_internal, VAULT_TOKEN = var.vault_root_token, diff --git a/enos/modules/test_e2e_docker/test_runner.sh b/enos/modules/test_e2e_docker/test_runner.sh index 4ea6accbcd..05b144e9fc 100644 --- a/enos/modules/test_e2e_docker/test_runner.sh +++ b/enos/modules/test_e2e_docker/test_runner.sh @@ -20,6 +20,7 @@ docker run \ -e "E2E_TARGET_IP=$E2E_TARGET_IP" \ -e "E2E_SSH_USER=$E2E_SSH_USER" \ -e "E2E_SSH_PORT=$E2E_SSH_PORT" \ + -e "E2E_SSH_CA_KEY=$E2E_SSH_CA_KEY" \ -e "E2E_SSH_KEY_PATH=/keys/target.pem" \ -e "VAULT_ADDR=$VAULT_ADDR_INTERNAL" \ -e "VAULT_TOKEN=$VAULT_TOKEN" \ diff --git a/testing/internal/e2e/tests/base_with_vault/env_test.go b/testing/internal/e2e/tests/base_with_vault/env_test.go index e1f9370fed..0698007d18 100644 --- a/testing/internal/e2e/tests/base_with_vault/env_test.go +++ b/testing/internal/e2e/tests/base_with_vault/env_test.go @@ -9,7 +9,9 @@ type config struct { TargetIp string `envconfig:"E2E_TARGET_IP" required:"true"` // e.g. 192.168.0.1 TargetSshUser string `envconfig:"E2E_SSH_USER" required:"true"` // e.g. ubuntu TargetSshKeyPath string `envconfig:"E2E_SSH_KEY_PATH" required:"true"` // e.g. /Users/username/key.pem - TargetPort string `envconfig:"E2E_SSH_PORT" required:"true"` + TargetPort string `envconfig:"E2E_SSH_PORT" required:"true"` // e.g. 22 + // Note: Key is base64 encoded + TargetCaKey string `envconfig:"E2E_SSH_CA_KEY" required:"true"` // VaultAddr is the address that the Boundary server uses to interact with the running Vault instance VaultAddr string `envconfig:"E2E_VAULT_ADDR" required:"true"` // e.g. "http://127.0.0.1:8200" VaultSecretPath string `envconfig:"E2E_VAULT_SECRET_PATH" default:"e2e_secrets"`