diff --git a/enos/enos-modules.hcl b/enos/enos-modules.hcl index 5229ca30b8c..d914d4a7a1a 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 00000000000..e6d8d8716b2 --- /dev/null +++ b/enos/modules/docker_openssh_server_ca_key/custom-cont-init.d/00-trust-user-ca @@ -0,0 +1,12 @@ +#!/usr/bin/with-contenv bash + +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 00000000000..9c1e2c7197e --- /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_docker/main.tf b/enos/modules/test_e2e_docker/main.tf index 1ed8467f893..a3156194211 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 4ea6accbcdc..3f253b887e0 100644 --- a/enos/modules/test_e2e_docker/test_runner.sh +++ b/enos/modules/test_e2e_docker/test_runner.sh @@ -7,40 +7,43 @@ set -eux -o pipefail -docker run \ - --rm \ - --name test-runner \ - -e "TEST_PACKAGE=$TEST_PACKAGE" \ - -e "TEST_TIMEOUT=$TEST_TIMEOUT" \ - -e "E2E_TESTS=$E2E_TESTS" \ - -e "BOUNDARY_ADDR=$BOUNDARY_ADDR" \ - -e "E2E_PASSWORD_AUTH_METHOD_ID=$E2E_PASSWORD_AUTH_METHOD_ID" \ - -e "E2E_PASSWORD_ADMIN_LOGIN_NAME=$E2E_PASSWORD_ADMIN_LOGIN_NAME" \ - -e "E2E_PASSWORD_ADMIN_PASSWORD=$E2E_PASSWORD_ADMIN_PASSWORD" \ - -e "E2E_TARGET_IP=$E2E_TARGET_IP" \ - -e "E2E_SSH_USER=$E2E_SSH_USER" \ - -e "E2E_SSH_PORT=$E2E_SSH_PORT" \ - -e "E2E_SSH_KEY_PATH=/keys/target.pem" \ - -e "VAULT_ADDR=$VAULT_ADDR_INTERNAL" \ - -e "VAULT_TOKEN=$VAULT_TOKEN" \ - -e "E2E_VAULT_ADDR=$E2E_VAULT_ADDR" \ - -e "E2E_AWS_ACCESS_KEY_ID=$E2E_AWS_ACCESS_KEY_ID" \ - -e "E2E_AWS_SECRET_ACCESS_KEY=$E2E_AWS_SECRET_ACCESS_KEY" \ - -e "E2E_AWS_HOST_SET_FILTER=$E2E_AWS_HOST_SET_FILTER" \ - -e "E2E_AWS_HOST_SET_IPS=$E2E_AWS_HOST_SET_IPS" \ - -e "E2E_AWS_HOST_SET_FILTER2=$E2E_AWS_HOST_SET_FILTER2" \ - -e "E2E_AWS_HOST_SET_IPS2=$E2E_AWS_HOST_SET_IPS2" \ - -e "E2E_AWS_REGION=$E2E_AWS_REGION" \ - -e "E2E_AWS_BUCKET_NAME=$E2E_AWS_BUCKET_NAME" \ - -e "E2E_WORKER_TAG=$E2E_WORKER_TAG" \ - --mount type=bind,src=$BOUNDARY_DIR,dst=/src/boundary/ \ - --mount type=bind,src=$MODULE_DIR/../..,dst=/testlogs \ - --mount type=bind,src=$(go env GOCACHE),dst=/root/.cache/go-build \ - --mount type=bind,src=$(go env GOMODCACHE),dst=/go/pkg/mod \ - -v "$MODULE_DIR/test.sh:/scripts/test.sh" \ - -v "$E2E_SSH_KEY_PATH:/keys/target.pem" \ - -v "$BOUNDARY_CLI_DIR:/boundary.zip" \ - --network $TEST_NETWORK_NAME \ - --cap-add=CAP_IPC_LOCK \ - $TEST_RUNNER_IMAGE \ - /bin/sh -c /scripts/test.sh +cmd_string="docker run" +cmd_string+=" --rm" +cmd_string+=" --name test-runner" +cmd_string+=" -e TEST_PACKAGE=$TEST_PACKAGE" +cmd_string+=" -e TEST_TIMEOUT=$TEST_TIMEOUT" +cmd_string+=" -e E2E_TESTS=$E2E_TESTS" +cmd_string+=" -e BOUNDARY_ADDR=$BOUNDARY_ADDR" +cmd_string+=" -e E2E_PASSWORD_AUTH_METHOD_ID=$E2E_PASSWORD_AUTH_METHOD_ID" +cmd_string+=" -e E2E_PASSWORD_ADMIN_LOGIN_NAME=$E2E_PASSWORD_ADMIN_LOGIN_NAME" +cmd_string+=" -e E2E_PASSWORD_ADMIN_PASSWORD=$E2E_PASSWORD_ADMIN_PASSWORD" +cmd_string+=" -e E2E_TARGET_IP=$E2E_TARGET_IP" +cmd_string+=" -e E2E_SSH_USER=$E2E_SSH_USER" +cmd_string+=" -e E2E_SSH_PORT=$E2E_SSH_PORT" +cmd_string+=" -e E2E_SSH_KEY_PATH=/keys/target.pem" +cmd_string+=" -e E2E_SSH_CA_KEY=$E2E_SSH_CA_KEY" +cmd_string+=" -e VAULT_ADDR=$VAULT_ADDR_INTERNAL" +cmd_string+=" -e VAULT_TOKEN=$VAULT_TOKEN" +cmd_string+=" -e E2E_VAULT_ADDR=$E2E_VAULT_ADDR" +cmd_string+=" -e E2E_AWS_ACCESS_KEY_ID=$E2E_AWS_ACCESS_KEY_ID" +cmd_string+=" -e E2E_AWS_SECRET_ACCESS_KEY=$E2E_AWS_SECRET_ACCESS_KEY" +cmd_string+=" -e E2E_AWS_HOST_SET_FILTER=$E2E_AWS_HOST_SET_FILTER" +cmd_string+=" -e E2E_AWS_HOST_SET_IPS=$E2E_AWS_HOST_SET_IPS" +cmd_string+=" -e E2E_AWS_HOST_SET_FILTER2=$E2E_AWS_HOST_SET_FILTER2" +cmd_string+=" -e E2E_AWS_HOST_SET_IPS2=$E2E_AWS_HOST_SET_IPS2" +cmd_string+=" -e E2E_AWS_REGION=$E2E_AWS_REGION" +cmd_string+=" -e E2E_AWS_BUCKET_NAME=$E2E_AWS_BUCKET_NAME" +cmd_string+=" -e E2E_WORKER_TAG=$E2E_WORKER_TAG" +cmd_string+=" --mount type=bind,src=$BOUNDARY_DIR,dst=/src/boundary/" +cmd_string+=" --mount type=bind,src=$MODULE_DIR/../..,dst=/testlogs" +cmd_string+=" --mount type=bind,src=$(go env GOCACHE),dst=/root/.cache/go-build" +cmd_string+=" --mount type=bind,src=$(go env GOMODCACHE),dst=/go/pkg/mod" +cmd_string+=" -v $MODULE_DIR/test.sh:/scripts/test.sh" +cmd_string+=" -v $E2E_SSH_KEY_PATH:/keys/target.pem" +cmd_string+=" -v $BOUNDARY_CLI_DIR:/boundary.zip" +cmd_string+=" --network $TEST_NETWORK_NAME" +cmd_string+=" --cap-add=CAP_IPC_LOCK" +cmd_string+=" $TEST_RUNNER_IMAGE" +cmd_string+=" /bin/sh -c /scripts/test.sh" + +($cmd_string) 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 e1f9370fed2..0698007d185 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"` diff --git a/testing/internal/e2e/tests/base_with_vault/testdata/ssh-certificate-injection-role.json b/testing/internal/e2e/tests/base_with_vault/testdata/ssh-certificate-injection-role.json new file mode 100644 index 00000000000..a2f6f4018b2 --- /dev/null +++ b/testing/internal/e2e/tests/base_with_vault/testdata/ssh-certificate-injection-role.json @@ -0,0 +1,10 @@ +{ + "key_type": "ca", + "allow_user_certificates": true, + "default_user": "admin", + "default_extensions": { + "permit-pty": "" + }, + "allowed_users": "*", + "allowed_extensions": "*" +}