VAULT-41086 Verify vault can generate dynamic credentials and rotate root password. (#11344) (#11681)

* Verify vault can generate dynamic credentials and rotate root password

* Added new line at end of the script file

* Remove extra space in sh script

* Remove extra space in sh script

* Created modular structure and other fixes

* linting issues

* lint issues

* Linting issue in verify-secrets.sh

* Linting issue in verify-secrets.sh

* Linting issues in verify-secrets.sh and verify-rotation.sh

* Linting issues

* Linting issues

* Linting issues

* Reverted the changes made to ldap-configs.sh and ldap-verify-configs

* Fix missing newline at end of ldap-verify-configs

Add a newline at the end of the ldap-verify-configs script.

* test ldap changes

* test ldap changes

* reverted the configuration for testing ldap [ci skip]

* reverted the configuration for testing ldap [ci skip]

* Refactoring

* Update ldap.tf

* Update ldap.tf [ci skip]

* Update ldap.tf

* Update test-run-enos-scenario-matrix.yml to test ldap changes

* reverted Update test-run-enos-scenario-matrix.yml to test ldap changes

---------

Co-authored-by: pranaya092000 <pranaya.p@hashicorp.com>
Co-authored-by: Pranaya <Pranaya.P@ibm.com>
This commit is contained in:
Vault Automation 2026-01-09 13:32:54 -08:00 committed by GitHub
parent 1211b75aaf
commit 8a3aa76513
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 430 additions and 8 deletions

View file

@ -93,8 +93,8 @@ resource "enos_remote_exec" "secrets_enable_ldap_secret" {
}
}
# Configuring Openldap Server and Vault LDAP
resource "enos_remote_exec" "ldap_configurations" {
# Setup OpenLDAP infrastructure
resource "enos_remote_exec" "ldap_setup" {
depends_on = [
enos_remote_exec.secrets_enable_ldap_secret
]
@ -110,7 +110,7 @@ resource "enos_remote_exec" "ldap_configurations" {
VAULT_TOKEN = var.vault_root_token
}
scripts = [abspath("${path.module}/../../../scripts/ldap-configs.sh")]
scripts = [abspath("${path.module}/../../../scripts/ldap/setup.sh")]
transport = {
ssh = {

View file

@ -38,13 +38,44 @@ variable "vault_root_token" {
default = null
}
locals {
ldap_login_data = jsondecode(enos_remote_exec.ldap_verify_configs.stdout)
variable "credential_ttl_buffer" {
description = "Buffer (seconds) to wait after LDAP credential TTL expiry"
type = number
default = 80
}
# Verifying Vault LDAP Configurations
resource "enos_remote_exec" "ldap_verify_configs" {
variable "default_ttl" {
description = "Default time-to-live (in seconds) for issued LDAP credentials."
type = number
default = 60
}
variable "max_ttl" {
description = "Maximum time-to-live (in seconds) allowed for issued LDAP credentials"
type = number
default = 60
}
variable "enable_secrets_verification" {
type = bool
description = "Enable LDAP secrets engine verification (dynamic credentials)"
default = true
}
variable "enable_rotation_verification" {
type = bool
description = "Enable LDAP root rotation verification"
default = true
}
variable "enable_auth_verification" {
type = bool
description = "Enable LDAP authentication verification"
default = true
}
resource "enos_remote_exec" "ldap_verify_auth" {
count = var.enable_auth_verification ? 1 : 0
environment = {
MOUNT = "${var.create_state.ldap.ldap_mount}"
LDAP_SERVER = "${var.create_state.ldap.host.private_ip}"
@ -55,8 +86,59 @@ resource "enos_remote_exec" "ldap_verify_configs" {
VAULT_INSTALL_DIR = var.vault_install_dir
VAULT_TOKEN = var.vault_root_token
}
scripts = [abspath("${path.module}/../../../scripts/ldap/verify-auth.sh")]
transport = {
ssh = {
host = var.hosts[0].public_ip
}
}
}
scripts = [abspath("${path.module}/../../../scripts/ldap-verify-configs")]
# Configure and verify LDAP secrets engine
resource "enos_remote_exec" "ldap_verify_secrets" {
count = var.enable_secrets_verification ? 1 : 0
environment = {
MOUNT = "${var.create_state.ldap.ldap_mount}"
LDAP_SERVER = "${var.create_state.ldap.host.private_ip}"
LDAP_PORT = "${var.create_state.ldap.port}"
LDAP_USERNAME = "${var.create_state.ldap.username}"
LDAP_ADMIN_PW = "${var.create_state.ldap.pw}"
VAULT_ADDR = var.vault_addr
VAULT_INSTALL_DIR = var.vault_install_dir
VAULT_TOKEN = var.vault_root_token
CREDENTIAL_TTL_BUFFER = tostring(var.credential_ttl_buffer)
DEFAULT_TTL = tostring(var.default_ttl)
MAX_TTL = tostring(var.max_ttl)
}
scripts = [abspath("${path.module}/../../../scripts/ldap/verify-secrets.sh")]
transport = {
ssh = {
host = var.hosts[0].public_ip
}
}
}
# Verify LDAP root rotation
resource "enos_remote_exec" "ldap_verify_rotation" {
count = var.enable_rotation_verification ? 1 : 0
depends_on = [
enos_remote_exec.ldap_verify_secrets
]
environment = {
MOUNT = "${var.create_state.ldap.ldap_mount}"
LDAP_SERVER = "${var.create_state.ldap.host.private_ip}"
LDAP_PORT = "${var.create_state.ldap.port}"
LDAP_USERNAME = "${var.create_state.ldap.username}"
LDAP_ADMIN_PW = "${var.create_state.ldap.pw}"
VAULT_ADDR = var.vault_addr
VAULT_INSTALL_DIR = var.vault_install_dir
VAULT_TOKEN = var.vault_root_token
}
scripts = [abspath("${path.module}/../../../scripts/ldap/verify-rotation.sh")]
transport = {
ssh = {

View file

@ -0,0 +1,71 @@
#!/usr/bin/env bash
# Copyright IBM Corp. 2016, 2025
# SPDX-License-Identifier: BUSL-1.1
set -e
fail() {
echo "$1" 1>&2
exit 1
}
[[ -z "$MOUNT" ]] && fail "MOUNT env variable has not been set"
[[ -z "$LDAP_SERVER" ]] && fail "LDAP_SERVER env variable has not been set"
[[ -z "$LDAP_PORT" ]] && fail "LDAP_PORT env variable has not been set"
[[ -z "$LDAP_USERNAME" ]] && fail "LDAP_USERNAME env variable has not been set"
[[ -z "$LDAP_ADMIN_PW" ]] && fail "LDAP_ADMIN_PW env variable has not been set"
[[ -z "$VAULT_ADDR" ]] && fail "VAULT_ADDR env variable has not been set"
[[ -z "$VAULT_INSTALL_DIR" ]] && fail "VAULT_INSTALL_DIR env variable has not been set"
[[ -z "$VAULT_TOKEN" ]] && fail "VAULT_TOKEN env variable has not been set"
binpath=${VAULT_INSTALL_DIR}/vault
test -x "$binpath" || fail "unable to locate vault binary at $binpath"
export VAULT_FORMAT=json
echo "OpenLDAP: Checking for OpenLDAP Server Connection: ${LDAP_SERVER}:${LDAP_PORT}"
ldapsearch -x -H "ldap://${LDAP_SERVER}:${LDAP_PORT}" -b "dc=${LDAP_USERNAME},dc=com" -D "cn=admin,dc=${LDAP_USERNAME},dc=com" -w "${LDAP_ADMIN_PW}"
# Creating Users Org Unit LDIF file and adding users organizational unit
echo "OpenLDAP: Creating Users Org Unit LDIF file and adding users organizational unit"
GROUP_LDIF="group.ldif"
cat << EOF > ${GROUP_LDIF}
dn: ou=users,dc=$LDAP_USERNAME,dc=com
objectClass: organizationalUnit
ou: users
dn: ou=groups,dc=$LDAP_USERNAME,dc=com
objectClass: organizationalUnit
ou: groups
EOF
ldapadd -x -H "ldap://${LDAP_SERVER}:${LDAP_PORT}" -D "cn=admin,dc=${LDAP_USERNAME},dc=com" -w "${LDAP_ADMIN_PW}" -f ${GROUP_LDIF}
ADMIN_LDIF="admin.ldif"
cat << EOF > ${ADMIN_LDIF}
dn: cn=admin,dc=$LDAP_USERNAME,dc=com
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator
userPassword: $LDAP_ADMIN_PW
EOF
ldapadd -x -H "ldap://${LDAP_SERVER}:${LDAP_PORT}" -D "cn=admin,dc=${LDAP_USERNAME},dc=com" -w "${LDAP_ADMIN_PW}" -f ${ADMIN_LDIF}
echo "OpenLDAP: Creating User LDIF file and adding user to LDAP"
USER_LDIF="user.ldif"
cat << EOF > ${USER_LDIF}
# User: enos
dn: uid=$LDAP_USERNAME,ou=users,dc=$LDAP_USERNAME,dc=com
objectClass: inetOrgPerson
sn: $LDAP_USERNAME
cn: $LDAP_USERNAME user
uid: $LDAP_USERNAME
userPassword: $LDAP_ADMIN_PW
# Group: devs
dn: cn=devs,ou=groups,dc=$LDAP_USERNAME,dc=com
objectClass: groupOfNames
cn: devs
member: uid=$LDAP_USERNAME,ou=users,dc=$LDAP_USERNAME,dc=com
EOF
ldapadd -x -H "ldap://${LDAP_SERVER}:${LDAP_PORT}" -D "cn=admin,dc=${LDAP_USERNAME},dc=com" -w "${LDAP_ADMIN_PW}" -f ${USER_LDIF}

View file

@ -0,0 +1,74 @@
#!/usr/bin/env bash
# Copyright IBM Corp. 2016, 2025
# SPDX-License-Identifier: BUSL-1.1
set -e
fail() {
echo "$1" 1>&2
exit 1
}
# Validate required environment variables
[[ -z "$MOUNT" ]] && fail "MOUNT env variable has not been set"
[[ -z "$LDAP_SERVER" ]] && fail "LDAP_SERVER env variable has not been set"
[[ -z "$LDAP_PORT" ]] && fail "LDAP_PORT env variable has not been set"
[[ -z "$LDAP_USERNAME" ]] && fail "LDAP_USERNAME env variable has not been set"
[[ -z "$LDAP_ADMIN_PW" ]] && fail "LDAP_ADMIN_PW env variable has not been set"
[[ -z "$VAULT_ADDR" ]] && fail "VAULT_ADDR env variable has not been set"
[[ -z "$VAULT_INSTALL_DIR" ]] && fail "VAULT_INSTALL_DIR env variable has not been set"
[[ -z "$VAULT_TOKEN" ]] && fail "VAULT_TOKEN env variable has not been set"
binpath=${VAULT_INSTALL_DIR}/vault
test -x "$binpath" || fail "unable to locate vault binary at $binpath"
export VAULT_FORMAT=json
echo "Vault: Creating ldap auth and creating auth/ldap/config route"
"$binpath" auth enable "${MOUNT}" > /dev/null 2>&1 || echo "Warning: Vault ldap auth already enabled"
"$binpath" write "auth/${MOUNT}/config" \
url="ldap://test_${LDAP_SERVER}:${LDAP_PORT}" \
binddn="cn=admin,dc=${LDAP_USERNAME},dc=com" \
bindpass="${LDAP_ADMIN_PW}" \
userdn="ou=users,dc=${LDAP_USERNAME},dc=com" \
userattr="uid" \
groupdn="ou=groups,dc=${LDAP_USERNAME},dc=com" \
groupfilter="(&(objectClass=groupOfNames)(member={{.UserDN}}))" \
groupattr="cn" \
insecure_tls=true
echo "Vault: Updating ldap auth and creating auth/ldap/config route"
"$binpath" write "auth/${MOUNT}/config" \
url="ldap://${LDAP_SERVER}:${LDAP_PORT}" \
binddn="cn=admin,dc=${LDAP_USERNAME},dc=com" \
bindpass="${LDAP_ADMIN_PW}" \
userdn="ou=users,dc=${LDAP_USERNAME},dc=com" \
userattr="uid" \
groupdn="ou=groups,dc=${LDAP_USERNAME},dc=com" \
groupfilter="(&(objectClass=groupOfNames)(member={{.UserDN}}))" \
groupattr="cn" \
insecure_tls=true
echo "Vault: Creating Vault Policy for LDAP and assigning user to policy"
VAULT_LDAP_POLICY="ldap_reader.hcl"
cat << EOF > ${VAULT_LDAP_POLICY}
path "secret/data/*" {
capabilities = ["read", "list"]
}
EOF
LDAP_READER_POLICY="reader-policy"
"$binpath" policy write ${LDAP_READER_POLICY} "${VAULT_LDAP_POLICY}"
"$binpath" write "auth/${MOUNT}/users/${LDAP_USERNAME}" policies="${LDAP_READER_POLICY}"
echo "Vault: Creating Vault Policy for LDAP DEV and assigning user to policy"
VAULT_LDAP_DEV_POLICY="ldap_dev.hcl"
cat << EOF > ${VAULT_LDAP_DEV_POLICY}
path "secret/data/dev/*" {
capabilities = ["read", "list"]
}
EOF
LDAP_DEV_POLICY="dev-policy"
"$binpath" policy write ${LDAP_DEV_POLICY} "${VAULT_LDAP_DEV_POLICY}"
"$binpath" write "auth/${MOUNT}/groups/devs" policies="${LDAP_DEV_POLICY}"
echo "SUCCESS: LDAP auth engine configured and verified"

View file

@ -0,0 +1,58 @@
#!/usr/bin/env bash
# Copyright IBM Corp. 2016, 2025
# SPDX-License-Identifier: BUSL-1.1
set -e
fail() {
echo "$1" 1>&2
exit 1
}
[[ -z "$MOUNT" ]] && fail "MOUNT env variable has not been set"
[[ -z "$LDAP_SERVER" ]] && fail "LDAP_SERVER env variable has not been set"
[[ -z "$LDAP_PORT" ]] && fail "LDAP_PORT env variable has not been set"
[[ -z "$LDAP_USERNAME" ]] && fail "LDAP_USERNAME env variable has not been set"
[[ -z "$LDAP_ADMIN_PW" ]] && fail "LDAP_ADMIN_PW env variable has not been set"
[[ -z "$VAULT_ADDR" ]] && fail "VAULT_ADDR env variable has not been set"
[[ -z "$VAULT_INSTALL_DIR" ]] && fail "VAULT_INSTALL_DIR env variable has not been set"
[[ -z "$VAULT_TOKEN" ]] && fail "VAULT_TOKEN env variable has not been set"
binpath=${VAULT_INSTALL_DIR}/vault
test -x "$binpath" || fail "unable to locate vault binary at $binpath"
export VAULT_FORMAT=json
# Verifying LDAP Server Configs
LDAP_UID=$(ldapsearch -x -LLL -H "ldap://${LDAP_SERVER}:${LDAP_PORT}" -b "dc=${LDAP_USERNAME},dc=com" -D "cn=admin,dc=${LDAP_USERNAME},dc=com" -w "${LDAP_ADMIN_PW}" "(uid=${LDAP_USERNAME})" 2> /dev/null)
[[ -z "$LDAP_UID" ]] && fail "Could not search ldap server for uid: ${LDAP_USERNAME}"
# Authenticate Using Vault LDAP login
VAULT_LDAP_LOGIN=$("$binpath" login -method="${MOUNT}" username="${LDAP_USERNAME}" password="${LDAP_ADMIN_PW}")
# Verifying Vault LDAP Login Token
VAULT_LDAP_TOKEN=$(echo "$VAULT_LDAP_LOGIN" | jq -r ".auth.client_token")
[[ -z "$VAULT_LDAP_TOKEN" ]] && fail "Vault LDAP could not log in correctly: ${VAULT_LDAP_TOKEN}"
# Verifying Vault LDAP Policies
VAULT_POLICY_COUNT=$(echo "$VAULT_LDAP_LOGIN" | jq -r ".auth.policies | length")
[[ -z "$VAULT_POLICY_COUNT" ]] && fail "Vault LDAP number of policies does not look correct: ${VAULT_POLICY_COUNT}"
echo "${VAULT_LDAP_LOGIN}"
#Attempting to rotate root with root token--should pass.
if "$binpath" write -f "${MOUNT}/rotate-root" > /dev/null 2>&1; then
echo "SUCCESS:rotate-root write passed (permissions OK)"
else
fail "Error: rotate-root write failed even though token had permissions"
fi
#Attempting to rotate root with LDAP token--should fail as the policy does not allow it.
ROOT_ROTATE=$(VAULT_TOKEN="$VAULT_LDAP_TOKEN" "$binpath" write -f "${MOUNT}/rotate-root" 2>&1 || true)
if echo "$ROOT_ROTATE" | grep -qi "permission denied"; then
echo "SUCCESS: Vault correctly denied root rotation for LDAP token as policy does not allow."
else
fail "ERROR: LDAP token does not have permission to rotate, still rotation succeeded"
fi

View file

@ -0,0 +1,137 @@
#!/usr/bin/env bash
# Copyright IBM Corp. 2016, 2025
# SPDX-License-Identifier: BUSL-1.1
set -e
fail() {
echo "$1" 1>&2
exit 1
}
# Function to generate LDIF files with DN
generate_ldif() {
local filename="$1"
local content="$2"
local ou="${3:-users}"
cat << EOF > "${filename}"
dn: cn={{.Username}},ou=${ou},dc=${LDAP_USERNAME},dc=com
${content}
EOF
}
# Validate required environment variables
[[ -z "$LDAP_SERVER" ]] && fail "LDAP_SERVER env variable has not been set"
[[ -z "$LDAP_PORT" ]] && fail "LDAP_PORT env variable has not been set"
[[ -z "$LDAP_USERNAME" ]] && fail "LDAP_USERNAME env variable has not been set"
[[ -z "$LDAP_ADMIN_PW" ]] && fail "LDAP_ADMIN_PW env variable has not been set"
[[ -z "$VAULT_ADDR" ]] && fail "VAULT_ADDR env variable has not been set"
[[ -z "$VAULT_INSTALL_DIR" ]] && fail "VAULT_INSTALL_DIR env variable has not been set"
[[ -z "$VAULT_TOKEN" ]] && fail "VAULT_TOKEN env variable has not been set"
binpath=${VAULT_INSTALL_DIR}/vault
test -x "$binpath" || fail "unable to locate vault binary at $binpath"
export VAULT_FORMAT=json
# Set LDAP bind DN, password, and server URL for Vault's LDAP secrets engine
echo "Vault: Configuring LDAP secrets engine"
"$binpath" write ldap/config \
binddn="cn=admin,dc=${LDAP_USERNAME},dc=com" \
bindpass="${LDAP_ADMIN_PW}" \
url="ldap://${LDAP_SERVER}:${LDAP_PORT}"
# Create the LDIF template that Vault will use to generate dynamic LDAP users
echo "Vault: Creating creation.ldif for dynamic LDAP role"
CREATION_LDIF="creation.ldif"
generate_ldif "${CREATION_LDIF}" "objectClass: person
objectClass: top
cn: {{.Username}}
sn: {{.Password | utf16le | base64}}
userPassword: {{.Password}}" "users"
# Create the LDIF template used by Vault to delete dynamic LDAP user entries
echo "Vault: Creating deletion.ldif for dynamic LDAP role"
DELETION_LDIF="deletion.ldif"
generate_ldif "${DELETION_LDIF}" "changetype: delete" "users"
# Create the LDIF template used by Vault to roll back user creation if an error occurs
echo "Vault: Creating rollback.ldif for dynamic LDAP role"
ROLLBACK_LDIF="rollback.ldif"
generate_ldif "${ROLLBACK_LDIF}" "changetype: delete" "users"
# Create the dynamic LDAP role in Vault using the LDIF templates
echo "Vault: Creating dynamic LDAP role dynamic-role"
"$binpath" write ldap/role/dynamic-role \
creation_ldif=@${CREATION_LDIF} \
deletion_ldif=@${DELETION_LDIF} \
rollback_ldif=@${ROLLBACK_LDIF} \
default_ttl="${DEFAULT_TTL}" \
max_ttl="${MAX_TTL}"
# Generating dynamic LDAP credentials from role dynamic-role
echo "Vault: Generating dynamic LDAP credentials from role dynamic-role"
DYNAMIC_CREDS=$("$binpath" read ldap/creds/dynamic-role)
DYNAMIC_PASSWORD=$(echo "$DYNAMIC_CREDS" | jq -r '.data.password')
DYN_DN=$(echo "$DYNAMIC_CREDS" | jq -r '.data.distinguished_names[0]')
if [[ -z "$DYN_DN" || "$DYN_DN" == "null" ]]; then
fail "Vault did not return a distinguished_name for dynamic LDAP user"
fi
#Verify Dynamic Credentials
if ldapwhoami -x -H "ldap://${LDAP_SERVER}:${LDAP_PORT}" -D "${DYN_DN}" -w "${DYNAMIC_PASSWORD}" > /dev/null 2>&1; then
echo "LDAP dynamic credentials valid"
else
fail "Error: LDAP dynamic credentials validation failed"
fi
# Attempt to use expired credentials — verify LDAP authentication fails.
CREDENTIAL_TTL_BUFFER=${CREDENTIAL_TTL_BUFFER:-80}
sleep "$CREDENTIAL_TTL_BUFFER"
if ldapwhoami -x -H "ldap://${LDAP_SERVER}:${LDAP_PORT}" -D "$DYN_DN" -w "$DYNAMIC_PASSWORD" &> /dev/null; then
fail "Error: Dynamic credentials still valid — TTL did NOT expire"
else
echo "Dynamic credentials expired as expected"
fi
#Testing invalid dynamic LDAP role configuration by giving an invalid OU.
INVALID_CREATION_LDIF="invalid_creation.ldif"
INVALID_DELETION_LDIF="invalid_deletion.ldif"
generate_ldif "${INVALID_CREATION_LDIF}" "objectClass: person
objectClass: top
cn: {{.Username}}
sn: {{.Password}}
userPassword: {{.Password}}" "invalid_ou"
generate_ldif "${INVALID_DELETION_LDIF}" "changetype: delete" "invalid_ou"
echo "Vault: Attempting to create invalid-role (should fail)..."
"$binpath" write ldap/role/invalid-role \
creation_ldif=@${INVALID_CREATION_LDIF} \
deletion_ldif=@${INVALID_DELETION_LDIF} \
rollback_ldif=@${INVALID_DELETION_LDIF} \
default_ttl="${DEFAULT_TTL}" \
max_ttl="${MAX_TTL}" || true
echo "Attempting to read creds from invalid-role"
INVALID_CREDS_OUTPUT=$(
"$binpath" read ldap/creds/invalid-role 2>&1 || true
)
echo "$INVALID_CREDS_OUTPUT"
#check for error message indicating invalid DN/OU.
if echo "$INVALID_CREDS_OUTPUT" | grep -qi "No Such Object"; then
echo "SUCCESS: Vault failed dynamic credential creation due to invalid OU/DN."
"$binpath" delete ldap/role/invalid-role
else
fail "ERROR: Vault did NOT fail when invalid DN/OU was used!"
fi