{"id":1042,"date":"2026-08-09T02:42:55","date_gmt":"2026-08-09T02:42:55","guid":{"rendered":"https:\/\/www.devopsschool.com\/tutorials\/?p=1042"},"modified":"2026-08-09T02:42:56","modified_gmt":"2026-08-09T02:42:56","slug":"hashicorp-vault-master-lab-consul-secrets-engine-userpass-authentication-vault-policies-dynamic-consul-credentials","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/tutorials\/hashicorp-vault-master-lab-consul-secrets-engine-userpass-authentication-vault-policies-dynamic-consul-credentials\/","title":{"rendered":"HashiCorp Vault Master Lab &#8211; Consul Secrets Engine + Userpass Authentication + Vault Policies + Dynamic Consul Credentials"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Beginner-Friendly Hands-On Lab for Ubuntu Linux<\/h3>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">1. Lab Objective<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">In this lab, we will build the following environment from scratch:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>                    Ubuntu Linux Server\n                           |\n              +------------+-------------+\n              |                          |\n        HashiCorp Vault             HashiCorp Consul\n          127.0.0.1:8200              127.0.0.1:8500\n              |                          |\n              |                          |\n        userpass auth                    |\n              |                          |\n          student1                       |\n              |                          |\n     consul-engine-admin                 |\n          Vault Policy                   |\n              |                          |\n              v                          |\n      Consul Secrets Engine ------------+\n              |\n              |\n      student-role\n              |\n              v\n      Dynamic Consul Token\n              |\n              v\n       Consul ACL Policy\n          student-kv\n              |\n              v\n        student\/* KV\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">By the end of the lab, students will understand:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>how to install Vault and Consul;<\/li>\n\n\n\n<li>how to start Vault in development mode;<\/li>\n\n\n\n<li>how to start Consul in development mode with ACLs;<\/li>\n\n\n\n<li>how Consul ACL bootstrap works;<\/li>\n\n\n\n<li>how to enable the Vault Consul secrets engine;<\/li>\n\n\n\n<li>how Vault authenticates to Consul;<\/li>\n\n\n\n<li>how to create a Consul ACL policy;<\/li>\n\n\n\n<li>how to create a Vault ACL policy;<\/li>\n\n\n\n<li>how to enable the Vault <code>userpass<\/code> authentication method;<\/li>\n\n\n\n<li>how to create a Vault user;<\/li>\n\n\n\n<li>how to attach a Vault policy to that user;<\/li>\n\n\n\n<li>how to log in using username\/password;<\/li>\n\n\n\n<li>how to perform Create, Read, Update, List, and Delete operations on Consul secrets-engine roles;<\/li>\n\n\n\n<li>how to generate short-lived Consul credentials;<\/li>\n\n\n\n<li>how to use the dynamically generated Consul token;<\/li>\n\n\n\n<li>how Vault leases work;<\/li>\n\n\n\n<li>how to renew a lease;<\/li>\n\n\n\n<li>how to revoke a lease;<\/li>\n\n\n\n<li>how to confirm that the Consul credential stops working after revocation;<\/li>\n\n\n\n<li>how Vault policies prevent access to unrelated secret engines.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The current Vault documentation is on the Vault 2.x release line. As of <strong>August 9, 2026<\/strong>, HashiCorp&#8217;s release notes list <strong>Vault 2.0.4<\/strong>, released August 4, 2026. The current Consul install material lists <strong>Consul 2.0.2<\/strong>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">2. Important Lab Warning<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">This tutorial intentionally uses:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Vault development mode\nConsul development mode\nHTTP instead of HTTPS\nA known Vault root token\nA locally stored Consul bootstrap token\nA broad Vault policy\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">These choices make the environment easy for beginners to understand.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Do not use this architecture in production.<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Vault development mode:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>starts initialized;<\/li>\n\n\n\n<li>starts unsealed;<\/li>\n\n\n\n<li>stores its data in memory;<\/li>\n\n\n\n<li>listens on <code>127.0.0.1:8200<\/code>;<\/li>\n\n\n\n<li>can use a predetermined root token;<\/li>\n\n\n\n<li>loses its data when stopped.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">HashiCorp explicitly identifies dev mode as an experimentation\/development environment rather than a production deployment.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">3. Lab Environment<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Recommended environment:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Operating System : Ubuntu Server\nVault             : 2.0.4 or newer compatible 2.x\nConsul            : 2.0.2 or newer compatible 2.x\nVault Address     : http:\/\/127.0.0.1:8200\nConsul Address    : http:\/\/127.0.0.1:8500\nVault Root Token  : root\nVault User        : student1\nVault Password    : StudentLab@2026\nVault Policy      : consul-engine-admin\nVault Engine      : consul\/\nConsul Policy     : student-kv\nVault Consul Role : student-role\nConsul KV Prefix  : student\/\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Everything in this tutorial runs on the <strong>same Ubuntu server<\/strong>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">4. Understanding the Two Different Policies<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Before running commands, students should understand that this lab uses <strong>two completely different policy systems<\/strong>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Vault Policy<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Our Vault policy will be named:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>consul-engine-admin\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">It controls what the Vault user <code>student1<\/code> can do <strong>inside Vault<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Can student1 create a Vault Consul role?\nCan student1 read the role?\nCan student1 modify the role?\nCan student1 delete the role?\nCan student1 request a dynamic Consul token?\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Vault policies map paths to capabilities such as:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>create\nread\nupdate\ndelete\nlist\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Vault&#8217;s current policy documentation maps these capabilities to operations on Vault paths.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Consul ACL Policy<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Our Consul ACL policy will be named:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>student-kv\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This policy controls what a <strong>Consul token generated by Vault<\/strong> can do inside Consul.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We will allow the generated token to manage:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>student\/*\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">but not:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>private\/*\nproduction\/*\nanything-else\/*\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">A Consul <code>write<\/code> policy permits reading and modifying the matching resources.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">5. Step 1 \u2014 Update Ubuntu<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt update\nsudo apt upgrade -y\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Install utilities required during the lab:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt install -y \\\n  curl \\\n  wget \\\n  gpg \\\n  lsb-release \\\n  jq\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Verify <code>jq<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>jq --version\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>jq-1.7\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">6. Step 2 \u2014 Add the Official HashiCorp Repository<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Download the HashiCorp repository signing key:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>wget -O- https:\/\/apt.releases.hashicorp.com\/gpg \\\n  | sudo gpg --dearmor \\\n  -o \/usr\/share\/keyrings\/hashicorp-archive-keyring.gpg\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Add the HashiCorp repository:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>echo \"deb &#91;arch=$(dpkg --print-architecture) signed-by=\/usr\/share\/keyrings\/hashicorp-archive-keyring.gpg] https:\/\/apt.releases.hashicorp.com $(grep -oP '(?&lt;=UBUNTU_CODENAME=).*' \/etc\/os-release || lsb_release -cs) main\" \\\n  | sudo tee \/etc\/apt\/sources.list.d\/hashicorp.list\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Update the package list:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt update\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">HashiCorp publishes both Vault and Consul through its Ubuntu\/Debian package repository.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">7. Step 3 \u2014 Install Vault and Consul<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Install both packages:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt install -y vault consul\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">8. Step 4 \u2014 Check Installed Versions<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault version\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">At the time this lab was validated against the release documentation, the current Vault release is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Vault v2.0.4\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now check Consul:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>consul version\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Current Consul should be from the 2.0.x line, with the current install release being:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Consul v2.0.2\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Consul&#8217;s <code>version<\/code> command is the supported way to inspect the installed version.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">9. Step 5 \u2014 Create a Working Directory<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Rather than scattering files around the server, create one directory for everything related to the lab.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mkdir -p \"$HOME\/vault-consul-lab\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Set an environment variable:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export LAB_DIR=\"$HOME\/vault-consul-lab\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Verify:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>echo \"$LAB_DIR\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/home\/&lt;your-user&gt;\/vault-consul-lab\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Move into the directory:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cd \"$LAB_DIR\"\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">10. Step 6 \u2014 Configure Consul ACLs<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Create:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cat &gt; \"$LAB_DIR\/consul-lab.hcl\" &lt;&lt;'EOF'\ndatacenter = \"dc1\"\n\nacl = {\n  enabled                  = true\n  default_policy           = \"deny\"\n  enable_token_persistence = true\n}\nEOF\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Display the file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cat \"$LAB_DIR\/consul-lab.hcl\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>datacenter = \"dc1\"\n\nacl = {\n  enabled                  = true\n  default_policy           = \"deny\"\n  enable_token_persistence = true\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This enables the Consul ACL system and sets the default policy to <code>deny<\/code>. HashiCorp recommends <code>deny<\/code> for a new secured Consul environment.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">11. Step 7 \u2014 Start Consul<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">First ensure another Consul process is not already running:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>pgrep -a consul || true\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">For a fresh lab, there should normally be no output.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Start Consul:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>nohup consul agent \\\n  -dev \\\n  -node=consul-lab \\\n  -config-file=\"$LAB_DIR\/consul-lab.hcl\" \\\n  &gt; \"$LAB_DIR\/consul.log\" 2&gt;&amp;1 &amp;\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Save the process ID:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>echo $! &gt; \"$LAB_DIR\/consul.pid\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Display the PID:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cat \"$LAB_DIR\/consul.pid\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Wait approximately two seconds:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sleep 2\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Development mode runs an in-memory single-server Consul agent and is intended for rapid development and experimentation.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">12. Step 8 \u2014 Verify Consul<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Check the log:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>tail -20 \"$LAB_DIR\/consul.log\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Check whether port <code>8500<\/code> is listening:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ss -lnt | grep 8500\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You should see something similar to:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>LISTEN ... 127.0.0.1:8500\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Check the Consul leader:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>curl -s http:\/\/127.0.0.1:8500\/v1\/status\/leader\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected output will resemble:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\"127.0.0.1:8300\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The exact address may vary slightly.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">13. Step 9 \u2014 Bootstrap the Consul ACL System<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Consul ACLs are enabled, but no management token exists yet.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>consul acl bootstrap -format=json \\\n  &gt; \"$LAB_DIR\/consul-bootstrap.json\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Protect the file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>chmod 600 \"$LAB_DIR\/consul-bootstrap.json\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">View the non-secret portions:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>jq 'del(.SecretID)' \"$LAB_DIR\/consul-bootstrap.json\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The bootstrap command creates the initial token associated with Consul&#8217;s unrestricted <code>global-management<\/code> policy. Consul only permits the ACL bootstrap operation once for a given ACL state.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">14. Step 10 \u2014 Capture the Consul Management Token<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Extract the Secret ID:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export CONSUL_MGMT_TOKEN=\"$(\n  jq -r '.SecretID' \"$LAB_DIR\/consul-bootstrap.json\"\n)\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Check that we captured something:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>test -n \"$CONSUL_MGMT_TOKEN\" \\\n  &amp;&amp; test \"$CONSUL_MGMT_TOKEN\" != \"null\" \\\n  &amp;&amp; echo \"Consul management token captured successfully.\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Consul management token captured successfully.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Do <strong>not<\/strong> print this token unnecessarily.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Configure the Consul CLI to use it:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export CONSUL_HTTP_TOKEN=\"$CONSUL_MGMT_TOKEN\"\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">15. Step 11 \u2014 Test Consul Administrative Access<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>consul acl policy list\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You should see built-in policies such as:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>global-management\nbuiltin\/global-read-only\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The exact displayed formatting may differ.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">16. Step 12 \u2014 Create a Consul Policy for Vault-Generated Tokens<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">We do <strong>not<\/strong> want Vault to generate unrestricted Consul management tokens for students.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Instead, create a restricted Consul ACL policy.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cat &gt; \"$LAB_DIR\/student-kv-policy.hcl\" &lt;&lt;'EOF'\nkey_prefix \"student\/\" {\n  policy = \"write\"\n}\nEOF\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Display it:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cat \"$LAB_DIR\/student-kv-policy.hcl\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>key_prefix \"student\/\" {\n  policy = \"write\"\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This policy allows generated Consul tokens to read and modify keys underneath:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>student\/\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Consul&#8217;s current ACL rules define <code>write<\/code> as permitting both read and modification operations.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">17. Step 13 \u2014 Create the Consul ACL Policy<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>consul acl policy create \\\n  -name=\"student-kv\" \\\n  -description=\"Vault generated tokens may manage student KV data\" \\\n  -rules=@\"$LAB_DIR\/student-kv-policy.hcl\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">A successful response will contain fields similar to:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ID:\nName:        student-kv\nDescription: Vault generated tokens may manage student KV data\nRules:\nkey_prefix \"student\/\" {\n  policy = \"write\"\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Consul&#8217;s current CLI supports loading ACL policy rules from a file by prefixing the filename with <code>@<\/code>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">18. Step 14 \u2014 Read the Consul Policy<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>consul acl policy read -name=\"student-kv\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Verify that you see:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Name: student-kv\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">and:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>key_prefix \"student\/\" {\n  policy = \"write\"\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">At this point the Consul side of the permission model exists.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">19. Step 15 \u2014 Start Vault<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Before starting Vault, check whether another Vault process exists:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>pgrep -a vault || true\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Start the Vault development server:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>nohup vault server \\\n  -dev \\\n  -dev-root-token-id=\"root\" \\\n  -dev-listen-address=\"127.0.0.1:8200\" \\\n  &gt; \"$LAB_DIR\/vault.log\" 2&gt;&amp;1 &amp;\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Save the PID:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>echo $! &gt; \"$LAB_DIR\/vault.pid\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Wait:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sleep 2\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">HashiCorp&#8217;s current Vault server CLI supports <code>-dev<\/code>, <code>-dev-root-token-id<\/code>, and <code>-dev-listen-address<\/code>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">20. Step 16 \u2014 Configure the Vault CLI<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Set the Vault server address:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export VAULT_ADDR='http:\/\/127.0.0.1:8200'\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Set the root token:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export VAULT_TOKEN='root'\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Confirm:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>echo \"$VAULT_ADDR\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>http:&#47;&#47;127.0.0.1:8200\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">21. Step 17 \u2014 Verify Vault<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault status\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected output should contain:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Initialized       true\nSealed            false\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Because this is a development server, Vault starts initialized and unsealed automatically.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">22. Step 18 \u2014 Confirm Root Access<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault token lookup\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You should see:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>policies    &#91;root]\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>root<\/code> policy gives unrestricted access and should only be used for the administrative setup section of this lab. Root tokens have unrestricted Vault privileges.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">23. Step 19 \u2014 Check Existing Secrets Engines<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault secrets list\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You will see several built-in mounts.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The important point is that:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>consul\/\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">should <strong>not<\/strong> exist yet.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">24. Step 20 \u2014 Enable the Consul Secrets Engine<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault secrets enable consul\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Success! Enabled the consul secrets engine at: consul\/\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Verify:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault secrets list\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You should now find:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>consul\/\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The supported command for enabling the secrets engine at its default mount is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault secrets enable consul\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">25. Step 21 \u2014 Configure Vault to Communicate with Consul<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Vault now has the plugin, but the plugin does not yet know:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Where is Consul?\nWhat credential should Vault use to create Consul tokens?\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Configure it:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault write consul\/config\/access \\\n  address=\"127.0.0.1:8500\" \\\n  scheme=\"http\" \\\n  token=\"$CONSUL_MGMT_TOKEN\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Success! Data written to: consul\/config\/access\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Vault&#8217;s Consul secrets engine requires the Consul address and, for an already-bootstrapped Consul ACL environment, a Consul management token that Vault can use to create and revoke ACL tokens.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">26. Step 22 \u2014 Stop Using the Consul Management Token Directly<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">This is an important lab practice.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Vault now has the credential it needs.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Remove the management credential from the active shell:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>unset CONSUL_HTTP_TOKEN\nunset CONSUL_MGMT_TOKEN\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Verify:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>env | grep CONSUL_HTTP_TOKEN || true\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">There should be no output.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">From this point onward, we want students to work with credentials generated by <strong>Vault<\/strong>, not with the powerful Consul bootstrap credential.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">27. Step 23 \u2014 Create the Vault Policy<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Now create the policy that will eventually be attached to our Vault <code>userpass<\/code> user.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cat &gt; \"$LAB_DIR\/consul-engine-admin.hcl\" &lt;&lt;'EOF'\n# Full CRUD-style access to everything underneath the\n# Consul secrets engine mount.\n#\n# LAB ONLY: This includes sensitive Consul engine configuration.\n\npath \"consul\/*\" {\n  capabilities = &#91;\n    \"create\",\n    \"read\",\n    \"update\",\n    \"delete\",\n    \"list\"\n  ]\n}\n\n# Allow looking up an individual dynamic-secret lease.\n\npath \"sys\/leases\/lookup\" {\n  capabilities = &#91;\"update\"]\n}\n\n# Allow renewal of an individual lease.\n\npath \"sys\/leases\/renew\" {\n  capabilities = &#91;\"update\"]\n}\n\npath \"sys\/leases\/renew\/*\" {\n  capabilities = &#91;\"update\"]\n}\n\n# Allow revocation of an individual lease.\n\npath \"sys\/leases\/revoke\" {\n  capabilities = &#91;\"update\"]\n}\n\npath \"sys\/leases\/revoke\/*\" {\n  capabilities = &#91;\"update\"]\n}\nEOF\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">28. Step 24 \u2014 Examine the Vault Policy<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cat \"$LAB_DIR\/consul-engine-admin.hcl\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The central section is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>path \"consul\/*\" {\n  capabilities = &#91;\n    \"create\",\n    \"read\",\n    \"update\",\n    \"delete\",\n    \"list\"\n  ]\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This means:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CREATE  -&gt; permitted\nREAD    -&gt; permitted\nUPDATE  -&gt; permitted\nDELETE  -&gt; permitted\nLIST    -&gt; permitted\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Vault policies are path based, and these capabilities map to the corresponding operations supported by a Vault endpoint.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">29. Step 25 \u2014 Load the Policy into Vault<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault policy write \\\n  consul-engine-admin \\\n  \"$LAB_DIR\/consul-engine-admin.hcl\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Success! Uploaded policy: consul-engine-admin\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Vault supports loading an HCL ACL policy using <code>vault policy write<\/code>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">30. Step 26 \u2014 Read the Vault Policy<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault policy read consul-engine-admin\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Verify the policy is displayed correctly.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">31. Step 27 \u2014 List Vault Policies<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault policy list\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You should see something similar to:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>consul-engine-admin\ndefault\nroot\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">32. Step 28 \u2014 Enable Userpass Authentication<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Now enable username\/password authentication.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault auth enable userpass\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Success! Enabled userpass auth method at: userpass\/\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Verify:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault auth list\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You should find:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>userpass\/\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Vault&#8217;s current documentation supports enabling the method with exactly:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault auth enable userpass\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">33. Step 29 \u2014 Create One Vault User<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Create:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Username: student1\nPassword: StudentLab@2026\nPolicy:   consul-engine-admin\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault write auth\/userpass\/users\/student1 \\\n  password='StudentLab@2026' \\\n  policies='consul-engine-admin' \\\n  token_ttl='1h' \\\n  token_max_ttl='4h'\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Success! Data written to: auth\/userpass\/users\/student1\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Vault&#8217;s userpass configuration associates users with policies, and successful authentication produces a Vault token carrying those policies.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">34. Step 30 \u2014 Read the User Configuration<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Still using the root token, run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault read auth\/userpass\/users\/student1\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You should see information including:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>token_policies\ntoken_ttl\ntoken_max_ttl\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The password itself will not be returned.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The current Userpass API exposes reading user configuration but does not reveal the stored password.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">35. Step 31 \u2014 Administrator Setup Is Complete<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">At this point root has completed:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Consul installation\nConsul ACL setup\nConsul ACL policy creation\nVault installation\nVault Consul secrets engine\nVault-to-Consul connection\nVault policy\nUserpass authentication\nVault user creation\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now we switch identities.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Everything from the next step should be performed as:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>student1\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">36. Step 32 \u2014 Remove Root from the Current Shell<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">This step is extremely important.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>unset VAULT_TOKEN\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Verify:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>echo \"${VAULT_TOKEN:-VAULT_TOKEN is not set}\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>VAULT_TOKEN is not set\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If students accidentally leave:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>VAULT_TOKEN=root\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">then their tests are meaningless because every command continues to execute as root.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">37. Step 33 \u2014 Login Using Userpass<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault login -method=userpass \\\n  username='student1' \\\n  password='StudentLab@2026'\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected output will contain something similar to:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>token                 &lt;generated-vault-token&gt;\ntoken_duration        1h\ntoken_renewable       true\ntoken_policies        &#91;\"consul-engine-admin\" \"default\"]\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The precise token will be different.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The supported CLI authentication form is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault login -method=userpass username=... password=...\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">38. Step 34 \u2014 Verify the Current Vault Identity<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault token lookup\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Check:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>display_name\npolicies\nttl\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The policies should include:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>consul-engine-admin\ndefault\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">They should <strong>not<\/strong> include:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>root\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This is a critical checkpoint.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">39. Step 35 \u2014 Verify the Student&#8217;s Vault Capabilities<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault token capabilities consul\/roles\/student-role\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The output should contain capabilities similar to:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>create, delete, list, read, update\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now check the credential endpoint:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault token capabilities consul\/creds\/student-role\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Again, the policy allows access.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now test an unrelated Vault engine:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault token capabilities secret\/data\/my-secret\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>deny\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This proves that the student is not a Vault administrator.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">They have permissions on:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>consul\/*\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">but not arbitrary Vault paths.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">40. Step 36 \u2014 First Negative Security Test<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Try writing into Vault&#8217;s development KV engine:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault kv put secret\/not-allowed \\\n  username=student \\\n  password=test\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This should fail with a permission error similar to:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>permission denied\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>This failure is correct.<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The student&#8217;s policy only gives access to:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>consul\/*\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This demonstrates authorization working correctly.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">41. Step 37 \u2014 Understand Vault Consul Roles<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">The Vault Consul secrets engine uses roles.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Think of a Vault role as a template that tells Vault:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">When someone requests Consul credentials from this role, which Consul policy should be attached to the generated token and how long should the token live?<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Our role will be:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>student-role\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">and it will reference the Consul policy:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>student-kv\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Current Vault Consul API documentation supports creating\/updating roles with <code>consul_policies<\/code>, assigning TTLs, reading roles, listing them, deleting them, and generating credentials from them.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">42. Step 38 \u2014 CREATE a Consul Secrets-Engine Role<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Run as <code>student1<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault write consul\/roles\/student-role \\\n  consul_policies='student-kv' \\\n  ttl='30m' \\\n  max_ttl='1h'\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Success! Data written to: consul\/roles\/student-role\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">We have just performed the <strong>CREATE<\/strong> operation.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">43. Step 39 \u2014 READ the Role<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault read consul\/roles\/student-role\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You should see fields corresponding to the role, including its Consul policy and TTL configuration.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This is the <strong>READ<\/strong> operation.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">44. Step 40 \u2014 LIST the Roles<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault list consul\/roles\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Keys\n----\nstudent-role\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This is the <strong>LIST<\/strong> operation.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The Consul secrets engine explicitly supports <code>LIST \/consul\/roles<\/code>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">45. Step 41 \u2014 UPDATE the Role<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Originally:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>TTL     = 30 minutes\nMax TTL = 1 hour\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Change it to:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>TTL     = 15 minutes\nMax TTL = 30 minutes\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault write consul\/roles\/student-role \\\n  consul_policies='student-kv' \\\n  ttl='15m' \\\n  max_ttl='30m'\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Success! Data written to: consul\/roles\/student-role\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This demonstrates <strong>UPDATE<\/strong>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">46. Step 42 \u2014 Verify the Update<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault read consul\/roles\/student-role\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Verify the new TTL settings.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">47. Step 43 \u2014 DELETE the Role<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault delete consul\/roles\/student-role\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Success! Data deleted (if it existed) at: consul\/roles\/student-role\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This demonstrates <strong>DELETE<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The secrets engine&#8217;s current API supports <code>DELETE \/consul\/roles\/:name<\/code>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">48. Step 44 \u2014 Confirm the Role Is Gone<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault list consul\/roles\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You may receive:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>No value found at consul\/roles\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Alternatively, if other roles exist, <code>student-role<\/code> should be absent.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">49. Step 45 \u2014 Recreate the Role<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">We need the role for the dynamic-credential portion of the lab.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault write consul\/roles\/student-role \\\n  consul_policies='student-kv' \\\n  ttl='30m' \\\n  max_ttl='1h'\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Verify:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault read consul\/roles\/student-role\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">50. CRUD Checkpoint<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Students have now successfully demonstrated:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CREATE\nvault write consul\/roles\/student-role ...\n\nREAD\nvault read consul\/roles\/student-role\n\nUPDATE\nvault write consul\/roles\/student-role ...\n\nLIST\nvault list consul\/roles\n\nDELETE\nvault delete consul\/roles\/student-role\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This is the core Vault ACL policy exercise.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">51. Step 46 \u2014 Generate a Dynamic Consul Credential<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Now request a Consul token.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault read consul\/creds\/student-role\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Vault should return information resembling:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Key                 Value\n---                 -----\nlease_id            consul\/creds\/student-role\/&lt;unique-id&gt;\nlease_duration      30m\nlease_renewable     true\ntoken               &lt;dynamic-consul-token&gt;\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Exact fields and values may vary.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Every request creates a <strong>new Consul ACL token<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The current Consul secrets-engine credential endpoint is a read operation on:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>consul\/creds\/:role\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">even though that read causes Vault to create a new credential. This is why the Vault policy requires <code>read<\/code> capability on that path.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">52. Step 47 \u2014 Capture the Dynamic Credential Safely<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Instead of manually copying the token, request JSON:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CREDS_JSON=\"$(\n  vault read -format=json consul\/creds\/student-role\n)\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Capture the Vault lease ID:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export LEASE_ID=\"$(\n  printf '%s' \"$CREDS_JSON\" \\\n  | jq -r '.lease_id'\n)\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Capture the generated Consul token:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export DYNAMIC_CONSUL_TOKEN=\"$(\n  printf '%s' \"$CREDS_JSON\" \\\n  | jq -r '.data.token'\n)\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Remove the JSON variable:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>unset CREDS_JSON\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">53. Step 48 \u2014 Verify Variables Were Captured<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Check the lease ID:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>echo \"$LEASE_ID\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">It should resemble:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>consul\/creds\/student-role\/&lt;unique-id&gt;\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Do not print the Consul token unnecessarily.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Instead verify that it exists:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>test -n \"$DYNAMIC_CONSUL_TOKEN\" \\\n  &amp;&amp; test \"$DYNAMIC_CONSUL_TOKEN\" != \"null\" \\\n  &amp;&amp; echo \"Dynamic Consul token captured successfully.\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Dynamic Consul token captured successfully.\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">54. Step 49 \u2014 Use the Vault-Generated Consul Token<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">We now use the generated token directly against Consul.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Write a KV value:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CONSUL_HTTP_TOKEN=\"$DYNAMIC_CONSUL_TOKEN\" \\\n  consul kv put \\\n  student\/application\/database \\\n  \"training-database\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Success! Data written to: student\/application\/database\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Depending on the Consul CLI version, successful KV writes may instead display:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Success! Data written\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">or:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>true\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The important result is success.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">55. Step 50 \u2014 Read the Consul KV Value<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CONSUL_HTTP_TOKEN=\"$DYNAMIC_CONSUL_TOKEN\" \\\n  consul kv get student\/application\/database\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>training-database\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The Vault-generated Consul token works.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">56. Step 51 \u2014 Update the Consul KV Value<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CONSUL_HTTP_TOKEN=\"$DYNAMIC_CONSUL_TOKEN\" \\\n  consul kv put \\\n  student\/application\/database \\\n  \"production-style-training-value\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Read it:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CONSUL_HTTP_TOKEN=\"$DYNAMIC_CONSUL_TOKEN\" \\\n  consul kv get student\/application\/database\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>production-style-training-value\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">57. Step 52 \u2014 List Student Keys<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CONSUL_HTTP_TOKEN=\"$DYNAMIC_CONSUL_TOKEN\" \\\n  consul kv get -recurse student\/\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You should see the values underneath:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>student\/\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">A token with Consul <code>write<\/code> access on the matching prefix also has read\/list functionality for that prefix.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">58. Step 53 \u2014 Prove the Consul Token Is Restricted<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Now try writing outside the permitted prefix:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CONSUL_HTTP_TOKEN=\"$DYNAMIC_CONSUL_TOKEN\" \\\n  consul kv put \\\n  production\/database\/password \\\n  \"should-not-work\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This should fail with an ACL\/permission error.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That failure is <strong>correct<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Why?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Because the dynamically generated token has:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>key_prefix \"student\/\" {\n  policy = \"write\"\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">It does not have:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>key_prefix \"production\/\" {\n  policy = \"write\"\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This demonstrates the difference between:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Vault authorization\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">and:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Consul authorization\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">59. Step 54 \u2014 Create a Value for the Lease Test<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Create another key:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CONSUL_HTTP_TOKEN=\"$DYNAMIC_CONSUL_TOKEN\" \\\n  consul kv put \\\n  student\/lease-test \\\n  \"credential-is-currently-valid\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Verify:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CONSUL_HTTP_TOKEN=\"$DYNAMIC_CONSUL_TOKEN\" \\\n  consul kv get student\/lease-test\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>credential-is-currently-valid\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Keep this key in Consul.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We will use it to prove credential revocation.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">60. Step 55 \u2014 Understand Vault Leases<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Dynamic secrets issued by Vault have leases.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Our lease ID looks similar to:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>consul\/creds\/student-role\/ABC123...\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The lease tells Vault:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>which dynamic secret was issued\nwhen it was issued\nhow long it should live\nwhether it can be renewed\nhow Vault should revoke it\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Vault&#8217;s lease system tracks dynamic secrets and automatically revokes them when their lease expires.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">61. Step 56 \u2014 Lookup the Lease<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault lease lookup \"$LEASE_ID\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Look for fields such as:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>issue_time\nexpire_time\nlast_renewal_time\nttl\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">62. Step 57 \u2014 Renew the Dynamic Credential<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault lease renew \\\n  -increment=10m \\\n  \"$LEASE_ID\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected output resembles:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>lease_id          consul\/creds\/student-role\/...\nlease_duration    ...\nlease_renewable   true\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The requested increment is advisory; the backend may apply TTL limits configured by the role or mount.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">63. Step 58 \u2014 Confirm the Token Still Works<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CONSUL_HTTP_TOKEN=\"$DYNAMIC_CONSUL_TOKEN\" \\\n  consul kv get student\/lease-test\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>credential-is-currently-valid\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The token is still active.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">64. Step 59 \u2014 Revoke the Dynamic Credential<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Now manually revoke its Vault lease.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault lease revoke \\\n  -sync \\\n  \"$LEASE_ID\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Success! Revoked lease: consul\/creds\/student-role\/...\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Using <code>-sync<\/code> makes the revocation synchronous rather than merely queueing the work in the background. The current Vault CLI exposes this option on <code>vault lease revoke<\/code>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">65. Step 60 \u2014 Prove the Consul Credential Was Revoked<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Try the same Consul command using the old token:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CONSUL_HTTP_TOKEN=\"$DYNAMIC_CONSUL_TOKEN\" \\\n  consul kv get student\/lease-test\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This should now fail with a Consul ACL\/token error.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>This failure is the expected result.<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The sequence proves:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Vault generated the token\n        \u2193\nToken worked in Consul\n        \u2193\nVault tracked it using a lease\n        \u2193\nVault revoked the lease\n        \u2193\nVault revoked the Consul token\n        \u2193\nOld Consul token stopped working\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Vault&#8217;s Consul secrets engine requires management-level Consul access precisely so that it can create and revoke these generated ACL tokens.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">66. Step 61 \u2014 Request Another Dynamic Credential<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault read consul\/creds\/student-role\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You will receive:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>a different lease ID\na different Consul token\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This demonstrates one of the major benefits of dynamic credentials:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Applications do not need to share one permanent Consul password\/token.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">New credentials can be requested when required and expired\/revoked afterward.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">67. Complete Authentication and Authorization Flow<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Students should now understand this entire chain:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>1. student1 supplies username\/password\n                     |\n                     v\n2. Vault userpass authenticates student1\n                     |\n                     v\n3. Vault issues student1 a Vault token\n                     |\n                     v\n4. Vault token contains consul-engine-admin policy\n                     |\n                     v\n5. Policy permits operations against consul\/*\n                     |\n                     v\n6. student1 requests consul\/creds\/student-role\n                     |\n                     v\n7. Vault reads student-role\n                     |\n                     v\n8. student-role references Consul policy student-kv\n                     |\n                     v\n9. Vault authenticates to Consul using its management token\n                     |\n                     v\n10. Vault asks Consul to create a new ACL token\n                     |\n                     v\n11. Consul attaches student-kv to that token\n                     |\n                     v\n12. Vault returns the short-lived token to student1\n                     |\n                     v\n13. Token can access student\/*\n                     |\n                     v\n14. Vault tracks the credential using a lease\n                     |\n                     v\n15. Lease expiration\/revocation causes the Consul token to be revoked\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">68. Vault CRUD Summary<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">CREATE<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>vault write consul\/roles\/student-role \\\n  consul_policies='student-kv' \\\n  ttl='30m' \\\n  max_ttl='1h'\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">READ<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>vault read consul\/roles\/student-role\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">UPDATE<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>vault write consul\/roles\/student-role \\\n  consul_policies='student-kv' \\\n  ttl='15m' \\\n  max_ttl='30m'\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">LIST<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>vault list consul\/roles\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">DELETE<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>vault delete consul\/roles\/student-role\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">GENERATE DYNAMIC SECRET<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>vault read consul\/creds\/student-role\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">69. Userpass Command Summary<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Enable Userpass<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>vault auth enable userpass\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Create User<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>vault write auth\/userpass\/users\/student1 \\\n  password='StudentLab@2026' \\\n  policies='consul-engine-admin' \\\n  token_ttl='1h' \\\n  token_max_ttl='4h'\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Read User<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Root\/admin only in this lab:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault read auth\/userpass\/users\/student1\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Login<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>vault login -method=userpass \\\n  username='student1' \\\n  password='StudentLab@2026'\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The current userpass API also supports reading users, updating users\/passwords\/policies, listing users, and deleting them.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">70. Consul Secrets Engine Command Summary<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Enable Engine<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>vault secrets enable consul\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Configure Connection<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>vault write consul\/config\/access \\\n  address=\"127.0.0.1:8500\" \\\n  scheme=\"http\" \\\n  token=\"&lt;CONSUL-MANAGEMENT-TOKEN&gt;\"\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Create Role<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>vault write consul\/roles\/student-role \\\n  consul_policies='student-kv' \\\n  ttl='30m' \\\n  max_ttl='1h'\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Read Role<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>vault read consul\/roles\/student-role\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">List Roles<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>vault list consul\/roles\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Delete Role<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>vault delete consul\/roles\/student-role\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Generate Credential<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>vault read consul\/creds\/student-role\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">These paths match the current Vault Consul secrets-engine API: configuration at <code>consul\/config\/access<\/code>, role management at <code>consul\/roles\/:name<\/code>, and credential generation at <code>consul\/creds\/:name<\/code>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">71. Vault Policy Used in This Lab<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Complete file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>path \"consul\/*\" {\n  capabilities = &#91;\n    \"create\",\n    \"read\",\n    \"update\",\n    \"delete\",\n    \"list\"\n  ]\n}\n\npath \"sys\/leases\/lookup\" {\n  capabilities = &#91;\"update\"]\n}\n\npath \"sys\/leases\/renew\" {\n  capabilities = &#91;\"update\"]\n}\n\npath \"sys\/leases\/renew\/*\" {\n  capabilities = &#91;\"update\"]\n}\n\npath \"sys\/leases\/revoke\" {\n  capabilities = &#91;\"update\"]\n}\n\npath \"sys\/leases\/revoke\/*\" {\n  capabilities = &#91;\"update\"]\n}\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">72. Why This Vault Policy Is Intentionally Broad<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">The requirement for this particular lab is:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">Give one user complete CRUD-style access to the Consul secrets engine.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Therefore:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>path \"consul\/*\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">is intentionally broad.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It also means the user could potentially change sensitive configuration underneath the Consul engine.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That makes this policy appropriate for:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>training\nlabs\nexperimentation\nadministrative demonstrations\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">but usually <strong>not<\/strong> appropriate for a normal application in production.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">73. Safer Production-Style Vault Policy<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">After students understand the broad policy, show them this safer version:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Allow role management.\n\npath \"consul\/roles\" {\n  capabilities = &#91;\"list\"]\n}\n\npath \"consul\/roles\/*\" {\n  capabilities = &#91;\n    \"create\",\n    \"read\",\n    \"update\",\n    \"delete\"\n  ]\n}\n\n# Allow credential generation.\n\npath \"consul\/creds\/*\" {\n  capabilities = &#91;\"read\"]\n}\n\n# Do NOT give the user access to:\n#\n# consul\/config\/access\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This illustrates an important Vault security principle:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Give the identity only the permissions it actually requires.\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">74. Student Verification Checklist<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">A student has successfully completed the lab when all of these conditions are true:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91; ] vault version works\n\n&#91; ] consul version works\n\n&#91; ] Consul listens on 127.0.0.1:8500\n\n&#91; ] Consul ACL system has been bootstrapped\n\n&#91; ] Consul policy student-kv exists\n\n&#91; ] Vault listens on 127.0.0.1:8200\n\n&#91; ] Vault is initialized\n\n&#91; ] Vault is unsealed\n\n&#91; ] consul\/ secrets engine exists\n\n&#91; ] Vault can communicate with Consul\n\n&#91; ] consul-engine-admin Vault policy exists\n\n&#91; ] userpass auth method exists\n\n&#91; ] student1 exists\n\n&#91; ] student1 can login\n\n&#91; ] student1 receives consul-engine-admin\n\n&#91; ] student1 does not have root policy\n\n&#91; ] student1 cannot write to secret\/\n\n&#91; ] student1 can create student-role\n\n&#91; ] student1 can read student-role\n\n&#91; ] student1 can list roles\n\n&#91; ] student1 can update student-role\n\n&#91; ] student1 can delete student-role\n\n&#91; ] student1 can generate a Consul token\n\n&#91; ] generated token can write student\/*\n\n&#91; ] generated token can read student\/*\n\n&#91; ] generated token cannot write production\/*\n\n&#91; ] generated credential has a Vault lease\n\n&#91; ] lease can be renewed\n\n&#91; ] lease can be revoked\n\n&#91; ] revoked Consul token stops working\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">75. Troubleshooting \u2014 Vault Connection Refused<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Error:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>connect: connection refused\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Check:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>pgrep -a vault\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Check port:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ss -lnt | grep 8200\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Check log:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>tail -50 \"$LAB_DIR\/vault.log\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Check:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>echo \"$VAULT_ADDR\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">It should be:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>http:&#47;&#47;127.0.0.1:8200\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">76. Troubleshooting \u2014 Consul Connection Refused<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Check process:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>pgrep -a consul\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Check port:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ss -lnt | grep 8500\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Check log:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>tail -50 \"$LAB_DIR\/consul.log\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Check leader:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>curl -s http:\/\/127.0.0.1:8500\/v1\/status\/leader\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">77. Troubleshooting \u2014 Consul ACL Bootstrap Fails<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">If:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>consul acl bootstrap\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">reports that ACL bootstrapping has already occurred, you probably still have an existing Consul development server\/state.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For this disposable lab, stop Consul:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kill \"$(cat \"$LAB_DIR\/consul.pid\")\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Confirm:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>pgrep -a consul || true\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then restart the clean Consul development lab.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A Consul ACL environment can normally be bootstrapped only once.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">78. Troubleshooting \u2014 Vault Permission Denied<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Check which token you are using:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault token lookup\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Check policies:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault token lookup -format=json \\\n  | jq '.data.policies'\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected for the student:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;\n  \"consul-engine-admin\",\n  \"default\"\n]\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Check capability:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault token capabilities consul\/roles\/student-role\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">79. Troubleshooting \u2014 Student Accidentally Still Has Root Access<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Check:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>echo \"${VAULT_TOKEN:-not-set}\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If you see:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>root\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">then:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>unset VAULT_TOKEN\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Login again:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault login -method=userpass \\\n  username='student1' \\\n  password='StudentLab@2026'\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault token lookup\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Make sure:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>root\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">is absent from the policies.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">80. Troubleshooting \u2014 Dynamic Consul Credential Cannot Be Generated<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Check that the role exists:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vault read consul\/roles\/student-role\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Check the Consul policy name:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>student-kv\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Check Vault&#8217;s logs:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>tail -50 \"$LAB_DIR\/vault.log\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Check Consul logs:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>tail -50 \"$LAB_DIR\/consul.log\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Typical causes are:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Vault cannot reach Consul\nVault has an invalid Consul management token\nstudent-kv Consul policy does not exist\nstudent-role is incorrectly configured\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">81. Troubleshooting \u2014 Generated Token Cannot Access <code>student\/<\/code><\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Make sure you are actually supplying the generated token:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>test -n \"$DYNAMIC_CONSUL_TOKEN\" \\\n  &amp;&amp; echo \"Token variable exists.\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CONSUL_HTTP_TOKEN=\"$DYNAMIC_CONSUL_TOKEN\" \\\n  consul kv put student\/test \"hello\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If that fails, verify that the Consul role was created with:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>consul_policies=student-kv\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">82. Troubleshooting \u2014 Wrong Password Entered Several Times<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Vault includes user-lockout behavior for supported authentication methods including <code>userpass<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Repeated failed authentication attempts can temporarily result in immediate permission-denied responses.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For a classroom environment, encourage students to copy the lab password correctly:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>StudentLab@2026\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">rather than repeatedly guessing it.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">83. Cleanup<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Because both servers are operating in development mode, cleanup is simple.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Remove sensitive shell variables:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>unset DYNAMIC_CONSUL_TOKEN\nunset LEASE_ID\nunset CONSUL_HTTP_TOKEN\nunset CONSUL_MGMT_TOKEN\nunset VAULT_TOKEN\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Stop Vault:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kill \"$(cat \"$LAB_DIR\/vault.pid\")\" 2&gt;\/dev\/null || true\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Stop Consul:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kill \"$(cat \"$LAB_DIR\/consul.pid\")\" 2&gt;\/dev\/null || true\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Verify:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>pgrep -a vault || true\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">and:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>pgrep -a consul || true\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Remove the lab files:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>rm -rf \"$LAB_DIR\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Optionally remove the locally cached Vault CLI token created by <code>vault login<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>rm -f \"$HOME\/.vault-token\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Unset:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>unset LAB_DIR\nunset VAULT_ADDR\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Because development mode uses in-memory state, stopping the servers destroys the lab&#8217;s Vault and Consul runtime data.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">84. What Students Should Remember<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">Authentication<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>Who are you?\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In this lab:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>userpass\nusername = student1\npassword = StudentLab@2026\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Vault Authorization<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>What are you allowed to do in Vault?\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Controlled by:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>consul-engine-admin\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Vault Consul Role<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>What type of Consul credential should Vault generate?\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Controlled by:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>student-role\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Consul Authorization<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>What can the generated token do inside Consul?\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Controlled by:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>student-kv\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Dynamic Secret<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>What credential did Vault dynamically create?\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Answer:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>A short-lived Consul ACL token.\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Lease<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>How does Vault track the lifecycle of that credential?\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Answer:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Using a Vault lease.\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">85. Final Architecture<\/h1>\n\n\n\n<pre class=\"wp-block-code\"><code>                    +----------------------+\n                    |       student1       |\n                    +----------+-----------+\n                               |\n                               | username\/password\n                               v\n                    +----------------------+\n                    |   Vault Userpass     |\n                    +----------+-----------+\n                               |\n                               | authenticates\n                               v\n                    +----------------------+\n                    |    Vault Token       |\n                    |                      |\n                    | consul-engine-admin  |\n                    +----------+-----------+\n                               |\n                               | permits access\n                               v\n                    +----------------------+\n                    |  Consul Secret       |\n                    |  Engine: consul\/     |\n                    +----------+-----------+\n                               |\n                               | uses\n                               v\n                    +----------------------+\n                    |   student-role       |\n                    |                      |\n                    | Consul policy:       |\n                    | student-kv           |\n                    +----------+-----------+\n                               |\n                               | Vault talks to Consul\n                               v\n                    +----------------------+\n                    |      Consul          |\n                    |     ACL System       |\n                    +----------+-----------+\n                               |\n                               | dynamically creates\n                               v\n                    +----------------------+\n                    | Dynamic Consul Token |\n                    +----------+-----------+\n                               |\n                               | student-kv\n                               v\n                    +----------------------+\n                    | Consul KV            |\n                    |                      |\n                    | student\/*  -&gt; ALLOW  |\n                    | other\/*    -&gt; DENY   |\n                    +----------------------+\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">86. Master Lab Success<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">If the entire lab works correctly, the following sequence has been proven:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Ubuntu\n  \u2193\nVault\n  \u2193\nuserpass\n  \u2193\nstudent1\n  \u2193\nVault Policy\n  \u2193\nConsul Secrets Engine\n  \u2193\nVault Consul Role\n  \u2193\nDynamic Consul ACL Token\n  \u2193\nRestricted Consul Permissions\n  \u2193\nVault Lease\n  \u2193\nRenew\n  \u2193\nRevoke\n  \u2193\nCredential becomes invalid\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">That gives students an end-to-end introduction to <strong>Vault authentication, Vault authorization, the Consul dynamic secrets engine, Consul ACL authorization, dynamic credentials, TTLs, leases, renewal, and revocation<\/strong> in one coherent exercise.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Validation Notes<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">This guide has been syntax-checked against the current official <strong>Vault 2.x<\/strong> and <strong>Consul 2.0.x<\/strong> documentation, including the current Userpass API, Consul secrets-engine API, Vault ACL capability model, Consul ACL bootstrap and policy commands, and Vault lease renew\/revoke commands. Vault&#8217;s current release notes identify <strong>2.0.4<\/strong> as the August 4, 2026 fix release.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The lab intentionally uses only currently documented fields such as <code>consul_policies<\/code>; older examples using legacy base64 <code>policy<\/code>, older Consul token types, or deprecated role fields have been avoided. Vault&#8217;s current Consul API specifically identifies older <code>policy<\/code> and <code>policies<\/code> role parameters as deprecated in favor of the current Consul-policy model.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The commands have been validated against the current documentation rather than executed on your particular Ubuntu host, so the first run on your server should also be treated as the final environment-specific runtime validation.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Beginner-Friendly Hands-On Lab for Ubuntu Linux 1. Lab Objective In this lab, we will build the following environment from scratch: By the end of the lab, students&#8230; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1042","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/posts\/1042","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/comments?post=1042"}],"version-history":[{"count":1,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/posts\/1042\/revisions"}],"predecessor-version":[{"id":1043,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/posts\/1042\/revisions\/1043"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/media?parent=1042"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/categories?post=1042"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/tutorials\/wp-json\/wp\/v2\/tags?post=1042"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}