Skip to content

Commit 63e969b

Browse files
Merge remote-tracking branch 'remotes/from/ce/main'
2 parents f0834d4 + 6841981 commit 63e969b

File tree

1 file changed

+187
-62
lines changed

1 file changed

+187
-62
lines changed

enos/modules/verify_secrets_engines/scripts/ldap/verify-secrets.sh

Lines changed: 187 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,63 @@
55
set -e
66

77
fail() {
8-
echo "$1" 1>&2
9-
exit 1
8+
echo "$1" 1>&2
9+
exit 1
1010
}
1111

1212
# Function to generate LDIF files with DN
1313
generate_ldif() {
14-
local filename="$1"
15-
local content="$2"
16-
local ou="${3:-users}"
14+
local filename="$1"
15+
local content="$2"
16+
local ou="${3:-users}"
1717

18-
cat << EOF > "${filename}"
18+
cat << EOF > "${filename}"
1919
dn: cn={{.Username}},ou=${ou},dc=${LDAP_USERNAME},dc=com
2020
${content}
2121
EOF
2222
}
2323

24+
# Function to create a password policy in Vault
25+
create_password_policy() {
26+
local policy_name="$1"
27+
local length="$2"
28+
local lowercase_min="$3"
29+
local uppercase_min="$4"
30+
local digit_min="$5"
31+
local special_chars="$6"
32+
local special_min="$7"
33+
34+
echo "Vault: Creating ${policy_name} password policy"
35+
cat > "${policy_name}.hcl" << EOF
36+
length = ${length}
37+
38+
rule "charset" {
39+
charset = "abcdefghijklmnopqrstuvwxyz"
40+
min-chars = ${lowercase_min}
41+
}
42+
43+
rule "charset" {
44+
charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
45+
min-chars = ${uppercase_min}
46+
}
47+
48+
rule "charset" {
49+
charset = "0123456789"
50+
min-chars = ${digit_min}
51+
}
52+
53+
rule "charset" {
54+
charset = "${special_chars}"
55+
min-chars = ${special_min}
56+
}
57+
EOF
58+
59+
"$binpath" write sys/policies/password/"${policy_name}" policy=@"${policy_name}.hcl"
60+
echo "Password policy '${policy_name}' created"
61+
}
62+
2463
# Validate required environment variables
64+
[[ -z "$MOUNT" ]] && fail "MOUNT env variable has not been set"
2565
[[ -z "$LDAP_SERVER" ]] && fail "LDAP_SERVER env variable has not been set"
2666
[[ -z "$LDAP_PORT" ]] && fail "LDAP_PORT env variable has not been set"
2767
[[ -z "$LDAP_USERNAME" ]] && fail "LDAP_USERNAME env variable has not been set"
@@ -35,14 +75,34 @@ test -x "$binpath" || fail "unable to locate vault binary at $binpath"
3575

3676
export VAULT_FORMAT=json
3777

78+
CREDENTIAL_TTL_BUFFER=${CREDENTIAL_TTL_BUFFER:-80}
79+
DYNAMIC_ROLE_NAME="dynamic-role"
80+
INVALID_ROLE_NAME="invalid-role"
81+
82+
# Define password policy constants
83+
readonly DEFAULT_POLICY="default-policy"
84+
readonly STRONG_POLICY="strong-policy"
85+
readonly DEFAULT_LENGTH=20
86+
readonly DEFAULT_MIN_CHARS=1
87+
readonly STRONG_POLICY_LENGTH=24
88+
readonly SPECIAL_CHARS="!@#\$%^&*"
89+
90+
# Create password policy for LDAP
91+
create_password_policy "$DEFAULT_POLICY" "$DEFAULT_LENGTH" "$DEFAULT_MIN_CHARS" "$DEFAULT_MIN_CHARS" "$DEFAULT_MIN_CHARS" "$SPECIAL_CHARS" "$DEFAULT_MIN_CHARS"
92+
3893
# Set LDAP bind DN, password, and server URL for Vault's LDAP secrets engine
3994
echo "Vault: Configuring LDAP secrets engine"
40-
"$binpath" write ldap/config \
95+
"$binpath" write "${MOUNT}/config" \
4196
binddn="cn=admin,dc=${LDAP_USERNAME},dc=com" \
4297
bindpass="${LDAP_ADMIN_PW}" \
43-
url="ldap://${LDAP_SERVER}:${LDAP_PORT}"
98+
url="ldap://${LDAP_SERVER}:${LDAP_PORT}" \
99+
userdn="ou=users,dc=${LDAP_USERNAME},dc=com" \
100+
schema="openldap" \
101+
password_policy="$DEFAULT_POLICY"
102+
103+
echo "LDAP config written with $DEFAULT_POLICY"
44104

45-
# Create the LDIF template that Vault will use to generate dynamic LDAP users
105+
# Create LDIF files for dynamic LDAP role
46106
echo "Vault: Creating creation.ldif for dynamic LDAP role"
47107
CREATION_LDIF="creation.ldif"
48108
generate_ldif "${CREATION_LDIF}" "objectClass: person
@@ -51,87 +111,152 @@ cn: {{.Username}}
51111
sn: {{.Password | utf16le | base64}}
52112
userPassword: {{.Password}}" "users"
53113

54-
# Create the LDIF template used by Vault to delete dynamic LDAP user entries
55114
echo "Vault: Creating deletion.ldif for dynamic LDAP role"
56115
DELETION_LDIF="deletion.ldif"
57116
generate_ldif "${DELETION_LDIF}" "changetype: delete" "users"
58117

59-
# Create the LDIF template used by Vault to roll back user creation if an error occurs
60118
echo "Vault: Creating rollback.ldif for dynamic LDAP role"
61119
ROLLBACK_LDIF="rollback.ldif"
62120
generate_ldif "${ROLLBACK_LDIF}" "changetype: delete" "users"
63121

64122
# Create the dynamic LDAP role in Vault using the LDIF templates
65-
echo "Vault: Creating dynamic LDAP role dynamic-role"
66-
"$binpath" write ldap/role/dynamic-role \
123+
echo "Vault: Creating dynamic LDAP role ${DYNAMIC_ROLE_NAME}"
124+
"$binpath" write "${MOUNT}/role/${DYNAMIC_ROLE_NAME}" \
67125
creation_ldif=@${CREATION_LDIF} \
68126
deletion_ldif=@${DELETION_LDIF} \
69127
rollback_ldif=@${ROLLBACK_LDIF} \
70128
default_ttl="${DEFAULT_TTL}" \
71129
max_ttl="${MAX_TTL}"
72130

73-
# Generating dynamic LDAP credentials from role dynamic-role
74-
echo "Vault: Generating dynamic LDAP credentials from role dynamic-role"
131+
# Test1: Read Root Credential Config - Verify password is excluded
132+
test_read_config_password_exclusion() {
133+
echo "Test: Reading LDAP config to verify password exclusion"
134+
CONFIG_OUTPUT=$("$binpath" read "${MOUNT}/config")
75135

76-
DYNAMIC_CREDS=$("$binpath" read ldap/creds/dynamic-role)
136+
BIND_DN=$(jq -r '.data.binddn' <<< "$CONFIG_OUTPUT")
137+
URL=$(jq -r '.data.url' <<< "$CONFIG_OUTPUT")
138+
SCHEMA=$(jq -r '.data.schema' <<< "$CONFIG_OUTPUT")
139+
PASSWORD_POLICY=$(jq -r '.data.password_policy' <<< "$CONFIG_OUTPUT")
77140

78-
DYNAMIC_PASSWORD=$(echo "$DYNAMIC_CREDS" | jq -r '.data.password')
79-
DYN_DN=$(echo "$DYNAMIC_CREDS" | jq -r '.data.distinguished_names[0]')
141+
# Verify bindpass is NOT returned (should not exist in the response)
142+
if ! jq -e '.data.bindpass' <<< "$CONFIG_OUTPUT" > /dev/null 2>&1; then
143+
echo "SUCCESS: bindpass is excluded from config read"
144+
else
145+
fail "ERROR: bindpass was returned in config"
146+
fi
80147

81-
if [[ -z "$DYN_DN" || "$DYN_DN" == "null" ]]; then
82-
fail "Vault did not return a distinguished_name for dynamic LDAP user"
83-
fi
148+
# Verify other expected fields are present
149+
if [[ -n "$BIND_DN" ]] && [[ -n "$URL" ]] && [[ -n "$SCHEMA" ]]; then
150+
echo "SUCCESS: All config fields are present when reading config"
151+
else
152+
fail "ERROR: Some config fields are missing when reading config"
153+
fi
84154

85-
#Verify Dynamic Credentials
86-
if ldapwhoami -x -H "ldap://${LDAP_SERVER}:${LDAP_PORT}" -D "${DYN_DN}" -w "${DYNAMIC_PASSWORD}" > /dev/null 2>&1; then
87-
echo "LDAP dynamic credentials valid"
88-
else
89-
fail "Error: LDAP dynamic credentials validation failed"
90-
fi
155+
# Verify password policy is set
156+
if [[ "$PASSWORD_POLICY" == "$DEFAULT_POLICY" ]]; then
157+
echo "SUCCESS: Password policy '$DEFAULT_POLICY' is configured"
158+
else
159+
fail "ERROR: Password policy not set correctly. Expected: $DEFAULT_POLICY, Got: $PASSWORD_POLICY"
160+
fi
161+
}
91162

92-
# Attempt to use expired credentials — verify LDAP authentication fails.
93-
CREDENTIAL_TTL_BUFFER=${CREDENTIAL_TTL_BUFFER:-80}
94-
sleep "$CREDENTIAL_TTL_BUFFER"
163+
# Test: Update Root Credentials Config - Update with different password policy
164+
test_update_password_policy() {
165+
echo "Test: Updating LDAP config with different password policy"
166+
167+
# Create a different password policy (strong-policy)
168+
create_password_policy "$STRONG_POLICY" "$STRONG_POLICY_LENGTH" "$DEFAULT_MIN_CHARS" "$DEFAULT_MIN_CHARS" "$DEFAULT_MIN_CHARS" "$SPECIAL_CHARS" "$DEFAULT_MIN_CHARS"
95169

96-
if ldapwhoami -x -H "ldap://${LDAP_SERVER}:${LDAP_PORT}" -D "$DYN_DN" -w "$DYNAMIC_PASSWORD" &> /dev/null; then
97-
fail "Error: Dynamic credentials still valid — TTL did NOT expire"
98-
else
99-
echo "Dynamic credentials expired as expected"
100-
fi
170+
"$binpath" write "${MOUNT}/config" \
171+
password_policy="$STRONG_POLICY"
101172

102-
#Testing invalid dynamic LDAP role configuration by giving an invalid OU.
173+
echo "Updated LDAP config with $STRONG_POLICY"
103174

104-
INVALID_CREATION_LDIF="invalid_creation.ldif"
105-
INVALID_DELETION_LDIF="invalid_deletion.ldif"
175+
# Verify the update by reading config again
176+
UPDATED_CONFIG=$("$binpath" read "${MOUNT}/config")
177+
UPDATED_POLICY=$(jq -r '.data.password_policy' <<< "$UPDATED_CONFIG")
106178

107-
generate_ldif "${INVALID_CREATION_LDIF}" "objectClass: person
179+
if [[ "$UPDATED_POLICY" == "$STRONG_POLICY" ]]; then
180+
echo "SUCCESS: Password policy updated to '$STRONG_POLICY'"
181+
else
182+
fail "ERROR: Password policy not updated. Expected: $STRONG_POLICY, Got: $UPDATED_POLICY"
183+
fi
184+
}
185+
186+
# Test: Generate and verify dynamic LDAP credentials
187+
test_dynamic_credentials() {
188+
189+
# Generating dynamic LDAP credentials from role ${DYNAMIC_ROLE_NAME}
190+
echo "Vault: Generating dynamic LDAP credentials from role ${DYNAMIC_ROLE_NAME}"
191+
192+
DYNAMIC_CREDS=$("$binpath" read "${MOUNT}/creds/${DYNAMIC_ROLE_NAME}")
193+
194+
DYNAMIC_PASSWORD=$(jq -r '.data.password' <<< "$DYNAMIC_CREDS")
195+
DYN_DN=$(jq -r '.data.distinguished_names[0]' <<< "$DYNAMIC_CREDS")
196+
197+
if [[ -z "$DYN_DN" || "$DYN_DN" == "null" ]]; then
198+
fail "Vault did not return a distinguished_name for dynamic LDAP user"
199+
fi
200+
201+
# Verify Dynamic Credentials
202+
if ldapwhoami -x -H "ldap://${LDAP_SERVER}:${LDAP_PORT}" -D "${DYN_DN}" -w "${DYNAMIC_PASSWORD}" > /dev/null 2>&1; then
203+
echo "LDAP dynamic credentials valid"
204+
else
205+
fail "Error: LDAP dynamic credentials validation failed"
206+
fi
207+
}
208+
209+
# Test: Verify credentials expire after TTL
210+
test_credential_expiration() {
211+
212+
sleep "$CREDENTIAL_TTL_BUFFER"
213+
214+
if ldapwhoami -x -H "ldap://${LDAP_SERVER}:${LDAP_PORT}" -D "$DYN_DN" -w "$DYNAMIC_PASSWORD" &> /dev/null; then
215+
fail "Error: Dynamic credentials still valid — TTL did NOT expire"
216+
else
217+
echo "Dynamic credentials expired as expected"
218+
fi
219+
}
220+
221+
# Test: Invalid dynamic LDAP role configuration
222+
test_invalid_role_configuration() {
223+
echo "Test: Testing invalid dynamic LDAP role configuration"
224+
225+
INVALID_CREATION_LDIF="invalid_creation.ldif"
226+
INVALID_DELETION_LDIF="invalid_deletion.ldif"
227+
228+
generate_ldif "${INVALID_CREATION_LDIF}" "objectClass: person
108229
objectClass: top
109230
cn: {{.Username}}
110231
sn: {{.Password}}
111232
userPassword: {{.Password}}" "invalid_ou"
112233

113-
generate_ldif "${INVALID_DELETION_LDIF}" "changetype: delete" "invalid_ou"
234+
generate_ldif "${INVALID_DELETION_LDIF}" "changetype: delete" "invalid_ou"
114235

115-
echo "Vault: Attempting to create invalid-role (should fail)..."
236+
echo "Vault: Attempting to create ${INVALID_ROLE_NAME} (should fail)..."
116237

117-
"$binpath" write ldap/role/invalid-role \
118-
creation_ldif=@${INVALID_CREATION_LDIF} \
119-
deletion_ldif=@${INVALID_DELETION_LDIF} \
120-
rollback_ldif=@${INVALID_DELETION_LDIF} \
121-
default_ttl="${DEFAULT_TTL}" \
122-
max_ttl="${MAX_TTL}" || true
123-
124-
echo "Attempting to read creds from invalid-role"
125-
126-
INVALID_CREDS_OUTPUT=$(
127-
"$binpath" read ldap/creds/invalid-role 2>&1 || true
128-
)
129-
echo "$INVALID_CREDS_OUTPUT"
130-
131-
#check for error message indicating invalid DN/OU.
132-
if echo "$INVALID_CREDS_OUTPUT" | grep -qi "No Such Object"; then
133-
echo "SUCCESS: Vault failed dynamic credential creation due to invalid OU/DN."
134-
"$binpath" delete ldap/role/invalid-role
135-
else
136-
fail "ERROR: Vault did NOT fail when invalid DN/OU was used!"
137-
fi
238+
"$binpath" write "${MOUNT}/role/${INVALID_ROLE_NAME}" \
239+
creation_ldif=@${INVALID_CREATION_LDIF} \
240+
deletion_ldif=@${INVALID_DELETION_LDIF} \
241+
rollback_ldif=@${INVALID_DELETION_LDIF} \
242+
default_ttl="${DEFAULT_TTL}" \
243+
max_ttl="${MAX_TTL}" || true
244+
245+
echo "Attempting to read creds from ${INVALID_ROLE_NAME}"
246+
247+
if ! "$binpath" read "${MOUNT}/creds/${INVALID_ROLE_NAME}" > /dev/null 2>&1; then
248+
echo "SUCCESS: Vault failed dynamic credential creation due to invalid OU/DN."
249+
"$binpath" delete "${MOUNT}/role/${INVALID_ROLE_NAME}"
250+
else
251+
fail "ERROR: Vault did NOT fail when invalid DN/OU was used!"
252+
fi
253+
}
254+
255+
# Run test cases
256+
test_read_config_password_exclusion
257+
test_update_password_policy
258+
test_dynamic_credentials
259+
test_credential_expiration
260+
test_invalid_role_configuration
261+
262+
echo "All tests completed successfully!"

0 commit comments

Comments
 (0)