Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VAULT-30187: Create Enos AWS Engine tests #29566

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions enos/ci/service-user-iam/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ data "aws_iam_policy_document" "enos_scenario" {
"iam:DeleteRolePolicy",
"iam:DetachRolePolicy",
"iam:GetInstanceProfile",
"iam:GetPolicy",
"iam:GetRole",
"iam:GetRolePolicy",
"iam:ListAccountAliases",
Expand Down
1 change: 1 addition & 0 deletions enos/enos-scenario-agent.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,7 @@ scenario "agent" {

output "secrets_engines_state" {
description = "The state of configured secrets engines"
sensitive = true
value = step.verify_secrets_engines_create.state
}

Expand Down
1 change: 1 addition & 0 deletions enos/enos-scenario-autopilot.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -910,6 +910,7 @@ scenario "autopilot" {

output "secrets_engines_state" {
description = "The state of configured secrets engines"
sensitive = true
value = step.verify_secrets_engines_create.state
}

Expand Down
1 change: 1 addition & 0 deletions enos/enos-scenario-dr-replication.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -1308,6 +1308,7 @@ scenario "dr_replication" {

output "secrets_engines_state" {
description = "The state of configured secrets engines"
sensitive = true
value = step.verify_secrets_engines_on_primary.state
}

Expand Down
1 change: 1 addition & 0 deletions enos/enos-scenario-pr-replication.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -1288,6 +1288,7 @@ scenario "pr_replication" {

output "secrets_engines_state" {
description = "The state of configured secrets engines"
sensitive = true
value = step.verify_secrets_engines_on_primary.state
}

Expand Down
1 change: 1 addition & 0 deletions enos/enos-scenario-proxy.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,7 @@ scenario "proxy" {

output "secrets_engines_state" {
description = "The state of configured secrets engines"
sensitive = true
value = step.verify_secrets_engines_create.state
}

Expand Down
1 change: 1 addition & 0 deletions enos/enos-scenario-seal-ha.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -1132,6 +1132,7 @@ scenario "seal_ha" {

output "secrets_engines_state" {
description = "The state of configured secrets engines"
sensitive = true
value = step.verify_secrets_engines_create.state
}

Expand Down
1 change: 1 addition & 0 deletions enos/enos-scenario-smoke.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,7 @@ scenario "smoke" {

output "secrets_engines_state" {
description = "The state of configured secrets engines"
sensitive = true
value = step.verify_secrets_engines_create.state
}

Expand Down
1 change: 1 addition & 0 deletions enos/enos-scenario-upgrade.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -841,6 +841,7 @@ scenario "upgrade" {

output "secrets_engines_state" {
description = "The state of configured secrets engines"
sensitive = true
value = step.verify_secrets_engines_create.state
}

Expand Down
102 changes: 102 additions & 0 deletions enos/modules/verify_secrets_engines/modules/create/aws.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1

locals {
// Variables
aws_mount = "aws"
vault_aws_role = "enos_test_role"
my_email = split("/", data.aws_caller_identity.current.arn)[2]

// Output
aws_output = {
aws_role = data.aws_iam_role.premade_demo_assumed_role.name
aws_role_arn = data.aws_iam_role.premade_demo_assumed_role.arn
aws_policy_arn = data.aws_iam_policy.premade_demo_user_policy.arn
aws_user_name = aws_iam_user.aws_enos_test_user.name
aws_access_key = aws_iam_access_key.aws_enos_test_user.id
aws_secret_key = aws_iam_access_key.aws_enos_test_user.secret
mount = local.aws_mount
region = data.aws_region.current.name
vault_aws_role = local.vault_aws_role
}
}

data "aws_caller_identity" "current" {}

data "aws_region" "current" {}

# Using Pre-made policy and role
data "aws_iam_policy" "premade_demo_user_policy" {
name = "DemoUser"
}

data "aws_iam_role" "premade_demo_assumed_role" {
name = "vault-assumed-role-credentials-demo"
}

# Creating new test user
resource "aws_iam_user" "aws_enos_test_user" {
name = "demo-${local.my_email}"
permissions_boundary = data.aws_iam_policy.premade_demo_user_policy.arn
force_destroy = true
}

resource "aws_iam_user_policy_attachment" "aws_enos_test_user" {
user = aws_iam_user.aws_enos_test_user.name
policy_arn = data.aws_iam_policy.premade_demo_user_policy.arn
}

resource "aws_iam_access_key" "aws_enos_test_user" {
user = aws_iam_user.aws_enos_test_user.name
lifecycle {
prevent_destroy = false
}
}

# Enable AWS secrets engine
resource "enos_remote_exec" "secrets_enable_aws_secret" {
environment = {
ENGINE = local.aws_mount
MOUNT = local.aws_mount
VAULT_ADDR = var.vault_addr
VAULT_TOKEN = var.vault_root_token
VAULT_INSTALL_DIR = var.vault_install_dir
}

scripts = [abspath("${path.module}/../../scripts/secrets-enable.sh")]

transport = {
ssh = {
host = var.leader_host.public_ip
}
}
}

# Generate AWS Credentials
resource "enos_remote_exec" "aws_generate_roles" {
depends_on = [enos_remote_exec.secrets_enable_aws_secret]
for_each = var.hosts

environment = {
AWS_REGION = local.aws_output.region
ENGINE = local.aws_mount
MOUNT = local.aws_mount
AWS_USER_NAME = local.aws_output.aws_user_name
AWS_POLICY_ARN = local.aws_output.aws_policy_arn
AWS_ROLE_ARN = local.aws_output.aws_role_arn
AWS_ACCESS_KEY_ID = local.aws_output.aws_access_key
AWS_SECRET_ACCESS_KEY = local.aws_output.aws_secret_key
VAULT_AWS_ROLE = local.vault_aws_role
VAULT_ADDR = var.vault_addr
VAULT_TOKEN = var.vault_root_token
VAULT_INSTALL_DIR = var.vault_install_dir
}

scripts = [abspath("${path.module}/../../scripts/aws-generate-roles.sh")]

transport = {
ssh = {
host = each.value.public_ip
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,6 @@ output "state" {
identity = local.identity_output
kv = local.kv_output
pki = local.pki_output
aws = local.aws_output
}
}
28 changes: 28 additions & 0 deletions enos/modules/verify_secrets_engines/modules/read/aws.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1

# Verify PKI Certificate
resource "enos_remote_exec" "aws_verify_new_creds" {
for_each = var.hosts

environment = {
AWS_REGION = "${var.create_state.aws.region}"
MOUNT = "${var.create_state.aws.mount}"
AWS_USER_NAME = "${var.create_state.aws.aws_user_name}"
AWS_ACCESS_KEY_ID = "${var.create_state.aws.aws_access_key}"
AWS_SECRET_ACCESS_KEY = "${var.create_state.aws.aws_secret_key}"
VAULT_AWS_ROLE = "${var.create_state.aws.vault_aws_role}"
VAULT_ADDR = var.vault_addr
VAULT_TOKEN = var.vault_root_token
VAULT_INSTALL_DIR = var.vault_install_dir
}

scripts = [abspath("${path.module}/../../scripts/aws-verify-new-creds.sh")]

transport = {
ssh = {
host = each.value.public_ip
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#!/usr/bin/env bash
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1

set -e

fail() {
echo "$1" 1>&2
exit 1
}

[[ -z "$MOUNT" ]] && fail "MOUNT env variable has not been set"
[[ -z "$VAULT_ADDR" ]] && fail "VAULT_ADDR env variable has not been set"
[[ -z "$VAULT_INSTALL_DIR" ]] && fail "VAULT_INSTALL_DIR env variable has not been set"
[[ -z "$VAULT_TOKEN" ]] && fail "VAULT_TOKEN env variable has not been set"
[[ -z "$VAULT_AWS_ROLE" ]] && fail "VAULT_AWS_ROLE env variable has not been set"
[[ -z "$AWS_REGION" ]] && fail "AWS_REGION env variable has not been set"
[[ -z "$AWS_POLICY_ARN" ]] && fail "AWS_POLICY_ARN env variable has not been set"
[[ -z "$AWS_ROLE_ARN" ]] && fail "AWS_ROLE_ARN env variable has not been set"
[[ -z "$AWS_USER_NAME" ]] && fail "AWS_USER_NAME env variable has not been set"
[[ -z "$AWS_ACCESS_KEY_ID" ]] && fail "AWS_ACCESS_KEY_ID env variable has not been set"
[[ -z "$AWS_SECRET_ACCESS_KEY" ]] && fail "AWS_SECRET_ACCESS_KEY env variable has not been set"

binpath=${VAULT_INSTALL_DIR}/vault
test -x "$binpath" || fail "unable to locate vault binary at $binpath"

export VAULT_FORMAT=json

while true; do
echo -e "Waiting for IAM user to be done setting up... \n"
# Fetch the IAM user creation date and convert it to a Unix timestamp
create_timestamp=$(aws iam get-user --user-name ${AWS_USER_NAME} --query 'User.CreateDate' --output text | sed 's/\([+-][0-9]\{2\}:[0-9]\{2\}\)$//' | date -f - "+%s")
if (( $(date +%s) - create_timestamp > 75 )); then
break
fi
sleep 2
done

echo -e "Configuring Vault AWS \n"
USERNAME_TEMPLATE="{{ if (eq .Type \"STS\") }}{{ printf \"${AWS_USER_NAME}-%s-%s\" (random 20) (unix_time) | truncate 32 }}{{ else }}{{ printf \"${AWS_USER_NAME}-%s-%s\" (unix_time) (random 20) | truncate 60 }}{{ end }}"
"$binpath" write "${MOUNT}/config/root" access_key="${AWS_ACCESS_KEY_ID}" secret_key="${AWS_SECRET_ACCESS_KEY}" region="${AWS_REGION}" username_template="${USERNAME_TEMPLATE}"

echo -e "Creating Role to create user \n"
"$binpath" write "aws/roles/${VAULT_AWS_ROLE}" \
credential_type=iam_user \
permissions_boundary_arn="${AWS_POLICY_ARN}" \
policy_document=-<<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["ec2:DescribeRegions"],
"Resource": ["*"]
}
]
}
EOF

echo -e "Verifying root config \n"
"$binpath" read "${MOUNT}/config/root"
ROOT_USERNAME_TEMPLATE=$("$binpath" read "${MOUNT}/config/root" | jq -r '.data.username_template')
[[ "$ROOT_USERNAME_TEMPLATE" == *"$AWS_USER_NAME"* ]] || fail "Uername Template does not include the current role"
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/usr/bin/env bash
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1

set -e

fail() {
echo "$1" 1>&2
exit 1
}


[[ -z "$MOUNT" ]] && fail "MOUNT env variable has not been set"
[[ -z "$VAULT_ADDR" ]] && fail "VAULT_ADDR env variable has not been set"
[[ -z "$VAULT_INSTALL_DIR" ]] && fail "VAULT_INSTALL_DIR env variable has not been set"
[[ -z "$VAULT_TOKEN" ]] && fail "VAULT_TOKEN env variable has not been set"
[[ -z "$VAULT_AWS_ROLE" ]] && fail "VAULT_AWS_ROLE env variable has not been set"
[[ -z "$AWS_REGION" ]] && fail "AWS_REGION env variable has not been set"
[[ -z "$AWS_USER_NAME" ]] && fail "AWS_USER_NAME env variable has not been set"
[[ -z "$AWS_ACCESS_KEY_ID" ]] && fail "AWS_ACCESS_KEY_ID env variable has not been set"
[[ -z "$AWS_SECRET_ACCESS_KEY" ]] && fail "AWS_SECRET_ACCESS_KEY env variable has not been set"

binpath=${VAULT_INSTALL_DIR}/vault
test -x "$binpath" || fail "unable to locate vault binary at $binpath"

export VAULT_FORMAT=json

echo -e "Configuring Vault AWS \n"
USERNAME_TEMPLATE="{{ if (eq .Type \"STS\") }}{{ printf \"${AWS_USER_NAME}-%s-%s\" (random 20) (unix_time) | truncate 32 }}{{ else }}{{ printf \"${AWS_USER_NAME}-%s-%s\" (unix_time) (random 20) | truncate 60 }}{{ end }}"
"$binpath" write "${MOUNT}/config/root" access_key="${AWS_ACCESS_KEY_ID}" secret_key="${AWS_SECRET_ACCESS_KEY}" region="${AWS_REGION}" username_template="${USERNAME_TEMPLATE}"

echo -e "Verifying root config \n"
"$binpath" read "${MOUNT}/config/root"
ROOT_USERNAME_TEMPLATE=$("$binpath" read "${MOUNT}/config/root" | jq -r '.data.username_template')
[[ "$ROOT_USERNAME_TEMPLATE" == *"$AWS_USER_NAME"* ]] || fail "Uername Template does not include the current role"

echo -e "Verifying roles list \n"
"$binpath" list "${MOUNT}/roles"
ROLE=$("$binpath" list "${MOUNT}/roles" | jq -r '.[]')
[[ -z "$ROLE" ]] && fail "No AWS roles created!"

echo -e "Generate New Credentials \n"
TEMP_IAM_USER=$("$binpath" read "${MOUNT}/creds/${VAULT_AWS_ROLE}") || fail "Failed to generate new credentials for iam user: ${VAULT_AWS_ROLE}"
TEMP_ACCESS_KEY=$(echo ${TEMP_IAM_USER} | jq -r '.data.access_key') || fail "Failed to get access key from: ${VAULT_AWS_ROLE}"
if [[ -z "$TEMP_ACCESS_KEY" && "$TEMP_ACCESS_KEY" != "$AWS_USER_NAME" ]]; then
failed "The new access key is empty or is matching the old one: ${TEMP_ACCESS_KEY}"
fi
Loading