Keyless Applications – Keep Your Secrets Hidden

Hashicorp - Vault

In my previous Blog Send Attackers Phishing Somewhere Else, you may have noticed the following HTTP request made to the Hashicorp Vault service in order to retrieve a temporary set of database credentials:

$ curl --header "X-Vault-Token: 7b7dd433-01cc-f716-8cf8-35e57ffc0d6b" https://vault.somedomain.com/v1/database/creds/my-role | jq '.'
{
  "request_id": "947aa9ca-4518-1ba9-bd0f-44e7b133a043",
  "lease_id": "database/creds/my-role/8568b2c6-b967-296a-ceb1-baa6a60b35c3",
  "renewable": true,
  "lease_duration": 60,
  "data": {
    "password": "A1a-TgFA8MyrR1dAffCP",
    "username": "v-root-my-role-oOBwwjM8P7ydGp07j"
  },
  "wrap_info": null,
  "warnings": null,
  "auth": null
}
$

In that request, you will notice the HTTP header X-Vault-Token is present in the request.  But what is this Vault Token? In Hashicorp Vault’s documentation for tokens you will see “Tokens are the core method for authentication within Vault”. But wait, wasn’t the whole point of using Hashicorp Vault so that I didn’t have to configure my web application with credentials, and now I need a Vault token as a credential instead of database username and password credentials? What was the point of that, why didn’t I just configure my database credentials to begin with?

In fact, the demo web application I built for Send Attackers Phishing Somewhere Else used the following line of Java code:

String vaultToken = System.getProperty("VAULT_TOKEN");

Which essentially just requires that the environment in which the Java web application is running is expected to have an environment variable set with the value of the VAULT_TOKEN required by my web application to authenticate with Vault and give it permission to obtain database credentials. In the same manner as discussed in the previous article, an administrator would be expected to provision a VAULT_TOKEN from the Vault service, and then copy that value over to the environment that the web application runs in and record it somewhere (perhaps in a shell script on a server). This administrative step may compromise the security of the system in exactly the same way as discussed in my previous article.

But a vault token is not the only way to authenticate with a Vault service, in fact Hashicorp provides a variety of Auth Methods you can use for authentication, and the focus of this article will be on the use of the AWS Auth Method. The AWS Auth Method allows you to use any AWS Identity and Access Management (IAM) principal to authenticate with the Vault service and exchange for a Vault token automatically. Combined with AWS’ instance profile, an IAM principal based on the IAM role type, which is provisioned to an instance running within the AWS cloud, one would not even have to provision any credentials or configure them in your web application in order to use the Vault service. Let’s take a deeper look into how this works within Vault itself.

First, you would need to enable your Vault service to use the AWS Auth method, and you do so by running the following command to vault with an authenticated login:

vault auth enable aws

Second, you would need to configure vault’s aws authentication to only authenticate requests that contain a X-Vault-AWS-IAM-Server-ID Header value, which is recommended by Hashicorp to mitigate replay attacks.

vault write auth/aws/config/client iam_server_id_header_value=vault.somedomain.com

Third, you would need to provision an IAM principal, in this case an IAM role, in AWS to use for authenticating with Vault using the AWS Auth Method. I will skip the details of IAM role creation in this article, just know that when you are done with this step you will need the ARN (Amazon Resource Name) of the IAM role for the next step. In my case, I am using:  arn:aws:iam::<account id>:role/bwvaulttest-eb

Finally, you would need to authorize your IAM role in Vault by running a command similar to the following:

vault write auth/aws/role/bwvaulttest-eb auth_type=iam bound_iam_principal_arn=arn:aws:iam::<account id>:role/bwvaulttest-eb policies=bwvaulttest-eb max_ttl=500h

This command has several elements to it that bear discussion. 

    • The command creates a new Vault service role called bwvaulttest-eb, which can be any arbitrary value you choose, and which is located at the path auth/aws/role/bwvaulttest-eb in Vault.
    •  It uses the iam auth_type for the type of authentication Vault will use, which is the auth_type with the most usage flexibility in Vault involving IAM principals. 
    •  Most importantly, it is binding the iam auth_type to the IAM principal arn:aws:iam::<account id>:role/bwvaulttest-eb which we created earlier.
    • We are telling Vault which permissions to allow in vault through the use of the policies option and by specifying an existing Vault policy for the role to be bound to (for this article we will not dive into vault permissions).  
    • We are telling Vault to limit how long the authentication is good for using the max_ttl option.  Once this command is done, you are now able to use the IAM principal to authenticate with Vault and exchange for a Vault token.

In this case our web application uses instance metadata available on the AWS cloud instance to sign a request made to the Vault service (see EC2 Auth Method for further technical details), and the Vault service verifies this signature with AWS to prove your principal is authentic. The web application would need to implement this API request in order to exchange its IAM principal identity for a Vault token. Vault provides AWS Auth Method API documentation for how to go about making this API request.

Once the AWS Auth Method API call is made in our web application, we eliminate the need to have VAULT_TOKEN set in our environment anymore, and as long as we are running the web application on an AWS cloud instance with the instance profile using the IAM role arn:aws:iam::<account id>:role/bwvaulttest-eb we created in an earlier step, our web application is able to retrieve its own vault token directly from the Vault service.

The power of Vault’s AWS Auth method in combination with AWS instance profile is that we never have to provision Vault tokens for our web application, or any other application we add to our environment. As long as each new application gets an IAM principal provisioned, and as long as each new IAM principal is authorized to use Vault, each new application can simply use its IAM principal to authenticate with Vault and take advantage of any static or dynamic secrets stored in our Vault service. And, if we combine this with Vaults secrets engines, as discussed in Send Attackers Phishing Somewhere Else for dynamic database credentials, now we have a web application that doesn’t need either database credentials or a Vault token provisioned for it, it is truly dynamic authentication based on AWS IAM principals.

Combine all of this with infrastructure as code to provision resources for our web application, and you have security by default without ever having to think about it.

A highly available Vault service can easily be provisioned using Hashicorp Terraform, taking all of the pain away from getting started using it. Foghorn Consulting has built such a Terraform module for assisting our clients in deploying a Vault service. Reach out and we can assist you with getting up and running with your own Vault service rapidly.

Previous

Next