All authenticated requests to Vault must be accompanied by a valid token, which means that Vault clients must first authenticate with Vault, and acquire a token.
The Secure Introduction of Vault Clients tutorial details available approaches for solving the secret zero problem.
One comprehensive and robust way to solve this problem is to use Vault Agent. Vault Agent can also manage the lifecycle of additional secrets beyond secret zero.
»Challenge
Vault Agent is most effective when available to the client application or user environment on a continuous basis and operated as a system service instead of a foreground user process.
»Solution
Vault Agent can be configured to operate as a Windows service so that it is automatically started when the operating system starts, and is readily available for use when the client application or user needs it.
»Scenario Introduction
There are multiple solutions for registering Vault as a Windows service. You will use either the Service Control tool, sc.exe
or the New-Service
cmdlet to register Vault Agent as a Windows service in this tutorial.
For the example scenario, you will use two Powershell sessions and multiple command line invocations to start a Vault dev mode server and configure the AppRole auth method for use by Vault Agent.
You will then configure Vault Agent and register it as a service.
Finally, you will confirm that the Agent service can start and authenticate with the dev mode Vault server.
»Prerequisites
You need the following to successfully complete this section of the tutorial:
A Windows host (This tutorial was tested with Windows Server 2019).
An Administrator level user account on the Windows host that has the capability to register system services.
Vault version 1.7 or later; you can follow the Install Vault tutorial to install Vault on Windows. The open source edition is suitable for successfully completing the example scenario.
jq is used for consuming Vault JSON formatted output and capturing specific fields for output to files;
jq
is required to follow specific steps in the example scenario.
»Create scenario directory
From a Powershell session, create a top-level directory to contain the configuration and other data created when following the example scenario.
$ md c:\vault-agent
Directory: C:\
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 3/18/2021 8:35 AM vault-agent
NOTE: The examples use a the directory path C:\vault-agent
, but you can use any name you prefer and have access to, so long as you substitute it whenever the scenario directory name is referenced.
»Install Vault
If you have not already installed Vault in your Windows environment, you can follow the Install Vault tutorial and choose the installation instructions for either Chocolatey or Scoop.
Once you have successfully installed Vault, you can validate that the vault
binary is executable from a Powershell session.
Open a new Powershell session and validate the Vault executable.
$ vault version
The output should include Vault v1.7.0 or higher.
»Install jq
If you have not already installed Vault in your Windows environment, you can install it with Chocolatey.
$ choco install jq
Or you can install jq with Scoop if that is your preference.
$ scoop install jq
You can optionally validate that the jq installation was successful in the same Powershell session.
$ jq --version
jq-1.6
»Start and prepare the Vault server
In production use, your Vault Agent will likely use an external Vault cluster, but for the purposes of this example scenario, you will start and prepare a Vault dev mode server for use by the Agent service.
In doing so, you gain both an understanding of operating Vault Agent as a Windows service, and a hands on example service configuration that you can immediately try in your local environment.
TIP: The dev mode server stores everything in memory, so you can just stop it when finished to clean up.
Start the Vault dev mode server, and specify root
as the initial root token value.
$ vault server -dev -dev-root-token-id=root
==> Vault server configuration:
Api Address: http://127.0.0.1:8200
Cgo: disabled
Cluster Address: https://127.0.0.1:8201
Go Version: go1.15.10
Listener 1: tcp (addr: "127.0.0.1:8200", cluster address: "127.0.0.1:8201", max_request_duration: "1m30s", max_request_size: "33554432", tls: "disabled")
Log Level: info
Mlock: supported: false, enabled: false
Recovery Mode: false
Storage: inmem
Version: Vault v1.7.0
Version Sha: d77a09d565024d3c8bef98a101752ef620ed3063
...
snip
...
WARNING! dev mode is enabled! In this mode, Vault runs entirely in-memory
and starts unsealed with a single unseal key. The root token is already
authenticated to the CLI, so you can immediately begin using Vault.
You may need to set the following environment variable:
PowerShell:
$env:VAULT_ADDR="http://127.0.0.1:8200"
cmd.exe:
set VAULT_ADDR=http://127.0.0.1:8200
The unseal key and root token are displayed below in case you want to
seal/unseal the Vault or re-authenticate.
Unseal Key: ahOWBI3/vLhSJuW5eYhq8rdEM8g0JGROiaSzVSUY794=
Root Token: root
Development mode should NOT be used in production installations!
Insecure operation: Do not run a Vault dev server in production. This approach is only used here to simplify the unsealing process for this demonstration.
The Vault dev mode server is now ready for use.
You can leave it running in this Powershell session while you complete the rest of the example scenario in another session.
»Enable and configure AppRole auth method
NOTE: Open another Powershell session for the following steps.
Vault Agent needs an enabled auth method for automatically authenticating to Vault.
To ensure that the service example is fully functional later, you will enable and configure an instance of the AppRole auth method in your Vault dev mode server.
First, you should set some environment variables to both specify the Vault dev mode server address and the initial root token value.
Set the dev mode server address.
$ $env:VAULT_ADDR="http://127.0.0.1:8200"
Set the initial root token value.
$ $env:VAULT_TOKEN="root"
»Enable AppRole auth method
Enable the AppRole auth method.
$ vault auth enable approle
Success! Enabled approle auth method at: approle/
The success message indicates that the AppRole auth method is enabled at the default path approle/
.
»Create a named role
Create an AppRole named role, vault-agent-role
for later use by the Agent.
$ vault write auth/approle/role/vault-agent-role secret_id_ttl=90m token_num_uses=10 token_ttl=60m token_max_ttl=120m secret_id_num_uses=20
Success! Data written to: auth/approle/role/vault-agent-role
The restrictions on token use from this example role emphasize the importance of short lived secrets.
In the vault-agent-role
, the AppRole secret ID has a 90 minute time to live (TTL) and can only be used 20 times. Tokens acquired from this role can only be used 10 times and have a maximum time to live of 2 hours.
Vault Agent will use this AppRole named role by passing a role ID and secret ID when it performs the automatic authentication.
»Write role ID and secret ID
The last step in preparing the AppRole auth method is to write the vault-agent-role
role ID and a matching secret ID to files in the scenario directory.
When the Agent service starts, it will consume these files as part of its automatic authentication functionality.
NOTE: The default behavior for each automatic authentication attempt by the Agent when using AppRole is to delete the secret ID file whether or not the authenticate attempt succeeds. You should expect the agent-secret-id
file to be missing after starting the service.
Write the role ID to file in the scenario directory called agent-role-id
.
$ vault read auth/approle/role/vault-agent-role/role-id -format=json | jq -r '.data.role_id' | Out-File -encoding ascii C:\vault-agent\agent-role-id -NoNewline
Write the secret ID to file in the scenario directory called agent-secret-id
.
$ vault write -f auth/approle/role/vault-agent-role/secret-id -format=json | jq -r '.data.secret_id' | Out-File -encoding ascii C:\vault-agent\agent-secret-id -NoNewline
You can optionally validate the file contents, keeping in mind that this will reveal the secret ID value.
$ cat c:\vault-agent\agent-role-id ; cat c:\vault-agent\agent-secret-id
28a05ccc-99bd-babd-9be0-29e890c279f3
8f941d1a-ed3b-bd3b-a939-2836b633e541
With the role ID and secret ID values written to files, you can proceed to configure the Agent.
»Configure Vault Agent
In this scenario, Vault Agent will be execute with a minimal example configuration that instructs it to connect to the Vault dev mode server and auto authenticate using the previously created AppRole auth method.
After doing so, a Vault token will be present at C:\vault-agent\agent-token
.
Before you can register the Vault Agent service, you need to write the configuration file, vault-agent.hcl
to the scenario directory.
Assign the file content to a variable named AgentConfiguration
.
$AgentConfiguration = @"
pid_file = "/vault-agent/agent.pid"
vault {
address = "http://127.0.0.1:8200"
}
auto_auth {
method "approle" {
config = {
role_id_file_path = "/vault-agent/agent-role-id"
secret_id_file_path = "/vault-agent/agent-secret-id"
}
}
sink "file" {
config = {
path = "/vault-agent/agent-token"
}
}
}
cache {
use_auto_auth_token = true
}
listener "tcp" {
address = "127.0.0.1:8100"
tls_disable = true
}
"@
Write the AgentConfiguration
variable contents to the Agent configuration file.
$ Set-Content C:\vault-agent\vault-agent.hcl $AgentConfiguration
You are now prepared to register the Agent service.
»Register Vault Agent as a service
One way to register the service is to use Service Control.
Service Control works best if the path to your Vault binary and the associated Agent configuration file do not contain space characters. Service Control can be difficult to correctly configure if your path contains spaces, as paths containing spaces must be quoted and correctly escaping quotes is non-trivial.
Another alternative is to use the New-Service cmdlet. New-Service is more tolerant about escaping quotes in paths containing spaces, and can sometimes be easier to configure if your path contains spaces or you prefer not to use Service Control.
Choose the method you prefer to learn about, and register the Vault Agent service.
Heads up: When you use the Service Control tool, ensure that you explicitly invoke sc.exe
, and not just sc
so that you do not invoke the Set-Content
built-in alias by mistake.
The following example command registers a Vault Agent service that uses "Vault Agent" as the display name and automatically starts when Windows boots.
The binPath
argument should include the fully qualified path to the Vault binary executable, and all required arguments. In this case, it includes the -config
flag to specify the Agent configuration that you just created.
NOTE: The spacing after the equals sign (=
) in all of the arguments is intentional and required to successfully register the service. The binPath
value here is for the vault.exe
location when Vault installed with Chocolatey, and you should adjust it to match your Vault executable path if you installed Vault another way.
$ sc.exe create VaultAgent binPath= "C:\ProgramData\chocolatey\lib\vault\tools\vault.exe agent -config=C:\vault-agent\vault-agent.hcl" displayName= "Vault Agent" start= auto
[SC] CreateService SUCCESS
If the output shows "[SC] CreateService SUCCESS", then service registration is complete.
If you encounter an error, verify the path to the Vault binary, and check the arguments, by running the contents of binPath=
directly in a PowerShell session and observing the results.
»Start the Vault Agent service
You can start the service with Service Control, the Start-Service
cmdlet, or with the UI in the Windows Service Manager.
Start the Agent service with sc.exe
.
$ sc.exe start VaultAgent
SERVICE_NAME: VaultAgent
TYPE : 10 WIN32_OWN_PROCESS
STATE : 2 START_PENDING
(NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x7d0
PID : 4728
FLAGS :
»Validate the Agent token
If the Agent is operating properly, it will automatically authenticate with Vault using AppRole and acquire a token that it will write to the file sink at C:\vault-agent\agent-token
.
Using this token ID value and the Vault Agent address, you can further authenticate with Vault.
Set the Vault Agent address as the value to the VAULT_ADDR
environment variable so that you are communicating directly to the Agent and not the Vault dev mode server.
$ $env:VAULT_ADDR="http://127.0.0.1:8100"
Capture the the token contained in the agent-token
file as the VAULT_TOKEN
environment variable value.
$ $env:VAULT_TOKEN = Get-Content C:\vault-agent\agent-token -Raw
Attempt a token lookup.
$ vault token lookup
Key Value
--- -----
creation_time 1616100193
creation_ttl 1h
display_name approle
entity_id c0a7378e-1d42-dade-dfb0-d6d448228008
expire_time 2021-03-18T15:25:13.1964324-07:00
explicit_max_ttl 0s
issue_time 2021-03-18T13:43:13.1406039-07:00
last_renewal 2021-03-18T14:25:13.1964324-07:00
last_renewal_time 1616102713
meta map[role_name:vault-agent-role]
num_uses 7
orphan true
path auth/approle/login
policies [default]
renewable true
ttl 20m22s
type service
Insecure operation: Displaying plaintext values in terminal sessions is typically discouraged; this command is for illustrative purposes only.
Note that the role_name
contained in the meta
is vault-agent-role
, and the token has only the default policy attached. This validates that the token was acquired from the AppRole auth method on the dev server.
»Next Steps
You have learned how to configure Vault Agent as a Windows service and validate that the service registers and successfully starts.
You further validated that the Vault Agent was able to connect to the Vault dev mode server and successfully authenticate by checking for the presence of a Vault token at the configured sink location.
Finally, you used the Agent and token ID value to authenticate with Vault as a secondary validation that the token was successfully acquired by Agent from the AppRole auth method.
From here, you can expand your Vault Agent knowledge, and learn about more advanced features, such as Agent Caching and Agent Templates.