Reputation: 1120
I am using this code as an example to use AppRole based authentification to Vault. For the secret_id I wanna use an wrapped token to be more secure
import unittest
from hvac import Client
URL = "https://p.vault.myfine-company.de"
JENKINS_TOKEN = "mylovelytoken"
def test_ci_startup(self):
# Jenkins authentifies with token as secure instance
jenkins_client = Client(url=URL, token=JENKINS_TOKEN)
# fetch the role_id and stores this somewhere in the image of the app
resp = jenkins_client.auth.approle.read_role_id(role_name='workshop')
role_id = resp["data"]["role_id"]
# get a wrapped secret_id and passes this to the starting app
result = jenkins_client.write(path='auth/approle/role/workshop/secret-id',wrap_ttl="2s")
unwrap_token = result['wrap_info']['token']
# No the app comes in place
app_client = Client(url=URL) # , token=JENKINS_TOKEN)
# unwrap the secret_id
unwrap_response = app_client.sys.unwrap(unwrap_token) # !!! Here I get permission denied
secret_id = unwrap_response['data']['secret_id']
# use role_id and secret_id to login
login_result = app_client.auth.approle.login(role_id=role_id, secret_id=secret_id)
client_token = login_result['auth']['client_token']
# Read the database credential
read_response = app_client.secrets.kv.v2.read_secret_version(path='test/webapp')
self.assertEqual("users", read_response['data']['data']['db_name'])
return
Unfortunatly when try to unwrap the secret_id with app_client.sys.unwrap(unwrap_token)
there is an 403 "permission denied" When I use the app_client-Connection with app_client = Client(url=URL), token=JENKINS_TOKEN)
everything works fine. But this of course this not the way the AppRole based authentication should be used. All this is bases on the following Tutorials and Best Practices :
https://developer.hashicorp.com/vault/tutorials/recommended-patterns/pattern-approle https://developer.hashicorp.com/vault/tutorials/auth-methods/approle?in=vault%2Fauth-methods
I think is somewhat related to policies. But I did not find the solution yet.
Upvotes: 0
Views: 1815
Reputation: 1120
Bash window 1:
$ export VAULT_ADDR="https://p.vault.myfine-company.de"
$ export VAULT_TOKEN="my-fine-token"
$ # This creates a secret
$ vault kv put secret/mysql/webapp db_name="users" username="admin" password="passw0rd"
$ # this writes the policy to access the secret
$ vault policy write jenkins -<<EOF\n# Read-only permission on secrets stored at 'secret/data/mysql/webapp'\npath "secret/data/mysql/webapp" {\n capabilities = [ "read" ]\n}\nEOF\n
$ # This creates an approle jenkins
$ vault write auth/approle/role/jenkins token_policies="jenkins" \\n token_ttl=1h token_max_ttl=4h\n
$ # this reads the role-id
$ vault read auth/approle/role/jenkins/role-id
Key Value
--- -----
role_id fcff5e13-wonderfull-my-fine-role-id
$ This creates a wrapping token with TTL 120s
$ vault write -wrap-ttl=120s -force auth/approle/role/jenkins/secret-id
Key Value
--- -----
wrapping_token: hvs.wonderfull-msgiIp9nu91c1fLrcwGh4KHGh2cy5HMmw4bkh2-my-fine-wrapping-token
wrapping_accessor: ddXZLPFmy-fine-accessor
wrapping_token_ttl: 2m
wrapping_token_creation_time: 2022-11-23 12:19:46.958503493 +0000 UTC
wrapping_token_creation_path: auth/approle/role/jenkins/secret-id
wrapped_accessor: 5superp-6-my-fine-wrapped-accessor
role_id
and wrapping_token
is now used in bash window 2:
$ # unwrap token to obtain the secret-id
$ VAULT_TOKEN=hvs.wonderfull-msgiIp9nu91c1fLrcwGh4KHGh2cy5HMmw4bkh2-my-fine-wrapping-token vault unwrap
Key Value
--- -----
secret_id ac8b3594-my-wundervolles-secret-id
secret_id_accessor 485423my-wundervolles-secret-accessor
secret_id_ttl 0s
$ # login to vault and get a APP_TOKEN to be used to read secrets
$ vault write auth/approle/login role_id=fcff5e13-wonderfull-my-fine-role-id secret_id=ac8b3594-my-wundervolles-secret-id
Key Value
--- -----
token hvs.CAESIEW-so-a-nice-token-lEgXb9ZIf-my-wonderfull-token
token_accessor MehfK-my-wonderfull-accessor
token_duration 1h
token_renewable true
token_policies ["default" "jenkins"]
identity_policies []
policies ["default" "jenkins"]
token_meta_role_name jenkins
$ export APP_TOKEN=hvs.CAESIEW-so-a-nice-token-lEgXb9ZIf-my-wonderfull-token
$ # Read a secret
$ VAULT_TOKEN=$APP_TOKEN vault kv get secret/mysql/webapp
====== Secret Path ======
secret/data/mysql/webapp
======= Metadata =======
Key Value
--- -----
created_time 2022-11-23T09:44:24.429733013Z
custom_metadata <nil>
deletion_time n/a
destroyed false
version 1
====== Data ======
Key Value
--- -----
db_name users
password passw0rd
username admin
The advantage with this wrapped_token is that the CI Pipeline passes this short lived token to the app. The app uses this token to retrieve the secret-id
(by unwrapping it) and performs the login together with the role-id
to obtain the access token to read the database secret.
Solution :
The Problem is solved by providing the unwrap_token
to app_client = Client(url=URL) token=unwrap_token
as mentioned in a still open pull-request to hvac (as of 2022-11-30) :
import hvac
client = hvac.Client(url='https://127.0.0.1:8200')
client.token = "hvs.wonderfull-msgiIp9nu91c1fLrcwGh4KHGh2cy5HMmw4bkh2-my-fine-wrapping-token"
# When authenticating with just the wrapping token, should not pass token into unwrap call
unwrap_response = client.sys.unwrap()
print('Unwrapped approle role token secret id accessor: "%s"' % unwrap_response['data']['secret_id_accessor'])
Upvotes: 0