AppRole policies for transit secret engine "datakey" concept

Hi,

I want to implement the “datakey” concept [1] with the vault-java-driver [2] to be able to en/decrypt large files in my application.
I am able to execute the cmds to fetch and decrypt the “datakey” on cmd line with Admin credentials.
However, when I try to decrypt the “datakey” in Java with AppRole credentials I get a 403 permission denied.

...
//Successfully logged in with AppRole via "wrapped token" and read VAULT_DATAKEY_CIPHERTEXT via Admin credentials

//When trying to access the transits secret engine: 403 in the response
LogicalResponse decryptResponse = vault
	.logical()
	.write("v1/transit/decrypt/master-key",
	 Collections.singletonMap("ciphertext", VAULT_DATAKEY_CIPHERTEXT));

I applied the suggested policies in the approle config file:

# Policies taken from:
# https://learn.hashicorp.com/vault/encryption-as-a-service/eaas-transit#policy-requirements
# for the "transit secrets engine"
# Enable transit secrets engine
path "sys/mounts/transit" {
  capabilities = [ "create", "read", "update", "delete", "list" ]
}

# To read enabled secrets engines
path "sys/mounts" {
  capabilities = [ "read" ]
}

# Manage the transit secrets engine
path "transit/*" {
  capabilities = [ "create", "read", "update", "delete", "list" ]
}

But this still results in a 403.

Questions:

  1. Is the AppRole supposed to do the decrypt operation? In [1] the suggested role is “Persona: operator”. But, all the steps in this tutorial are assigned to the operator.

  2. If the AppRole can do this: what policies are needed in the approle config file?

Thanks
Paul

[1] https://learn.hashicorp.com/vault/encryption-as-a-service/eaas-transit#step-6-generate-data-key
[2] https://github.com/BetterCloud/vault-java-driver

Not in expert in Java or this use case, but I thought to list mounts you needed

# To read enabled secrets engines
path "sys/mounts" {
  capabilities = [ "read","list" ]
}

Are you using a token on the CLI that has policy=your-approle-policy?

Hi Mike,

Thx for your reply.

I added the “list” to the policy as you suggested, with the same result.

I am a newbie when it comes to Vault policiy administration.
I test against a local vault instance in dev mode, and the Admin is probably connected to the root policy.
So in that sense my AppRole policy is a subset of the root policy.

I went back to cmd line, to execute the cmds with Admin token and with Approle token.
This is the output from the test script (with shortened outputs):

Create a named encryption key
Success! Data written to: transit/keys/master-key

Read the corresponding ‘datakey’ (with Admin token)
RESPONSE_DATA_KEY: Key Value — ----- ciphertext vault:v1:XkLE… plaintext GZMj
VAULT_DATAKEY_CIPHERTEXT: vault:v1:XkLE…
Decrypt ‘datakey’ (with Admin token)
RESPONSE_DATA_KEY_PLAIN: Key Value — ----- plaintext GZMj

Read the corresponding ‘datakey’ via cURL (with Approle token)
RESPONSE_DATA_KEY_CURL: {“request_id”:“811e…”, … “data”:{“ciphertext”:“vault:v1:szpA…”,“plaintext":"SL6y…”}…}
Decrypt ‘datakey’ via cURL (with Approle token)
RESPONSE_DATA_KEY_PLAIN_CURL: {“request_id”:“fd88…”, … “data”:{“plaintext":"GZMj…”},…}

So no 403s here, but I notice that when I execute with the Approle token the plaintext keys do not match. Hmm…

UPDATE: OK, I need to base64 decode the plaintext from the RESPONSE_DATA_KEY_PLAIN_CURL result, so I get the same value for the plaintext keys and thus the same behaviour for Admin and AppRole access on cmd line.
Which indicates that the AppRole policy should be fine. So back to digging into the Java client (vault-java-driver 5.1.0) running against Vault 1.4.3 (in dev mode).

cmds are here:

Thanks
Paul

Turns out that the vault-java-driver uses for all read/write requests the engineVersion param to tweak the URL with the “data” part, which is needed when accessing the KV Secrets Engine.

The default is: 2, which causes the 403 when accessing Transit Secret Engine URLs (because of the added “data” part). To access URLs of Transit Secret Engine the engineVersion needs to be set to 1. This is done in the tests.

So the code above looks sth like this:

VaultConfig config = new VaultConfig()
  .address(address)
  .engineVersion(1)  //Set to 1, because we do not want the "data" part in the URL here
  .token(authClientToken)
  .build();

Map<String, String> responseData = new Vault(config)
  .logical()
  .write("transit/decrypt/master-key",
   Collections.singletonMap("ciphertext", VAULT_DATAKEY_CIPHERTEXT))
  .getData();
responseData.get("plaintext");

What confused me was the 403 (= Forbidden) response code of the Vault API, I expected a 404.
The answers to my questions above are:

  1. Yes, with the correct policies in place the AppRole can within a Java application:
    fetch a new “datakey pair” to encrypt a large file
    and later decrypt the “datakey ciphertext part” to decrypt a large file

  2. The policies above are sufficient.