Skip to content

Commit a99aaeb

Browse files
Allow setting Hashicorp Vault token from File (apache#9644)
1 parent fddc572 commit a99aaeb

File tree

4 files changed

+42
-5
lines changed

4 files changed

+42
-5
lines changed

airflow/providers/hashicorp/_internal_client/vault_client.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ class _VaultClient(LoggingMixin): # pylint: disable=too-many-instance-attribute
6767
:param token: Authentication token to include in requests sent to Vault
6868
(for ``token`` and ``github`` auth_type).
6969
:type token: str
70+
:param token_path: path to file containing authentication token to include in requests sent to Vault
71+
(for ``token`` and ``github`` auth_type).
72+
:type token_path: str
7073
:param username: Username for Authentication (for ``ldap`` and ``userpass`` auth_types).
7174
:type username: str
7275
:param password: Password for Authentication (for ``ldap`` and ``userpass`` auth_types).
@@ -110,6 +113,7 @@ def __init__( # pylint: disable=too-many-arguments
110113
mount_point: str = "secret",
111114
kv_engine_version: Optional[int] = None,
112115
token: Optional[str] = None,
116+
token_path: Optional[str] = None,
113117
username: Optional[str] = None,
114118
password: Optional[str] = None,
115119
key_id: Optional[str] = None,
@@ -134,10 +138,10 @@ def __init__( # pylint: disable=too-many-arguments
134138
if auth_type not in VALID_AUTH_TYPES:
135139
raise VaultError(f"The auth_type is not supported: {auth_type}. "
136140
f"It should be one of {VALID_AUTH_TYPES}")
137-
if auth_type == "token" and not token:
138-
raise VaultError("The 'token' authentication type requires 'token'")
139-
if auth_type == "github" and not token:
140-
raise VaultError("The 'github' authentication type requires 'token'")
141+
if auth_type == "token" and not token and not token_path:
142+
raise VaultError("The 'token' authentication type requires 'token' or 'token_path'")
143+
if auth_type == "github" and not token and not token_path:
144+
raise VaultError("The 'github' authentication type requires 'token' or 'token_path'")
141145
if auth_type == "approle" and not role_id:
142146
raise VaultError("The 'approle' authentication type requires 'role_id'")
143147
if auth_type == "kubernetes":
@@ -161,6 +165,7 @@ def __init__( # pylint: disable=too-many-arguments
161165
self.auth_type = auth_type
162166
self.kwargs = kwargs
163167
self.token = token
168+
self.token_path = token_path
164169
self.auth_mount_point = auth_mount_point
165170
self.mount_point = mount_point
166171
self.username = username
@@ -206,7 +211,7 @@ def client(self) -> hvac.Client:
206211
elif self.auth_type == "radius":
207212
self._auth_radius(_client)
208213
elif self.auth_type == "token":
209-
_client.token = self.token
214+
self._set_token(_client)
210215
elif self.auth_type == "userpass":
211216
self._auth_userpass(_client)
212217
else:
@@ -307,6 +312,13 @@ def _auth_approle(self, _client: hvac.Client) -> None:
307312
else:
308313
_client.auth_approle(role_id=self.role_id, secret_id=self.secret_id)
309314

315+
def _set_token(self, _client: hvac.Client) -> None:
316+
if self.token_path:
317+
with open(self.token_path) as f:
318+
_client.token = f.read()
319+
else:
320+
_client.token = self.token
321+
310322
def get_secret(self, secret_path: str, secret_version: Optional[int] = None) -> Optional[dict]:
311323
"""
312324
Get secret value from the KV engine.

airflow/providers/hashicorp/hooks/vault.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ class VaultHook(BaseHook):
8989
:param kubernetes_jwt_path: Path for kubernetes jwt token (for ``kubernetes`` auth_type, default:
9090
``/var/run/secrets/kubernetes.io/serviceaccount/token``)
9191
:type kubernetes_jwt_path: str
92+
:param token_path: path to file containing authentication token to include in requests sent to Vault
93+
(for ``token`` and ``github`` auth_type).
94+
:type token_path: str
9295
:param gcp_key_path: Path to GCP Credential JSON file (for ``gcp`` auth_type)
9396
Mutually exclusive with gcp_keyfile_dict
9497
:type gcp_key_path: str
@@ -114,6 +117,7 @@ def __init__( # pylint: disable=too-many-arguments
114117
role_id: Optional[str] = None,
115118
kubernetes_role: Optional[str] = None,
116119
kubernetes_jwt_path: Optional[str] = None,
120+
token_path: Optional[str] = None,
117121
gcp_key_path: Optional[str] = None,
118122
gcp_scopes: Optional[str] = None,
119123
azure_tenant_id: Optional[str] = None,
@@ -178,6 +182,7 @@ def __init__( # pylint: disable=too-many-arguments
178182
mount_point=mount_point,
179183
kv_engine_version=kv_engine_version,
180184
token=self.connection.password,
185+
token_path=token_path,
181186
username=self.connection.login,
182187
password=self.connection.password,
183188
key_id=self.connection.login,

airflow/providers/hashicorp/secrets/vault.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ class VaultBackend(BaseSecretsBackend, LoggingMixin):
6969
:param token: Authentication token to include in requests sent to Vault.
7070
(for ``token`` and ``github`` auth_type)
7171
:type token: str
72+
:param token_path: path to file containing authentication token to include in requests sent to Vault
73+
(for ``token`` and ``github`` auth_type).
74+
:type token_path: str
7275
:param username: Username for Authentication (for ``ldap`` and ``userpass`` auth_type).
7376
:type username: str
7477
:param password: Password for Authentication (for ``ldap`` and ``userpass`` auth_type).
@@ -114,6 +117,7 @@ def __init__( # pylint: disable=too-many-arguments
114117
mount_point: str = 'secret',
115118
kv_engine_version: int = 2,
116119
token: Optional[str] = None,
120+
token_path: Optional[str] = None,
117121
username: Optional[str] = None,
118122
password: Optional[str] = None,
119123
key_id: Optional[str] = None,
@@ -143,6 +147,7 @@ def __init__( # pylint: disable=too-many-arguments
143147
mount_point=mount_point,
144148
kv_engine_version=kv_engine_version,
145149
token=token,
150+
token_path=token_path,
146151
username=username,
147152
password=password,
148153
key_id=key_id,

tests/providers/hashicorp/_internal_client/test_vault_client.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,21 @@ def test_token(self, mock_hvac):
478478
self.assertEqual(2, vault_client.kv_engine_version)
479479
self.assertEqual("secret", vault_client.mount_point)
480480

481+
@mock.patch("airflow.providers.hashicorp._internal_client.vault_client.hvac")
482+
def test_token_path(self, mock_hvac):
483+
mock_client = mock.MagicMock()
484+
mock_hvac.Client.return_value = mock_client
485+
with open('/tmp/test_token.txt', 'w+') as the_file:
486+
the_file.write('s.7AU0I51yv1Q1lxOIg1F3ZRAS')
487+
vault_client = _VaultClient(auth_type="token",
488+
token_path="/tmp/test_token.txt", url="http://localhost:8180")
489+
client = vault_client.client
490+
mock_hvac.Client.assert_called_with(url='http://localhost:8180')
491+
client.is_authenticated.assert_called_with()
492+
self.assertEqual("s.7AU0I51yv1Q1lxOIg1F3ZRAS", client.token)
493+
self.assertEqual(2, vault_client.kv_engine_version)
494+
self.assertEqual("secret", vault_client.mount_point)
495+
481496
@mock.patch("airflow.providers.hashicorp._internal_client.vault_client.hvac")
482497
def test_default_auth_type(self, mock_hvac):
483498
mock_client = mock.MagicMock()

0 commit comments

Comments
 (0)