Create IPv6 and dual stack enos tests (#5212)
Co-authored-by: Danielle Miu <29378233+DanielleMiu@users.noreply.github.com> Co-authored-by: Damian Debkowski <damian.debkowski@hashicorp.com>
This commit is contained in:
59 files changed
+1773
-301
No files matched your search
@@ -76,7 +76,7 @@ jobs:
|
||||
fail-fast: false # don't fail as that can skip required cleanup steps for jobs
|
||||
matrix:
|
||||
include:
|
||||
- filter: 'e2e_aws builder:crt'
|
||||
- filter: 'e2e_aws builder:crt ip_version:4'
|
||||
- filter: 'e2e_database'
|
||||
- filter: 'e2e_docker_base builder:crt'
|
||||
- filter: 'e2e_docker_base_plus builder:crt'
|
||||
@@ -279,7 +279,7 @@ jobs:
|
||||
- name: Split matrix filter name
|
||||
id: split
|
||||
run: |
|
||||
SCENARIO=$(echo "${{ matrix.filter }}" | cut -d' ' -f1)
|
||||
SCENARIO=$(echo "${{ matrix.filter }}" | cut -d' ' -f1,3 | sed 's/:/_/g')
|
||||
echo fragment="${SCENARIO}" >> "$GITHUB_OUTPUT"
|
||||
- name: Upload e2e tests output
|
||||
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
|
||||
|
||||
@@ -82,6 +82,18 @@ module "aws_vpc" {
|
||||
}
|
||||
}
|
||||
|
||||
module "aws_vpc_ipv6" {
|
||||
source = "./modules/aws_vpc_ipv6"
|
||||
|
||||
environment = var.environment
|
||||
common_tags = {
|
||||
"Project" : "Enos",
|
||||
"Project Name" : "qti-enos-boundary",
|
||||
"Enos User" : var.enos_user,
|
||||
"Environment" : var.environment
|
||||
}
|
||||
}
|
||||
|
||||
module "read_license" {
|
||||
source = "./modules/read_license"
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ scenario "e2e_aws_base_with_vault" {
|
||||
module = module.read_license
|
||||
|
||||
variables {
|
||||
file_name = local.license_path
|
||||
license_path = local.license_path
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,6 +108,7 @@ scenario "e2e_aws_base_with_vault" {
|
||||
]
|
||||
|
||||
variables {
|
||||
deploy = true
|
||||
ami_id = step.create_base_infra.ami_ids["ubuntu"]["amd64"]
|
||||
instance_type = var.vault_instance_type
|
||||
instance_count = 1
|
||||
|
||||
@@ -45,7 +45,7 @@ scenario "e2e_aws_base" {
|
||||
module = module.read_license
|
||||
|
||||
variables {
|
||||
file_name = local.license_path
|
||||
license_path = local.license_path
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,18 +11,22 @@ scenario "e2e_aws" {
|
||||
]
|
||||
|
||||
matrix {
|
||||
builder = ["local", "crt"]
|
||||
builder = ["local", "crt"]
|
||||
ip_version = ["4"]
|
||||
}
|
||||
|
||||
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
|
||||
license_path = abspath(var.boundary_license_path != null ? var.boundary_license_path : joinpath(path.root, "./support/boundary.hclic"))
|
||||
boundary_license_path = abspath(var.boundary_license_path != null ? var.boundary_license_path : joinpath(path.root, "./support/boundary.hclic"))
|
||||
vault_license_path = abspath(var.vault_license_path != null ? var.vault_license_path : joinpath(path.root, "./support/vault.hclic"))
|
||||
|
||||
build_path = {
|
||||
"local" = "/tmp",
|
||||
"crt" = var.crt_bundle_path == null ? null : abspath(var.crt_bundle_path)
|
||||
}
|
||||
|
||||
tags = merge({
|
||||
"Project Name" : var.project_name
|
||||
"Project" : "Enos",
|
||||
@@ -41,12 +45,12 @@ scenario "e2e_aws" {
|
||||
}
|
||||
}
|
||||
|
||||
step "read_license" {
|
||||
step "read_boundary_license" {
|
||||
skip_step = var.boundary_edition == "oss"
|
||||
module = module.read_license
|
||||
|
||||
variables {
|
||||
file_name = local.license_path
|
||||
license_path = local.boundary_license_path
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +68,8 @@ scenario "e2e_aws" {
|
||||
}
|
||||
|
||||
step "create_base_infra" {
|
||||
module = module.aws_vpc
|
||||
module = matrix.ip_version == "4" ? module.aws_vpc : module.aws_vpc_ipv6
|
||||
|
||||
depends_on = [
|
||||
step.find_azs,
|
||||
]
|
||||
@@ -75,30 +80,59 @@ scenario "e2e_aws" {
|
||||
}
|
||||
}
|
||||
|
||||
step "create_vault_cluster" {
|
||||
module = module.vault
|
||||
depends_on = [
|
||||
step.create_base_infra,
|
||||
]
|
||||
|
||||
variables {
|
||||
deploy = matrix.ip_version == "4" ? false : 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 = matrix.ip_version
|
||||
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_db_password,
|
||||
step.build_boundary
|
||||
step.build_boundary,
|
||||
step.create_vault_cluster
|
||||
]
|
||||
|
||||
variables {
|
||||
boundary_binary_name = var.boundary_binary_name
|
||||
boundary_install_dir = local.boundary_install_dir
|
||||
boundary_license = var.boundary_edition != "oss" ? step.read_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.artifact_path
|
||||
ubuntu_ami_id = step.create_base_infra.ami_ids["ubuntu"]["amd64"]
|
||||
vpc_id = step.create_base_infra.vpc_id
|
||||
vpc_tag_module = step.create_base_infra.vpc_tag_module
|
||||
worker_count = var.worker_count
|
||||
worker_instance_type = var.worker_instance_type
|
||||
aws_region = var.aws_region
|
||||
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.artifact_path
|
||||
ubuntu_ami_id = step.create_base_infra.ami_ids["ubuntu"]["amd64"]
|
||||
vpc_id = step.create_base_infra.vpc_id
|
||||
vpc_tag_module = step.create_base_infra.vpc_tag_module
|
||||
worker_count = var.worker_count
|
||||
worker_instance_type = var.worker_instance_type
|
||||
aws_region = var.aws_region
|
||||
ip_version = matrix.ip_version
|
||||
controller_config_file_path = matrix.ip_version == "4" ? "templates/controller.hcl" : "templates/controller_vault_kms.hcl"
|
||||
worker_config_file_path = matrix.ip_version == "4" ? "templates/worker.hcl" : "templates/worker_vault_kms.hcl"
|
||||
vault_address = matrix.ip_version == "4" ? "" : step.create_vault_cluster.instance_public_ips[0]
|
||||
vault_transit_token = matrix.ip_version == "4" ? "" : step.create_vault_cluster.vault_transit_token
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,6 +163,9 @@ scenario "e2e_aws" {
|
||||
target_count = var.target_count <= 1 ? 2 : var.target_count
|
||||
additional_tags = step.create_tag1_inputs.tag_map
|
||||
subnet_ids = step.create_boundary_cluster.subnet_ids
|
||||
ingress_cidr = matrix.ip_version == "4" ? ["10.0.0.0/8"] : []
|
||||
ingress_ipv6_cidr = step.create_boundary_cluster.worker_ipv6_cidr
|
||||
ip_version = matrix.ip_version
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,7 +190,7 @@ scenario "e2e_aws" {
|
||||
}
|
||||
|
||||
locals {
|
||||
egress_tag = "egress"
|
||||
isolated_tag = "isolated"
|
||||
}
|
||||
|
||||
step "create_isolated_worker" {
|
||||
@@ -164,13 +201,16 @@ scenario "e2e_aws" {
|
||||
availability_zones = step.create_base_infra.availability_zone_names
|
||||
kms_key_arn = step.create_base_infra.kms_key_arn
|
||||
ubuntu_ami_id = step.create_base_infra.ami_ids["ubuntu"]["amd64"]
|
||||
vpc_cidr = step.create_base_infra.vpc_cidr
|
||||
vpc_cidr_ipv6 = matrix.ip_version == "4" ? "" : step.create_base_infra.vpc_cidr_ipv6
|
||||
local_artifact_path = step.build_boundary.artifact_path
|
||||
boundary_install_dir = local.boundary_install_dir
|
||||
name_prefix = step.create_boundary_cluster.name_prefix
|
||||
cluster_tag = step.create_boundary_cluster.cluster_tag
|
||||
controller_addresses = step.create_boundary_cluster.public_controller_addresses
|
||||
controller_sg_id = step.create_boundary_cluster.controller_aux_sg_id
|
||||
worker_type_tags = [local.egress_tag]
|
||||
worker_type_tags = [local.isolated_tag]
|
||||
ip_version = matrix.ip_version
|
||||
config_file_path = "templates/worker.hcl"
|
||||
}
|
||||
}
|
||||
@@ -204,8 +244,10 @@ scenario "e2e_aws" {
|
||||
vpc_id = step.create_base_infra.vpc_id
|
||||
target_count = 1
|
||||
subnet_ids = step.create_isolated_worker.subnet_ids
|
||||
ingress_cidr = ["10.13.9.0/24"]
|
||||
ingress_cidr = matrix.ip_version == "4" ? ["10.13.9.0/24"] : []
|
||||
ingress_ipv6_cidr = step.create_isolated_worker.worker_ipv6_cidr
|
||||
additional_tags = step.create_tag2_inputs.tag_map
|
||||
ip_version = matrix.ip_version
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,9 +279,10 @@ scenario "e2e_aws" {
|
||||
aws_host_set_filter2 = step.create_tag2_inputs.tag_string
|
||||
aws_host_set_ips2 = step.create_isolated_target.target_private_ips
|
||||
target_address = step.create_isolated_target.target_private_ips[0]
|
||||
worker_tag_egress = local.egress_tag
|
||||
worker_tag_isolated = local.isolated_tag
|
||||
max_page_size = step.create_boundary_cluster.max_page_size
|
||||
aws_region = var.aws_region
|
||||
ip_version = matrix.ip_version
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ scenario "e2e_database" {
|
||||
module = module.read_license
|
||||
|
||||
variables {
|
||||
file_name = local.license_path
|
||||
license_path = local.license_path
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ scenario "e2e_database" {
|
||||
module = module.test_e2e
|
||||
depends_on = [
|
||||
step.create_targets_with_tag,
|
||||
step.iam_setup,
|
||||
step.iam_setup
|
||||
]
|
||||
|
||||
variables {
|
||||
|
||||
@@ -68,7 +68,7 @@ scenario "e2e_docker_base_plus" {
|
||||
module = module.read_license
|
||||
|
||||
variables {
|
||||
file_name = local.license_path
|
||||
license_path = local.license_path
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ scenario "e2e_docker_base_with_gcp" {
|
||||
module = module.read_license
|
||||
|
||||
variables {
|
||||
file_name = local.license_path
|
||||
license_path = local.license_path
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ scenario "e2e_docker_base_with_vault" {
|
||||
module = module.read_license
|
||||
|
||||
variables {
|
||||
file_name = local.license_path
|
||||
license_path = local.license_path
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ scenario "e2e_docker_base_with_worker" {
|
||||
module = module.read_license
|
||||
|
||||
variables {
|
||||
file_name = local.license_path
|
||||
license_path = local.license_path
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ scenario "e2e_docker_base" {
|
||||
module = module.read_license
|
||||
|
||||
variables {
|
||||
file_name = local.license_path
|
||||
license_path = local.license_path
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ scenario "e2e_docker_worker_registration_controller_led" {
|
||||
module = module.read_license
|
||||
|
||||
variables {
|
||||
file_name = local.license_path
|
||||
license_path = local.license_path
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ scenario "e2e_docker_worker_registration_worker_led" {
|
||||
module = module.read_license
|
||||
|
||||
variables {
|
||||
file_name = local.license_path
|
||||
license_path = local.license_path
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ scenario "e2e_ui_aws" {
|
||||
module = module.read_license
|
||||
|
||||
variables {
|
||||
file_name = local.license_path
|
||||
license_path = local.license_path
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,6 +114,7 @@ scenario "e2e_ui_aws" {
|
||||
]
|
||||
|
||||
variables {
|
||||
deploy = true
|
||||
ami_id = step.create_base_infra.ami_ids["ubuntu"]["amd64"]
|
||||
instance_type = var.vault_instance_type
|
||||
instance_count = 1
|
||||
|
||||
@@ -68,7 +68,7 @@ scenario "e2e_ui_docker" {
|
||||
module = module.read_license
|
||||
|
||||
variables {
|
||||
file_name = local.license_path
|
||||
license_path = local.license_path
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -175,6 +175,12 @@ variable "boundary_license_path" {
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "vault_license_path" {
|
||||
description = "Vault license path"
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "go_test_timeout" {
|
||||
description = "Timeout for go test used in e2e tests"
|
||||
type = string
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
## running ipv6-only enos tests without an ipv6 connection
|
||||
|
||||
1. create ipv6-enabled vpc
|
||||
2. create ipv6-enabled subnet
|
||||
3. create internet gateway and route
|
||||
- likely needs more detail
|
||||
4. create t2-medium instance
|
||||
- attach the vpc
|
||||
- add public ipv4
|
||||
- add public ipv6
|
||||
- use at least 20gb storage
|
||||
5. create a new policy and attach it to the ec2 instance
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "VisualEditor0",
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"ec2:DescribeImages",
|
||||
"ec2:DescribeInstanceTypeOfferings",
|
||||
"ec2:DescribeAvailabilityZones",
|
||||
"ec2:CreateVpc",
|
||||
"kms:CreateKey",
|
||||
"ec2:CreateTags",
|
||||
"kms:DescribeKey",
|
||||
"ec2:DescribeVpcs",
|
||||
"kms:ScheduleKeyDeletion",
|
||||
"kms:GetKeyPolicy",
|
||||
"kms:GetKeyRotationStatus",
|
||||
"kms:ListResourceTags",
|
||||
"kms:CreateAlias",
|
||||
"ec2:DeleteVpc",
|
||||
"ec2:ModifyVpcAttribute",
|
||||
"kms:ListAliases",
|
||||
"ec2:DescribeVpcAttribute",
|
||||
"kms:DeleteAlias",
|
||||
"ec2:CreateSubnet",
|
||||
"ec2:CreateInternetGateway",
|
||||
"ec2:CreateSecurityGroup",
|
||||
"ec2:DescribeSecurityGroups",
|
||||
"ec2:AttachInternetGateway",
|
||||
"ec2:DescribeSubnets",
|
||||
"ec2:DescribeNetworkInterfaces",
|
||||
"ec2:DeleteSubnet",
|
||||
"ec2:DeleteSecurityGroup",
|
||||
"ec2:RevokeSecurityGroupEgress",
|
||||
"ec2:ModifySubnetAttribute",
|
||||
"ec2:DetachInternetGateway",
|
||||
"ec2:AuthorizeSecurityGroupIngress",
|
||||
"ec2:DeleteInternetGateway",
|
||||
"ec2:AuthorizeSecurityGroupEgress",
|
||||
"ec2:DescribeInternetGateways",
|
||||
"ec2:DescribeRouteTables",
|
||||
"ec2:CreateRoute",
|
||||
"ec2:RevokeSecurityGroupIngress",
|
||||
"iam:CreateUser",
|
||||
"iam:DeleteUser",
|
||||
"iam:TagUser",
|
||||
"iam:GetUser",
|
||||
"iam:ListGroupsForUser",
|
||||
"iam:CreateAccessKey",
|
||||
"iam:DeleteAccessKey",
|
||||
"iam:PutUserPolicy",
|
||||
"iam:GetUserPolicy",
|
||||
"iam:DeleteUserPolicy",
|
||||
"ec2:DeleteRoute",
|
||||
"ec2:RunInstances",
|
||||
"ec2:DescribeInstances",
|
||||
"rds:CreateDBSubnetGroup",
|
||||
"iam:CreateRole",
|
||||
"elasticloadbalancing:DescribeTargetGroups",
|
||||
"ec2:TerminateInstances",
|
||||
"ec2:DescribeInstanceTypes",
|
||||
"rds:DescribeDBSubnetGroups",
|
||||
"iam:GetRole",
|
||||
"elasticloadbalancing:CreateTargetGroup",
|
||||
"elasticloadbalancing:DeleteTargetGroup",
|
||||
"rds:DeleteDBSubnetGroup",
|
||||
"iam:ListInstanceProfilesForRole",
|
||||
"iam:DeleteRole",
|
||||
"ec2:DescribeTags",
|
||||
"rds:ListTagsForResource",
|
||||
"iam:ListRolePolicies",
|
||||
"elasticloadbalancing:AddTags",
|
||||
"ec2:DescribeInstanceAttribute",
|
||||
"rds:CreateDBInstance",
|
||||
"iam:ListAttachedRolePolicies",
|
||||
"elasticloadbalancing:ModifyTargetGroupAttributes",
|
||||
"rds:DeleteDBInstance",
|
||||
"ec2:DescribeVolumes",
|
||||
"rds:AddTagsToResource",
|
||||
"iam:PutRolePolicy",
|
||||
"iam:DeleteRolePolicy",
|
||||
"iam:CreateInstanceProfile",
|
||||
"iam:DeleteInstanceProfile",
|
||||
"elasticloadbalancing:DescribeTargetGroupAttributes",
|
||||
"ec2:DescribeInstanceCreditSpecifications",
|
||||
"rds:DescribeDBInstances",
|
||||
"iam:GetRolePolicy",
|
||||
"iam:GetInstanceProfile",
|
||||
"elasticloadbalancing:DescribeTags",
|
||||
"iam:RemoveRoleFromInstanceProfile",
|
||||
"iam:AddRoleToInstanceProfile",
|
||||
"elasticloadbalancing:DescribeLoadBalancers",
|
||||
"elasticloadbalancing:RegisterTargets",
|
||||
"elasticloadbalancing:CreateLoadBalancer",
|
||||
"elasticloadbalancing:DeregisterTargets",
|
||||
"elasticloadbalancing:ModifyLoadBalancerAttributes",
|
||||
"elasticloadbalancing:DeleteLoadBalancer",
|
||||
"elasticloadbalancing:DescribeLoadBalancerAttributes",
|
||||
"elasticloadbalancing:CreateListener",
|
||||
"elasticloadbalancing:DescribeListeners",
|
||||
"elasticloadbalancing:DeleteListener",
|
||||
"ec2:AssociateRouteTable",
|
||||
"ec2:DisassociateRouteTable",
|
||||
"ec2:CreateIpam",
|
||||
"ec2:DeleteIpam",
|
||||
"ec2:ModifyIpam",
|
||||
"ec2:DescribeIpams",
|
||||
"ec2:CreateIpamPool",
|
||||
"ec2:DeleteIpamPool",
|
||||
"ec2:ModifyIpamPool",
|
||||
"ec2:DescribeIpamPools",
|
||||
"ec2:AllocateIpamPoolCidr",
|
||||
"ec2:ProvisionIpamPoolCidr",
|
||||
"s3:CreateBucket",
|
||||
"s3:DeleteBucket",
|
||||
"s3:ListBucket",
|
||||
"s3:ListAllMyBuckets",
|
||||
"s3:GetAccelerateConfiguration",
|
||||
"s3:PutAccelerateConfiguration",
|
||||
"s3:GetLifecycleConfiguration",
|
||||
"s3:PutLifecycleConfiguration",
|
||||
"s3:GetReplicationConfiguration",
|
||||
"s3:PutReplicationConfiguration",
|
||||
"s3:GetBucket*",
|
||||
"s3:PutBucket*",
|
||||
"s3:GetEncryptionConfiguration",
|
||||
"s3:PutEncryptionConfiguration",
|
||||
"ec2:AttachNetworkInterface",
|
||||
"ec2:DetachNetworkInterface",
|
||||
"iam:CreateServiceLinkedRole",
|
||||
"iam:DeleteServiceLinkedRole",
|
||||
"iam:PassRole"
|
||||
],
|
||||
"Resource": "*"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
6. change sudo password
|
||||
- `sudo passwd ec2-user`
|
||||
- enter new password (doesn't need to be secure)
|
||||
7. install git
|
||||
- `sudo yum install git`
|
||||
8. install homebrew
|
||||
- https://brew.sh/
|
||||
- follow post-install instructions given by homebrew in the cli (install gcc and other utils)
|
||||
9. install enos deps
|
||||
- https://github.com/hashicorp/boundary/blob/main/enos/README.md
|
||||
- you do **not** need to install doormat
|
||||
- you will need to create/add/use a github token on the ec2 instance
|
||||
- https://docs.github.com/en/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account
|
||||
- also install nvm and run `nvm install 20` and `nvm use 20`
|
||||
- https://github.com/nvm-sh/nvm?tab=readme-ov-file#installing-and-updating
|
||||
10. you should now be able to run enos instances from the enos directory
|
||||
@@ -1,11 +1,22 @@
|
||||
# Copyright (c) HashiCorp, Inc.
|
||||
# SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
locals {
|
||||
stack = {
|
||||
"4" = "ipv4",
|
||||
"dual" = "dualstack",
|
||||
"6" = "dualstack-without-public-ipv4",
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_alb" "boundary_alb" {
|
||||
name = "boundary-alb-${random_string.cluster_id.result}"
|
||||
depends_on = [aws_instance.controller]
|
||||
security_groups = [aws_security_group.boundary_alb_sg.id]
|
||||
subnets = data.aws_subnets.infra.ids
|
||||
|
||||
ip_address_type = lookup(local.stack, var.ip_version, local.stack["4"])
|
||||
|
||||
tags = merge(local.common_tags,
|
||||
{
|
||||
Name = "boundary-alb-${random_string.cluster_id.result}"
|
||||
@@ -14,10 +25,11 @@ resource "aws_alb" "boundary_alb" {
|
||||
}
|
||||
|
||||
resource "aws_alb_target_group" "boundary_tg" {
|
||||
name = "boundary-tg-${random_string.cluster_id.result}"
|
||||
port = var.listener_api_port
|
||||
protocol = "HTTP"
|
||||
vpc_id = var.vpc_id
|
||||
name = "boundary-tg-${random_string.cluster_id.result}"
|
||||
port = var.listener_api_port
|
||||
protocol = "HTTP"
|
||||
vpc_id = var.vpc_id
|
||||
ip_address_type = var.ip_version == "6" ? "ipv6" : "ipv4"
|
||||
|
||||
health_check {
|
||||
path = var.healthcheck_path
|
||||
@@ -26,6 +38,7 @@ resource "aws_alb_target_group" "boundary_tg" {
|
||||
timeout = 2
|
||||
healthy_threshold = 2
|
||||
}
|
||||
|
||||
tags = merge(local.common_tags,
|
||||
{
|
||||
Name = "boundary-tg-${random_string.cluster_id.result}"
|
||||
@@ -45,6 +58,7 @@ resource "aws_alb_listener" "boundary" {
|
||||
load_balancer_arn = aws_alb.boundary_alb.arn
|
||||
port = var.alb_listener_api_port
|
||||
protocol = "HTTP"
|
||||
|
||||
default_action {
|
||||
target_group_arn = aws_alb_target_group.boundary_tg.arn
|
||||
type = "forward"
|
||||
|
||||
@@ -15,6 +15,7 @@ resource "aws_instance" "controller" {
|
||||
key_name = var.ssh_aws_keypair
|
||||
iam_instance_profile = aws_iam_instance_profile.boundary_profile.name
|
||||
monitoring = var.controller_monitoring
|
||||
ipv6_address_count = local.network_stack[var.ip_version].ipv6_address_count
|
||||
|
||||
root_block_device {
|
||||
iops = var.controller_ebs_iops
|
||||
@@ -41,6 +42,7 @@ resource "aws_instance" "worker" {
|
||||
key_name = var.ssh_aws_keypair
|
||||
iam_instance_profile = aws_iam_instance_profile.boundary_profile.name
|
||||
monitoring = var.worker_monitoring
|
||||
ipv6_address_count = local.network_stack[var.ip_version].ipv6_address_count
|
||||
|
||||
root_block_device {
|
||||
iops = var.worker_ebs_iops
|
||||
@@ -69,7 +71,7 @@ resource "enos_bundle_install" "controller" {
|
||||
|
||||
transport = {
|
||||
ssh = {
|
||||
host = aws_instance.controller[tonumber(each.value)].public_ip
|
||||
host = var.ip_version == "6" ? aws_instance.controller[tonumber(each.value)].ipv6_addresses[0] : aws_instance.controller[tonumber(each.value)].public_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -86,7 +88,7 @@ resource "enos_remote_exec" "update_path_controller" {
|
||||
|
||||
transport = {
|
||||
ssh = {
|
||||
host = aws_instance.controller[tonumber(each.value)].public_ip
|
||||
host = var.ip_version == "6" ? aws_instance.controller[tonumber(each.value)].ipv6_addresses[0] : aws_instance.controller[tonumber(each.value)].public_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -101,26 +103,29 @@ resource "enos_file" "controller_config" {
|
||||
destination = "/etc/boundary/boundary.hcl"
|
||||
content = templatefile("${path.module}/${var.controller_config_file_path}", {
|
||||
id = each.value
|
||||
dbuser = var.db_user,
|
||||
dbpass = var.db_pass,
|
||||
dbuser = var.db_user
|
||||
dbpass = var.db_pass
|
||||
dbhost = var.db_host == null ? aws_db_instance.boundary[0].address : var.db_host
|
||||
dbport = var.db_port
|
||||
dbname = local.db_name,
|
||||
dbname = local.db_name
|
||||
db_max_open_connections = var.db_max_open_connections
|
||||
kms_key_id = data.aws_kms_key.kms_key.id,
|
||||
local_ipv4 = aws_instance.controller[tonumber(each.value)].private_ip
|
||||
kms_key_id = data.aws_kms_key.kms_key.id
|
||||
listener_address = var.ip_version == "4" ? "0.0.0.0" : "[::]"
|
||||
api_port = var.listener_api_port
|
||||
ops_port = var.listener_ops_port
|
||||
cluster_address = var.ip_version == "4" ? aws_instance.controller[tonumber(each.value)].private_ip : format("[%s]", aws_instance.controller[tonumber(each.value)].ipv6_addresses[0])
|
||||
cluster_port = var.listener_cluster_port
|
||||
region = var.aws_region
|
||||
max_page_size = var.max_page_size
|
||||
audit_log_dir = local.audit_log_directory
|
||||
vault_address = local.network_stack[var.ip_version].vault_address
|
||||
vault_transit_token = var.vault_transit_token
|
||||
})
|
||||
for_each = toset([for idx in range(var.controller_count) : tostring(idx)])
|
||||
|
||||
transport = {
|
||||
ssh = {
|
||||
host = aws_instance.controller[tonumber(each.value)].public_ip
|
||||
host = var.ip_version == "6" ? aws_instance.controller[tonumber(each.value)].ipv6_addresses[0] : aws_instance.controller[tonumber(each.value)].public_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -135,7 +140,7 @@ resource "enos_boundary_init" "controller" {
|
||||
|
||||
transport = {
|
||||
ssh = {
|
||||
host = try(aws_instance.controller[0].public_ip, null)
|
||||
host = try(var.ip_version == "6" ? aws_instance.controller[0].ipv6_addresses[0] : aws_instance.controller[0].public_ip, null)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,7 +157,7 @@ resource "enos_boundary_start" "controller_start" {
|
||||
|
||||
transport = {
|
||||
ssh = {
|
||||
host = aws_instance.controller[tonumber(each.value)].public_ip
|
||||
host = var.ip_version == "6" ? aws_instance.controller[tonumber(each.value)].ipv6_addresses[0] : aws_instance.controller[tonumber(each.value)].public_ip
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,10 +182,11 @@ resource "enos_remote_exec" "create_controller_audit_log_dir" {
|
||||
|
||||
transport = {
|
||||
ssh = {
|
||||
host = aws_instance.controller[tonumber(each.value)].public_ip
|
||||
host = var.ip_version == "6" ? aws_instance.controller[tonumber(each.value)].ipv6_addresses[0] : aws_instance.controller[tonumber(each.value)].public_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "enos_bundle_install" "worker" {
|
||||
depends_on = [aws_instance.worker]
|
||||
for_each = toset([for idx in range(var.worker_count) : tostring(idx)])
|
||||
@@ -193,7 +199,7 @@ resource "enos_bundle_install" "worker" {
|
||||
|
||||
transport = {
|
||||
ssh = {
|
||||
host = aws_instance.worker[tonumber(each.value)].public_ip
|
||||
host = var.ip_version == "6" ? aws_instance.worker[tonumber(each.value)].ipv6_addresses[0] : aws_instance.worker[tonumber(each.value)].public_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -210,7 +216,7 @@ resource "enos_remote_exec" "update_path_worker" {
|
||||
|
||||
transport = {
|
||||
ssh = {
|
||||
host = aws_instance.worker[tonumber(each.value)].public_ip
|
||||
host = var.ip_version == "6" ? aws_instance.worker[tonumber(each.value)].ipv6_addresses[0] : aws_instance.worker[tonumber(each.value)].public_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -221,19 +227,22 @@ resource "enos_file" "worker_config" {
|
||||
content = templatefile("${path.module}/${var.worker_config_file_path}", {
|
||||
id = each.value
|
||||
kms_key_id = data.aws_kms_key.kms_key.id,
|
||||
controller_ips = jsonencode(aws_instance.controller.*.private_ip),
|
||||
public_addr = aws_instance.worker[tonumber(each.value)].public_ip
|
||||
controller_ips = var.ip_version == "4" ? jsonencode(aws_instance.controller.*.private_ip) : jsonencode(formatlist("[%s]:9201", flatten(aws_instance.controller.*.ipv6_addresses)))
|
||||
listener_address = var.ip_version == "4" ? "0.0.0.0" : "[::]"
|
||||
public_address = var.ip_version == "6" ? format("[%s]", aws_instance.worker[tonumber(each.value)].ipv6_addresses[0]) : aws_instance.worker[tonumber(each.value)].public_ip
|
||||
region = var.aws_region
|
||||
type = jsonencode(var.worker_type_tags)
|
||||
recording_storage_path = var.recording_storage_path
|
||||
audit_log_dir = local.audit_log_directory
|
||||
hcp_boundary_cluster_id = var.hcp_boundary_cluster_id
|
||||
vault_address = local.network_stack[var.ip_version].vault_address
|
||||
vault_transit_token = var.vault_transit_token
|
||||
})
|
||||
for_each = toset([for idx in range(var.worker_count) : tostring(idx)])
|
||||
|
||||
transport = {
|
||||
ssh = {
|
||||
host = aws_instance.worker[tonumber(each.value)].public_ip
|
||||
host = var.ip_version == "6" ? aws_instance.worker[tonumber(each.value)].ipv6_addresses[0] : aws_instance.worker[tonumber(each.value)].public_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -250,7 +259,7 @@ resource "enos_boundary_start" "worker_start" {
|
||||
|
||||
transport = {
|
||||
ssh = {
|
||||
host = aws_instance.worker[tonumber(each.value)].public_ip
|
||||
host = var.ip_version == "6" ? aws_instance.worker[tonumber(each.value)].ipv6_addresses[0] : aws_instance.worker[tonumber(each.value)].public_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -270,7 +279,7 @@ resource "enos_remote_exec" "create_worker_audit_log_dir" {
|
||||
|
||||
transport = {
|
||||
ssh = {
|
||||
host = aws_instance.worker[tonumber(each.value)].public_ip
|
||||
host = var.ip_version == "6" ? aws_instance.worker[tonumber(each.value)].ipv6_addresses[0] : aws_instance.worker[tonumber(each.value)].public_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -282,7 +291,7 @@ resource "enos_remote_exec" "get_worker_token" {
|
||||
inline = ["timeout 10s bash -c 'set -eo pipefail; until journalctl -u boundary.service | cat | grep \"Worker Auth Registration Request: .*\" | rev | cut -d \" \" -f 1 | rev | xargs; do sleep 2; done'"]
|
||||
transport = {
|
||||
ssh = {
|
||||
host = aws_instance.worker[tonumber(each.value)].public_ip
|
||||
host = var.ip_version == "6" ? aws_instance.worker[tonumber(each.value)].ipv6_addresses[0] : aws_instance.worker[tonumber(each.value)].public_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,49 @@ locals {
|
||||
Pet = random_pet.default.id
|
||||
},
|
||||
)
|
||||
|
||||
network_stack = {
|
||||
"4" = {
|
||||
ingress_cidr_blocks = flatten([
|
||||
formatlist("%s/32", data.enos_environment.localhost.public_ipv4_addresses),
|
||||
join(",", data.aws_vpc.infra.cidr_block_associations.*.cidr_block),
|
||||
formatlist("%s/32", var.alb_sg_additional_ips),
|
||||
])
|
||||
ingress_ipv6_cidr_blocks = [],
|
||||
egress_cidr_blocks = ["0.0.0.0/0"],
|
||||
egress_ipv6_cidr_blocks = [],
|
||||
ipv6_address_count = 0,
|
||||
vault_address = var.vault_address,
|
||||
},
|
||||
"6" = {
|
||||
ingress_cidr_blocks = [],
|
||||
ingress_ipv6_cidr_blocks = flatten([
|
||||
try([for ip in coalesce(data.enos_environment.localhost.public_ipv6_addresses, []) : cidrsubnet("${ip}/64", 0, 0)], []),
|
||||
[data.aws_vpc.infra.ipv6_cidr_block],
|
||||
[for ip in var.alb_sg_additional_ipv6_ips : cidrsubnet("${ip}/64", 0, 0)],
|
||||
])
|
||||
egress_cidr_blocks = [],
|
||||
egress_ipv6_cidr_blocks = ["::/0"],
|
||||
ipv6_address_count = 1,
|
||||
vault_address = format("[%s]", var.vault_address)
|
||||
},
|
||||
"dual" = {
|
||||
ingress_cidr_blocks = flatten([
|
||||
formatlist("%s/32", data.enos_environment.localhost.public_ipv4_addresses),
|
||||
join(",", data.aws_vpc.infra.cidr_block_associations.*.cidr_block),
|
||||
formatlist("%s/32", var.alb_sg_additional_ips),
|
||||
])
|
||||
ingress_ipv6_cidr_blocks = flatten([
|
||||
try([for ip in coalesce(data.enos_environment.localhost.public_ipv6_addresses, []) : cidrsubnet("${ip}/64", 0, 0)], []),
|
||||
[data.aws_vpc.infra.ipv6_cidr_block],
|
||||
[for ip in var.alb_sg_additional_ipv6_ips : cidrsubnet("${ip}/64", 0, 0)],
|
||||
]),
|
||||
egress_cidr_blocks = ["0.0.0.0/0"],
|
||||
egress_ipv6_cidr_blocks = ["::/0"],
|
||||
ipv6_address_count = 1,
|
||||
vault_address = try(format("[%s]", var.vault_address), "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "random_string" "cluster_id" {
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
|
||||
output "controller_ips" {
|
||||
description = "Public IPs of boundary controllers"
|
||||
value = aws_instance.controller.*.public_ip
|
||||
value = var.ip_version == "6" ? flatten(aws_instance.controller.*.ipv6_addresses) : aws_instance.controller.*.public_ip
|
||||
}
|
||||
|
||||
output "worker_ips" {
|
||||
description = "Public IPs of boundary workers"
|
||||
value = aws_instance.worker.*.public_ip
|
||||
value = var.ip_version == "6" ? flatten(aws_instance.worker.*.ipv6_addresses) : aws_instance.worker.*.public_ip
|
||||
}
|
||||
|
||||
output "alb_hostname" {
|
||||
@@ -208,7 +208,7 @@ output "cluster_tag" {
|
||||
}
|
||||
|
||||
output "public_controller_addresses" {
|
||||
value = aws_instance.controller[*].public_ip
|
||||
value = var.ip_version == "4" ? aws_instance.controller[*].public_ip : aws_instance.controller[*].ipv6_addresses[0]
|
||||
}
|
||||
|
||||
output "controller_aux_sg_id" {
|
||||
@@ -232,3 +232,13 @@ output "worker_tokens" {
|
||||
for token in enos_remote_exec.get_worker_token : trimspace(token.stdout)
|
||||
], null)
|
||||
}
|
||||
|
||||
output "worker_cidr" {
|
||||
description = "List of ipv4 subnets of all workers"
|
||||
value = formatlist("%s/32", aws_instance.worker.*.public_ip)
|
||||
}
|
||||
|
||||
output "worker_ipv6_cidr" {
|
||||
description = "List of ipv6 subnets of all workers"
|
||||
value = distinct([for ip in flatten(aws_instance.worker.*.ipv6_addresses) : cidrsubnet("${ip}/64", 0, 0)])
|
||||
}
|
||||
@@ -17,9 +17,11 @@ resource "aws_db_instance" "boundary" {
|
||||
instance_class = var.db_class
|
||||
monitoring_interval = var.db_monitoring_interval
|
||||
monitoring_role_arn = var.db_monitoring_role_arn
|
||||
publicly_accessible = true
|
||||
publicly_accessible = false
|
||||
db_name = local.db_name
|
||||
|
||||
network_type = var.ip_version == "4" ? "IPV4" : "DUAL"
|
||||
|
||||
// username and password must not be provided when restoring from a snapshot
|
||||
username = local.is_restored_db ? null : var.db_user
|
||||
password = local.is_restored_db ? null : var.db_pass
|
||||
|
||||
@@ -22,24 +22,22 @@ resource "aws_security_group" "boundary_sg" {
|
||||
|
||||
# SSH
|
||||
ingress {
|
||||
from_port = 22
|
||||
to_port = 22
|
||||
protocol = "tcp"
|
||||
cidr_blocks = flatten([formatlist("%s/32", data.enos_environment.localhost.public_ipv4_addresses)])
|
||||
from_port = 22
|
||||
to_port = 22
|
||||
protocol = "tcp"
|
||||
cidr_blocks = local.network_stack[var.ip_version].ingress_cidr_blocks
|
||||
ipv6_cidr_blocks = local.network_stack[var.ip_version].ingress_ipv6_cidr_blocks
|
||||
}
|
||||
|
||||
dynamic "ingress" {
|
||||
for_each = local.listener_ports
|
||||
|
||||
content {
|
||||
cidr_blocks = flatten([
|
||||
formatlist("%s/32", data.enos_environment.localhost.public_ipv4_addresses),
|
||||
join(",", data.aws_vpc.infra.cidr_block_associations.*.cidr_block),
|
||||
])
|
||||
cidr_blocks = local.network_stack[var.ip_version].ingress_cidr_blocks
|
||||
ipv6_cidr_blocks = local.network_stack[var.ip_version].ingress_ipv6_cidr_blocks
|
||||
description = ingress.key
|
||||
from_port = ingress.value
|
||||
to_port = ingress.value
|
||||
ipv6_cidr_blocks = []
|
||||
prefix_list_ids = []
|
||||
protocol = "tcp"
|
||||
self = null
|
||||
@@ -48,10 +46,11 @@ resource "aws_security_group" "boundary_sg" {
|
||||
}
|
||||
|
||||
egress {
|
||||
from_port = 0
|
||||
to_port = 0
|
||||
protocol = "-1"
|
||||
cidr_blocks = ["0.0.0.0/0"]
|
||||
from_port = 0
|
||||
to_port = 0
|
||||
protocol = "-1"
|
||||
cidr_blocks = local.network_stack[var.ip_version].egress_cidr_blocks
|
||||
ipv6_cidr_blocks = local.network_stack[var.ip_version].egress_ipv6_cidr_blocks
|
||||
}
|
||||
|
||||
tags = merge(
|
||||
@@ -86,27 +85,29 @@ resource "aws_security_group" "boundary_alb_sg" {
|
||||
|
||||
content {
|
||||
cidr_blocks = flatten([
|
||||
formatlist("%s/32", data.enos_environment.localhost.public_ipv4_addresses),
|
||||
join(",", data.aws_vpc.infra.cidr_block_associations.*.cidr_block),
|
||||
try(format("%s/32", aws_instance.controller.0.public_ip), []),
|
||||
formatlist("%s/32", var.alb_sg_additional_ips)
|
||||
])
|
||||
description = ingress.key
|
||||
from_port = ingress.value
|
||||
to_port = ingress.value
|
||||
ipv6_cidr_blocks = []
|
||||
prefix_list_ids = []
|
||||
protocol = "tcp"
|
||||
self = null
|
||||
security_groups = []
|
||||
local.network_stack[var.ip_version].ingress_cidr_blocks]
|
||||
)
|
||||
ipv6_cidr_blocks = flatten([
|
||||
try(cidrsubnet("${aws_instance.controller.0.ipv6_addresses[0]}/64", 0, 0), []),
|
||||
local.network_stack[var.ip_version].ingress_ipv6_cidr_blocks]
|
||||
)
|
||||
description = ingress.key
|
||||
from_port = ingress.value
|
||||
to_port = ingress.value
|
||||
prefix_list_ids = []
|
||||
protocol = "tcp"
|
||||
self = null
|
||||
security_groups = []
|
||||
}
|
||||
}
|
||||
|
||||
egress {
|
||||
from_port = 0
|
||||
to_port = 0
|
||||
protocol = "-1"
|
||||
cidr_blocks = ["0.0.0.0/0"]
|
||||
from_port = 0
|
||||
to_port = 0
|
||||
protocol = "-1"
|
||||
cidr_blocks = local.network_stack[var.ip_version].egress_cidr_blocks
|
||||
ipv6_cidr_blocks = local.network_stack[var.ip_version].egress_ipv6_cidr_blocks
|
||||
}
|
||||
|
||||
tags = merge(
|
||||
@@ -124,11 +125,11 @@ resource "aws_security_group" "boundary_db_sg" {
|
||||
vpc_id = var.vpc_id
|
||||
|
||||
ingress {
|
||||
cidr_blocks = flatten([formatlist("%s/32", data.enos_environment.localhost.public_ipv4_addresses), join(",", data.aws_vpc.infra.cidr_block_associations.*.cidr_block)])
|
||||
cidr_blocks = local.network_stack[var.ip_version].ingress_cidr_blocks
|
||||
ipv6_cidr_blocks = local.network_stack[var.ip_version].ingress_ipv6_cidr_blocks
|
||||
description = "database"
|
||||
from_port = 5432
|
||||
to_port = 5432
|
||||
ipv6_cidr_blocks = []
|
||||
prefix_list_ids = []
|
||||
protocol = "tcp"
|
||||
self = null
|
||||
@@ -136,10 +137,11 @@ resource "aws_security_group" "boundary_db_sg" {
|
||||
}
|
||||
|
||||
egress {
|
||||
from_port = 0
|
||||
to_port = 0
|
||||
protocol = "-1"
|
||||
cidr_blocks = ["0.0.0.0/0"]
|
||||
from_port = 0
|
||||
to_port = 0
|
||||
protocol = "-1"
|
||||
cidr_blocks = local.network_stack[var.ip_version].egress_cidr_blocks
|
||||
ipv6_cidr_blocks = local.network_stack[var.ip_version].egress_ipv6_cidr_blocks
|
||||
}
|
||||
|
||||
tags = merge(local.common_tags,
|
||||
|
||||
@@ -18,7 +18,7 @@ controller {
|
||||
# API listener configuration block
|
||||
listener "tcp" {
|
||||
# Should be the address of the NIC that the controller server will be reached on
|
||||
address = "${local_ipv4}:${api_port}"
|
||||
address = "${listener_address}:${api_port}"
|
||||
# The purpose of this listener block
|
||||
purpose = "api"
|
||||
tls_disable = true
|
||||
@@ -31,7 +31,7 @@ listener "tcp" {
|
||||
|
||||
# API listener configuration block
|
||||
listener "tcp" {
|
||||
address = "${local_ipv4}:${ops_port}"
|
||||
address = "${listener_address}:${ops_port}"
|
||||
purpose = "ops"
|
||||
tls_disable = true
|
||||
}
|
||||
@@ -39,7 +39,7 @@ listener "tcp" {
|
||||
# Data-plane listener configuration block (used for worker coordination)
|
||||
listener "tcp" {
|
||||
# Should be the IP of the NIC that the worker will connect on
|
||||
address = "${local_ipv4}:${cluster_port}"
|
||||
address = "${cluster_address}:${cluster_port}"
|
||||
# The purpose of this listener
|
||||
purpose = "cluster"
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ controller {
|
||||
# API listener configuration block
|
||||
listener "tcp" {
|
||||
# Should be the address of the NIC that the controller server will be reached on
|
||||
address = "${local_ipv4}:${api_port}"
|
||||
address = "${listener_address}:${api_port}"
|
||||
# The purpose of this listener block
|
||||
purpose = "api"
|
||||
tls_disable = true
|
||||
@@ -31,7 +31,7 @@ listener "tcp" {
|
||||
|
||||
# API listener configuration block
|
||||
listener "tcp" {
|
||||
address = "${local_ipv4}:${ops_port}"
|
||||
address = "${listener_address}:${ops_port}"
|
||||
purpose = "ops"
|
||||
tls_disable = true
|
||||
}
|
||||
@@ -39,7 +39,7 @@ listener "tcp" {
|
||||
# Data-plane listener configuration block (used for worker coordination)
|
||||
listener "tcp" {
|
||||
# Should be the IP of the NIC that the worker will connect on
|
||||
address = "${local_ipv4}:${cluster_port}"
|
||||
address = "${cluster_address}:${cluster_port}"
|
||||
# The purpose of this listener
|
||||
purpose = "cluster"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
# Copyright (c) HashiCorp, Inc.
|
||||
# SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
disable_mlock = true
|
||||
|
||||
controller {
|
||||
name = "boundary-controller-${id}"
|
||||
description = "Enos Boundary controller ${id}"
|
||||
|
||||
max_page_size = ${max_page_size}
|
||||
|
||||
database {
|
||||
url = "postgresql://${dbuser}:${dbpass}@${dbhost}:${dbport}/${dbname}"
|
||||
max_open_connections = ${db_max_open_connections}
|
||||
}
|
||||
}
|
||||
|
||||
# API listener configuration block
|
||||
listener "tcp" {
|
||||
# Should be the address of the NIC that the controller server will be reached on
|
||||
address = "${listener_address}:${api_port}"
|
||||
# The purpose of this listener block
|
||||
purpose = "api"
|
||||
tls_disable = true
|
||||
|
||||
# Uncomment to enable CORS for the Admin UI. Be sure to set the allowed origin(s)
|
||||
# to appropriate values.
|
||||
#cors_enabled = true
|
||||
#cors_allowed_origins = ["https://yourcorp.yourdomain.com", "serve://boundary"]
|
||||
}
|
||||
|
||||
# API listener configuration block
|
||||
listener "tcp" {
|
||||
address = "${listener_address}:${ops_port}"
|
||||
purpose = "ops"
|
||||
tls_disable = true
|
||||
}
|
||||
|
||||
# Data-plane listener configuration block (used for worker coordination)
|
||||
listener "tcp" {
|
||||
# Should be the IP of the NIC that the worker will connect on
|
||||
address = "${cluster_address}:${cluster_port}"
|
||||
# The purpose of this listener
|
||||
purpose = "cluster"
|
||||
}
|
||||
|
||||
kms "transit" {
|
||||
purpose = "worker-auth"
|
||||
address = "http://${vault_address}:8200"
|
||||
token = "${vault_transit_token}"
|
||||
disable_renewal = "false"
|
||||
key_name = "boundary-worker-auth"
|
||||
mount_path = "transit/"
|
||||
tls_skip_verify = "true"
|
||||
}
|
||||
|
||||
kms "transit" {
|
||||
purpose = "root"
|
||||
address = "http://${vault_address}:8200"
|
||||
token = "${vault_transit_token}"
|
||||
disable_renewal = "false"
|
||||
key_name = "boundary-root"
|
||||
mount_path = "transit/"
|
||||
tls_skip_verify = "true"
|
||||
}
|
||||
|
||||
kms "transit" {
|
||||
purpose = "recovery"
|
||||
address = "http://${vault_address}:8200"
|
||||
token = "${vault_transit_token}"
|
||||
disable_renewal = "false"
|
||||
key_name = "boundary-recovery"
|
||||
mount_path = "transit/"
|
||||
tls_skip_verify = "true"
|
||||
}
|
||||
|
||||
kms "transit" {
|
||||
purpose = "bsr"
|
||||
address = "http://${vault_address}:8200"
|
||||
token = "${vault_transit_token}"
|
||||
disable_renewal = "false"
|
||||
key_name = "boundary-bsr"
|
||||
mount_path = "transit/"
|
||||
tls_skip_verify = "true"
|
||||
}
|
||||
|
||||
events {
|
||||
audit_enabled = true
|
||||
observations_enabled = true
|
||||
sysevents_enabled = true
|
||||
|
||||
sink "stderr" {
|
||||
name = "all-events"
|
||||
description = "All events sent to stderr"
|
||||
event_types = ["*"]
|
||||
format = "cloudevents-json"
|
||||
|
||||
deny_filters = [
|
||||
"\"/data/request_info/method\" contains \"Status\"",
|
||||
"\"/data/request_info/path\" contains \"/health\"",
|
||||
]
|
||||
}
|
||||
|
||||
sink {
|
||||
name = "audit-sink"
|
||||
description = "Audit sent to a file"
|
||||
event_types = ["audit"]
|
||||
format = "cloudevents-json"
|
||||
|
||||
deny_filters = [
|
||||
"\"/data/request_info/method\" contains \"Status\"",
|
||||
]
|
||||
|
||||
file {
|
||||
path = "${audit_log_dir}"
|
||||
file_name = "audit.log"
|
||||
}
|
||||
|
||||
audit_config {
|
||||
audit_filter_overrides {
|
||||
secret = "encrypt"
|
||||
sensitive = "hmac-sha256"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
# Copyright (c) HashiCorp, Inc.
|
||||
# SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
disable_mlock = true
|
||||
|
||||
controller {
|
||||
name = "boundary-controller-${id}"
|
||||
description = "Enos Boundary controller ${id}"
|
||||
max_page_size = ${max_page_size}
|
||||
|
||||
database {
|
||||
url = "postgresql://${dbuser}:${dbpass}@${dbhost}:${dbport}/${dbname}"
|
||||
max_open_connections = ${db_max_open_connections}
|
||||
}
|
||||
}
|
||||
|
||||
# API listener configuration block
|
||||
listener "tcp" {
|
||||
# Should be the address of the NIC that the controller server will be reached on
|
||||
address = "${listener_address}:${api_port}"
|
||||
# The purpose of this listener block
|
||||
purpose = "api"
|
||||
tls_disable = true
|
||||
|
||||
# Uncomment to enable CORS for the Admin UI. Be sure to set the allowed origin(s)
|
||||
# to appropriate values.
|
||||
#cors_enabled = true
|
||||
#cors_allowed_origins = ["https://yourcorp.yourdomain.com", "serve://boundary"]
|
||||
}
|
||||
|
||||
# API listener configuration block
|
||||
listener "tcp" {
|
||||
address = "${listener_address}:${ops_port}"
|
||||
purpose = "ops"
|
||||
tls_disable = true
|
||||
}
|
||||
|
||||
# Data-plane listener configuration block (used for worker coordination)
|
||||
listener "tcp" {
|
||||
# Should be the IP of the NIC that the worker will connect on
|
||||
address = "${cluster_address}:${cluster_port}"
|
||||
# The purpose of this listener
|
||||
purpose = "cluster"
|
||||
}
|
||||
|
||||
kms "transit" {
|
||||
purpose = "worker-auth"
|
||||
address = "http://${vault_address}:8200"
|
||||
token = "${vault_transit_token}"
|
||||
disable_renewal = "false"
|
||||
key_name = "boundary-worker-auth"
|
||||
mount_path = "transit/"
|
||||
tls_skip_verify = "true"
|
||||
}
|
||||
|
||||
kms "transit" {
|
||||
purpose = "root"
|
||||
address = "http://${vault_address}:8200"
|
||||
token = "${vault_transit_token}"
|
||||
disable_renewal = "false"
|
||||
key_name = "boundary-root"
|
||||
mount_path = "transit/"
|
||||
tls_skip_verify = "true"
|
||||
}
|
||||
|
||||
kms "transit" {
|
||||
purpose = "recovery"
|
||||
address = "http://${vault_address}:8200"
|
||||
token = "${vault_transit_token}"
|
||||
disable_renewal = "false"
|
||||
key_name = "boundary-recovery"
|
||||
mount_path = "transit/"
|
||||
tls_skip_verify = "true"
|
||||
}
|
||||
|
||||
events {
|
||||
audit_enabled = true
|
||||
observations_enabled = true
|
||||
sysevents_enabled = true
|
||||
|
||||
sink "stderr" {
|
||||
name = "all-events"
|
||||
description = "All events sent to stderr"
|
||||
event_types = ["*"]
|
||||
format = "cloudevents-json"
|
||||
|
||||
deny_filters = [
|
||||
"\"/data/request_info/method\" contains \"Status\"",
|
||||
"\"/data/request_info/path\" contains \"/health\"",
|
||||
]
|
||||
}
|
||||
|
||||
sink {
|
||||
name = "audit-sink"
|
||||
description = "Audit sent to a file"
|
||||
event_types = ["audit"]
|
||||
format = "cloudevents-json"
|
||||
|
||||
deny_filters = [
|
||||
"\"/data/request_info/method\" contains \"Status\"",
|
||||
]
|
||||
|
||||
file {
|
||||
path = "${audit_log_dir}"
|
||||
file_name = "audit.log"
|
||||
}
|
||||
|
||||
audit_config {
|
||||
audit_filter_overrides {
|
||||
secret = "encrypt"
|
||||
sensitive = "hmac-sha256"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,9 @@
|
||||
# SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
listener "tcp" {
|
||||
purpose = "proxy"
|
||||
purpose = "proxy"
|
||||
tls_disable = true
|
||||
address = "0.0.0.0"
|
||||
address = "${listener_address}"
|
||||
}
|
||||
|
||||
worker {
|
||||
@@ -15,7 +15,7 @@ worker {
|
||||
# Workers must be able to reach controllers on :9201
|
||||
initial_upstreams = ${controller_ips}
|
||||
|
||||
public_addr = "${public_addr}"
|
||||
public_addr = "${public_address}"
|
||||
|
||||
tags {
|
||||
type = ${type}
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
# SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
listener "tcp" {
|
||||
purpose = "proxy"
|
||||
purpose = "proxy"
|
||||
tls_disable = true
|
||||
address = "0.0.0.0"
|
||||
address = "${listener_address}"
|
||||
}
|
||||
|
||||
worker {
|
||||
@@ -15,7 +15,7 @@ worker {
|
||||
# Workers must be able to reach controllers on :9201
|
||||
initial_upstreams = ${controller_ips}
|
||||
|
||||
public_addr = "${public_addr}"
|
||||
public_addr = "${public_address}"
|
||||
|
||||
tags {
|
||||
type = ${type}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
# Copyright (c) HashiCorp, Inc.
|
||||
# SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
listener "tcp" {
|
||||
purpose = "proxy"
|
||||
tls_disable = true
|
||||
address = "${listener_address}:9202"
|
||||
}
|
||||
|
||||
worker {
|
||||
# Name attr must be unique across workers
|
||||
name = "demo-worker-${id}"
|
||||
description = "Enos Boundary worker ${id}"
|
||||
|
||||
# Workers must be able to reach controllers on :9201
|
||||
initial_upstreams = ${controller_ips}
|
||||
|
||||
public_addr = "${public_address}"
|
||||
|
||||
tags {
|
||||
type = ${type}
|
||||
region = ["${region}"]
|
||||
}
|
||||
|
||||
recording_storage_path = "${recording_storage_path}"
|
||||
}
|
||||
|
||||
# must be same key as used on controller config
|
||||
kms "transit" {
|
||||
purpose = "worker-auth"
|
||||
address = "http://${vault_address}:8200"
|
||||
token = "${vault_transit_token}"
|
||||
disable_renewal = "false"
|
||||
key_name = "boundary-worker-auth"
|
||||
mount_path = "transit/"
|
||||
tls_skip_verify = "true"
|
||||
}
|
||||
|
||||
events {
|
||||
audit_enabled = true
|
||||
observations_enabled = true
|
||||
sysevents_enabled = true
|
||||
|
||||
sink "stderr" {
|
||||
name = "all-events"
|
||||
description = "All events sent to stderr"
|
||||
event_types = ["*"]
|
||||
format = "cloudevents-json"
|
||||
|
||||
deny_filters = [
|
||||
"\"/data/request_info/method\" contains \"Status\"",
|
||||
"\"/data/request_info/path\" contains \"/health\"",
|
||||
]
|
||||
}
|
||||
|
||||
sink {
|
||||
name = "audit-sink"
|
||||
description = "Audit sent to a file"
|
||||
event_types = ["audit"]
|
||||
format = "cloudevents-json"
|
||||
|
||||
deny_filters = [
|
||||
"\"/data/request_info/method\" contains \"Status\"",
|
||||
]
|
||||
|
||||
file {
|
||||
path = "${audit_log_dir}"
|
||||
file_name = "audit.log"
|
||||
}
|
||||
|
||||
audit_config {
|
||||
audit_filter_overrides {
|
||||
secret = "encrypt"
|
||||
sensitive = "hmac-sha256"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,15 +2,15 @@
|
||||
# SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
listener "tcp" {
|
||||
purpose = "proxy"
|
||||
purpose = "proxy"
|
||||
tls_disable = true
|
||||
address = "0.0.0.0"
|
||||
address = "${listener_address}"
|
||||
}
|
||||
|
||||
hcp_boundary_cluster_id = "${hcp_boundary_cluster_id}"
|
||||
|
||||
worker {
|
||||
public_addr = "${public_addr}"
|
||||
public_addr = "${public_address}"
|
||||
|
||||
tags {
|
||||
type = ${type}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
# Copyright (c) HashiCorp, Inc.
|
||||
# SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
listener "tcp" {
|
||||
purpose = "proxy"
|
||||
tls_disable = true
|
||||
address = "${listener_address}"
|
||||
}
|
||||
|
||||
worker {
|
||||
# Name attr must be unique across workers
|
||||
name = "demo-worker-${id}"
|
||||
description = "Enos Boundary worker ${id}"
|
||||
|
||||
# Workers must be able to reach controllers on :9201
|
||||
initial_upstreams = ${controller_ips}
|
||||
|
||||
public_addr = "${public_address}"
|
||||
|
||||
tags {
|
||||
type = ${type}
|
||||
region = ["${region}"]
|
||||
}
|
||||
}
|
||||
|
||||
# must be same key as used on controller config
|
||||
kms "transit" {
|
||||
purpose = "worker-auth"
|
||||
address = "http://${vault_address}:8200"
|
||||
token = "${vault_transit_token}"
|
||||
disable_renewal = "false"
|
||||
key_name = "boundary-worker-auth"
|
||||
mount_path = "transit/"
|
||||
tls_skip_verify = "true"
|
||||
}
|
||||
|
||||
events {
|
||||
audit_enabled = true
|
||||
observations_enabled = true
|
||||
sysevents_enabled = true
|
||||
|
||||
sink "stderr" {
|
||||
name = "all-events"
|
||||
description = "All events sent to stderr"
|
||||
event_types = ["*"]
|
||||
format = "cloudevents-json"
|
||||
|
||||
deny_filters = [
|
||||
"\"/data/request_info/method\" contains \"Status\"",
|
||||
"\"/data/request_info/path\" contains \"/health\"",
|
||||
]
|
||||
}
|
||||
|
||||
sink {
|
||||
name = "audit-sink"
|
||||
description = "Audit sent to a file"
|
||||
event_types = ["audit"]
|
||||
format = "cloudevents-json"
|
||||
|
||||
deny_filters = [
|
||||
"\"/data/request_info/method\" contains \"Status\"",
|
||||
]
|
||||
|
||||
file {
|
||||
path = "${audit_log_dir}"
|
||||
file_name = "audit.log"
|
||||
}
|
||||
|
||||
audit_config {
|
||||
audit_filter_overrides {
|
||||
secret = "encrypt"
|
||||
sensitive = "hmac-sha256"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -334,6 +334,12 @@ variable "alb_sg_additional_ips" {
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "alb_sg_additional_ipv6_ips" {
|
||||
description = "Additional ipv6 IPs to be allowed (ingress) on an ALB Security Group"
|
||||
type = list(string)
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "boundary_license" {
|
||||
description = "Boundary license (not needed for OSS, required for enterprise)"
|
||||
type = string
|
||||
@@ -378,3 +384,26 @@ variable "hcp_boundary_cluster_id" {
|
||||
// If using HCP int, ensure that the cluster id starts with "int-"
|
||||
// Example: "int-19283a-123123-..."
|
||||
}
|
||||
|
||||
variable "ip_version" {
|
||||
description = "ip version used to setup boundary instance, should be 4, 6, or dual"
|
||||
type = string
|
||||
default = "4"
|
||||
|
||||
validation {
|
||||
condition = contains(["4", "6", "dual"], var.ip_version)
|
||||
error_message = "ip_version must be one of: [4, 6, dual]"
|
||||
}
|
||||
}
|
||||
|
||||
variable "vault_address" {
|
||||
description = "network address to a vault instance"
|
||||
type = string
|
||||
default = "localhost"
|
||||
}
|
||||
|
||||
variable "vault_transit_token" {
|
||||
description = "vault token used for kms transit in the boundary config"
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
@@ -26,36 +26,84 @@ variable "ingress_cidr" {
|
||||
default = ["10.0.0.0/8"]
|
||||
}
|
||||
|
||||
variable "ingress_ipv6_cidr" {
|
||||
type = list(string)
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "ip_version" {
|
||||
description = "ip version used to setup boundary instance, should be 4, 6, or dual"
|
||||
type = string
|
||||
default = "4"
|
||||
|
||||
validation {
|
||||
condition = contains(["4", "6", "dual"], var.ip_version)
|
||||
error_message = "ip_version must be one of: [4, 6, dual]"
|
||||
}
|
||||
}
|
||||
|
||||
data "enos_environment" "current" {}
|
||||
|
||||
data "aws_caller_identity" "current" {}
|
||||
locals {
|
||||
network_stack = {
|
||||
"4" = {
|
||||
ingress_cidr_blocks = flatten([
|
||||
formatlist("%s/32", data.enos_environment.current.public_ipv4_addresses),
|
||||
var.ingress_cidr,
|
||||
])
|
||||
ingress_ipv6_cidr_blocks = [],
|
||||
egress_cidr_blocks = ["0.0.0.0/0"],
|
||||
egress_ipv6_cidr_blocks = [],
|
||||
ipv6_address_count = 0,
|
||||
},
|
||||
"6" = {
|
||||
ingress_cidr_blocks = [],
|
||||
ingress_ipv6_cidr_blocks = flatten([
|
||||
[for ip in coalesce(data.enos_environment.current.public_ipv6_addresses, []) : cidrsubnet("${ip}/64", 0, 0)],
|
||||
var.ingress_ipv6_cidr,
|
||||
])
|
||||
egress_cidr_blocks = [],
|
||||
egress_ipv6_cidr_blocks = ["::/0"],
|
||||
ipv6_address_count = 1,
|
||||
},
|
||||
"dual" = {
|
||||
ingress_cidr_blocks = flatten([
|
||||
# allow ingress from ipv4 to allow for test setup from ci
|
||||
formatlist("%s/32", data.enos_environment.current.public_ipv4_addresses),
|
||||
var.ingress_cidr,
|
||||
])
|
||||
ingress_ipv6_cidr_blocks = flatten([
|
||||
[for ip in coalesce(data.enos_environment.current.public_ipv6_addresses, []) : cidrsubnet("${ip}/64", 0, 0)],
|
||||
var.ingress_ipv6_cidr,
|
||||
])
|
||||
egress_cidr_blocks = [],
|
||||
egress_ipv6_cidr_blocks = ["::/0"],
|
||||
ipv6_address_count = 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_security_group" "boundary_target" {
|
||||
name_prefix = "boundary-target-sg"
|
||||
description = "SSH and boundary Traffic"
|
||||
vpc_id = var.vpc_id
|
||||
|
||||
# SSH
|
||||
ingress {
|
||||
from_port = 22
|
||||
to_port = 22
|
||||
protocol = "tcp"
|
||||
cidr_blocks = var.ingress_cidr
|
||||
}
|
||||
|
||||
ingress {
|
||||
description = "SSH to the instance"
|
||||
from_port = 22
|
||||
to_port = 22
|
||||
protocol = "tcp"
|
||||
cidr_blocks = flatten([formatlist("%s/32", data.enos_environment.current.public_ipv4_addresses)])
|
||||
description = "SSH to the instance"
|
||||
from_port = 22
|
||||
to_port = 22
|
||||
protocol = "tcp"
|
||||
cidr_blocks = local.network_stack[var.ip_version].ingress_cidr_blocks
|
||||
ipv6_cidr_blocks = local.network_stack[var.ip_version].ingress_ipv6_cidr_blocks
|
||||
}
|
||||
|
||||
egress {
|
||||
from_port = 0
|
||||
to_port = 0
|
||||
protocol = "-1"
|
||||
cidr_blocks = ["0.0.0.0/0"]
|
||||
from_port = 0
|
||||
to_port = 0
|
||||
protocol = "-1"
|
||||
cidr_blocks = local.network_stack[var.ip_version].egress_cidr_blocks
|
||||
ipv6_cidr_blocks = local.network_stack[var.ip_version].egress_ipv6_cidr_blocks
|
||||
}
|
||||
|
||||
tags = {
|
||||
@@ -71,6 +119,8 @@ resource "aws_instance" "target" {
|
||||
subnet_id = var.subnet_ids[count.index % length(var.subnet_ids)]
|
||||
key_name = var.aws_ssh_keypair_name
|
||||
|
||||
ipv6_address_count = local.network_stack[var.ip_version].ipv6_address_count
|
||||
|
||||
tags = merge(var.additional_tags, {
|
||||
"Name" : "boundary-target-${count.index}-${split(":", data.aws_caller_identity.current.user_id)[1]}",
|
||||
"Type" : "target",
|
||||
@@ -90,15 +140,15 @@ resource "enos_remote_exec" "wait" {
|
||||
|
||||
transport = {
|
||||
ssh = {
|
||||
host = aws_instance.target[each.key].public_ip
|
||||
host = var.ip_version == "6" ? aws_instance.target[each.key].ipv6_addresses[0] : aws_instance.target[each.key].public_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output "target_private_ips" {
|
||||
value = aws_instance.target.*.private_ip
|
||||
value = var.ip_version == "4" ? aws_instance.target.*.private_ip : formatlist("[%s]", flatten(aws_instance.target.*.ipv6_addresses))
|
||||
}
|
||||
|
||||
output "target_public_ips" {
|
||||
value = aws_instance.target.*.public_ip
|
||||
value = var.ip_version == "4" ? aws_instance.target.*.public_ip : formatlist("[%s]", flatten(aws_instance.target.*.ipv6_addresses))
|
||||
}
|
||||
@@ -36,17 +36,20 @@ data "aws_iam_policy_document" "vault_profile" {
|
||||
}
|
||||
|
||||
resource "aws_iam_role" "vault_instance_role" {
|
||||
count = var.deploy ? 1 : 0
|
||||
name = "vault_instance_role-${random_string.cluster_id.result}"
|
||||
assume_role_policy = data.aws_iam_policy_document.vault_instance_role.json
|
||||
}
|
||||
|
||||
resource "aws_iam_instance_profile" "vault_profile" {
|
||||
name = "vault_instance_profile-${random_string.cluster_id.result}"
|
||||
role = aws_iam_role.vault_instance_role.name
|
||||
count = var.deploy ? 1 : 0
|
||||
name = "vault_instance_profile-${random_string.cluster_id.result}"
|
||||
role = aws_iam_role.vault_instance_role[0].name
|
||||
}
|
||||
|
||||
resource "aws_iam_role_policy" "vault_policy" {
|
||||
count = var.deploy ? 1 : 0
|
||||
name = "vault_policy-${random_string.cluster_id.result}"
|
||||
role = aws_iam_role.vault_instance_role.id
|
||||
role = aws_iam_role.vault_instance_role[0].id
|
||||
policy = data.aws_iam_policy_document.vault_profile.json
|
||||
}
|
||||
@@ -11,9 +11,9 @@ locals {
|
||||
"awskms" = null
|
||||
"shamir" = 3
|
||||
}
|
||||
followers = toset(slice(local.instances, 1, length(local.instances)))
|
||||
instances = [for idx in range(var.instance_count) : tostring(idx)]
|
||||
leader = toset(slice(local.instances, 0, 1))
|
||||
followers = var.deploy ? toset(slice(local.instances, 1, length(local.instances))) : toset([])
|
||||
instances = var.deploy ? [for idx in range(var.instance_count) : tostring(idx)] : []
|
||||
leader = var.deploy ? toset(slice(local.instances, 0, 1)) : toset([])
|
||||
name_suffix = "${var.project_name}-${var.environment}"
|
||||
recovery_shares = {
|
||||
"awskms" = 5
|
||||
@@ -53,4 +53,41 @@ locals {
|
||||
audit_device_file_path = "/var/log/vault/vault_audit.log"
|
||||
vault_service_user = "vault"
|
||||
enable_audit_device = var.enable_file_audit_device && var.vault_init
|
||||
network_stack = {
|
||||
"4" = {
|
||||
ingress_cidr_blocks = flatten([
|
||||
formatlist("%s/32", data.enos_environment.localhost.public_ipv4_addresses),
|
||||
join(",", data.aws_vpc.infra.cidr_block_associations.*.cidr_block),
|
||||
formatlist("%s/32", var.sg_additional_ips),
|
||||
])
|
||||
ingress_ipv6_cidr_blocks = [],
|
||||
egress_cidr_blocks = ["0.0.0.0/0"],
|
||||
egress_ipv6_cidr_blocks = [],
|
||||
ipv6_address_count = 0,
|
||||
},
|
||||
"6" = {
|
||||
ingress_cidr_blocks = [],
|
||||
ingress_ipv6_cidr_blocks = flatten([
|
||||
[for ip in coalesce(data.enos_environment.localhost.public_ipv6_addresses, []) : cidrsubnet("${ip}/64", 0, 0)],
|
||||
[data.aws_vpc.infra.ipv6_cidr_block],
|
||||
[for ip in var.sg_additional_ipv6_ips : cidrsubnet("${ip}/64", 0, 0)],
|
||||
])
|
||||
egress_cidr_blocks = [],
|
||||
egress_ipv6_cidr_blocks = ["::/0"],
|
||||
ipv6_address_count = 1,
|
||||
},
|
||||
"dual" = {
|
||||
ingress_cidr_blocks = flatten([
|
||||
formatlist("%s/32", data.enos_environment.localhost.public_ipv4_addresses),
|
||||
])
|
||||
ingress_ipv6_cidr_blocks = flatten([
|
||||
[for ip in coalesce(data.enos_environment.localhost.public_ipv6_addresses, []) : cidrsubnet("${ip}/64", 0, 0)],
|
||||
[data.aws_vpc.infra.ipv6_cidr_block],
|
||||
[for ip in var.sg_additional_ipv6_ips : cidrsubnet("${ip}/64", 0, 0)],
|
||||
])
|
||||
egress_cidr_blocks = [],
|
||||
egress_ipv6_cidr_blocks = ["::/0"],
|
||||
ipv6_address_count = 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ output "instance_ids" {
|
||||
|
||||
output "instance_public_ips" {
|
||||
description = "Public IPs of Vault instances"
|
||||
value = [for instance in aws_instance.vault_instance : instance.public_ip]
|
||||
value = var.ip_version == "4" ? [for instance in aws_instance.vault_instance : instance.public_ip] : flatten([for instance in aws_instance.vault_instance : instance.ipv6_addresses])
|
||||
}
|
||||
|
||||
output "instance_private_ips" {
|
||||
@@ -40,6 +40,10 @@ output "vault_root_token" {
|
||||
value = coalesce(var.vault_root_token, try(enos_vault_init.leader[0].root_token, null), "none")
|
||||
}
|
||||
|
||||
output "vault_transit_token" {
|
||||
value = try([for token in enos_remote_exec.vault_kms_policy : trimspace(token.stdout)][0], "")
|
||||
}
|
||||
|
||||
output "vault_unseal_keys_b64" {
|
||||
value = try(enos_vault_init.leader[0].unseal_keys_b64, [])
|
||||
}
|
||||
|
||||
@@ -2,52 +2,44 @@
|
||||
# SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
resource "aws_security_group" "enos_vault_sg" {
|
||||
count = var.deploy ? 1 : 0
|
||||
name = "vault-sg-${random_string.cluster_id.result}"
|
||||
description = "SSH and Vault Traffic"
|
||||
vpc_id = var.vpc_id
|
||||
|
||||
# SSH
|
||||
ingress {
|
||||
from_port = 22
|
||||
to_port = 22
|
||||
protocol = "tcp"
|
||||
cidr_blocks = flatten([
|
||||
formatlist("%s/32", data.enos_environment.localhost.public_ipv4_addresses),
|
||||
join(",", data.aws_vpc.infra.cidr_block_associations.*.cidr_block),
|
||||
])
|
||||
from_port = 22
|
||||
to_port = 22
|
||||
protocol = "tcp"
|
||||
cidr_blocks = local.network_stack[var.ip_version].ingress_cidr_blocks
|
||||
ipv6_cidr_blocks = local.network_stack[var.ip_version].ingress_ipv6_cidr_blocks
|
||||
}
|
||||
|
||||
# Vault traffic
|
||||
ingress {
|
||||
from_port = 8200
|
||||
to_port = 8201
|
||||
protocol = "tcp"
|
||||
cidr_blocks = flatten([
|
||||
formatlist("%s/32", data.enos_environment.localhost.public_ipv4_addresses),
|
||||
join(",", data.aws_vpc.infra.cidr_block_associations.*.cidr_block),
|
||||
formatlist("%s/32", var.sg_additional_ips),
|
||||
])
|
||||
from_port = 8200
|
||||
to_port = 8201
|
||||
protocol = "tcp"
|
||||
cidr_blocks = local.network_stack[var.ip_version].ingress_cidr_blocks
|
||||
ipv6_cidr_blocks = local.network_stack[var.ip_version].ingress_ipv6_cidr_blocks
|
||||
}
|
||||
|
||||
# Consul Agent traffic
|
||||
ingress {
|
||||
from_port = 8301
|
||||
to_port = 8301
|
||||
protocol = "tcp"
|
||||
cidr_blocks = flatten([
|
||||
formatlist("%s/32", data.enos_environment.localhost.public_ipv4_addresses),
|
||||
join(",", data.aws_vpc.infra.cidr_block_associations.*.cidr_block),
|
||||
])
|
||||
from_port = 8301
|
||||
to_port = 8301
|
||||
protocol = "tcp"
|
||||
cidr_blocks = local.network_stack[var.ip_version].ingress_cidr_blocks
|
||||
ipv6_cidr_blocks = local.network_stack[var.ip_version].ingress_ipv6_cidr_blocks
|
||||
}
|
||||
|
||||
ingress {
|
||||
from_port = 8301
|
||||
to_port = 8301
|
||||
protocol = "udp"
|
||||
cidr_blocks = flatten([
|
||||
formatlist("%s/32", data.enos_environment.localhost.public_ipv4_addresses),
|
||||
join(",", data.aws_vpc.infra.cidr_block_associations.*.cidr_block),
|
||||
])
|
||||
from_port = 8301
|
||||
to_port = 8301
|
||||
protocol = "udp"
|
||||
cidr_blocks = local.network_stack[var.ip_version].ingress_cidr_blocks
|
||||
ipv6_cidr_blocks = local.network_stack[var.ip_version].ingress_ipv6_cidr_blocks
|
||||
}
|
||||
|
||||
# Internal Traffic
|
||||
@@ -59,10 +51,11 @@ resource "aws_security_group" "enos_vault_sg" {
|
||||
}
|
||||
|
||||
egress {
|
||||
from_port = 0
|
||||
to_port = 0
|
||||
protocol = "-1"
|
||||
cidr_blocks = ["0.0.0.0/0"]
|
||||
from_port = 0
|
||||
to_port = 0
|
||||
protocol = "-1"
|
||||
cidr_blocks = local.network_stack[var.ip_version].egress_cidr_blocks
|
||||
ipv6_cidr_blocks = local.network_stack[var.ip_version].egress_ipv6_cidr_blocks
|
||||
}
|
||||
|
||||
tags = merge(
|
||||
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
#!/bin/bash
|
||||
# Copyright (c) HashiCorp, Inc.
|
||||
# SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
function retry {
|
||||
local retries=$1
|
||||
shift
|
||||
local count=0
|
||||
|
||||
until "$@"; do
|
||||
exit=$?
|
||||
wait=$((2 ** count))
|
||||
count=$((count + 1))
|
||||
|
||||
if [ "$count" -lt "$retries" ]; then
|
||||
sleep "$wait"
|
||||
else
|
||||
return "$exit"
|
||||
fi
|
||||
done
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
export VAULT_ADDR=http://localhost:8200
|
||||
export VAULT_TOKEN='${vault_root_token}'
|
||||
|
||||
cat > ./kms-transit.hcl << EOF
|
||||
# Copyright (c) HashiCorp, Inc.
|
||||
# SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
path "transit/encrypt/boundary-recovery" {
|
||||
capabilities = ["create", "update"]
|
||||
}
|
||||
|
||||
path "transit/decrypt/boundary-recovery" {
|
||||
capabilities = ["create", "update"]
|
||||
}
|
||||
|
||||
path "transit/encrypt/boundary-worker-auth" {
|
||||
capabilities = ["create", "update"]
|
||||
}
|
||||
|
||||
path "transit/decrypt/boundary-worker-auth" {
|
||||
capabilities = ["create", "update"]
|
||||
}
|
||||
|
||||
path "transit/encrypt/boundary-root" {
|
||||
capabilities = ["create", "update"]
|
||||
}
|
||||
|
||||
path "transit/decrypt/boundary-root" {
|
||||
capabilities = ["create", "update"]
|
||||
}
|
||||
|
||||
path "transit/encrypt/boundary-bsr" {
|
||||
capabilities = ["create", "update"]
|
||||
}
|
||||
|
||||
path "transit/decrypt/boundary-bsr" {
|
||||
capabilities = ["create", "update"]
|
||||
}
|
||||
EOF
|
||||
|
||||
retry 5 ${vault_bin_path} secrets enable transit > /dev/null
|
||||
|
||||
retry 5 ${vault_bin_path} policy write boundary-kms-transit-policy ./kms-transit.hcl > /dev/null
|
||||
|
||||
rm ./kms-transit.hcl > /dev/null
|
||||
|
||||
retry 5 ${vault_bin_path} token create -policy=boundary-kms-transit-policy -field=token
|
||||
@@ -71,6 +71,12 @@ variable "environment" {
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "deploy" {
|
||||
description = "Flag to toggle whether or not all the resources defined in this module should be deployed."
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
|
||||
variable "instance_count" {
|
||||
description = "Number of EC2 instances in each subnet"
|
||||
type = number
|
||||
@@ -101,7 +107,13 @@ variable "project_name" {
|
||||
}
|
||||
|
||||
variable "sg_additional_ips" {
|
||||
description = "A list of additional IPs to allow by Vault security groups (use with caution)"
|
||||
description = "A list of additional IPv4 IPs to allow by Vault security groups (use with caution)"
|
||||
type = list(string)
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "sg_additional_ipv6_ips" {
|
||||
description = "A list of additional IPv6 IPs to allow by Vault security groups (use with caution)"
|
||||
type = list(string)
|
||||
default = []
|
||||
}
|
||||
@@ -253,3 +265,14 @@ variable "enable_file_audit_device" {
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "ip_version" {
|
||||
type = string
|
||||
description = "Optional variable that configures the vault instance to run on a ipv4, ipv6, or dualstack network"
|
||||
default = "4"
|
||||
|
||||
validation {
|
||||
condition = contains(["4", "6", "dual"], var.ip_version)
|
||||
error_message = "Valid values for ip_version are (4, 6, dual)."
|
||||
}
|
||||
}
|
||||
@@ -5,10 +5,11 @@ resource "aws_instance" "vault_instance" {
|
||||
for_each = local.vault_instances
|
||||
ami = var.ami_id
|
||||
instance_type = var.instance_type
|
||||
vpc_security_group_ids = [aws_security_group.enos_vault_sg.id]
|
||||
vpc_security_group_ids = [aws_security_group.enos_vault_sg[0].id]
|
||||
subnet_id = tolist(data.aws_subnets.infra.ids)[each.key % length(data.aws_subnets.infra.ids)]
|
||||
key_name = var.ssh_aws_keypair
|
||||
iam_instance_profile = aws_iam_instance_profile.vault_profile.name
|
||||
iam_instance_profile = aws_iam_instance_profile.vault_profile[0].name
|
||||
ipv6_address_count = local.network_stack[var.ip_version].ipv6_address_count
|
||||
tags = merge(
|
||||
var.common_tags,
|
||||
{
|
||||
@@ -31,7 +32,7 @@ resource "enos_remote_exec" "install_dependencies" {
|
||||
|
||||
transport = {
|
||||
ssh = {
|
||||
host = aws_instance.vault_instance[each.value].public_ip
|
||||
host = var.ip_version == "6" ? aws_instance.vault_instance[each.value].ipv6_addresses[0] : aws_instance.vault_instance[each.value].public_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,7 +48,7 @@ resource "enos_bundle_install" "consul" {
|
||||
|
||||
transport = {
|
||||
ssh = {
|
||||
host = each.value.public_ip
|
||||
host = var.ip_version == "6" ? each.value.ipv6_addresses[0] : each.value.public_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -62,7 +63,7 @@ resource "enos_bundle_install" "vault" {
|
||||
|
||||
transport = {
|
||||
ssh = {
|
||||
host = each.value.public_ip
|
||||
host = var.ip_version == "6" ? each.value.ipv6_addresses[0] : each.value.public_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -88,7 +89,7 @@ resource "enos_consul_start" "consul" {
|
||||
|
||||
transport = {
|
||||
ssh = {
|
||||
host = aws_instance.vault_instance[each.key].public_ip
|
||||
host = var.ip_version == "6" ? aws_instance.vault_instance[each.key].ipv6_addresses[0] : aws_instance.vault_instance[each.key].public_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -104,13 +105,13 @@ resource "enos_vault_start" "leader" {
|
||||
config_dir = var.vault_config_dir
|
||||
manage_service = var.manage_service
|
||||
config = {
|
||||
api_addr = "http://${aws_instance.vault_instance[each.key].private_ip}:8200"
|
||||
cluster_addr = "http://${aws_instance.vault_instance[each.key].private_ip}:8201"
|
||||
api_addr = var.ip_version == "4" ? "http://${aws_instance.vault_instance[each.key].private_ip}:8200" : "http://[${aws_instance.vault_instance[each.key].ipv6_addresses[0]}]:8200"
|
||||
cluster_addr = var.ip_version == "4" ? "http://${aws_instance.vault_instance[each.key].private_ip}:8201" : "http://[${aws_instance.vault_instance[each.key].ipv6_addresses[0]}]:8201"
|
||||
cluster_name = local.vault_cluster_tag
|
||||
listener = {
|
||||
type = "tcp"
|
||||
attributes = {
|
||||
address = "0.0.0.0:8200"
|
||||
address = var.ip_version == "4" ? "0.0.0.0:8200" : "[::]:8200"
|
||||
tls_disable = "true"
|
||||
}
|
||||
}
|
||||
@@ -130,7 +131,7 @@ resource "enos_vault_start" "leader" {
|
||||
|
||||
transport = {
|
||||
ssh = {
|
||||
host = aws_instance.vault_instance[each.key].public_ip
|
||||
host = var.ip_version == "6" ? aws_instance.vault_instance[each.key].ipv6_addresses[0] : aws_instance.vault_instance[each.key].public_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -145,14 +146,14 @@ resource "enos_vault_start" "followers" {
|
||||
config_dir = var.vault_config_dir
|
||||
manage_service = var.manage_service
|
||||
config = {
|
||||
api_addr = "http://${aws_instance.vault_instance[each.key].private_ip}:8200"
|
||||
cluster_addr = "http://${aws_instance.vault_instance[each.key].private_ip}:8201"
|
||||
api_addr = var.ip_version == "4" ? "http://${aws_instance.vault_instance[each.key].private_ip}:8200" : "http://[${aws_instance.vault_instance[each.key].ipv6_addresses[0]}]:8200"
|
||||
cluster_addr = var.ip_version == "4" ? "http://${aws_instance.vault_instance[each.key].private_ip}:8201" : "http://[${aws_instance.vault_instance[each.key].ipv6_addresses[0]}]:8201"
|
||||
cluster_name = local.vault_cluster_tag
|
||||
log_level = var.vault_log_level
|
||||
listener = {
|
||||
type = "tcp"
|
||||
attributes = {
|
||||
address = "0.0.0.0:8200"
|
||||
address = var.ip_version == "4" ? "0.0.0.0:8200" : "[::]:8200"
|
||||
tls_disable = "true"
|
||||
}
|
||||
}
|
||||
@@ -171,7 +172,7 @@ resource "enos_vault_start" "followers" {
|
||||
|
||||
transport = {
|
||||
ssh = {
|
||||
host = aws_instance.vault_instance[each.key].public_ip
|
||||
host = var.ip_version == "6" ? aws_instance.vault_instance[each.key].ipv6_addresses[0] : aws_instance.vault_instance[each.key].public_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -194,7 +195,7 @@ resource "enos_vault_init" "leader" {
|
||||
|
||||
transport = {
|
||||
ssh = {
|
||||
host = aws_instance.vault_instance[0].public_ip
|
||||
host = var.ip_version == "6" ? aws_instance.vault_instance[0].ipv6_addresses[0] : aws_instance.vault_instance[0].public_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -212,7 +213,7 @@ resource "enos_vault_unseal" "leader" {
|
||||
|
||||
transport = {
|
||||
ssh = {
|
||||
host = aws_instance.vault_instance[0].public_ip
|
||||
host = var.ip_version == "6" ? aws_instance.vault_instance[0].ipv6_addresses[0] : aws_instance.vault_instance[0].public_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -237,7 +238,7 @@ resource "enos_remote_exec" "create_audit_log_dir" {
|
||||
|
||||
transport = {
|
||||
ssh = {
|
||||
host = aws_instance.vault_instance[each.value].public_ip
|
||||
host = var.ip_version == "6" ? aws_instance.vault_instance[each.value].ipv6_addresses[0] : aws_instance.vault_instance[each.value].public_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -254,7 +255,7 @@ resource "enos_remote_exec" "init_audit_device" {
|
||||
|
||||
environment = {
|
||||
VAULT_TOKEN = enos_vault_init.leader[each.key].root_token
|
||||
VAULT_ADDR = "http://127.0.0.1:8200"
|
||||
VAULT_ADDR = var.ip_version == "4" ? "http://127.0.0.1:8200" : "http://[::1]:8200"
|
||||
VAULT_BIN_PATH = local.vault_bin_path
|
||||
LOG_FILE_PATH = local.audit_device_file_path
|
||||
SERVICE_USER = local.vault_service_user
|
||||
@@ -266,7 +267,7 @@ resource "enos_remote_exec" "init_audit_device" {
|
||||
|
||||
transport = {
|
||||
ssh = {
|
||||
host = aws_instance.vault_instance[each.key].public_ip
|
||||
host = var.ip_version == "6" ? aws_instance.vault_instance[each.key].ipv6_addresses[0] : aws_instance.vault_instance[each.key].public_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -289,7 +290,7 @@ resource "enos_vault_unseal" "followers" {
|
||||
|
||||
transport = {
|
||||
ssh = {
|
||||
host = aws_instance.vault_instance[0].public_ip
|
||||
host = var.ip_version == "6" ? aws_instance.vault_instance[0].ipv6_addresses[0] : aws_instance.vault_instance[0].public_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -315,13 +316,13 @@ resource "enos_vault_unseal" "when_vault_unseal_when_no_init_is_set" {
|
||||
|
||||
transport = {
|
||||
ssh = {
|
||||
host = aws_instance.vault_instance[each.key].public_ip
|
||||
host = var.ip_version == "6" ? aws_instance.vault_instance[each.key].ipv6_addresses[0] : aws_instance.vault_instance[each.key].public_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "enos_remote_exec" "vault_write_license" {
|
||||
count = var.vault_init ? 1 : 0
|
||||
count = var.deploy && var.vault_init ? 1 : 0
|
||||
depends_on = [
|
||||
enos_vault_unseal.leader,
|
||||
enos_vault_unseal.when_vault_unseal_when_no_init_is_set,
|
||||
@@ -335,7 +336,26 @@ resource "enos_remote_exec" "vault_write_license" {
|
||||
|
||||
transport = {
|
||||
ssh = {
|
||||
host = aws_instance.vault_instance[0].public_ip
|
||||
host = var.ip_version == "6" ? aws_instance.vault_instance[0].ipv6_addresses[0] : aws_instance.vault_instance[0].public_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "enos_remote_exec" "vault_kms_policy" {
|
||||
count = var.deploy && var.vault_init ? 1 : 0
|
||||
depends_on = [
|
||||
enos_remote_exec.vault_write_license,
|
||||
]
|
||||
|
||||
content = templatefile("${path.module}/templates/create-kms-policy.sh", {
|
||||
vault_bin_path = local.vault_bin_path,
|
||||
vault_root_token = coalesce(var.vault_root_token, try(enos_vault_init.leader[0].root_token, null), "none")
|
||||
policy_path = "${path.module}/policies/kms-transit.hcl"
|
||||
})
|
||||
|
||||
transport = {
|
||||
ssh = {
|
||||
host = var.ip_version == "6" ? aws_instance.vault_instance[0].ipv6_addresses[0] : aws_instance.vault_instance[0].public_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -210,7 +210,7 @@ output "vpc_id" {
|
||||
|
||||
output "vpc_cidr" {
|
||||
description = "CIDR for whole VPC"
|
||||
value = var.cidr
|
||||
value = aws_vpc.vpc.cidr_block
|
||||
}
|
||||
|
||||
output "vpc_subnets" {
|
||||
|
||||
@@ -0,0 +1,319 @@
|
||||
# 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"
|
||||
version = ">= 0.3.25"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
variable "name" {
|
||||
type = string
|
||||
default = "enos-vpc"
|
||||
description = "The name of the VPC"
|
||||
}
|
||||
|
||||
variable "availability_zones" {
|
||||
description = "List of AWS availability zones to use (or * for all available)"
|
||||
type = list(string)
|
||||
default = ["*"]
|
||||
}
|
||||
|
||||
variable "cidr" {
|
||||
type = string
|
||||
default = "10.13.0.0/16"
|
||||
description = "CIDR block for the VPC"
|
||||
}
|
||||
|
||||
variable "ipv6_cidr" {
|
||||
type = string
|
||||
default = "fd13:1:1::/48"
|
||||
description = "IPv6 CIDR block for the VPC"
|
||||
}
|
||||
|
||||
variable "environment" {
|
||||
description = "Name of the environment."
|
||||
type = string
|
||||
default = "enos-environment"
|
||||
}
|
||||
|
||||
variable "common_tags" {
|
||||
description = "Tags to set for all resources"
|
||||
type = map(string)
|
||||
default = { "Project" : "enos" }
|
||||
}
|
||||
|
||||
variable "create_kms_key" {
|
||||
description = "Whether or not to create an key management service key"
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "ami_architectures" {
|
||||
type = list(string)
|
||||
description = "The AMI architectures to fetch AMI IDs for."
|
||||
default = ["amd64", "arm64"]
|
||||
}
|
||||
|
||||
variable "ip_version" {
|
||||
description = "ip version used to setup boundary instance, should be 4, 6, or dual"
|
||||
type = string
|
||||
default = "4"
|
||||
|
||||
validation {
|
||||
condition = contains(["4", "6", "dual"], var.ip_version)
|
||||
error_message = "ip_version must be one of: [4, 6, dual]"
|
||||
}
|
||||
}
|
||||
|
||||
data "enos_environment" "localhost" {}
|
||||
|
||||
check "ipv6_connection" {
|
||||
assert {
|
||||
condition = var.ip_version != "6" || data.enos_environment.localhost.public_ipv6_addresses != null
|
||||
error_message = "no ipv6 connectivity detected, unable to set up ipv6-only tests"
|
||||
}
|
||||
}
|
||||
|
||||
locals {
|
||||
// AWS AMIs standardized on the x86_64 label for 64bit x86 architectures, therefore amd64 should be rather x86_64.
|
||||
architecture_filters = [for arch in var.ami_architectures : (arch == "amd64" ? "x86_64" : arch)]
|
||||
tag_module = "aws_vpc"
|
||||
common_tags = merge(
|
||||
var.common_tags,
|
||||
{
|
||||
"Module" = local.tag_module
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
data "aws_availability_zones" "available" {
|
||||
state = "available"
|
||||
|
||||
filter {
|
||||
name = "zone-name"
|
||||
values = var.availability_zones
|
||||
}
|
||||
}
|
||||
|
||||
data "aws_ami" "ubuntu" {
|
||||
most_recent = true
|
||||
count = length(local.architecture_filters)
|
||||
|
||||
# Currently latest LTS-1
|
||||
filter {
|
||||
name = "name"
|
||||
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-*-server-*"]
|
||||
}
|
||||
|
||||
filter {
|
||||
name = "virtualization-type"
|
||||
values = ["hvm"]
|
||||
}
|
||||
|
||||
filter {
|
||||
name = "architecture"
|
||||
values = [local.architecture_filters[count.index]]
|
||||
}
|
||||
|
||||
owners = ["099720109477"] # Canonical
|
||||
}
|
||||
|
||||
data "aws_ami" "rhel" {
|
||||
most_recent = true
|
||||
count = length(local.architecture_filters)
|
||||
|
||||
filter {
|
||||
name = "name"
|
||||
values = ["RHEL-8.8*HVM-20*"]
|
||||
}
|
||||
|
||||
filter {
|
||||
name = "virtualization-type"
|
||||
values = ["hvm"]
|
||||
}
|
||||
|
||||
filter {
|
||||
name = "architecture"
|
||||
values = [local.architecture_filters[count.index]]
|
||||
}
|
||||
|
||||
owners = ["309956199498"] # Redhat
|
||||
}
|
||||
|
||||
resource "random_string" "cluster_id" {
|
||||
length = 8
|
||||
lower = true
|
||||
upper = false
|
||||
numeric = false
|
||||
special = false
|
||||
}
|
||||
|
||||
resource "aws_kms_key" "key" {
|
||||
count = var.create_kms_key ? 1 : 0
|
||||
description = "enos-kms-key"
|
||||
deletion_window_in_days = 7 // 7 is the shortest allowed window
|
||||
}
|
||||
|
||||
resource "aws_kms_alias" "alias" {
|
||||
count = var.create_kms_key ? 1 : 0
|
||||
name = "alias/enos_key-${random_string.cluster_id.result}"
|
||||
target_key_id = aws_kms_key.key[0].key_id
|
||||
}
|
||||
|
||||
resource "aws_vpc" "vpc" {
|
||||
cidr_block = var.cidr
|
||||
enable_dns_hostnames = true
|
||||
enable_dns_support = true
|
||||
assign_generated_ipv6_cidr_block = true
|
||||
tags = merge(
|
||||
local.common_tags,
|
||||
{
|
||||
"Name" = var.name
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
resource "aws_subnet" "subnet" {
|
||||
count = length(data.aws_availability_zones.available.names)
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
cidr_block = cidrsubnet(var.cidr, 8, count.index)
|
||||
availability_zone = data.aws_availability_zones.available.names[count.index]
|
||||
map_public_ip_on_launch = true
|
||||
ipv6_cidr_block = cidrsubnet(aws_vpc.vpc.ipv6_cidr_block, 8, count.index + 16) # + 16 so we have some guaranteed unused subnets for other workers
|
||||
assign_ipv6_address_on_creation = true
|
||||
|
||||
tags = merge(
|
||||
local.common_tags,
|
||||
{
|
||||
"Name" = "${var.name}-subnet-${data.aws_availability_zones.available.names[count.index]}"
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
resource "aws_internet_gateway" "igw" {
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
|
||||
tags = merge(
|
||||
local.common_tags,
|
||||
{
|
||||
"Name" = "${var.name}-igw"
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
resource "aws_route" "igw_ipv6" {
|
||||
route_table_id = aws_vpc.vpc.default_route_table_id
|
||||
destination_ipv6_cidr_block = "::/0"
|
||||
gateway_id = aws_internet_gateway.igw.id
|
||||
}
|
||||
|
||||
resource "aws_route" "igw_ipv4" {
|
||||
count = var.ip_version == "6" ? 0 : 1
|
||||
route_table_id = aws_vpc.vpc.default_route_table_id
|
||||
destination_cidr_block = "0.0.0.0/0"
|
||||
gateway_id = aws_internet_gateway.igw.id
|
||||
}
|
||||
|
||||
resource "aws_security_group" "default" {
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
|
||||
ingress {
|
||||
description = "allow_ingress_from_ipv6_only"
|
||||
from_port = 0
|
||||
to_port = 0
|
||||
protocol = "tcp"
|
||||
ipv6_cidr_blocks = ["::/0"]
|
||||
}
|
||||
|
||||
ingress {
|
||||
description = "allow_ingress_only_from_ipv4_enos_host"
|
||||
from_port = 22
|
||||
to_port = 22
|
||||
protocol = "tcp"
|
||||
cidr_blocks = flatten([
|
||||
# allow ingress from ipv4 to allow for test setup from ci
|
||||
# TODO: remove this when github actions has ipv6 compatibility
|
||||
formatlist("%s/32", data.enos_environment.localhost.public_ipv4_addresses)
|
||||
])
|
||||
}
|
||||
|
||||
egress {
|
||||
description = "allow_egress_only_to_ipv4_enos_host"
|
||||
from_port = 22
|
||||
to_port = 22
|
||||
protocol = "tcp"
|
||||
cidr_blocks = flatten([
|
||||
# allow egress to ipv4 to allow for test setup from ci
|
||||
# TODO: remove this when github actions has ipv6 compatibility
|
||||
formatlist("%s/32", data.enos_environment.localhost.public_ipv4_addresses)
|
||||
])
|
||||
}
|
||||
|
||||
egress {
|
||||
description = "allow_egress_from_ipv6_only"
|
||||
from_port = 0
|
||||
to_port = 0
|
||||
protocol = "-1"
|
||||
ipv6_cidr_blocks = ["::/0"]
|
||||
}
|
||||
|
||||
tags = merge(
|
||||
local.common_tags,
|
||||
{
|
||||
"Name" = "${var.name}-default"
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
output "vpc_id" {
|
||||
description = "Created VPC ID"
|
||||
value = aws_vpc.vpc.id
|
||||
}
|
||||
|
||||
output "vpc_cidr" {
|
||||
description = "CIDR for whole VPC"
|
||||
value = aws_vpc.vpc.cidr_block
|
||||
}
|
||||
|
||||
output "vpc_cidr_ipv6" {
|
||||
description = "ipv6 CIDR for whole VPC"
|
||||
value = aws_vpc.vpc.ipv6_cidr_block
|
||||
}
|
||||
|
||||
output "vpc_subnets" {
|
||||
description = "Generated subnet IDs and CIDRs"
|
||||
value = { for s in aws_subnet.subnet : s.id => s.cidr_block }
|
||||
}
|
||||
|
||||
output "kms_key_arn" {
|
||||
description = "ARN of the generated KMS key"
|
||||
value = try(aws_kms_key.key[0].arn, null)
|
||||
}
|
||||
|
||||
output "kms_key_alias" {
|
||||
description = "Alias of the generated KMS key"
|
||||
value = try(aws_kms_alias.alias[0].name, null)
|
||||
}
|
||||
|
||||
output "availability_zone_names" {
|
||||
description = "All availability zones with resources"
|
||||
value = data.aws_availability_zones.available.names
|
||||
}
|
||||
|
||||
output "ami_ids" {
|
||||
description = "The AWS AMI IDs for to use for ubuntu and rhel based instance for the amd64 and arm64 architectures."
|
||||
value = {
|
||||
ubuntu = { for idx, arch in var.ami_architectures : arch => data.aws_ami.ubuntu[idx].id }
|
||||
rhel = { for idx, arch in var.ami_architectures : arch => data.aws_ami.rhel[idx].id }
|
||||
}
|
||||
}
|
||||
|
||||
output "vpc_tag_module" {
|
||||
value = local.tag_module
|
||||
}
|
||||
@@ -56,10 +56,13 @@ resource "random_integer" "az" {
|
||||
|
||||
# Create a subnet so that the worker doesn't share one with a controller
|
||||
resource "aws_subnet" "default" {
|
||||
vpc_id = var.vpc_id
|
||||
cidr_block = "10.13.9.0/24"
|
||||
map_public_ip_on_launch = true
|
||||
availability_zone = local.selected_az
|
||||
vpc_id = var.vpc_id
|
||||
cidr_block = "10.13.9.0/24"
|
||||
ipv6_cidr_block = var.ip_version != "4" ? cidrsubnet(var.vpc_cidr_ipv6, 8, 0) : null
|
||||
|
||||
map_public_ip_on_launch = true
|
||||
assign_ipv6_address_on_creation = var.ip_version != "4"
|
||||
availability_zone = local.selected_az
|
||||
tags = merge(
|
||||
local.common_tags,
|
||||
{
|
||||
@@ -79,22 +82,28 @@ resource "aws_security_group" "default" {
|
||||
from_port = 22
|
||||
to_port = 22
|
||||
protocol = "tcp"
|
||||
cidr_blocks = flatten([formatlist("%s/32", data.enos_environment.current.public_ipv4_addresses)])
|
||||
cidr_blocks = var.ip_version == "6" ? [] : flatten([
|
||||
# allow ingress from ipv4 to allow for test setup from ci
|
||||
formatlist("%s/32", data.enos_environment.current.public_ipv4_addresses)
|
||||
])
|
||||
ipv6_cidr_blocks = var.ip_version == "4" ? [] : (data.enos_environment.current.public_ipv6_addresses != null ? [for ip in data.enos_environment.current.public_ipv6_addresses : cidrsubnet("${ip}/64", 0, 0)] : [])
|
||||
}
|
||||
|
||||
ingress {
|
||||
description = "Communication from Boundary controller to worker"
|
||||
from_port = 9202
|
||||
to_port = 9202
|
||||
protocol = "tcp"
|
||||
cidr_blocks = ["0.0.0.0/0"]
|
||||
description = "Communication from Boundary controller to worker"
|
||||
from_port = 9202
|
||||
to_port = 9202
|
||||
protocol = "tcp"
|
||||
cidr_blocks = var.ip_version == "6" ? [] : ["0.0.0.0/0"]
|
||||
ipv6_cidr_blocks = var.ip_version == "4" ? [] : ["::/0"]
|
||||
}
|
||||
|
||||
egress {
|
||||
from_port = 0
|
||||
to_port = 0
|
||||
protocol = "-1"
|
||||
cidr_blocks = ["0.0.0.0/0"]
|
||||
from_port = 0
|
||||
to_port = 0
|
||||
protocol = "-1"
|
||||
cidr_blocks = var.ip_version == "6" ? [] : ["0.0.0.0/0"]
|
||||
ipv6_cidr_blocks = var.ip_version == "4" ? [] : ["::/0"]
|
||||
}
|
||||
|
||||
tags = merge(
|
||||
@@ -110,7 +119,8 @@ resource "aws_security_group" "default" {
|
||||
resource "aws_vpc_security_group_ingress_rule" "worker_to_controller" {
|
||||
description = "This rule allows traffic from a worker to controllers over WAN"
|
||||
security_group_id = var.controller_sg_id
|
||||
cidr_ipv4 = "${aws_instance.worker.public_ip}/32"
|
||||
cidr_ipv4 = var.ip_version == "4" ? "${aws_instance.worker.public_ip}/32" : null
|
||||
cidr_ipv6 = var.ip_version == "4" ? null : cidrsubnet("${aws_instance.worker.ipv6_addresses[0]}/64", 0, 0)
|
||||
from_port = 9201
|
||||
to_port = 9201
|
||||
ip_protocol = "tcp"
|
||||
@@ -134,6 +144,8 @@ resource "aws_instance" "worker" {
|
||||
iam_instance_profile = aws_iam_instance_profile.boundary_profile.name
|
||||
monitoring = var.worker_monitoring
|
||||
|
||||
ipv6_address_count = var.ip_version == "4" ? 0 : 1
|
||||
|
||||
root_block_device {
|
||||
iops = var.ebs_iops
|
||||
volume_size = var.ebs_size
|
||||
@@ -160,7 +172,7 @@ resource "enos_bundle_install" "worker" {
|
||||
|
||||
transport = {
|
||||
ssh = {
|
||||
host = aws_instance.worker.public_ip
|
||||
host = var.ip_version == "6" ? aws_instance.worker.ipv6_addresses[0] : aws_instance.worker.public_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -176,7 +188,7 @@ resource "enos_remote_exec" "update_path_worker" {
|
||||
|
||||
transport = {
|
||||
ssh = {
|
||||
host = aws_instance.worker.public_ip
|
||||
host = var.ip_version == "6" ? aws_instance.worker.ipv6_addresses[0] : aws_instance.worker.public_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -193,17 +205,20 @@ resource "enos_file" "worker_config" {
|
||||
content = templatefile("${path.module}/${var.config_file_path}", {
|
||||
id = random_pet.worker.id
|
||||
kms_key_id = data.aws_kms_key.kms_key.id
|
||||
public_addr = aws_instance.worker.public_ip
|
||||
controller_ips = var.ip_version == "4" ? jsonencode(var.controller_addresses) : jsonencode(formatlist("[%s]:9201", var.controller_addresses))
|
||||
listener_address = var.ip_version == "4" ? "0.0.0.0" : "[::]"
|
||||
public_address = var.ip_version == "6" ? format("[%s]", aws_instance.worker.ipv6_addresses[0]) : aws_instance.worker.public_ip
|
||||
type = jsonencode(var.worker_type_tags)
|
||||
region = data.aws_availability_zone.worker_az.region
|
||||
controller_addresses = jsonencode(var.controller_addresses)
|
||||
recording_storage_path = var.recording_storage_path
|
||||
audit_log_dir = local.audit_log_directory
|
||||
vault_address = var.ip_version == "4" ? var.vault_address : try(format("[%s]", var.vault_address), "")
|
||||
vault_transit_token = var.vault_transit_token
|
||||
})
|
||||
|
||||
transport = {
|
||||
ssh = {
|
||||
host = aws_instance.worker.public_ip
|
||||
host = var.ip_version == "6" ? aws_instance.worker.ipv6_addresses[0] : aws_instance.worker.public_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -219,7 +234,7 @@ resource "enos_boundary_start" "worker_start" {
|
||||
recording_storage_path = var.recording_storage_path != "" ? var.recording_storage_path : null
|
||||
transport = {
|
||||
ssh = {
|
||||
host = aws_instance.worker.public_ip
|
||||
host = var.ip_version == "6" ? aws_instance.worker.ipv6_addresses[0] : aws_instance.worker.public_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -238,7 +253,7 @@ resource "enos_remote_exec" "create_worker_audit_log_dir" {
|
||||
|
||||
transport = {
|
||||
ssh = {
|
||||
host = aws_instance.worker.public_ip
|
||||
host = var.ip_version == "6" ? aws_instance.worker.ipv6_addresses[0] : aws_instance.worker.public_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
output "worker_ip" {
|
||||
description = "The public IP of the Boundary worker"
|
||||
value = aws_instance.worker.public_ip
|
||||
value = var.ip_version == "6" ? format("[%s]", aws_instance.worker.ipv6_addresses[0]) : aws_instance.worker.public_ip
|
||||
}
|
||||
|
||||
output "worker_tags" {
|
||||
@@ -25,3 +25,13 @@ output "role_arn" {
|
||||
description = "The ARN of the IAM role used in this module"
|
||||
value = aws_iam_role.boundary_instance_role.arn
|
||||
}
|
||||
|
||||
output "worker_cidr" {
|
||||
description = "The subnet of the isolated worker"
|
||||
value = var.ip_version == "6" ? [] : [aws_subnet.default.cidr_block]
|
||||
}
|
||||
|
||||
output "worker_ipv6_cidr" {
|
||||
description = "The ipv6 subnet of the isolated worker"
|
||||
value = var.ip_version == "4" ? [] : [aws_subnet.default.ipv6_cidr_block]
|
||||
}
|
||||
@@ -2,9 +2,9 @@
|
||||
# SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
listener "tcp" {
|
||||
purpose = "proxy"
|
||||
purpose = "proxy"
|
||||
tls_disable = true
|
||||
address = "0.0.0.0"
|
||||
address = "${listener_address}:9202"
|
||||
}
|
||||
|
||||
worker {
|
||||
@@ -13,9 +13,9 @@ worker {
|
||||
description = "Enos Boundary worker ${id}"
|
||||
|
||||
# Workers must be able to reach controllers on :9201
|
||||
initial_upstreams = ${controller_addresses}
|
||||
initial_upstreams = ${controller_ips}
|
||||
|
||||
public_addr = "${public_addr}"
|
||||
public_addr = "${public_address}"
|
||||
|
||||
tags {
|
||||
region = ["${region}"]
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
listener "tcp" {
|
||||
purpose = "proxy"
|
||||
tls_disable = true
|
||||
address = "0.0.0.0"
|
||||
address = "${listener_address}:9202"
|
||||
}
|
||||
|
||||
worker {
|
||||
@@ -13,9 +13,9 @@ worker {
|
||||
description = "Enos Boundary worker ${id}"
|
||||
|
||||
# Workers must be able to reach controllers on :9201
|
||||
initial_upstreams = ${controller_addresses}
|
||||
initial_upstreams = ${controller_ips}
|
||||
|
||||
public_addr = "${public_addr}"
|
||||
public_addr = "${public_address}"
|
||||
|
||||
tags {
|
||||
region = ["${region}"]
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
# Copyright (c) HashiCorp, Inc.
|
||||
# SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
listener "tcp" {
|
||||
purpose = "proxy"
|
||||
tls_disable = true
|
||||
address = "${listener_address}:9202"
|
||||
}
|
||||
|
||||
worker {
|
||||
# Name attr must be unique across workers
|
||||
name = "demo-worker-${id}"
|
||||
description = "Enos Boundary worker ${id}"
|
||||
|
||||
# Workers must be able to reach controllers on :9201
|
||||
initial_upstreams = ${controller_ips}
|
||||
|
||||
public_addr = "${public_address}"
|
||||
|
||||
tags {
|
||||
type = ${type}
|
||||
region = ["${region}"]
|
||||
}
|
||||
|
||||
recording_storage_path = "${recording_storage_path}"
|
||||
}
|
||||
|
||||
# must be same key as used on controller config
|
||||
kms "transit" {
|
||||
purpose = "worker-auth"
|
||||
address = "http://${vault_address}:8200"
|
||||
token = "${vault_transit_token}"
|
||||
disable_renewal = "false"
|
||||
key_name = "boundary-worker-auth"
|
||||
mount_path = "transit/"
|
||||
tls_skip_verify = "true"
|
||||
}
|
||||
|
||||
events {
|
||||
audit_enabled = true
|
||||
observations_enabled = true
|
||||
sysevents_enabled = true
|
||||
|
||||
sink "stderr" {
|
||||
name = "all-events"
|
||||
description = "All events sent to stderr"
|
||||
event_types = ["*"]
|
||||
format = "cloudevents-json"
|
||||
|
||||
deny_filters = [
|
||||
"\"/data/request_info/method\" contains \"Status\"",
|
||||
"\"/data/request_info/path\" contains \"/health\"",
|
||||
]
|
||||
}
|
||||
|
||||
sink {
|
||||
name = "audit-sink"
|
||||
description = "Audit sent to a file"
|
||||
event_types = ["audit"]
|
||||
format = "cloudevents-json"
|
||||
|
||||
deny_filters = [
|
||||
"\"/data/request_info/method\" contains \"Status\"",
|
||||
]
|
||||
|
||||
file {
|
||||
path = "${audit_log_dir}"
|
||||
file_name = "audit.log"
|
||||
}
|
||||
|
||||
audit_config {
|
||||
audit_filter_overrides {
|
||||
secret = "encrypt"
|
||||
sensitive = "hmac-sha256"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -142,3 +142,40 @@ variable "bucket_arn" {
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "vpc_cidr" {
|
||||
description = "cidr subnet of the vpc created for the enos scenario"
|
||||
type = string
|
||||
nullable = true
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "vpc_cidr_ipv6" {
|
||||
description = "ipv6 cidr subnet of the vpc created for the enos scenario"
|
||||
type = string
|
||||
nullable = true
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "ip_version" {
|
||||
description = "ip version used to setup boundary instance, should be 4, 6, or dual"
|
||||
type = string
|
||||
default = "4"
|
||||
|
||||
validation {
|
||||
condition = contains(["4", "6", "dual"], var.ip_version)
|
||||
error_message = "ip_version must be one of: [4, 6, dual]"
|
||||
}
|
||||
}
|
||||
|
||||
variable "vault_address" {
|
||||
description = "network address to a vault instance"
|
||||
type = string
|
||||
default = "localhost"
|
||||
}
|
||||
|
||||
variable "vault_transit_token" {
|
||||
description = "vault token used for kms transit in the boundary config"
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
# Copyright (c) HashiCorp, Inc.
|
||||
# SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
variable "file_name" {}
|
||||
variable "license_path" {}
|
||||
|
||||
output "license" {
|
||||
value = file(var.file_name)
|
||||
value = file(var.license_path)
|
||||
}
|
||||
@@ -140,7 +140,11 @@ variable "worker_tag_ingress" {
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
variable "worker_tag_egress" {
|
||||
variable "worker_tag_isolated" {
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
variable "worker_tag_collocated" {
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
@@ -157,6 +161,17 @@ variable "boundary_license" {
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "ip_version" {
|
||||
description = "ip version used to setup boundary instance, should be 4, 6, or dual"
|
||||
type = string
|
||||
default = "4"
|
||||
|
||||
validation {
|
||||
condition = contains(["4", "6", "dual"], var.ip_version)
|
||||
error_message = "ip_version must be one of: [4, 6, dual]"
|
||||
}
|
||||
}
|
||||
|
||||
locals {
|
||||
aws_ssh_private_key_path = abspath(var.aws_ssh_private_key_path)
|
||||
vault_addr = var.vault_addr != "" ? "http://${var.vault_addr}:${var.vault_port}" : ""
|
||||
@@ -192,9 +207,11 @@ resource "enos_local_exec" "run_e2e_test" {
|
||||
E2E_AWS_BUCKET_NAME = var.aws_bucket_name
|
||||
E2E_AWS_ROLE_ARN = var.aws_role_arn
|
||||
E2E_WORKER_TAG_INGRESS = var.worker_tag_ingress
|
||||
E2E_WORKER_TAG_EGRESS = var.worker_tag_egress
|
||||
E2E_WORKER_TAG_ISOLATED = var.worker_tag_isolated
|
||||
E2E_WORKER_TAG_COLLOCATED = var.worker_tag_collocated
|
||||
E2E_WORKER_ADDRESS = var.worker_address
|
||||
E2E_MAX_PAGE_SIZE = var.max_page_size
|
||||
E2E_IP_VERSION = var.ip_version
|
||||
}
|
||||
|
||||
inline = var.debug_no_run ? [""] : [
|
||||
|
||||
@@ -203,19 +203,30 @@ func AddHostToHostSetCli(t testing.TB, ctx context.Context, hostSetId string, ho
|
||||
|
||||
// CreateAwsHostCatalogCli uses the cli to create a new AWS dynamic host catalog.
|
||||
// Returns the id of the new host catalog.
|
||||
func CreateAwsHostCatalogCli(t testing.TB, ctx context.Context, projectId, accessKeyId, secretAccessKey, region string) (string, error) {
|
||||
func CreateAwsHostCatalogCli(t testing.TB, ctx context.Context, projectId, accessKeyId, secretAccessKey, region string, dualStack bool) (string, error) {
|
||||
name, err := base62.Random(16)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
output := e2e.RunCommand(ctx, "boundary",
|
||||
opts := []e2e.Option{
|
||||
e2e.WithArgs(
|
||||
"host-catalogs", "create", "plugin",
|
||||
"-scope-id", projectId,
|
||||
"-plugin-name", "aws",
|
||||
"-attr", "disable_credential_rotation=true",
|
||||
"-attr", fmt.Sprintf("region=%s", region),
|
||||
),
|
||||
}
|
||||
if dualStack {
|
||||
opts = append(opts,
|
||||
e2e.WithArgs(
|
||||
"-attr", fmt.Sprintf("dual_stack=%t", dualStack),
|
||||
),
|
||||
)
|
||||
}
|
||||
opts = append(opts,
|
||||
e2e.WithArgs(
|
||||
"-secret", "access_key_id=env://E2E_AWS_ACCESS_KEY_ID",
|
||||
"-secret", "secret_access_key=env://E2E_AWS_SECRET_ACCESS_KEY",
|
||||
"-name", fmt.Sprintf("e2e Host Catalog %s", name),
|
||||
@@ -225,6 +236,7 @@ func CreateAwsHostCatalogCli(t testing.TB, ctx context.Context, projectId, acces
|
||||
e2e.WithEnv("E2E_AWS_ACCESS_KEY_ID", accessKeyId),
|
||||
e2e.WithEnv("E2E_AWS_SECRET_ACCESS_KEY", secretAccessKey),
|
||||
)
|
||||
output := e2e.RunCommand(ctx, "boundary", opts...)
|
||||
if output.Err != nil {
|
||||
return "", fmt.Errorf("%w: %s", output.Err, string(output.Stderr))
|
||||
}
|
||||
@@ -242,22 +254,41 @@ func CreateAwsHostCatalogCli(t testing.TB, ctx context.Context, projectId, acces
|
||||
|
||||
// CreatePluginHostSetCli uses the cli to create a new host set from a dynamic host catalog.
|
||||
// Returns the id of the new host set.
|
||||
func CreatePluginHostSetCli(t testing.TB, ctx context.Context, hostCatalogId string, filter string) (string, error) {
|
||||
func CreatePluginHostSetCli(t testing.TB, ctx context.Context, hostCatalogId string, filter string, ipVersion string) (string, error) {
|
||||
name, err := base62.Random(16)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
output := e2e.RunCommand(ctx, "boundary",
|
||||
e2e.WithArgs(
|
||||
"host-sets", "create", "plugin",
|
||||
"-host-catalog-id", hostCatalogId,
|
||||
"-attr", "filters="+filter,
|
||||
"-name", fmt.Sprintf("e2e Host Set %s", name),
|
||||
"-description", "e2e",
|
||||
"-format", "json",
|
||||
),
|
||||
)
|
||||
var output *e2e.CommandResult
|
||||
switch ipVersion {
|
||||
case "4":
|
||||
output = e2e.RunCommand(ctx, "boundary",
|
||||
e2e.WithArgs(
|
||||
"host-sets", "create", "plugin",
|
||||
"-host-catalog-id", hostCatalogId,
|
||||
"-attr", "filters="+filter,
|
||||
"-name", fmt.Sprintf("e2e Host Set %s", name),
|
||||
"-description", "e2e",
|
||||
"-format", "json",
|
||||
),
|
||||
)
|
||||
case "6", "dual":
|
||||
output = e2e.RunCommand(ctx, "boundary",
|
||||
e2e.WithArgs(
|
||||
"host-sets", "create", "plugin",
|
||||
"-host-catalog-id", hostCatalogId,
|
||||
"-preferred-endpoint", "cidr:::/0",
|
||||
"-attr", "filters="+filter,
|
||||
"-name", fmt.Sprintf("e2e Host Set %s", name),
|
||||
"-description", "e2e",
|
||||
"-format", "json",
|
||||
),
|
||||
)
|
||||
default:
|
||||
return "", fmt.Errorf("unknown ip version: %q", ipVersion)
|
||||
}
|
||||
|
||||
if output.Err != nil {
|
||||
return "", fmt.Errorf("%w: %s", output.Err, string(output.Stderr))
|
||||
}
|
||||
|
||||
@@ -38,11 +38,11 @@ func TestCliCreateAwsDynamicHostCatalogWithEmptyHostSet(t *testing.T) {
|
||||
})
|
||||
projectId, err := boundary.CreateProjectCli(t, ctx, orgId)
|
||||
require.NoError(t, err)
|
||||
hostCatalogId, err := boundary.CreateAwsHostCatalogCli(t, ctx, projectId, c.AwsAccessKeyId, c.AwsSecretAccessKey, c.AwsRegion)
|
||||
hostCatalogId, err := boundary.CreateAwsHostCatalogCli(t, ctx, projectId, c.AwsAccessKeyId, c.AwsSecretAccessKey, c.AwsRegion, c.IpVersion != "4")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set up a host set
|
||||
hostSetId, err := boundary.CreatePluginHostSetCli(t, ctx, hostCatalogId, "tag:empty_test=true")
|
||||
hostSetId, err := boundary.CreatePluginHostSetCli(t, ctx, hostCatalogId, "tag:empty_test=true", c.IpVersion)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Check that there are no hosts in the host set
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"regexp"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -17,12 +17,17 @@ import (
|
||||
"github.com/hashicorp/boundary/api/hosts"
|
||||
"github.com/hashicorp/boundary/api/hostsets"
|
||||
"github.com/hashicorp/boundary/api/scopes"
|
||||
"github.com/hashicorp/boundary/api/sessions"
|
||||
"github.com/hashicorp/boundary/internal/session"
|
||||
"github.com/hashicorp/boundary/internal/target"
|
||||
"github.com/hashicorp/boundary/testing/internal/e2e"
|
||||
"github.com/hashicorp/boundary/testing/internal/e2e/boundary"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var sessionRegex = regexp.MustCompile("Session ID:\\s+(.+)(?:$|\n)")
|
||||
|
||||
// TestCliCreateAwsDynamicHostCatalogWithHostSet uses the boundary cli to create a host catalog with the AWS
|
||||
// plugin. The test sets up an AWS dynamic host catalog, creates some host sets, sets up a target to
|
||||
// one of the host sets, and attempts to connect to the target.
|
||||
@@ -43,11 +48,11 @@ func TestCliCreateAwsDynamicHostCatalogWithHostSet(t *testing.T) {
|
||||
})
|
||||
projectId, err := boundary.CreateProjectCli(t, ctx, orgId)
|
||||
require.NoError(t, err)
|
||||
hostCatalogId, err := boundary.CreateAwsHostCatalogCli(t, ctx, projectId, c.AwsAccessKeyId, c.AwsSecretAccessKey, c.AwsRegion)
|
||||
hostCatalogId, err := boundary.CreateAwsHostCatalogCli(t, ctx, projectId, c.AwsAccessKeyId, c.AwsSecretAccessKey, c.AwsRegion, c.IpVersion != "4")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set up a host set
|
||||
hostSetId1, err := boundary.CreatePluginHostSetCli(t, ctx, hostCatalogId, c.AwsHostSetFilter1)
|
||||
hostSetId1, err := boundary.CreatePluginHostSetCli(t, ctx, hostCatalogId, c.AwsHostSetFilter1, c.IpVersion)
|
||||
require.NoError(t, err)
|
||||
var targetIps1 []string
|
||||
err = json.Unmarshal([]byte(c.AwsHostSetIps1), &targetIps1)
|
||||
@@ -56,7 +61,7 @@ func TestCliCreateAwsDynamicHostCatalogWithHostSet(t *testing.T) {
|
||||
boundary.WaitForNumberOfHostsInHostSetCli(t, ctx, hostSetId1, expectedHostSetCount1)
|
||||
|
||||
// Set up another host set
|
||||
hostSetId2, err := boundary.CreatePluginHostSetCli(t, ctx, hostCatalogId, c.AwsHostSetFilter2)
|
||||
hostSetId2, err := boundary.CreatePluginHostSetCli(t, ctx, hostCatalogId, c.AwsHostSetFilter2, c.IpVersion)
|
||||
require.NoError(t, err)
|
||||
var targetIps2 []string
|
||||
err = json.Unmarshal([]byte(c.AwsHostSetIps2), &targetIps2)
|
||||
@@ -112,41 +117,63 @@ func TestCliCreateAwsDynamicHostCatalogWithHostSet(t *testing.T) {
|
||||
assert.Equal(t, expectedHostCatalogCount, actualHostCatalogCount, "Numbers of hosts in host catalog did not match expected amount")
|
||||
|
||||
// Create target
|
||||
targetId, err := boundary.CreateTargetCli(t, ctx, projectId, c.TargetPort)
|
||||
var targetId string
|
||||
if c.IpVersion == "4" {
|
||||
targetId, err = boundary.CreateTargetCli(t, ctx, projectId, c.TargetPort)
|
||||
} else {
|
||||
targetId, err = boundary.CreateTargetCli(t, ctx, projectId, c.TargetPort,
|
||||
target.WithIngressWorkerFilter(fmt.Sprintf(`"%s" in "/tags/type"`, c.WorkerTagCollocated)),
|
||||
)
|
||||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
err = boundary.AddHostSourceToTargetCli(t, ctx, targetId, hostSetId1)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Connect to target
|
||||
ctxCancel, cancel := context.WithCancel(context.Background())
|
||||
go func() {
|
||||
e2e.RunCommand(ctxCancel, "boundary",
|
||||
e2e.WithArgs(
|
||||
"connect",
|
||||
"-target-id", targetId,
|
||||
"-exec", "/usr/bin/ssh", "--",
|
||||
"-l", c.TargetSshUser,
|
||||
"-i", c.TargetSshKeyPath,
|
||||
"-o", "UserKnownHostsFile=/dev/null",
|
||||
"-o", "StrictHostKeyChecking=no",
|
||||
"-o", "IdentitiesOnly=yes", // forces the use of the provided key
|
||||
"-p", "{{boundary.port}}", // this is provided by boundary
|
||||
"{{boundary.ip}}",
|
||||
"hostname -i; sleep 60",
|
||||
),
|
||||
)
|
||||
}()
|
||||
t.Cleanup(cancel)
|
||||
|
||||
s := boundary.WaitForSessionCli(t, ctx, projectId)
|
||||
boundary.WaitForSessionStatusCli(t, ctx, s.Id, session.StatusActive.String())
|
||||
|
||||
output = e2e.RunCommand(ctx, "boundary",
|
||||
e2e.WithArgs(
|
||||
"connect",
|
||||
"-target-id", targetId,
|
||||
"-exec", "/usr/bin/ssh", "--",
|
||||
"-l", c.TargetSshUser,
|
||||
"-i", c.TargetSshKeyPath,
|
||||
"-o", "UserKnownHostsFile=/dev/null",
|
||||
"-o", "StrictHostKeyChecking=no",
|
||||
"-o", "IdentitiesOnly=yes", // forces the use of the provided key
|
||||
"-p", "{{boundary.port}}", // this is provided by boundary
|
||||
"{{boundary.ip}}",
|
||||
"hostname", "-i",
|
||||
),
|
||||
e2e.WithArgs("sessions", "read", "-id", s.Id, "-format", "json"),
|
||||
)
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
var sessionReadResult sessions.SessionReadResult
|
||||
err = json.Unmarshal(output.Stdout, &sessionReadResult)
|
||||
require.NoError(t, err)
|
||||
s = sessionReadResult.Item
|
||||
|
||||
parts := strings.Fields(string(output.Stdout))
|
||||
hostIp := parts[len(parts)-1]
|
||||
t.Log("Successfully connected to the target")
|
||||
|
||||
// Check if connected host exists in the host set
|
||||
hostIpInList := false
|
||||
for _, v := range targetIps1 {
|
||||
if v == hostIp {
|
||||
hostIpInList = true
|
||||
}
|
||||
require.Greater(t, len(s.Connections), 0)
|
||||
var hostIp string
|
||||
switch c.IpVersion {
|
||||
case "4":
|
||||
hostIp = s.Connections[0].EndpointTcpAddress
|
||||
case "6", "dual":
|
||||
hostIp = fmt.Sprintf("[%s]", s.Connections[0].EndpointTcpAddress)
|
||||
default:
|
||||
require.Fail(t, "unknown ip version", c.IpVersion)
|
||||
}
|
||||
require.True(t, hostIpInList, fmt.Sprintf("Connected host (%s) is not in expected list (%s)", hostIp, targetIps1))
|
||||
require.Contains(t, targetIps1, hostIp, fmt.Sprintf("Connected host (%s) is not in expected list (%s)", hostIp, targetIps1))
|
||||
}
|
||||
|
||||
// TestApiCreateAwsDynamicHostCatalog uses the Go api to create a host catalog with the AWS plugin.
|
||||
|
||||
@@ -6,21 +6,23 @@ package aws_test
|
||||
import "github.com/kelseyhightower/envconfig"
|
||||
|
||||
type config struct {
|
||||
AwsAccessKeyId string `envconfig:"E2E_AWS_ACCESS_KEY_ID" required:"true"`
|
||||
AwsBucketName string `envconfig:"E2E_AWS_BUCKET_NAME" required:"true"`
|
||||
AwsSecretAccessKey string `envconfig:"E2E_AWS_SECRET_ACCESS_KEY" required:"true"`
|
||||
AwsHostSetFilter1 string `envconfig:"E2E_AWS_HOST_SET_FILTER" required:"true"` // e.g. "tag:testtag=true"
|
||||
AwsHostSetIps1 string `envconfig:"E2E_AWS_HOST_SET_IPS" required:"true"` // e.g. "[\"1.2.3.4\", \"2.3.4.5\"]"
|
||||
AwsHostSetFilter2 string `envconfig:"E2E_AWS_HOST_SET_FILTER2" required:"true"` // e.g. "tag:testtagtwo=test"
|
||||
AwsHostSetIps2 string `envconfig:"E2E_AWS_HOST_SET_IPS2" required:"true"` // e.g. "[\"1.2.3.4\"]"
|
||||
AwsRegion string `envconfig:"E2E_AWS_REGION" required:"true"` // e.g. "us-east-1"
|
||||
TargetSshKeyPath string `envconfig:"E2E_SSH_KEY_PATH" required:"true"` // e.g. "/Users/username/key.pem"
|
||||
TargetSshUser string `envconfig:"E2E_SSH_USER" required:"true"` // e.g. "ubuntu"
|
||||
TargetPort string `envconfig:"E2E_TARGET_PORT" required:"true"` // e.g. "22"
|
||||
TargetAddress string `envconfig:"E2E_TARGET_ADDRESS" required:"true"` // e.g. "192.168.0.1"
|
||||
WorkerTagEgress string `envconfig:"E2E_WORKER_TAG_EGRESS" required:"true"` // e.g. "egress"
|
||||
WorkerAddress string `envconfig:"E2E_WORKER_ADDRESS" required:"true"` // e.g. ""192.168.0.2"
|
||||
MaxPageSize int `envconfig:"E2E_MAX_PAGE_SIZE" default:"1000"`
|
||||
AwsAccessKeyId string `envconfig:"E2E_AWS_ACCESS_KEY_ID" required:"true"`
|
||||
AwsBucketName string `envconfig:"E2E_AWS_BUCKET_NAME" required:"true"`
|
||||
AwsSecretAccessKey string `envconfig:"E2E_AWS_SECRET_ACCESS_KEY" required:"true"`
|
||||
AwsHostSetFilter1 string `envconfig:"E2E_AWS_HOST_SET_FILTER" required:"true"` // e.g. "tag:testtag=true"
|
||||
AwsHostSetIps1 string `envconfig:"E2E_AWS_HOST_SET_IPS" required:"true"` // e.g. "[\"1.2.3.4\", \"2.3.4.5\"]"
|
||||
AwsHostSetFilter2 string `envconfig:"E2E_AWS_HOST_SET_FILTER2" required:"true"` // e.g. "tag:testtagtwo=test"
|
||||
AwsHostSetIps2 string `envconfig:"E2E_AWS_HOST_SET_IPS2" required:"true"` // e.g. "[\"1.2.3.4\"]"
|
||||
AwsRegion string `envconfig:"E2E_AWS_REGION" required:"true"` // e.g. "us-east-1"
|
||||
TargetSshKeyPath string `envconfig:"E2E_SSH_KEY_PATH" required:"true"` // e.g. "/Users/username/key.pem"
|
||||
TargetSshUser string `envconfig:"E2E_SSH_USER" required:"true"` // e.g. "ubuntu"
|
||||
TargetPort string `envconfig:"E2E_TARGET_PORT" required:"true"` // e.g. "22"
|
||||
TargetAddress string `envconfig:"E2E_TARGET_ADDRESS" required:"true"` // e.g. "192.168.0.1"
|
||||
WorkerTagIsolated string `envconfig:"E2E_WORKER_TAG_ISOLATED" required:"true"` // e.g. "isolated"
|
||||
WorkerTagCollocated string `envconfig:"E2E_WORKER_TAG_COLLOCATED" required:"true"` // e.g. "collocated"
|
||||
WorkerAddress string `envconfig:"E2E_WORKER_ADDRESS" required:"true"` // e.g. "192.168.0.2"
|
||||
MaxPageSize int `envconfig:"E2E_MAX_PAGE_SIZE" default:"1000"`
|
||||
IpVersion string `envconfig:"E2E_IP_VERSION" default:"4"` // should always be 4, 6, or dual
|
||||
}
|
||||
|
||||
func loadTestConfig() (*config, error) {
|
||||
|
||||
@@ -74,7 +74,7 @@ func TestCliWorker(t *testing.T) {
|
||||
e2e.WithArgs(
|
||||
"targets", "update", "tcp",
|
||||
"-id", targetId,
|
||||
"-egress-worker-filter", fmt.Sprintf(`"%s" in "/tags/type"`, c.WorkerTagEgress),
|
||||
"-egress-worker-filter", fmt.Sprintf(`"%s" in "/tags/type"`, c.WorkerTagIsolated),
|
||||
"-format", "json",
|
||||
),
|
||||
)
|
||||
|
||||
@@ -241,9 +241,9 @@ func populateBoundaryDatabase(t testing.TB, ctx context.Context, c *config, te T
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create AWS dynamic host catalog
|
||||
awsHostCatalogId, err := boundary.CreateAwsHostCatalogCli(t, ctx, projectId, c.AwsAccessKeyId, c.AwsSecretAccessKey, c.AwsRegion)
|
||||
awsHostCatalogId, err := boundary.CreateAwsHostCatalogCli(t, ctx, projectId, c.AwsAccessKeyId, c.AwsSecretAccessKey, c.AwsRegion, false)
|
||||
require.NoError(t, err)
|
||||
awsHostSetId, err := boundary.CreatePluginHostSetCli(t, ctx, awsHostCatalogId, c.AwsHostSetFilter)
|
||||
awsHostSetId, err := boundary.CreatePluginHostSetCli(t, ctx, awsHostCatalogId, c.AwsHostSetFilter, "4")
|
||||
require.NoError(t, err)
|
||||
boundary.WaitForHostsInHostSetCli(t, ctx, awsHostSetId)
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ func TestCliCreateGcpDynamicHostCatalogWithEmptyHostSet(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set up a host set
|
||||
hostSetId, err := boundary.CreatePluginHostSetCli(t, ctx, hostCatalogId, "labels.empty_test=true")
|
||||
hostSetId, err := boundary.CreatePluginHostSetCli(t, ctx, hostCatalogId, "labels.empty_test=true", "4")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Check that there are no hosts in the host set
|
||||
|
||||
@@ -48,12 +48,12 @@ func TestCliCreateGcpDynamicHostCatalogWithHostSet(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// Set up a host set
|
||||
hostSetId1, err := boundary.CreatePluginHostSetCli(t, ctx, hostCatalogId, c.GcpHostSetFilter1)
|
||||
hostSetId1, err := boundary.CreatePluginHostSetCli(t, ctx, hostCatalogId, c.GcpHostSetFilter1, "4")
|
||||
require.NoError(t, err)
|
||||
boundary.WaitForNumberOfHostsInHostSetCli(t, ctx, hostSetId1, 1)
|
||||
|
||||
// Set up another host set
|
||||
hostSetId2, err := boundary.CreatePluginHostSetCli(t, ctx, hostCatalogId, c.GcpHostSetFilter2)
|
||||
hostSetId2, err := boundary.CreatePluginHostSetCli(t, ctx, hostCatalogId, c.GcpHostSetFilter2, "4")
|
||||
require.NoError(t, err)
|
||||
boundary.WaitForNumberOfHostsInHostSetCli(t, ctx, hostSetId2, 1)
|
||||
|
||||
|
||||
Reference in new issue
Block a user