test(e2e): Add vault tests
Adds the first set of vault tests. This test sets up vault as a credential store and creates a set of credentials for a target.
This commit is contained in:
1 parent
6e53747b97
commit
8fe0d13caa
13 files changed
+922
-92
No files matched your search
@@ -2,6 +2,10 @@ module "az_finder" {
|
||||
source = "./modules/az_finder"
|
||||
}
|
||||
|
||||
module "binary_finder" {
|
||||
source = "./modules/binary_finder"
|
||||
}
|
||||
|
||||
module "boundary" {
|
||||
source = "app.terraform.io/hashicorp-qti/aws-boundary/enos"
|
||||
version = ">= 0.2.6"
|
||||
@@ -58,6 +62,21 @@ module "target" {
|
||||
enos_user = var.enos_user
|
||||
}
|
||||
|
||||
module "vault" {
|
||||
source = "app.terraform.io/hashicorp-qti/aws-vault/enos"
|
||||
|
||||
project_name = "qti-enos-boundary"
|
||||
environment = var.environment
|
||||
common_tags = {
|
||||
"Project" : "Enos",
|
||||
"Project Name" : "qti-enos-boundary",
|
||||
"Enos User" : var.enos_user,
|
||||
"Environment" : var.environment
|
||||
}
|
||||
|
||||
ssh_aws_keypair = var.aws_ssh_keypair_name
|
||||
}
|
||||
|
||||
module "test_smoke" {
|
||||
source = "./modules/test_smoke"
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ scenario "e2e_target" {
|
||||
}
|
||||
}
|
||||
|
||||
step "launch_targets" {
|
||||
step "create_target" {
|
||||
module = module.target
|
||||
depends_on = [step.create_base_infra]
|
||||
|
||||
@@ -89,14 +89,15 @@ scenario "e2e_target" {
|
||||
enos_user = var.enos_user
|
||||
instance_type = var.target_instance_type
|
||||
vpc_id = step.create_base_infra.vpc_id
|
||||
target_count = 1
|
||||
}
|
||||
}
|
||||
|
||||
step "run_e2e_targets_test" {
|
||||
step "run_e2e_test" {
|
||||
module = module.test_e2e
|
||||
depends_on = [
|
||||
step.create_boundary_cluster,
|
||||
step.launch_targets
|
||||
step.create_target
|
||||
]
|
||||
|
||||
variables {
|
||||
@@ -107,11 +108,12 @@ scenario "e2e_target" {
|
||||
auth_password = step.create_boundary_cluster.auth_password
|
||||
local_boundary_dir = local.local_boundary_dir
|
||||
aws_ssh_private_key_path = local.aws_ssh_private_key_path
|
||||
target_ips = step.launch_targets.target_ips
|
||||
target_ips = step.create_target.target_ips
|
||||
target_user = "ubuntu"
|
||||
}
|
||||
}
|
||||
|
||||
output "test_results" {
|
||||
value = step.run_e2e_targets_test.test_results
|
||||
value = step.run_e2e_test.test_results
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
scenario "e2e_vault" {
|
||||
terraform_cli = terraform_cli.default
|
||||
terraform = terraform.default
|
||||
providers = [
|
||||
provider.aws.default,
|
||||
provider.enos.default
|
||||
]
|
||||
|
||||
matrix {
|
||||
builder = ["local", "crt"]
|
||||
}
|
||||
|
||||
locals {
|
||||
aws_ssh_private_key_path = abspath(var.aws_ssh_private_key_path)
|
||||
boundary_install_dir = abspath(var.boundary_install_dir)
|
||||
local_boundary_dir = abspath(var.local_boundary_dir)
|
||||
build_path = {
|
||||
"local" = "/tmp",
|
||||
"crt" = var.crt_bundle_path == null ? null : abspath(var.crt_bundle_path)
|
||||
}
|
||||
}
|
||||
|
||||
step "check_jq_is_installed" {
|
||||
module = module.binary_finder
|
||||
|
||||
variables {
|
||||
name = "jq"
|
||||
}
|
||||
}
|
||||
|
||||
step "find_azs" {
|
||||
module = module.az_finder
|
||||
|
||||
variables {
|
||||
instance_type = [
|
||||
var.worker_instance_type,
|
||||
var.controller_instance_type
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
step "create_db_password" {
|
||||
module = module.random_stringifier
|
||||
}
|
||||
|
||||
step "build_boundary" {
|
||||
module = matrix.builder == "crt" ? module.build_crt : module.build_local
|
||||
|
||||
variables {
|
||||
path = local.build_path[matrix.builder]
|
||||
}
|
||||
}
|
||||
|
||||
step "create_base_infra" {
|
||||
module = module.infra
|
||||
|
||||
variables {
|
||||
availability_zones = step.find_azs.availability_zones
|
||||
}
|
||||
}
|
||||
|
||||
step "create_boundary_cluster" {
|
||||
module = module.boundary
|
||||
depends_on = [
|
||||
step.create_base_infra,
|
||||
step.build_boundary
|
||||
]
|
||||
|
||||
variables {
|
||||
boundary_install_dir = local.boundary_install_dir
|
||||
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
|
||||
worker_count = var.worker_count
|
||||
worker_instance_type = var.worker_instance_type
|
||||
}
|
||||
}
|
||||
|
||||
step "create_vault_cluster" {
|
||||
module = module.vault
|
||||
depends_on = [
|
||||
step.create_base_infra,
|
||||
]
|
||||
|
||||
variables {
|
||||
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"
|
||||
sg_additional_ips = step.create_boundary_cluster.controller_ips
|
||||
unseal_method = "awskms"
|
||||
vault_release = {
|
||||
version = "1.11.0"
|
||||
edition = "oss"
|
||||
}
|
||||
vpc_id = step.create_base_infra.vpc_id
|
||||
}
|
||||
}
|
||||
|
||||
step "create_target" {
|
||||
module = module.target
|
||||
depends_on = [step.create_base_infra]
|
||||
|
||||
variables {
|
||||
ami_id = step.create_base_infra.ami_ids["ubuntu"]["amd64"]
|
||||
aws_ssh_keypair_name = var.aws_ssh_keypair_name
|
||||
enos_user = var.enos_user
|
||||
instance_type = var.target_instance_type
|
||||
vpc_id = step.create_base_infra.vpc_id
|
||||
target_count = 1
|
||||
}
|
||||
}
|
||||
|
||||
step "run_e2e_test" {
|
||||
module = module.test_e2e
|
||||
depends_on = [
|
||||
step.create_boundary_cluster,
|
||||
step.create_target,
|
||||
step.create_vault_cluster
|
||||
]
|
||||
|
||||
variables {
|
||||
test_package = "github.com/hashicorp/boundary/testing/internal/e2e/credential/vault"
|
||||
alb_boundary_api_addr = step.create_boundary_cluster.alb_boundary_api_addr
|
||||
auth_method_id = step.create_boundary_cluster.auth_method_id
|
||||
auth_login_name = step.create_boundary_cluster.auth_login_name
|
||||
auth_password = step.create_boundary_cluster.auth_password
|
||||
local_boundary_dir = local.local_boundary_dir
|
||||
aws_ssh_private_key_path = local.aws_ssh_private_key_path
|
||||
target_ips = step.create_target.target_ips
|
||||
target_user = "ubuntu"
|
||||
vault_addr = step.create_vault_cluster.instance_public_ips[0]
|
||||
vault_root_token = step.create_vault_cluster.vault_root_token
|
||||
}
|
||||
}
|
||||
|
||||
output "test_results" {
|
||||
value = step.run_e2e_test.test_results
|
||||
}
|
||||
}
|
||||
@@ -103,3 +103,9 @@ variable "skip_failing_bats_tests" {
|
||||
type = string
|
||||
default = "false"
|
||||
}
|
||||
|
||||
variable "vault_instance_type" {
|
||||
description = "Instance type for test target nodes"
|
||||
type = string
|
||||
default = "t3a.small"
|
||||
}
|
||||
@@ -30,6 +30,10 @@ variable "local_boundary_dir" {
|
||||
description = "Local Path to boundary executable"
|
||||
type = string
|
||||
}
|
||||
variable "target_user" {
|
||||
description = "SSH username for target"
|
||||
type = string
|
||||
}
|
||||
variable "aws_ssh_private_key_path" {
|
||||
description = "Local Path to key used to SSH onto created hosts"
|
||||
type = string
|
||||
@@ -38,9 +42,20 @@ variable "target_ips" {
|
||||
description = "List of IP Addresses of created hosts"
|
||||
type = list(string)
|
||||
}
|
||||
variable "vault_addr" {
|
||||
description = "URL of Vault instance"
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
variable "vault_root_token" {
|
||||
description = "Root token for vault instance"
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
|
||||
locals {
|
||||
aws_ssh_private_key_path = abspath(var.aws_ssh_private_key_path)
|
||||
vault_addr = var.vault_addr != "" ? "http://${var.vault_addr}:8200" : ""
|
||||
}
|
||||
|
||||
resource "enos_local_exec" "run_e2e_test" {
|
||||
@@ -50,8 +65,10 @@ resource "enos_local_exec" "run_e2e_test" {
|
||||
E2E_PASSWORD_ADMIN_LOGIN_NAME = var.auth_login_name,
|
||||
E2E_PASSWORD_ADMIN_PASSWORD = var.auth_password,
|
||||
E2E_TARGET_IP = var.target_ips[0],
|
||||
E2E_SSH_USER = "ubuntu"
|
||||
E2E_SSH_USER = var.target_user,
|
||||
E2E_SSH_KEY_PATH = local.aws_ssh_private_key_path,
|
||||
VAULT_ADDR = local.vault_addr,
|
||||
VAULT_TOKEN = var.vault_root_token
|
||||
}
|
||||
|
||||
inline = ["PATH=\"${var.local_boundary_dir}:$PATH\" go test -v ${var.test_package}"]
|
||||
|
||||
@@ -30,7 +30,13 @@ export E2E_PASSWORD_ADMIN_PASSWORD= # e.g. "password"
|
||||
export E2E_TARGET_IP= # e.g. 192.168.0.1
|
||||
export E2E_SSH_KEY_PATH= # e.g. /Users/username/key.pem
|
||||
export E2E_SSH_USER= # e.g. ubuntu
|
||||
export E2E_SSH_PORT= # e.g. 22
|
||||
|
||||
# For e2e/credential/vault
|
||||
export VAULT_ADDR= # e.g. http://127.0.0.1:8200
|
||||
export VAULT_TOKEN=
|
||||
export E2E_TARGET_IP= # e.g. 192.168.0.1
|
||||
export E2E_SSH_KEY_PATH= # e.g. /Users/username/key.pem
|
||||
export E2E_SSH_USER= # e.g. ubuntu
|
||||
```
|
||||
|
||||
Then, run...
|
||||
|
||||
@@ -5,11 +5,13 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/api"
|
||||
"github.com/hashicorp/boundary/api/authmethods"
|
||||
"github.com/hashicorp/boundary/testing/internal/e2e"
|
||||
"github.com/kelseyhightower/envconfig"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
@@ -80,22 +82,17 @@ func NewApiClient() (*api.Client, error) {
|
||||
}
|
||||
|
||||
// AuthenticateCli uses the cli to authenticate the specified Boundary instance.
|
||||
// Returns the result of the command.
|
||||
func AuthenticateCli() *e2e.CommandResult {
|
||||
func AuthenticateCli(t testing.TB) {
|
||||
c, err := loadConfig()
|
||||
if err != nil {
|
||||
return &e2e.CommandResult{Err: err}
|
||||
}
|
||||
require.NoError(t, err)
|
||||
err = c.validate()
|
||||
if err != nil {
|
||||
return &e2e.CommandResult{Err: err}
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
return e2e.RunCommand(
|
||||
"boundary", "authenticate", "password",
|
||||
output := e2e.RunCommand("boundary", e2e.WithArgs("authenticate", "password",
|
||||
"-addr", c.Address,
|
||||
"-auth-method-id", c.AuthMethodId,
|
||||
"-login-name", c.AdminLoginName,
|
||||
"-password", "env://E2E_PASSWORD_ADMIN_PASSWORD",
|
||||
)
|
||||
))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package boundary
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/api"
|
||||
"github.com/hashicorp/boundary/api/scopes"
|
||||
"github.com/hashicorp/boundary/testing/internal/e2e"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// CreateNewOrgApi creates a new organization in boundary using the go api.
|
||||
// Returns the id of the new org.
|
||||
func CreateNewOrgApi(t testing.TB, ctx context.Context, client *api.Client) string {
|
||||
scopeClient := scopes.NewClient(client)
|
||||
newOrgResult, err := scopeClient.Create(ctx, "global", scopes.WithName("e2e Automated Test Org"))
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
_, err := scopeClient.Delete(ctx, newOrgResult.Item.Id)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
return newOrgResult.Item.Id
|
||||
}
|
||||
|
||||
// CreateNewOrgCli creates a new organization in boundary using the cli.
|
||||
// Returns the id of the new org.
|
||||
func CreateNewOrgCli(t testing.TB) string {
|
||||
return createNewScopeCli(t, "e2e Automated Test Org", "global")
|
||||
}
|
||||
|
||||
// CreateNewProjectCli creates a new project in boundary using the cli.
|
||||
// Returns the id of the new project.
|
||||
func CreateNewProjectCli(t testing.TB, scopeId string) string {
|
||||
return createNewScopeCli(t, "e2e Automated Test Project", scopeId)
|
||||
}
|
||||
|
||||
func createNewScopeCli(t testing.TB, name string, scopeId string) string {
|
||||
output := e2e.RunCommand("boundary", e2e.WithArgs("scopes", "create",
|
||||
"-name", name,
|
||||
"-scope-id", scopeId,
|
||||
"-format", "json",
|
||||
))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
|
||||
var newOrgResult scopes.ScopeCreateResult
|
||||
err := json.Unmarshal(output.Stdout, &newOrgResult)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Cleanup(func() {
|
||||
output := e2e.RunCommand("boundary", e2e.WithArgs("scopes", "delete", "-id", newOrgResult.Item.Id))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
})
|
||||
|
||||
return newOrgResult.Item.Id
|
||||
}
|
||||
@@ -0,0 +1,419 @@
|
||||
package vaultcredential_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/api/credentiallibraries"
|
||||
"github.com/hashicorp/boundary/api/credentialstores"
|
||||
"github.com/hashicorp/boundary/api/hostcatalogs"
|
||||
"github.com/hashicorp/boundary/api/hosts"
|
||||
"github.com/hashicorp/boundary/api/hostsets"
|
||||
"github.com/hashicorp/boundary/api/scopes"
|
||||
"github.com/hashicorp/boundary/api/targets"
|
||||
"github.com/hashicorp/boundary/testing/internal/e2e"
|
||||
"github.com/hashicorp/boundary/testing/internal/e2e/boundary"
|
||||
"github.com/hashicorp/boundary/testing/internal/e2e/vault"
|
||||
"github.com/kelseyhightower/envconfig"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
TargetIp string `envconfig:"E2E_TARGET_IP"` // e.g. 192.168.0.1
|
||||
TargetSshUser string `envconfig:"E2E_SSH_USER"` // e.g. ubuntu
|
||||
TargetSshKeyPath string `envconfig:"E2E_SSH_KEY_PATH"` // e.g. /Users/username/key.pem
|
||||
TargetPort string `envconfig:"E2E_SSH_PORT" default:"22"`
|
||||
VaultSecretPath string `envconfig:"E2E_VAULT_SECRET_PATH" default:"e2e_secrets"`
|
||||
}
|
||||
|
||||
func (c *config) validate() error {
|
||||
if c.TargetIp == "" {
|
||||
return errors.New("TargetIp is empty. Set environment variable: E2E_TARGET_IP")
|
||||
}
|
||||
if c.TargetSshUser == "" {
|
||||
return errors.New("TargetSshUser is empty. Set environment variable: E2E_SSH_USER")
|
||||
}
|
||||
if c.TargetSshKeyPath == "" {
|
||||
return errors.New("TargetSshKeyPath is empty. Set environment variable: E2E_SSH_KEY_PATH")
|
||||
}
|
||||
if c.TargetPort == "" {
|
||||
return errors.New("TargetPort is empty. Set environment variable: E2E_SSH_PORT")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadConfig() (*config, error) {
|
||||
var c config
|
||||
err := envconfig.Process("", &c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &c, err
|
||||
}
|
||||
|
||||
// TestCreateVaultCredentialStoreCli uses the boundary and vault clis to add secrets management
|
||||
// for a target. The test sets up vault as a credential store, creates a set of credentials
|
||||
// in vault to be attached to a target, and attempts to connect to that target using those
|
||||
// credentials.
|
||||
func TestCreateVaultCredentialStoreCli(t *testing.T) {
|
||||
e2e.MaybeSkipTest(t)
|
||||
|
||||
c, err := loadConfig()
|
||||
require.NoError(t, err)
|
||||
err = c.validate()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Configure vault
|
||||
vaultAddr, boundaryPolicyName := vault.Setup(t)
|
||||
|
||||
output := e2e.RunCommand("vault", e2e.WithArgs("secrets", "enable", "-path="+c.VaultSecretPath, "kv-v2"))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
t.Cleanup(func() {
|
||||
output := e2e.RunCommand("vault", e2e.WithArgs("secrets", "disable", c.VaultSecretPath))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
})
|
||||
|
||||
// Create credential in vault
|
||||
secretName := "TestCreateVaultCredentialStoreCli"
|
||||
credentialPolicyName := vault.CreateKvPrivateKeyCredential(t, secretName, c.VaultSecretPath, c.TargetSshUser, c.TargetSshKeyPath)
|
||||
t.Log("Created Vault Credential")
|
||||
|
||||
// Create vault token for boundary
|
||||
output = e2e.RunCommand("vault", e2e.WithArgs("token", "create",
|
||||
"-no-default-policy=true",
|
||||
"-policy="+boundaryPolicyName,
|
||||
"-policy="+credentialPolicyName,
|
||||
"-orphan=true",
|
||||
"-period=20m",
|
||||
"-renewable=true",
|
||||
"-format=json",
|
||||
),
|
||||
e2e.WithPipe("jq", "-r", ".auth.client_token"),
|
||||
)
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
credStoreToken := strings.TrimSpace(string(output.Stdout))
|
||||
t.Log("Created Vault Cred Store Token")
|
||||
|
||||
// Authenticate boundary cli
|
||||
boundary.AuthenticateCli(t)
|
||||
|
||||
// Create an org
|
||||
newOrgId := boundary.CreateNewOrgCli(t)
|
||||
t.Logf("Created Org Id: %s", newOrgId)
|
||||
|
||||
// Create a project
|
||||
newProjectId := boundary.CreateNewProjectCli(t, newOrgId)
|
||||
t.Logf("Created Project Id: %s", newProjectId)
|
||||
|
||||
// Create a credential store
|
||||
output = e2e.RunCommand("boundary", e2e.WithArgs("credential-stores", "create", "vault",
|
||||
"-scope-id", newProjectId,
|
||||
"-vault-address", vaultAddr,
|
||||
"-vault-token", credStoreToken,
|
||||
"-format", "json",
|
||||
))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
var newCredentialStoreResult credentialstores.CredentialStoreCreateResult
|
||||
err = json.Unmarshal(output.Stdout, &newCredentialStoreResult)
|
||||
require.NoError(t, err)
|
||||
newCredentialStore := newCredentialStoreResult.Item
|
||||
t.Logf("Created Credential Store: %s", newCredentialStore.Id)
|
||||
|
||||
// Create a credential library
|
||||
output = e2e.RunCommand("boundary", e2e.WithArgs("credential-libraries", "create", "vault",
|
||||
"-credential-store-id", newCredentialStore.Id,
|
||||
"-vault-path", c.VaultSecretPath+"/data/"+secretName,
|
||||
"-name", "e2e Automated Test Vault Credential Library",
|
||||
"-credential-type", "ssh_private_key",
|
||||
"-format", "json",
|
||||
))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
var newCredentialLibraryResult credentiallibraries.CredentialLibraryCreateResult
|
||||
err = json.Unmarshal(output.Stdout, &newCredentialLibraryResult)
|
||||
require.NoError(t, err)
|
||||
newCredentialLibrary := newCredentialLibraryResult.Item
|
||||
t.Logf("Created Credential Library: %s", newCredentialLibrary.Id)
|
||||
|
||||
// Create a host catalog
|
||||
output = e2e.RunCommand("boundary", e2e.WithArgs("host-catalogs", "create", "static",
|
||||
"-scope-id", newProjectId,
|
||||
"-name", "e2e Automated Test Host Catalog",
|
||||
"-format", "json",
|
||||
))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
var newHostCatalogResult hostcatalogs.HostCatalogCreateResult
|
||||
err = json.Unmarshal(output.Stdout, &newHostCatalogResult)
|
||||
require.NoError(t, err)
|
||||
newHostCatalog := newHostCatalogResult.Item
|
||||
t.Logf("Created Host Catalog: %s", newHostCatalog.Id)
|
||||
|
||||
// Create a host set and add to catalog
|
||||
output = e2e.RunCommand("boundary", e2e.WithArgs("host-sets", "create", "static",
|
||||
"-host-catalog-id", newHostCatalog.Id,
|
||||
"-name", "e2e Automated Test Host Set",
|
||||
"-format", "json",
|
||||
))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
var newHostSetResult hostsets.HostSetCreateResult
|
||||
err = json.Unmarshal(output.Stdout, &newHostSetResult)
|
||||
require.NoError(t, err)
|
||||
newHostSet := newHostSetResult.Item
|
||||
t.Logf("Created Host Set: %s", newHostSet.Id)
|
||||
|
||||
// Create a host
|
||||
output = e2e.RunCommand("boundary", e2e.WithArgs("hosts", "create", "static",
|
||||
"-host-catalog-id", newHostCatalog.Id,
|
||||
"-name", c.TargetIp,
|
||||
"-address", c.TargetIp,
|
||||
"-format", "json"),
|
||||
)
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
var newHostResult hosts.HostCreateResult
|
||||
err = json.Unmarshal(output.Stdout, &newHostResult)
|
||||
require.NoError(t, err)
|
||||
newHost := newHostResult.Item
|
||||
t.Logf("Created Host: %s", newHost.Id)
|
||||
|
||||
// Add host to host set
|
||||
output = e2e.RunCommand("boundary", e2e.WithArgs("host-sets", "add-hosts",
|
||||
"-id", newHostSet.Id,
|
||||
"-host", newHost.Id,
|
||||
))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
|
||||
// Create Target
|
||||
output = e2e.RunCommand("boundary", e2e.WithArgs("targets", "create", "tcp",
|
||||
"-scope-id", newProjectId,
|
||||
"-default-port", c.TargetPort,
|
||||
"-name", "e2e Automated Test Target",
|
||||
"-format", "json",
|
||||
))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
var newTargetResult targets.TargetCreateResult
|
||||
err = json.Unmarshal(output.Stdout, &newTargetResult)
|
||||
require.NoError(t, err)
|
||||
newTarget := newTargetResult.Item
|
||||
t.Logf("Created Target: %s", newTarget.Id)
|
||||
|
||||
// Add host set to target
|
||||
output = e2e.RunCommand("boundary", e2e.WithArgs("targets", "add-host-sources",
|
||||
"-id", newTarget.Id,
|
||||
"-host-source", newHostSet.Id,
|
||||
))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
|
||||
// Add brokered credentials to target
|
||||
output = e2e.RunCommand("boundary", e2e.WithArgs("targets", "add-credential-sources",
|
||||
"-id", newTarget.Id,
|
||||
"-brokered-credential-source", newCredentialLibrary.Id,
|
||||
))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
|
||||
// Get credentials for target
|
||||
output = e2e.RunCommand("boundary", e2e.WithArgs("targets", "authorize-session", "-id", newTarget.Id, "-format", "json"))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
var newSessionAuthorizationResult targets.SessionAuthorizationResult
|
||||
err = json.Unmarshal(output.Stdout, &newSessionAuthorizationResult)
|
||||
require.NoError(t, err)
|
||||
|
||||
newSessionAuthorization := newSessionAuthorizationResult.Item
|
||||
retrievedUser := fmt.Sprintf("%s", newSessionAuthorization.Credentials[0].Credential["username"])
|
||||
retrievedKey := fmt.Sprintf("%s", newSessionAuthorization.Credentials[0].Credential["private_key"])
|
||||
assert.Equal(t, c.TargetSshUser, retrievedUser)
|
||||
|
||||
k, err := os.ReadFile(c.TargetSshKeyPath)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, string(k), retrievedKey)
|
||||
t.Log("Successfully retrieved credentials for target")
|
||||
|
||||
// Create key file
|
||||
retrievedKeyPath := fmt.Sprintf("%s/%s", t.TempDir(), "target_private_key.pem")
|
||||
f, err := os.Create(retrievedKeyPath)
|
||||
require.NoError(t, err)
|
||||
_, err = f.WriteString(retrievedKey)
|
||||
require.NoError(t, err)
|
||||
err = os.Chmod(retrievedKeyPath, 0o400)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Connect to target and print host's IP address using retrieved credentials
|
||||
output = e2e.RunCommand("boundary", e2e.WithArgs("connect",
|
||||
"-target-id", newTarget.Id,
|
||||
"-exec", "/usr/bin/ssh", "--",
|
||||
"-l", retrievedUser,
|
||||
"-i", retrievedKeyPath,
|
||||
"-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",
|
||||
))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
|
||||
parts := strings.Fields(string(output.Stdout))
|
||||
hostIp := parts[len(parts)-1]
|
||||
require.Equal(t, c.TargetIp, hostIp, "SSH session did not return expected output")
|
||||
t.Log("Successfully connected to target")
|
||||
}
|
||||
|
||||
// TestCreateVaultCredentialStoreApi uses the boundary go api along with the vault cli to
|
||||
// add secrets management for a target. The test sets up vault as a creential stores and creates
|
||||
// a set of credentials in vault that is attached to a target.
|
||||
func TestCreateVaultCredentialStoreApi(t *testing.T) {
|
||||
e2e.MaybeSkipTest(t)
|
||||
|
||||
c, err := loadConfig()
|
||||
require.NoError(t, err)
|
||||
err = c.validate()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Configure vault
|
||||
vaultAddr, boundaryPolicyName := vault.Setup(t)
|
||||
|
||||
output := e2e.RunCommand("vault", e2e.WithArgs("secrets", "enable", "-path="+c.VaultSecretPath, "kv-v2"))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
t.Cleanup(func() {
|
||||
output := e2e.RunCommand("vault", e2e.WithArgs("secrets", "disable", c.VaultSecretPath))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
})
|
||||
|
||||
// Create credential in vault
|
||||
secretName := "TestCreateVaultCredentialStoreCli"
|
||||
credentialPolicyName := vault.CreateKvPrivateKeyCredential(t, secretName, c.VaultSecretPath, c.TargetSshUser, c.TargetSshKeyPath)
|
||||
t.Log("Created Vault Credential")
|
||||
|
||||
// Create vault token for boundary
|
||||
output = e2e.RunCommand("vault", e2e.WithArgs("token", "create",
|
||||
"-no-default-policy=true",
|
||||
"-policy="+boundaryPolicyName,
|
||||
"-policy="+credentialPolicyName,
|
||||
"-orphan=true",
|
||||
"-period=20m",
|
||||
"-renewable=true",
|
||||
"-format=json",
|
||||
),
|
||||
e2e.WithPipe("jq", "-r", ".auth.client_token"),
|
||||
)
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
credStoreToken := strings.TrimSpace(string(output.Stdout))
|
||||
t.Log("Created Vault Cred Store Token")
|
||||
|
||||
// Create boundary api client
|
||||
client, err := boundary.NewApiClient()
|
||||
require.NoError(t, err)
|
||||
ctx := context.Background()
|
||||
|
||||
// Create an org
|
||||
scopeClient := scopes.NewClient(client)
|
||||
newOrgResult, err := scopeClient.Create(ctx, "global", scopes.WithName("e2e Automated Test Org"))
|
||||
require.NoError(t, err)
|
||||
newOrg := newOrgResult.Item
|
||||
t.Cleanup(func() {
|
||||
_, err := scopeClient.Delete(ctx, newOrg.Id)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
t.Logf("Created Org Id: %s", newOrg.Id)
|
||||
|
||||
// Create a project
|
||||
newProjectResult, err := scopeClient.Create(ctx, newOrg.Id, scopes.WithName("e2e Automated Test Project"))
|
||||
require.NoError(t, err)
|
||||
newProject := newProjectResult.Item
|
||||
t.Logf("Created Project Id: %s", newProject.Id)
|
||||
|
||||
// Create a credential store
|
||||
csClient := credentialstores.NewClient(client)
|
||||
newCredentialStoreResult, err := csClient.Create(ctx, "vault", newProject.Id,
|
||||
credentialstores.WithVaultCredentialStoreAddress(vaultAddr),
|
||||
credentialstores.WithVaultCredentialStoreToken(credStoreToken),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
newCredentialStore := newCredentialStoreResult.Item
|
||||
t.Logf("Created Credential Store: %s", newCredentialStore.Id)
|
||||
|
||||
// Create a credential library
|
||||
clClient := credentiallibraries.NewClient(client)
|
||||
newCredentialLibraryResult, err := clClient.Create(ctx, newCredentialStore.Id,
|
||||
credentiallibraries.WithVaultCredentialLibraryPath(c.VaultSecretPath+"/data/"+secretName),
|
||||
credentiallibraries.WithCredentialType("ssh_private_key"),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
newCredentialLibrary := newCredentialLibraryResult.Item
|
||||
t.Logf("Created Credential Library: %s", newCredentialLibrary.Id)
|
||||
|
||||
// Create a host catalog
|
||||
hcClient := hostcatalogs.NewClient(client)
|
||||
newHostCatalogResult, err := hcClient.Create(ctx, "static", newProject.Id,
|
||||
hostcatalogs.WithName("e2e Automated Test Host Catalog"),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
newHostCatalog := newHostCatalogResult.Item
|
||||
t.Logf("Created Host Catalog: %s", newHostCatalog.Id)
|
||||
|
||||
// Create a host set and add to catalog
|
||||
hsClient := hostsets.NewClient(client)
|
||||
newHostSetResult, err := hsClient.Create(ctx, newHostCatalog.Id)
|
||||
require.NoError(t, err)
|
||||
newHostSet := newHostSetResult.Item
|
||||
t.Logf("Created Host Set: %s", newHostSet.Id)
|
||||
|
||||
// Create a host
|
||||
hClient := hosts.NewClient(client)
|
||||
newHostResult, err := hClient.Create(ctx, newHostCatalog.Id,
|
||||
hosts.WithName(c.TargetIp),
|
||||
hosts.WithStaticHostAddress(c.TargetIp),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
newHost := newHostResult.Item
|
||||
t.Logf("Created Host: %s", newHost.Id)
|
||||
|
||||
// Add host to host set
|
||||
_, err = hsClient.AddHosts(ctx, newHostSet.Id, 0, []string{newHost.Id}, hostsets.WithAutomaticVersioning(true))
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create a target
|
||||
tClient := targets.NewClient(client)
|
||||
targetPort, err := strconv.ParseInt(c.TargetPort, 10, 32)
|
||||
newTargetResult, err := tClient.Create(ctx, "tcp", newProject.Id,
|
||||
targets.WithName("e2e Automated Test Target"),
|
||||
targets.WithTcpTargetDefaultPort(uint32(targetPort)),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
newTarget := newTargetResult.Item
|
||||
t.Logf("Created Target: %s", newTarget.Id)
|
||||
|
||||
// Add host set to target
|
||||
_, err = tClient.AddHostSources(ctx, newTarget.Id, 0,
|
||||
[]string{newHostSet.Id},
|
||||
targets.WithAutomaticVersioning(true),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Add brokered credentials to target
|
||||
_, err = tClient.AddCredentialSources(ctx, newTarget.Id, 0,
|
||||
targets.WithBrokeredCredentialSourceIds([]string{newCredentialLibrary.Id}),
|
||||
targets.WithAutomaticVersioning(true),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Get credentials for target
|
||||
newSessionAuthorizationResult, err := tClient.AuthorizeSession(ctx, newTarget.Id)
|
||||
require.NoError(t, err)
|
||||
newSessionAuthorization := newSessionAuthorizationResult.Item
|
||||
retrievedUser := fmt.Sprintf("%s", newSessionAuthorization.Credentials[0].Credential["username"])
|
||||
retrievedKey := fmt.Sprintf("%s", newSessionAuthorization.Credentials[0].Credential["private_key"])
|
||||
assert.Equal(t, c.TargetSshUser, retrievedUser)
|
||||
|
||||
k, err := os.ReadFile(c.TargetSshKeyPath)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, string(k), retrievedKey)
|
||||
t.Log("Successfully retrieved credentials for target")
|
||||
}
|
||||
@@ -4,11 +4,37 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Option is a func that sets optional attributes for a call. This does not need
|
||||
// to be used directly, but instead option arguments are built from the
|
||||
// functions in this package. WithX options set a value to that given in the
|
||||
// argument; DefaultX options indicate that the value should be set to its
|
||||
// default. When an API call is made options are processed in ther order they
|
||||
// appear in the function call, so for a given argument X, a succession of WithX
|
||||
// or DefaultX calls will result in the last call taking effect.
|
||||
type Option func(*options)
|
||||
|
||||
type options struct {
|
||||
withArgs []string
|
||||
withPipe []string
|
||||
}
|
||||
|
||||
func getOpts(opt ...Option) options {
|
||||
opts := options{}
|
||||
for _, o := range opt {
|
||||
if o != nil {
|
||||
o(&opts)
|
||||
}
|
||||
}
|
||||
|
||||
return opts
|
||||
}
|
||||
|
||||
// CommandResult encapsulates the output from running an external command
|
||||
type CommandResult struct {
|
||||
Stdout []byte
|
||||
@@ -20,16 +46,48 @@ type CommandResult struct {
|
||||
const EnvToCheckSkip = "E2E_PASSWORD_AUTH_METHOD_ID"
|
||||
|
||||
// RunCommand executes external commands on the system. Returns the results
|
||||
// of running the provided command. CommandResult is always valid even if there is
|
||||
// an error.
|
||||
func RunCommand(name string, args ...string) *CommandResult {
|
||||
// of running the provided command.
|
||||
//
|
||||
// RunCommand("ls")
|
||||
// RunCommand("ls", WithArgs("-al", "/path"))
|
||||
// RunCommand("ls", WithArgs("-al", "/path"), WithPipe("grep", "file"))
|
||||
//
|
||||
// CommandResult is always valid even if there is an error.
|
||||
func RunCommand(command string, opt ...Option) *CommandResult {
|
||||
var outbuf, errbuf bytes.Buffer
|
||||
var err error
|
||||
var c1, c2 *exec.Cmd
|
||||
|
||||
cmd := exec.Command(name, args...)
|
||||
cmd.Stdout = &outbuf
|
||||
cmd.Stderr = &errbuf
|
||||
opts := getOpts(opt...)
|
||||
|
||||
err := cmd.Run()
|
||||
if opts.withArgs == nil {
|
||||
c1 = exec.Command(command)
|
||||
} else {
|
||||
c1 = exec.Command(command, opts.withArgs...)
|
||||
}
|
||||
|
||||
if opts.withPipe == nil {
|
||||
c1.Stdout = &outbuf
|
||||
c1.Stderr = &errbuf
|
||||
err = c1.Run()
|
||||
} else {
|
||||
pipeCommand := opts.withPipe[0]
|
||||
pipeArgs := opts.withPipe[1:]
|
||||
c2 = exec.Command(pipeCommand, pipeArgs...)
|
||||
|
||||
r, w := io.Pipe()
|
||||
c1.Stdout = w
|
||||
c2.Stdin = r
|
||||
|
||||
c2.Stdout = &outbuf
|
||||
c2.Stderr = &errbuf
|
||||
|
||||
c1.Start()
|
||||
c2.Start()
|
||||
c1.Wait()
|
||||
w.Close()
|
||||
c2.Wait()
|
||||
}
|
||||
|
||||
var ee *exec.ExitError
|
||||
var exitCode int
|
||||
@@ -45,7 +103,24 @@ func RunCommand(name string, args ...string) *CommandResult {
|
||||
}
|
||||
}
|
||||
|
||||
func MaybeSkipTest(t *testing.T) {
|
||||
// WithArgs is an option to RunCommand that allows the user to specify arguments
|
||||
// for the provided command
|
||||
func WithArgs(args ...string) Option {
|
||||
return func(o *options) {
|
||||
o.withArgs = args
|
||||
}
|
||||
}
|
||||
|
||||
// WithPipe is an option to RunCommand that allows the user to specify a command+arguments
|
||||
// to pipe to
|
||||
func WithPipe(command ...string) Option {
|
||||
return func(o *options) {
|
||||
o.withPipe = command
|
||||
}
|
||||
}
|
||||
|
||||
// MaybeSkipTest is a check used at the start of the test to determine if the test should run
|
||||
func MaybeSkipTest(t testing.TB) {
|
||||
if _, ok := os.LookupEnv(EnvToCheckSkip); !ok {
|
||||
t.Skip(fmt.Sprintf(
|
||||
"Skipping test because environment variable '%s' is not set. This is needed for e2e tests.",
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -15,7 +16,6 @@ import (
|
||||
"github.com/hashicorp/boundary/testing/internal/e2e"
|
||||
"github.com/hashicorp/boundary/testing/internal/e2e/boundary"
|
||||
"github.com/kelseyhightower/envconfig"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -64,137 +64,99 @@ func TestConnectTargetCli(t *testing.T) {
|
||||
err = c.validate()
|
||||
require.NoError(t, err)
|
||||
|
||||
output := boundary.AuthenticateCli()
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
boundary.AuthenticateCli(t)
|
||||
|
||||
// Create an org
|
||||
output = e2e.RunCommand(
|
||||
"boundary", "scopes", "create",
|
||||
"-name", "e2e Automated Test Org",
|
||||
"-format", "json",
|
||||
)
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
var newOrgResult scopes.ScopeCreateResult
|
||||
err = json.Unmarshal(output.Stdout, &newOrgResult)
|
||||
require.NoError(t, err)
|
||||
newOrg := newOrgResult.Item
|
||||
t.Cleanup(func() {
|
||||
output := e2e.RunCommand("boundary", "scopes", "delete", "-id", newOrg.Id)
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
})
|
||||
t.Logf("Created Org Id: %s", newOrg.Id)
|
||||
newOrgId := boundary.CreateNewOrgCli(t)
|
||||
t.Logf("Created Org Id: %s", newOrgId)
|
||||
|
||||
// Create a project
|
||||
output = e2e.RunCommand(
|
||||
"boundary", "scopes", "create",
|
||||
"-scope-id", newOrg.Id,
|
||||
"-name", "e2e Automated Test Project",
|
||||
"-format", "json",
|
||||
)
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
var newProjectResult scopes.ScopeCreateResult
|
||||
err = json.Unmarshal(output.Stdout, &newProjectResult)
|
||||
require.NoError(t, err)
|
||||
newProject := newProjectResult.Item
|
||||
t.Cleanup(func() {
|
||||
output := e2e.RunCommand("boundary", "scopes", "delete", "-id", newProject.Id)
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
})
|
||||
t.Logf("Created Project Id: %s", newProject.Id)
|
||||
newProjectId := boundary.CreateNewProjectCli(t, newOrgId)
|
||||
t.Logf("Created Project Id: %s", newProjectId)
|
||||
|
||||
// Create a host catalog
|
||||
output = e2e.RunCommand(
|
||||
"boundary", "host-catalogs", "create", "static",
|
||||
"-scope-id", newProject.Id,
|
||||
output := e2e.RunCommand("boundary", e2e.WithArgs("host-catalogs", "create", "static",
|
||||
"-scope-id", newProjectId,
|
||||
"-name", "e2e Automated Test Host Catalog",
|
||||
"-format", "json",
|
||||
)
|
||||
))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
var newHostCatalogResult hostcatalogs.HostCatalogCreateResult
|
||||
err = json.Unmarshal(output.Stdout, &newHostCatalogResult)
|
||||
require.NoError(t, err)
|
||||
newHostCatalog := newHostCatalogResult.Item
|
||||
t.Cleanup(func() {
|
||||
output := e2e.RunCommand("boundary", "host-catalogs", "delete", "-id", newHostCatalog.Id)
|
||||
output := e2e.RunCommand("boundary", e2e.WithArgs("host-catalogs", "delete", "-id", newHostCatalog.Id))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
})
|
||||
t.Logf("Created Host Catalog: %s", newHostCatalog.Id)
|
||||
|
||||
// Create a host set and add to catalog
|
||||
output = e2e.RunCommand(
|
||||
"boundary", "host-sets", "create", "static",
|
||||
output = e2e.RunCommand("boundary", e2e.WithArgs("host-sets", "create", "static",
|
||||
"-host-catalog-id", newHostCatalog.Id,
|
||||
"-name", "e2e Automated Test Host Set",
|
||||
"-format", "json",
|
||||
)
|
||||
))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
var newHostSetResult hostsets.HostSetCreateResult
|
||||
err = json.Unmarshal(output.Stdout, &newHostSetResult)
|
||||
require.NoError(t, err)
|
||||
newHostSet := newHostSetResult.Item
|
||||
t.Cleanup(func() {
|
||||
output := e2e.RunCommand("boundary", "host-sets", "delete", "-id", newHostSet.Id)
|
||||
output := e2e.RunCommand("boundary", e2e.WithArgs("host-sets", "delete", "-id", newHostSet.Id))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
})
|
||||
t.Logf("Created Host Set: %s", newHostSet.Id)
|
||||
|
||||
// Create a host
|
||||
output = e2e.RunCommand(
|
||||
"boundary", "hosts", "create", "static",
|
||||
output = e2e.RunCommand("boundary", e2e.WithArgs("hosts", "create", "static",
|
||||
"-host-catalog-id", newHostCatalog.Id,
|
||||
"-name", c.TargetIp,
|
||||
"-address", c.TargetIp,
|
||||
"-format", "json",
|
||||
)
|
||||
))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
var newHostResult hosts.HostCreateResult
|
||||
err = json.Unmarshal(output.Stdout, &newHostResult)
|
||||
require.NoError(t, err)
|
||||
newHost := newHostResult.Item
|
||||
t.Cleanup(func() {
|
||||
output := e2e.RunCommand("boundary", "hosts", "delete", "-id", newHost.Id)
|
||||
output := e2e.RunCommand("boundary", e2e.WithArgs("hosts", "delete", "-id", newHost.Id))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
})
|
||||
t.Logf("Created Host: %s", newHost.Id)
|
||||
|
||||
// Add host to host set
|
||||
output = e2e.RunCommand(
|
||||
"boundary", "host-sets", "add-hosts",
|
||||
"-id", newHostSet.Id,
|
||||
"-host", newHost.Id,
|
||||
)
|
||||
output = e2e.RunCommand("boundary", e2e.WithArgs("host-sets", "add-hosts", "-id", newHostSet.Id, "-host", newHost.Id))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
|
||||
// Create a target
|
||||
output = e2e.RunCommand(
|
||||
"boundary", "targets", "create", "tcp",
|
||||
"-scope-id", newProject.Id,
|
||||
output = e2e.RunCommand("boundary", e2e.WithArgs("targets", "create", "tcp",
|
||||
"-scope-id", newProjectId,
|
||||
"-default-port", c.TargetPort,
|
||||
"-name", "e2e Automated Test Target",
|
||||
"-format", "json",
|
||||
)
|
||||
))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
var newTargetResult targets.TargetCreateResult
|
||||
err = json.Unmarshal(output.Stdout, &newTargetResult)
|
||||
require.NoError(t, err)
|
||||
newTarget := newTargetResult.Item
|
||||
t.Cleanup(func() {
|
||||
output := e2e.RunCommand("boundary", "targets", "delete", "-id", newTarget.Id)
|
||||
output := e2e.RunCommand("boundary", e2e.WithArgs("targets", "delete", "-id", newTarget.Id))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
})
|
||||
t.Logf("Created Target: %s", newTarget.Id)
|
||||
|
||||
// Add host set to target
|
||||
output = e2e.RunCommand(
|
||||
"boundary", "targets", "add-host-sources",
|
||||
output = e2e.RunCommand("boundary", e2e.WithArgs("targets", "add-host-sources",
|
||||
"-id", newTarget.Id,
|
||||
"-host-source", newHostSet.Id,
|
||||
"-host-source", newHostSet.Id),
|
||||
)
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
|
||||
// Connect to target and print host's IP address
|
||||
output = e2e.RunCommand(
|
||||
"boundary", "connect",
|
||||
output = e2e.RunCommand("boundary", e2e.WithArgs("connect",
|
||||
"-target-id", newTarget.Id,
|
||||
"-exec", "/usr/bin/ssh", "--",
|
||||
"-l", c.TargetSshUser,
|
||||
@@ -205,12 +167,12 @@ func TestConnectTargetCli(t *testing.T) {
|
||||
"-p", "{{boundary.port}}", // this is provided by boundary
|
||||
"{{boundary.ip}}",
|
||||
"hostname", "-i",
|
||||
)
|
||||
))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
|
||||
parts := strings.Fields(string(output.Stdout))
|
||||
hostIp := parts[len(parts)-1]
|
||||
assert.Equal(t, c.TargetIp, hostIp, "SSH session did not return expected output")
|
||||
require.Equal(t, c.TargetIp, hostIp, "SSH session did not return expected output")
|
||||
t.Log("Successfully connected to target")
|
||||
}
|
||||
|
||||
@@ -225,9 +187,9 @@ func TestCreateTargetApi(t *testing.T) {
|
||||
err = c.validate()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create boundary api client
|
||||
client, err := boundary.NewApiClient()
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// Create an org
|
||||
@@ -295,9 +257,10 @@ func TestCreateTargetApi(t *testing.T) {
|
||||
|
||||
// Create a target
|
||||
tClient := targets.NewClient(client)
|
||||
targetPort, err := strconv.ParseInt(c.TargetPort, 10, 32)
|
||||
newTargetResult, err := tClient.Create(ctx, "tcp", newProject.Id,
|
||||
targets.WithName("e2e Automated Test Target"),
|
||||
targets.WithTcpTargetDefaultPort(22),
|
||||
targets.WithTcpTargetDefaultPort(uint32(targetPort)),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
newTarget := newTargetResult.Item
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
path "auth/token/lookup-self" {
|
||||
capabilities = ["read"]
|
||||
}
|
||||
|
||||
path "auth/token/renew-self" {
|
||||
capabilities = ["update"]
|
||||
}
|
||||
|
||||
path "auth/token/revoke-self" {
|
||||
capabilities = ["update"]
|
||||
}
|
||||
|
||||
path "sys/leases/renew" {
|
||||
capabilities = ["update"]
|
||||
}
|
||||
|
||||
path "sys/leases/revoke" {
|
||||
capabilities = ["update"]
|
||||
}
|
||||
|
||||
path "sys/capabilities-self" {
|
||||
capabilities = ["update"]
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
// Package vault provides methods for commonly used vault actions that are used in end-to-end tests.
|
||||
package vault
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/testing/internal/e2e"
|
||||
"github.com/kelseyhightower/envconfig"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
VaultAddr string `envconfig:"VAULT_ADDR"` // e.g. "http://127.0.0.1:8200"
|
||||
VaultToken string `envconfig:"VAULT_TOKEN"`
|
||||
}
|
||||
|
||||
func (c *config) validate() error {
|
||||
if c.VaultAddr == "" {
|
||||
return errors.New("VaultAddr is empty. Set environment variable: VAULT_ADDR")
|
||||
}
|
||||
if c.VaultToken == "" {
|
||||
return errors.New("VaultToken is empty. Set environment variable: VAULT_TOKEN")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadConfig() (*config, error) {
|
||||
var c config
|
||||
err := envconfig.Process("", &c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &c, err
|
||||
}
|
||||
|
||||
// Setup verifies if appropriate credentials are set and adds the boundary controller
|
||||
// policy to vault. Returns the vault address.
|
||||
func Setup(t testing.TB) (string, string) {
|
||||
c, err := loadConfig()
|
||||
require.NoError(t, err)
|
||||
err = c.validate()
|
||||
require.NoError(t, err)
|
||||
|
||||
_, filename, _, ok := runtime.Caller(0)
|
||||
require.True(t, ok)
|
||||
policyName := "boundary-controller"
|
||||
output := e2e.RunCommand("vault", e2e.WithArgs("policy", "write", policyName,
|
||||
path.Join(path.Dir(filename), "boundary-controller-policy.hcl")),
|
||||
)
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
t.Cleanup(func() {
|
||||
output := e2e.RunCommand("vault", e2e.WithArgs("policy", "delete", policyName))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
})
|
||||
|
||||
return c.VaultAddr, policyName
|
||||
}
|
||||
|
||||
// CreateKvPrivateKeyCredential creates a private key credential in vault and creates a vault policy
|
||||
// to be able to read that credential. Returns the name of the policy.
|
||||
func CreateKvPrivateKeyCredential(t testing.TB, secretName string, secretPath string, user string, keyPath string) string {
|
||||
// Create policy file to read secret
|
||||
kvPolicyFileName := "kv-policy-test.hcl"
|
||||
kvPolicyFilePath := fmt.Sprintf("%s/%s", t.TempDir(), kvPolicyFileName)
|
||||
|
||||
f, err := os.Create(kvPolicyFilePath)
|
||||
require.NoError(t, err)
|
||||
_, err = f.WriteString(fmt.Sprintf("path \"%s/data/%s\" { capabilities = [\"read\"] }",
|
||||
secretPath,
|
||||
secretName,
|
||||
))
|
||||
require.NoError(t, err)
|
||||
|
||||
// Add policy to vault
|
||||
policyName := "kv-read"
|
||||
output := e2e.RunCommand("vault", e2e.WithArgs("policy", "write", policyName, kvPolicyFilePath))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
t.Cleanup(func() {
|
||||
output := e2e.RunCommand("vault", e2e.WithArgs("policy", "delete", policyName))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
})
|
||||
|
||||
// Create secret
|
||||
output = e2e.RunCommand("vault", e2e.WithArgs("kv", "put",
|
||||
"-mount", secretPath,
|
||||
secretName,
|
||||
"username="+user,
|
||||
"private_key=@"+keyPath,
|
||||
))
|
||||
require.NoError(t, output.Err, string(output.Stderr))
|
||||
|
||||
return policyName
|
||||
}
|
||||
Reference in new issue
Block a user