Secure authentication with MFA Login and Time-Based One Time Passwords
Vault first introduced Login MFA in version 1.10.0 to offer support for multiple authentication factors with Vault auth methods.
For enhanced security, Vault auth methods offer the option of Time-Based One Time Password (TOTP) with Multi-Factor Authentication (MFA) login. This tutorial uses acive directory authentcation method to demonstrate TOTP.
Challenge
Your organization uses the Vault Active Directory Auth Method to allow users to authenticate with Vault using their Active Directory credentials. You need to enforce additional authentication method, such as a Time-Based One Time Password (TOTP).
Solution
The Vault Login MFA functionality provides a means to link an auth method to additional authentication factors such as those offered by third party services. It also features a built in TOTP MFA method.
You can leverage the built-in TOTP MFA method with an authenticator application to enhance security with an additional authentication factor.
Target audience
Vault cluster administrators with privileged policies to manage auth methods and secrets engines. The admin persona performs the steps of this role in the hands-on scenario that is part of this tutorial.
Vault users authenticating to Vault with the Active Directory secrets engine. The user persona will authenticate with the Active Directory secrets engine and the authenticator application to authenticate with Vault.
Scenario introduction
To learn how Vault TOTP MFA works, you can use the hands on lab steps to spin up a virtual machine with a Windows Server with Active Directory. You will also run a Docker container running Vault in dev mode.
The diagram shows the Two-Phase MFA authentication workflow described in this tutorial.
The admin persona configures the Vault environment.
The user persona uses the Vault API, CLI, or UI and their authentication application on an enrolled device.
The user persona attempts authentication with Vault.
Vault returns a message advising that the authentication requires MFA.
The user persona interacts with their authenticator app, which returns a code used as the extra authentication factor.
The user persona validates their authentication with the code returned from authenticator app.
Vault verifies the code through the TOTP MFA method
If verification is successful, the authentication also succeeds and the user persona receives a Vault token.
Note
The Login MFA integration introduced in version 1.10.0 is a new solution, and you should not confuse it with the legacy MFA or Enterprise Step Up MFA. The solution covered in this tutorial is the preferred way to enable MFA for auth methods in all editions of Vault version 1.10.0 or greater.
Prerequisites
This lab functions end to end on macOS using an x86_64 based processor. If you are running macOS on an Apple silicon-based processor, use a x86_64 based Linux virtual machine in your preferred cloud provider.
A Windows environment with Active Directory. This scenario uses the community based Vagrant environment for a Windows Server based Active Directory project.
Docker. This scenario uses Docker Desktop for macOS.
Vagrant. Required if you choose to use the Vagrant environment for an Active Directory Server. This scenario was last tested with version 2.2.19.
- A supported Vagrant virtualization target; this scenario uses VirtualBox tested against version 6.1.34.
git required for cloning repositories used in the scenario.
An authenticator application; this scenario uses the Google Authenticator app for iOS, but you can use any compatible authenticator application.
If you are following along on a Linux based host, you'll need
xdg-open
. Sometimes this utility is part of anxdg-utils
meta-package that you can install with your OS package manager. Check your distribution specific documentation for details on how to installxdg-open
.
Lab setup
You will use a terminal session and command line to start an Active Directory virtual machine and Vault server container.
Open a new terminal session to begin the lab setup.
For ease of cleanup and simplicity, create a temporary directory to contain all required configuration for the scenario, and assign the directory name value to the environment variable HC_LEARN_LAB
.
$ export HC_LEARN_LAB="$(mktemp -d -t hc-learn-XXXX)"
Change into this directory; you will execute all scenario commands on the local host from this directory or one of its descendants.
$ cd $HC_LEARN_LAB
You can also echo this value so that you can find the files within the directory for using the generated QR code later.
$ echo $HC_LEARN_LAB
Windows Server with Active Directory
To set up your Windows Server environment with Active Directory environment, clone the project repository.
$ git clone https://github.com/splitbrain/vagrant-active-directory
Change into the project directory.
$ cd vagrant-active-directory
Note
If you are using VirtualBox version 6.1.26 or later, you need to add additional configuration to support the host-only
network adapter configured with this Vagrant box.
Create a directory for the extra VirtualBox network configuration.
$ sudo mkdir /etc/vbox
Write the configuration file.
$ sudo sh -c 'tee /etc/vbox/networks.conf << EOF* 10.0.0.0/8 192.168.0.0/16* 2001::/64EOF'
Start the virtual machine with Vagrant.
$ vagrant up
Note
The process of starting the Windows Server virtual machine and bringing up the Active Directory service is lengthy, and requires 20 minutes or more on a contemporary developer laptop.
The last lines in the Vagrant log output show that the Active Directory server is ready because it begins creating the users and groups:
dc: Waiting for the AD to become available... (Can take a long time) dc: Creating Groups... dc: Creating Users...
Confirm that the Active Directory services are available by connecting to the virtual machine with WinRM and using dcdiag to test services.
$ vagrant winrm -c 'dcdiag /test:Services' dc | grep passed ......................... DC passed test Connectivity ......................... DC passed test Services
If the tests also show passing status, then the Active Directory server is ready.
Docker network
Create a Docker network named learn-vault-network
.
$ docker network create learn-vault-network
Vault server
Start a dev mode Vault server container.
Note
A dev mode server stores all data in memory, and stopping the server process results in loss of all data.
$ docker run \ --name learn-vault \ --detach \ --rm \ --network learn-vault-network \ --cap-add=IPC_LOCK \ --publish 8200:8200 \ --hostname vault-server \ --volume /tmp:/tmp \ --env VAULT_ADDR=http://0.0.0.0:8200 \ hashicorp/vault server \ -dev \ -dev-root-token-id=root \ -dev-listen-address 0.0.0.0:8200
Access the learn-vault
container by executing a shell within it.
$ docker exec -it learn-vault sh
Notice that the prompt changes to:
/ #
Update the package cache.
$ apk update
Install jq
to parse JSON output.
$ apk add jq
Get Vault server status.
$ vault statusKey Value--- -----Seal Type shamirInitialized trueSealed falseTotal Shares 1Threshold 1Version 1.10.2Storage Type inmemCluster Name vault-cluster-313799f2Cluster ID 01478d6e-5d5c-af5d-7e51-6694c706f130HA Enabled false
The Vault server is ready.
For the purposes of this scenario, you will use the initial root token value with the VAULT_TOKEN
environment variable for the scenario steps.
Note
For these tasks with a dev mode server, you can use the root token. In production Vault use, you should use root tokens for initial setup or in emergencies.
Scenario tasks
Enable and configure LDAP auth method
Enable the LDAP auth method.
$ VAULT_TOKEN=root vault auth enable ldapSuccess! Enabled ldap auth method at: ldap/
Configure the LDAP auth method.
Tip
Since your Vault server is running within a container, you must reference the host network, not the local network. You can do so by specifying host.docker.internal
in the url
parameter value.
$ VAULT_TOKEN=root vault write auth/ldap/config \ url="ldaps://host.docker.internal:7636" \ userattr=sAMAccountName \ userdn="CN=Users,DC=example,DC=local" \ groupdn="CN=Users,DC=example,DC=local" \ groupfilter="(&(objectClass=person)(uid={{.Username}}))" \ groupattr="memberOf" \ binddn="CN=vagrant,CN=Users,DC=example,DC=local" \ bindpass='vagrant' \ insecure_tls=true
Successful output example:
Success! Data written to: auth/ldap/config
Since the Active Directory server for this scenario uses a self-signed TLS certificate, you instruct Vault to use insecure TLS with insecure_tls=true
. You should not use this setting in a production configuration. You should instead prefer using certificates which a known CA validates.
Login with LDAP auth method
Test the Vault login with LDAP auth method.
$ vault login -method=ldap username=w.kluge password='Foo_b_ar123!'
Successful output example:
Success! You are now authenticated. The token information displayed belowis already stored in the token helper. You do NOT need to run "vault login"again. Future Vault requests will automatically use this token.WARNING! The following warnings were returned from Vault: * no LDAP groups found in groupDN 'CN=Users,DC=example,DC=local'; only policies from locally-defined groups availableKey Value--- -----token hvs.CAESIEipBa8DtnBePdnrElWEc0WOh2ONelkG-i0wDLAeuHYiGh4KHGh2cy5LMFB6NFJzR0RxcTdncnh6ejdDdXNhTk4token_accessor s7FUF7n3f8BbWzzWRAW0zvXVtoken_duration 768htoken_renewable truetoken_policies ["default"]identity_policies []policies ["default"]token_meta_username w.kluge
You need to capture the identity entity ID of the w.kluge
user for configuration of the Login MFA method.
Export its value to the ENTITY_ID
environment variable for later use.
$ export ENTITY_ID=$(vault login -method=ldap username=w.kluge \ password='Foo_b_ar123!' -format=json \ | jq -r '.auth.entity_id')
Check the value.
$ echo $ENTITY_IDfcf3f7bc-5042-11dd-53f5-917aaede9300
Enable login MFA method
Enable a Login MFA method to enforce TOTP on the LDAP auth method.
Note
Authenticator applications are not consistent in their support of encryption algorithms. You should research the algorithms supported by your preferred authenticator app. The Configure TOTP MFA Method documentation lists algorithms supported by the Login MFA TOTP method. Google Authenticator supports SHA256, and that is used in this example.
Configure the Login MFA TOTP method and assign its method ID to the TOTP_METHOD_ID
environment variable.
$ TOTP_METHOD_ID=$(VAULT_TOKEN=root vault write identity/mfa/method/totp \ -format=json \ generate=true \ issuer=Vault \ period=30 \ key_size=30 \ algorithm=SHA256 \ digits=6 | jq -r '.data.method_id')
Check the value.
$ echo $TOTP_METHOD_ID29a3e898-50e6-5763-7fbe-834df79eea77
Generate authenticator app QR code
Generate QR code as a PNG image.
$ VAULT_TOKEN=root vault write -field=barcode \ /identity/mfa/method/totp/admin-generate \ method_id=$TOTP_METHOD_ID entity_id=$ENTITY_ID \ | base64 -d > /tmp/qr-code.png
You can open the QR code image from the host system in different ways depending on your operating system.
You can use an example for Linux, macOS, or Windows.
If you are using a graphical environment on Linux, open the QR code image this way:
$ xdg-open /tmp/qr-code.png
You can scan this image with your authenticator app to add Vault TOTP. Again, this scenario presumes that you will use the Google Authenticator app for this.
Create login MFA enforcement
Capture the LDAP auth method for use in creating a Login MFA enforcement.
$ LDAP_ACCESSOR=$(VAULT_TOKEN=root vault auth list -format=json \ --detailed | jq -r '."ldap/".accessor')
Check the value.
$ echo $LDAP_ACCESSORauth_ldap_cf1840a4
Create the enforcement.
$ VAULT_TOKEN=root vault write /identity/mfa/login-enforcement/adtotp \ mfa_method_ids="$TOTP_METHOD_ID" \ auth_method_accessors=$LDAP_ACCESSOR
Successful output example:
Success! Data written to: identity/mfa/login-enforcement/adtotp
Login with LDAP auth method
Use the CLI to login with the LDAP auth method a second time.
$ vault login -method=ldap username=w.kluge password='Foo_b_ar123!'Enter the passphrase for methodID "01194a79-e2d9-c038-029d-79b0091cafd0" of type "totp":
Enter the TOTP from your authenticator app when prompted.
Successful output example:
Key Value--- -----token hvs.CAESIE6K0E7BjHv2m1Gj2IAriFhBfUsB6xjtechsRIhL6-wbGh4KHGh2cy5VNDFTZE9XMm96UUN0UDZ1WWtKQm94SkItoken_accessor SXxDMVRc35h9OBIdbTAf52ROtoken_duration 768htoken_renewable truetoken_policies ["default"]identity_policies []policies ["default"]token_meta_username w.kluge
You have authenticated to Vault with the Active Directory. Enter exit
to quit out of the container.
Login TOTP is also supported when authenticating with the Vault user interface.
Navigate to http://127.0.0.1:8200
From the Method pulldown menu select LDAP.
Enter w.kluge
in the Username textbox and Foo_b_ar123!
in the Password textbox then click Sign In.
Cleanup
Stop the Vault server Docker container.
$ docker stop learn-vault
Tip
Since you started the container with the --rm
flag, it will be automatically removed when you stop it.
Remove the Docker network
$ docker network rm learn-vault-network
Change into the vagrant-active-directory
project directory.
$ cd $HC_LEARN_LAB/vagrant-active-directory
Destroy the virtual machine
$ vagrant destroy -f
Change to your home directory.
$ cd
To remove all configuration and other data you created during this scenario, you can recursively remove the $HC_LEARN_LAB
directory.
$ rm -rf $HC_LEARN_LAB
Remove the additional VirtualBox network configuration.
$ sudo rm -rf /etc/vbox
Summary
As the admin persona, you learned how to enable and configure Login MFA with the LDAP auth method and TOTP MFA method.
As the user persona, you learned how to use a Login MFA method when authenticating to Vault.
You can learn more about Vault authentication and auth methods in the Manage Authentication Methods tutorial, and the Auth Methods documentation.