From b3c6cb7929654a4bcc630ddef8a0072a50b1f520 Mon Sep 17 00:00:00 2001 From: Michael Li Date: Mon, 10 Nov 2025 13:31:47 -0500 Subject: [PATCH] test(e2e): Add RDP test for Vault LDAP (ce commits) (#6237) * refact(e2e): Add error output to SetupLdapWithOpenLdap (cherry picked from commit 12874ec3227500ac03ece452e342f44d9f1ebc7a) * test(e2e): Add method for setting up vault ldap with active directory (cherry picked from commit 4f0fe7bba78d25005a5d98e203a3d0bc037a2b69) * chore(e2e): Add domain controller ipv6 address to e2e tests (cherry picked from commit 3215194053cd82a4e650522e56f4699946f62ef3) --- enos/enos-scenario-e2e-aws-rdp-base.hcl | 1 + enos/modules/test_e2e/main.tf | 6 + .../credential_library_vault_ldap_test.go | 6 +- testing/internal/e2e/vault/vault.go | 111 ++++++++++++++++-- 4 files changed, 110 insertions(+), 14 deletions(-) diff --git a/enos/enos-scenario-e2e-aws-rdp-base.hcl b/enos/enos-scenario-e2e-aws-rdp-base.hcl index b802edb1b5..8c32925d33 100644 --- a/enos/enos-scenario-e2e-aws-rdp-base.hcl +++ b/enos/enos-scenario-e2e-aws-rdp-base.hcl @@ -309,6 +309,7 @@ scenario "e2e_aws_rdp_base" { max_page_size = step.create_boundary_cluster.max_page_size worker_tag_collocated = local.collocated_tag target_rdp_domain_controller_addr = step.create_rdp_domain_controller.private_ip + target_rdp_domain_controller_addr_ipv6 = step.create_rdp_domain_controller.ipv6[0] target_rdp_domain_controller_user = step.create_rdp_domain_controller.admin_username target_rdp_domain_controller_password = step.create_rdp_domain_controller.password target_rdp_member_server_addr = step.create_rdp_member_server.private_ip diff --git a/enos/modules/test_e2e/main.tf b/enos/modules/test_e2e/main.tf index 013c09ad03..bf8c43d720 100644 --- a/enos/modules/test_e2e/main.tf +++ b/enos/modules/test_e2e/main.tf @@ -161,6 +161,11 @@ variable "target_rdp_domain_controller_addr" { type = string default = "" } +variable "target_rdp_domain_controller_addr_ipv6" { + description = "IPV6 ddress of RDP domain controller" + type = string + default = "" +} variable "target_rdp_domain_controller_user" { description = "Username for RDP domain controller" type = string @@ -282,6 +287,7 @@ resource "enos_local_exec" "run_e2e_test" { E2E_MAX_PAGE_SIZE = var.max_page_size E2E_IP_VERSION = var.ip_version E2E_TARGET_RDP_DOMAIN_CONTROLLER_ADDR = var.target_rdp_domain_controller_addr + E2E_TARGET_RDP_DOMAIN_CONTROLLER_ADDR_IPV6 = var.target_rdp_domain_controller_addr_ipv6 E2E_TARGET_RDP_DOMAIN_CONTROLLER_USER = var.target_rdp_domain_controller_user E2E_TARGET_RDP_DOMAIN_CONTROLLER_PASSWORD = var.target_rdp_domain_controller_password E2E_TARGET_RDP_MEMBER_SERVER_ADDR = var.target_rdp_member_server_addr diff --git a/testing/internal/e2e/tests/base_with_vault/credential_library_vault_ldap_test.go b/testing/internal/e2e/tests/base_with_vault/credential_library_vault_ldap_test.go index 0bd6875583..77e723ab49 100644 --- a/testing/internal/e2e/tests/base_with_vault/credential_library_vault_ldap_test.go +++ b/testing/internal/e2e/tests/base_with_vault/credential_library_vault_ldap_test.go @@ -73,7 +73,7 @@ func TestApiVaultLdapCredentialLibrary(t *testing.T) { require.NoError(t, output.Err, string(output.Stderr)) }) - ldapPolicyName := vault.SetupLdap(t, c.VaultLdapPath, + ldapPolicyName, err := vault.SetupLdapWithOpenLdap(t, c.VaultLdapPath, c.LdapAddress, c.LdapAdminDn, c.LdapAdminPassword, c.LdapDomainDn, c.LdapUserName, c.LdapGroupName, ) @@ -89,6 +89,7 @@ func TestApiVaultLdapCredentialLibrary(t *testing.T) { ) require.NoError(t, output.Err, string(output.Stderr)) }) + require.NoError(t, err) // Create Vault token for Boundary. output := e2e.RunCommand(t.Context(), "vault", @@ -243,7 +244,7 @@ func TestCliVaultLdapCredentialLibrary(t *testing.T) { require.NoError(t, output.Err, string(output.Stderr)) }) - ldapPolicyName := vault.SetupLdap(t, c.VaultLdapPath, + ldapPolicyName, err := vault.SetupLdapWithOpenLdap(t, c.VaultLdapPath, c.LdapAddress, c.LdapAdminDn, c.LdapAdminPassword, c.LdapDomainDn, c.LdapUserName, c.LdapGroupName, ) @@ -259,6 +260,7 @@ func TestCliVaultLdapCredentialLibrary(t *testing.T) { ) require.NoError(t, output.Err, string(output.Stderr)) }) + require.NoError(t, err) // Create Vault token for Boundary. output := e2e.RunCommand(t.Context(), "vault", diff --git a/testing/internal/e2e/vault/vault.go b/testing/internal/e2e/vault/vault.go index f750225f4d..c021422a69 100644 --- a/testing/internal/e2e/vault/vault.go +++ b/testing/internal/e2e/vault/vault.go @@ -6,6 +6,7 @@ package vault import ( "context" + "errors" "fmt" "os" "path" @@ -36,24 +37,99 @@ func SetupForBoundaryController(t testing.TB, boundaryControllerFilePath string) return boundaryPolicyName } -// SetupLdap sets a Vault server up for LDAP against an OpenLDAP server. It +// SetupLdapWithAd sets a Vault server up for LDAP against an Active Directory server. It +// enables the LDAP secrets engine, configures it and creates a static user +// according to what is in Active Directory. Note that this function does not put any +// clean-up in place to run after a test is complete. When applicable, callers +// should destroy the Vault LDAP policy this function creates. +func SetupLdapWithAd(t testing.TB, vaultLdapMountPath, ldapAddr, ldapAdmin, ldapAdminPw, ldapUser, ldapDn string) (string, error) { + // Enable LDAP secrets engine. + output := e2e.RunCommand(t.Context(), "vault", + e2e.WithArgs("secrets", "enable", fmt.Sprintf("-path=%s", vaultLdapMountPath), "ldap"), + ) + if output.Err != nil { + return "", errors.New(strings.TrimSpace(string(output.Stderr))) + } + + // Define and write LDAP access policy to Vault. + vaultLdapPolicyFilePath := path.Join(t.TempDir(), "ldap-policy.hcl") + f, err := os.Create(vaultLdapPolicyFilePath) + if err != nil { + return "", err + } + _, err = fmt.Fprintf(f, ` + path "%[1]s/static-cred/%[2]s" { + capabilities = ["read"] + } + path "%[1]s/static-role/%[2]s" { + capabilities = ["create", "read", "update", "patch", "delete", "list"] + } + `, vaultLdapMountPath, ldapUser) + if err != nil { + return "", err + } + err = f.Sync() + if err != nil { + return "", err + } + _ = f.Close() + + policyName := WritePolicy(t, t.Context(), vaultLdapPolicyFilePath) + + // Configure LDAP secrets engine to point to AD service. + output = e2e.RunCommand(t.Context(), "vault", + e2e.WithArgs( + "write", + fmt.Sprintf("%s/config", vaultLdapMountPath), + fmt.Sprintf("url=%s", ldapAddr), + fmt.Sprintf("binddn=cn=%s,%s", ldapAdmin, ldapDn), + fmt.Sprintf("bindpass=%s", ldapAdminPw), + "schema=ad", + "insecure_tls=true", + ), + ) + if output.Err != nil { + return "", errors.New(strings.TrimSpace(string(output.Stderr))) + } + + // Create static LDAP user in Vault (already defined in AD server). + output = e2e.RunCommand(t.Context(), "vault", + e2e.WithArgs( + "write", + fmt.Sprintf("%s/static-role/%s", vaultLdapMountPath, ldapUser), + fmt.Sprintf("dn=cn=%s,%s", ldapUser, ldapDn), + fmt.Sprintf("username=%s", ldapUser), + "rotation_period=24h", + ), + ) + if output.Err != nil { + return "", errors.New(strings.TrimSpace(string(output.Stderr))) + } + + return policyName, nil +} + +// SetupLdapWithOpenLdap sets a Vault server up for LDAP against an OpenLDAP server. It // enables the LDAP secrets engine, configures it and creates a static user // according to what is in OpenLDAP. Additionally, it sets up Vault's ability to // manage LDAP users dynamically. Note that this function does not put any // clean-up in place to run after a test is complete. When applicable, callers -// should destroy the Vault LDAP policy and LDAP secrets engine this function -// creates. -func SetupLdap(t testing.TB, vaultLdapMountPath, ldapAddr, ldapAdminDn, ldapAdminPw, ldapDn, ldapUser, ldapGroup string) string { +// should destroy the Vault LDAP policy this function creates. +func SetupLdapWithOpenLdap(t testing.TB, vaultLdapMountPath, ldapAddr, ldapAdminDn, ldapAdminPw, ldapDn, ldapUser, ldapGroup string) (string, error) { // Enable LDAP secrets engine. output := e2e.RunCommand(t.Context(), "vault", e2e.WithArgs("secrets", "enable", fmt.Sprintf("-path=%s", vaultLdapMountPath), "ldap"), ) - require.NoError(t, output.Err, string(output.Stderr)) + if output.Err != nil { + return "", errors.New(strings.TrimSpace(string(output.Stderr))) + } // Define and write LDAP access policy to Vault. vaultLdapPolicyFilePath := path.Join(t.TempDir(), "ldap-policy.hcl") f, err := os.Create(vaultLdapPolicyFilePath) - require.NoError(t, err) + if err != nil { + return "", err + } _, err = fmt.Fprintf(f, ` path "%[1]s/static-cred/%[2]s" { @@ -70,8 +146,13 @@ func SetupLdap(t testing.TB, vaultLdapMountPath, ldapAddr, ldapAdminDn, ldapAdmi capabilities = ["create", "read", "update", "patch", "delete", "list"] } `, vaultLdapMountPath, ldapUser, ldapGroup) - require.NoError(t, err) - require.NoError(t, f.Sync()) + if err != nil { + return "", err + } + err = f.Sync() + if err != nil { + return "", err + } _ = f.Close() policyName := WritePolicy(t, t.Context(), vaultLdapPolicyFilePath) @@ -86,7 +167,9 @@ func SetupLdap(t testing.TB, vaultLdapMountPath, ldapAddr, ldapAdminDn, ldapAdmi fmt.Sprintf("bindpass=%s", ldapAdminPw), ), ) - require.NoError(t, output.Err, string(output.Stderr)) + if output.Err != nil { + return "", errors.New(strings.TrimSpace(string(output.Stderr))) + } // Create static LDAP user in Vault (already defined in OpenLDAP server). output = e2e.RunCommand(t.Context(), "vault", @@ -98,7 +181,9 @@ func SetupLdap(t testing.TB, vaultLdapMountPath, ldapAddr, ldapAdminDn, ldapAdmi "rotation_period=24h", ), ) - require.NoError(t, output.Err, string(output.Stderr)) + if output.Err != nil { + return "", errors.New(strings.TrimSpace(string(output.Stderr))) + } // Create Vault dynamic role for LDAP group. createLdif := fmt.Sprintf(` @@ -136,9 +221,11 @@ func SetupLdap(t testing.TB, vaultLdapMountPath, ldapAddr, ldapAdminDn, ldapAdmi "max_ttxl=24h", ), ) - require.NoError(t, output.Err, string(output.Stderr)) + if output.Err != nil { + return "", errors.New(strings.TrimSpace(string(output.Stderr))) + } - return policyName + return policyName, nil } // CreateKvPrivateKeyCredential creates a private key credential in vault and