VAULT-9688 Vault Agent Enos test (#17837)
* VAULT-9688 First attempt at Vault Agent Enos test * VAULT-9688 remove TODO, correct indentation * VAULT-9688 enos fmt * VAULT-9688 terraform fmt * VAULT-9688 small updates * VAULT-9688 add extra comment
This commit is contained in:
parent
d2e0f771ef
commit
a7028a9d64
|
@ -51,6 +51,20 @@ module "read_license" {
|
|||
source = "./modules/read_license"
|
||||
}
|
||||
|
||||
module "vault_agent" {
|
||||
source = "./modules/vault_agent"
|
||||
|
||||
vault_install_dir = var.vault_install_dir
|
||||
vault_instance_count = var.vault_instance_count
|
||||
}
|
||||
|
||||
|
||||
module "vault_verify_agent_output" {
|
||||
source = "./modules/vault_verify_agent_output"
|
||||
|
||||
vault_instance_count = var.vault_instance_count
|
||||
}
|
||||
|
||||
module "vault_cluster" {
|
||||
source = "app.terraform.io/hashicorp-qti/aws-vault/enos"
|
||||
# source = "../../terraform-enos-aws-vault"
|
||||
|
|
|
@ -0,0 +1,219 @@
|
|||
scenario "agent" {
|
||||
matrix {
|
||||
arch = ["amd64", "arm64"]
|
||||
artifact_source = ["local", "crt", "artifactory"]
|
||||
distro = ["ubuntu", "rhel"]
|
||||
edition = ["oss", "ent"]
|
||||
}
|
||||
|
||||
terraform_cli = terraform_cli.default
|
||||
terraform = terraform.default
|
||||
providers = [
|
||||
provider.aws.default,
|
||||
provider.enos.ubuntu,
|
||||
provider.enos.rhel
|
||||
]
|
||||
|
||||
locals {
|
||||
build_tags = {
|
||||
"oss" = ["ui"]
|
||||
"ent" = ["enterprise", "ent"]
|
||||
}
|
||||
bundle_path = matrix.artifact_source != "artifactory" ? abspath(var.vault_bundle_path) : null
|
||||
dependencies_to_install = ["jq"]
|
||||
enos_provider = {
|
||||
rhel = provider.enos.rhel
|
||||
ubuntu = provider.enos.ubuntu
|
||||
}
|
||||
install_artifactory_artifact = local.bundle_path == null
|
||||
tags = merge({
|
||||
"Project Name" : var.project_name
|
||||
"Project" : "Enos",
|
||||
"Environment" : "ci"
|
||||
}, var.tags)
|
||||
vault_instance_types = {
|
||||
amd64 = "t3a.small"
|
||||
arm64 = "t4g.small"
|
||||
}
|
||||
vault_instance_type = coalesce(var.vault_instance_type, local.vault_instance_types[matrix.arch])
|
||||
}
|
||||
|
||||
step "get_local_metadata" {
|
||||
skip_step = matrix.artifact_source != "local"
|
||||
module = module.get_local_metadata
|
||||
}
|
||||
|
||||
step "build_vault" {
|
||||
module = "build_${matrix.artifact_source}"
|
||||
|
||||
variables {
|
||||
build_tags = try(var.vault_local_build_tags, local.build_tags[matrix.edition])
|
||||
bundle_path = local.bundle_path
|
||||
goarch = matrix.arch
|
||||
goos = "linux"
|
||||
artifactory_host = matrix.artifact_source == "artifactory" ? var.artifactory_host : null
|
||||
artifactory_repo = matrix.artifact_source == "artifactory" ? var.artifactory_repo : null
|
||||
artifactory_username = matrix.artifact_source == "artifactory" ? var.artifactory_username : null
|
||||
artifactory_token = matrix.artifact_source == "artifactory" ? var.artifactory_token : null
|
||||
arch = matrix.artifact_source == "artifactory" ? matrix.arch : null
|
||||
vault_product_version = var.vault_product_version
|
||||
artifact_type = matrix.artifact_source == "artifactory" ? var.vault_artifact_type : null
|
||||
distro = matrix.artifact_source == "artifactory" ? matrix.distro : null
|
||||
edition = matrix.artifact_source == "artifactory" ? matrix.edition : null
|
||||
instance_type = matrix.artifact_source == "artifactory" ? local.vault_instance_type : null
|
||||
revision = var.vault_revision
|
||||
}
|
||||
}
|
||||
|
||||
step "find_azs" {
|
||||
module = module.az_finder
|
||||
|
||||
variables {
|
||||
instance_type = [
|
||||
var.backend_instance_type,
|
||||
local.vault_instance_type
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
step "create_vpc" {
|
||||
module = module.create_vpc
|
||||
|
||||
variables {
|
||||
ami_architectures = [matrix.arch]
|
||||
availability_zones = step.find_azs.availability_zones
|
||||
common_tags = local.tags
|
||||
}
|
||||
}
|
||||
|
||||
step "read_license" {
|
||||
skip_step = matrix.edition == "oss"
|
||||
module = module.read_license
|
||||
|
||||
variables {
|
||||
file_name = abspath(joinpath(path.root, "./support/vault.hclic"))
|
||||
}
|
||||
}
|
||||
|
||||
step "create_backend_cluster" {
|
||||
module = "backend_raft"
|
||||
depends_on = [step.create_vpc]
|
||||
|
||||
providers = {
|
||||
enos = provider.enos.ubuntu
|
||||
}
|
||||
|
||||
variables {
|
||||
ami_id = step.create_vpc.ami_ids["ubuntu"][matrix.arch]
|
||||
common_tags = local.tags
|
||||
instance_type = var.backend_instance_type
|
||||
kms_key_arn = step.create_vpc.kms_key_arn
|
||||
vpc_id = step.create_vpc.vpc_id
|
||||
}
|
||||
}
|
||||
|
||||
step "create_vault_cluster" {
|
||||
module = module.vault_cluster
|
||||
depends_on = [
|
||||
step.create_backend_cluster,
|
||||
step.build_vault,
|
||||
]
|
||||
|
||||
providers = {
|
||||
enos = local.enos_provider[matrix.distro]
|
||||
}
|
||||
|
||||
variables {
|
||||
ami_id = step.create_vpc.ami_ids[matrix.distro][matrix.arch]
|
||||
common_tags = local.tags
|
||||
consul_cluster_tag = step.create_backend_cluster.consul_cluster_tag
|
||||
dependencies_to_install = local.dependencies_to_install
|
||||
instance_type = local.vault_instance_type
|
||||
kms_key_arn = step.create_vpc.kms_key_arn
|
||||
storage_backend = "raft"
|
||||
unseal_method = "shamir"
|
||||
vault_local_artifact_path = local.bundle_path
|
||||
vault_artifactory_release = local.install_artifactory_artifact ? step.build_vault.vault_artifactory_release : null
|
||||
vault_license = matrix.edition != "oss" ? step.read_license.license : null
|
||||
vpc_id = step.create_vpc.vpc_id
|
||||
}
|
||||
}
|
||||
|
||||
step "start_vault_agent" {
|
||||
module = "vault_agent"
|
||||
depends_on = [
|
||||
step.create_backend_cluster,
|
||||
step.build_vault,
|
||||
step.create_vault_cluster,
|
||||
]
|
||||
|
||||
providers = {
|
||||
enos = local.enos_provider[matrix.distro]
|
||||
}
|
||||
|
||||
variables {
|
||||
vault_instances = step.create_vault_cluster.vault_instances
|
||||
vault_root_token = step.create_vault_cluster.vault_root_token
|
||||
vault_agent_template_destination = "/tmp/agent_output.txt"
|
||||
vault_agent_template_contents = "{{ with secret \\\"auth/token/lookup-self\\\" }}orphan={{ .Data.orphan }} display_name={{ .Data.display_name }}{{ end }}"
|
||||
}
|
||||
}
|
||||
|
||||
step "verify_vault_agent_output" {
|
||||
module = module.vault_verify_agent_output
|
||||
depends_on = [
|
||||
step.create_vault_cluster,
|
||||
step.start_vault_agent,
|
||||
]
|
||||
|
||||
providers = {
|
||||
enos = local.enos_provider[matrix.distro]
|
||||
}
|
||||
|
||||
variables {
|
||||
vault_instances = step.create_vault_cluster.vault_instances
|
||||
vault_agent_template_destination = "/tmp/agent_output.txt"
|
||||
vault_agent_expected_output = "orphan=true display_name=approle"
|
||||
}
|
||||
}
|
||||
|
||||
output "vault_cluster_instance_ids" {
|
||||
description = "The Vault cluster instance IDs"
|
||||
value = step.create_vault_cluster.instance_ids
|
||||
}
|
||||
|
||||
output "vault_cluster_pub_ips" {
|
||||
description = "The Vault cluster public IPs"
|
||||
value = step.create_vault_cluster.instance_public_ips
|
||||
}
|
||||
|
||||
output "vault_cluster_priv_ips" {
|
||||
description = "The Vault cluster private IPs"
|
||||
value = step.create_vault_cluster.instance_private_ips
|
||||
}
|
||||
|
||||
output "vault_cluster_key_id" {
|
||||
description = "The Vault cluster Key ID"
|
||||
value = step.create_vault_cluster.key_id
|
||||
}
|
||||
|
||||
output "vault_cluster_root_token" {
|
||||
description = "The Vault cluster root token"
|
||||
value = step.create_vault_cluster.vault_root_token
|
||||
}
|
||||
|
||||
output "vault_cluster_unseal_keys_b64" {
|
||||
description = "The Vault cluster unseal keys"
|
||||
value = step.create_vault_cluster.vault_unseal_keys_b64
|
||||
}
|
||||
|
||||
output "vault_cluster_unseal_keys_hex" {
|
||||
description = "The Vault cluster unseal keys hex"
|
||||
value = step.create_vault_cluster.vault_unseal_keys_hex
|
||||
}
|
||||
|
||||
output "vault_cluster_tag" {
|
||||
description = "The Vault cluster tag"
|
||||
value = step.create_vault_cluster.vault_cluster_tag
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
terraform {
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
}
|
||||
enos = {
|
||||
source = "app.terraform.io/hashicorp-qti/enos"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
variable "vault_agent_template_destination" {
|
||||
type = string
|
||||
description = "The destination of the template rendered by Agent"
|
||||
}
|
||||
|
||||
variable "vault_agent_template_contents" {
|
||||
type = string
|
||||
description = "The template contents to be rendered by Agent"
|
||||
}
|
||||
|
||||
variable "vault_root_token" {
|
||||
type = string
|
||||
description = "The Vault root token"
|
||||
}
|
||||
|
||||
variable "vault_instances" {
|
||||
type = map(object({
|
||||
private_ip = string
|
||||
public_ip = string
|
||||
}))
|
||||
description = "The Vault cluster instances that were created"
|
||||
}
|
||||
|
||||
variable "vault_instance_count" {
|
||||
type = number
|
||||
description = "How many vault instances are in the cluster"
|
||||
}
|
||||
|
||||
variable "vault_install_dir" {
|
||||
type = string
|
||||
description = "The directory where the Vault binary will be installed"
|
||||
}
|
||||
|
||||
locals {
|
||||
vault_instances = {
|
||||
for idx in range(var.vault_instance_count) : idx => {
|
||||
public_ip = values(var.vault_instances)[idx].public_ip
|
||||
private_ip = values(var.vault_instances)[idx].private_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "enos_remote_exec" "set_up_approle_auth_and_agent" {
|
||||
content = templatefile("${path.module}/templates/set-up-approle-and-agent.sh", {
|
||||
vault_install_dir = var.vault_install_dir
|
||||
vault_token = var.vault_root_token
|
||||
vault_agent_template_destination = var.vault_agent_template_destination
|
||||
vault_agent_template_contents = var.vault_agent_template_contents
|
||||
})
|
||||
|
||||
transport = {
|
||||
ssh = {
|
||||
host = local.vault_instances[0].public_ip
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
binpath=${vault_install_dir}/vault
|
||||
|
||||
fail() {
|
||||
echo "$1" 1>&2
|
||||
return 1
|
||||
}
|
||||
|
||||
test -x "$binpath" || fail "unable to locate vault binary at $binpath"
|
||||
|
||||
export VAULT_ADDR='http://127.0.0.1:8200'
|
||||
export VAULT_TOKEN='${vault_token}'
|
||||
|
||||
# If approle was already enabled, disable it as we're about to re-enable it (the || true is so we don't fail if it doesn't already exist)
|
||||
$binpath auth disable approle || true
|
||||
|
||||
approle_create_status=$($binpath auth enable approle)
|
||||
|
||||
approle_status=$($binpath write auth/approle/role/agent-role secret_id_ttl=700h token_num_uses=1000 token_ttl=600h token_max_ttl=700h secret_id_num_uses=1000)
|
||||
|
||||
ROLEID=$($binpath read --format=json auth/approle/role/agent-role/role-id | jq -r '.data.role_id')
|
||||
|
||||
if [[ "$ROLEID" == '' ]]; then
|
||||
fail "expected ROLEID to be nonempty, but it is empty"
|
||||
fi
|
||||
|
||||
SECRETID=$($binpath write -f --format=json auth/approle/role/agent-role/secret-id | jq -r '.data.secret_id')
|
||||
|
||||
if [[ "$SECRETID" == '' ]]; then
|
||||
fail "expected SECRETID to be nonempty, but it is empty"
|
||||
fi
|
||||
|
||||
echo $ROLEID > /tmp/role-id
|
||||
echo $SECRETID > /tmp/secret-id
|
||||
|
||||
cat > /tmp/vault-agent.hcl <<- EOM
|
||||
pid_file = "/tmp/pidfile"
|
||||
|
||||
vault {
|
||||
address = "http://127.0.0.1:8200"
|
||||
tls_skip_verify = true
|
||||
retry {
|
||||
num_retries = 10
|
||||
}
|
||||
}
|
||||
|
||||
cache {
|
||||
enforce_consistency = "always"
|
||||
use_auto_auth_token = true
|
||||
}
|
||||
|
||||
listener "tcp" {
|
||||
address = "127.0.0.1:8100"
|
||||
tls_disable = true
|
||||
}
|
||||
|
||||
template {
|
||||
destination = "${vault_agent_template_destination}"
|
||||
contents = "${vault_agent_template_contents}"
|
||||
exec {
|
||||
command = "pkill -F /tmp/pidfile"
|
||||
}
|
||||
}
|
||||
|
||||
auto_auth {
|
||||
method {
|
||||
type = "approle"
|
||||
config = {
|
||||
role_id_file_path = "/tmp/role-id"
|
||||
secret_id_file_path = "/tmp/secret-id"
|
||||
}
|
||||
}
|
||||
sink {
|
||||
type = "file"
|
||||
config = {
|
||||
path = "/tmp/token"
|
||||
}
|
||||
}
|
||||
}
|
||||
EOM
|
||||
|
||||
# If Agent is still running from a previous run, kill it
|
||||
pkill -F /tmp/pidfile || true
|
||||
|
||||
# If the template file already exists, remove it
|
||||
rm ${vault_agent_template_destination} || true
|
||||
|
||||
# Run agent (it will kill itself when it finishes rendering the template)
|
||||
$binpath agent -config=/tmp/vault-agent.hcl > /tmp/agent-logs.txt 2>&1
|
|
@ -0,0 +1,53 @@
|
|||
terraform {
|
||||
required_providers {
|
||||
enos = {
|
||||
source = "app.terraform.io/hashicorp-qti/enos"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
variable "vault_agent_template_destination" {
|
||||
type = string
|
||||
description = "The destination of the template rendered by Agent"
|
||||
}
|
||||
|
||||
variable "vault_agent_expected_output" {
|
||||
type = string
|
||||
description = "The output that's expected in the rendered template at vault_agent_template_destination"
|
||||
}
|
||||
|
||||
variable "vault_instance_count" {
|
||||
type = number
|
||||
description = "How many vault instances are in the cluster"
|
||||
}
|
||||
|
||||
variable "vault_instances" {
|
||||
type = map(object({
|
||||
private_ip = string
|
||||
public_ip = string
|
||||
}))
|
||||
description = "The vault cluster instances that were created"
|
||||
}
|
||||
|
||||
locals {
|
||||
vault_instances = {
|
||||
for idx in range(var.vault_instance_count) : idx => {
|
||||
public_ip = values(var.vault_instances)[idx].public_ip
|
||||
private_ip = values(var.vault_instances)[idx].private_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "enos_remote_exec" "verify_vault_agent_output" {
|
||||
content = templatefile("${path.module}/templates/verify-vault-agent-output.sh", {
|
||||
vault_agent_template_destination = var.vault_agent_template_destination
|
||||
vault_agent_expected_output = var.vault_agent_expected_output
|
||||
vault_instances = jsonencode(local.vault_instances)
|
||||
})
|
||||
|
||||
transport = {
|
||||
ssh = {
|
||||
host = local.vault_instances[0].public_ip
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
fail() {
|
||||
echo "$1" 1>&2
|
||||
return 1
|
||||
}
|
||||
|
||||
actual_output=$(cat ${vault_agent_template_destination})
|
||||
if [[ "$actual_output" != "${vault_agent_expected_output}" ]]; then
|
||||
fail "expected '${vault_agent_expected_output}' to be the Agent output, but got: '$actual_output'"
|
||||
fi
|
Loading…
Reference in New Issue