Skip to content

Instantly share code, notes, and snippets.

@chrishoffman
Last active March 9, 2022 22:10
Show Gist options
  • Save chrishoffman/e3c0ab487bdd0e04a437b59beb975c57 to your computer and use it in GitHub Desktop.
Save chrishoffman/e3c0ab487bdd0e04a437b59beb975c57 to your computer and use it in GitHub Desktop.
MFA Login for Vault 1.10+
#!/bin/bash
## Tools required
# brew install oath-toolkit qrencode jq
# Vault binary in path (1.10+)
# This script uses Vault Enterprise but just remove the namespace commands for OSS
export VAULT_ADDR=http://127.0.0.1:8200
export VAULT_TOKEN=root
# Create admin namespace
vault namespace create admin
export VAULT_NAMESPACE=admin
TOTP_DIGITS=6
TOTP_ALGORITHM=SHA256
TOTP_PERIOD=30
TOTP_ISSUER=Vault
# Set up userpass
vault auth enable userpass
vault write auth/userpass/users/test_user password="password"
USERPASS_ACCESSOR=$(vault auth list -format=json | jq -r '.["userpass/"].accessor')
# Generate an identity
ENTITY_ID=$(vault write -f -format=json identity/entity | jq -r .data.id)
# Attach entity to user
vault write identity/entity-alias name=test_user canonical_id=$ENTITY_ID mount_accessor=$USERPASS_ACCESSOR
# Create MFA config
TOTP_METHOD_ID=$(vault write -format=json \
identity/mfa/method/totp \
issuer=$TOTP_ISSUER \
period=$TOTP_PERIOD \
algorithm=$TOTP_ALGORITHM \
digits=$TOTP_DIGITS | \
jq -r .data.method_id)
# Attached MFA to Entity
MFA_CONFIG=$(vault write -f -format=json identity/mfa/method/totp/admin-generate entity_id=$ENTITY_ID method_id=$TOTP_METHOD_ID)
MFA_SECRET=$(jq -r .data.url <<< $MFA_CONFIG | cut -d'=' -f6)
# Display QR code, cannot use URL returned since Google Authenticator seems to require the secret
# to be the first parameter
MFA_URL="otpauth://totp/$TOTP_ISSUER:$ENTITY_ID?secret=$MFA_SECRET&issuer=$TOTP_ISSUER&algorithm=$TOTP_ALGORITHM&digits=$TOTP_DIGITS&period=$TOTP_PERIOD"
qrencode -t ansiutf8 <<< $MFA_URL
# Enable login MFA enforcement for all userpass mounts
vault write identity/mfa/login-enforcement/test auth_method_types=userpass mfa_method_ids=$TOTP_METHOD_ID
# Generate TOTP code
MFA_CODE=$(oathtool --totp=$TOTP_ALGORITHM --time-step-size=$TOTP_PERIOD --base32 $MFA_SECRET)
# Send login request that requires MFA
MFA_REQUEST_ID=$(curl --data "password=password" --header "X-Vault-Namespace: $VAULT_NAMESPACE" $VAULT_ADDR/v1/auth/userpass/login/test_user | jq -r .auth.mfa_requirement.mfa_request_id)
# Respond with MFA code
MFA_CODE=$(oathtool --totp=$TOTP_ALGORITHM --time-step-size=$TOTP_PERIOD --base32 $MFA_SECRET)
MFA_PAYLOAD="{
\"mfa_request_id\": \"$MFA_REQUEST_ID\",
\"mfa_payload\": {
\"$TOTP_METHOD_ID\": [\"$MFA_CODE\"]
}
}"
curl \
--header "X-Vault-Namespace: $VAULT_NAMESPACE" \
--data "$MFA_PAYLOAD" \
$VAULT_ADDR/v1/sys/mfa/validate | jq
@kalafut
Copy link

kalafut commented Mar 9, 2022

Nice script. One comment fix: s/oath-tools/oath-toolkit on line 4

@chrishoffman
Copy link
Author

Thanks. Updated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment