You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by po...@apache.org on 2020/06/29 13:21:22 UTC

[airflow] 16/37: Support k8s auth method in Vault Secrets provider (#8640)

This is an automated email from the ASF dual-hosted git repository.

potiuk pushed a commit to branch v1-10-test
in repository https://gitbox.apache.org/repos/asf/airflow.git

commit 05d033b5b53f2e1e48ab95941213e38d0dc5fcea
Author: Aaron Son <aa...@liquidata.co>
AuthorDate: Sun May 3 16:10:25 2020 -0700

    Support k8s auth method in Vault Secrets provider (#8640)
    
    (cherry picked from commit d8cb0b5ddb02d194742e374d9ac90dd8231f6e80)
---
 airflow/contrib/secrets/hashicorp_vault.py    | 17 ++++++++++++++++-
 tests/contrib/secrets/test_hashicorp_vault.py | 27 +++++++++++++++++++++++++++
 2 files changed, 43 insertions(+), 1 deletion(-)

diff --git a/airflow/contrib/secrets/hashicorp_vault.py b/airflow/contrib/secrets/hashicorp_vault.py
index 8713733..8f6b53c 100644
--- a/airflow/contrib/secrets/hashicorp_vault.py
+++ b/airflow/contrib/secrets/hashicorp_vault.py
@@ -58,7 +58,7 @@ class VaultBackend(BaseSecretsBackend, LoggingMixin):
     :param url: Base URL for the Vault instance being addressed.
     :type url: str
     :param auth_type: Authentication Type for Vault (one of 'token', 'ldap', 'userpass', 'approle',
-        'github', 'gcp). Default is ``token``.
+        'github', 'gcp', 'kubernetes'). Default is ``token``.
     :type auth_type: str
     :param mount_point: The "path" the secret engine was mounted on. (Default: ``secret``)
     :type mount_point: str
@@ -73,6 +73,11 @@ class VaultBackend(BaseSecretsBackend, LoggingMixin):
     :type password: str
     :param role_id: Role ID for Authentication (for ``approle`` auth_type)
     :type role_id: str
+    :param kubernetes_role: Role for Authentication (for ``kubernetes`` auth_type)
+    :type kubernetes_role: str
+    :param kubernetes_jwt_path: Path for kubernetes jwt token (for ``kubernetes`` auth_type, deafult:
+        ``/var/run/secrets/kubernetes.io/serviceaccount/token``)
+    :type kubernetes_jwt_path: str
     :param secret_id: Secret ID for Authentication (for ``approle`` auth_type)
     :type secret_id: str
     :param gcp_key_path: Path to GCP Credential JSON file (for ``gcp`` auth_type)
@@ -92,6 +97,8 @@ class VaultBackend(BaseSecretsBackend, LoggingMixin):
         username=None,  # type: Optional[str]
         password=None,  # type: Optional[str]
         role_id=None,  # type: Optional[str]
+        kubernetes_role=None,  # type: Optional[str]
+        kubernetes_jwt_path='/var/run/secrets/kubernetes.io/serviceaccount/token',  # type: str
         secret_id=None,  # type: Optional[str]
         gcp_key_path=None,  # type: Optional[str]
         gcp_scopes=None,  # type: Optional[str]
@@ -107,6 +114,8 @@ class VaultBackend(BaseSecretsBackend, LoggingMixin):
         self.username = username
         self.password = password
         self.role_id = role_id
+        self.kubernetes_role = kubernetes_role
+        self.kubernetes_jwt_path = kubernetes_jwt_path
         self.secret_id = secret_id
         self.mount_point = mount_point
         self.kv_engine_version = kv_engine_version
@@ -132,6 +141,12 @@ class VaultBackend(BaseSecretsBackend, LoggingMixin):
             _client.auth_userpass(username=self.username, password=self.password)
         elif self.auth_type == "approle":
             _client.auth_approle(role_id=self.role_id, secret_id=self.secret_id)
+        elif self.auth_type == "kubernetes":
+            if not self.kubernetes_role:
+                raise VaultError("kubernetes_role cannot be None for auth_type='kubernetes'")
+            with open(self.kubernetes_jwt_path) as f:
+                jwt = f.read()
+                _client.auth_kubernetes(role=self.kubernetes_role, jwt=jwt)
         elif self.auth_type == "github":
             _client.auth.github.login(token=self.token)
         elif self.auth_type == "gcp":
diff --git a/tests/contrib/secrets/test_hashicorp_vault.py b/tests/contrib/secrets/test_hashicorp_vault.py
index 0d52c3a..f027ad7 100644
--- a/tests/contrib/secrets/test_hashicorp_vault.py
+++ b/tests/contrib/secrets/test_hashicorp_vault.py
@@ -234,3 +234,30 @@ class TestVaultSecrets(TestCase):
 
         with six.assertRaisesRegex(self, VaultError, "token cannot be None for auth_type='token'"):
             VaultBackend(**kwargs).get_connections(conn_id='test')
+
+    def test_auth_type_kubernetes_without_role_raises_error(self):
+        kwargs = {
+            "auth_type": "kubernetes",
+            "url": "http://127.0.0.1:8200",
+        }
+
+        with six.assertRaisesRegex(self, VaultError,
+                                   "kubernetes_role cannot be None for auth_type='kubernetes'"):
+            VaultBackend(**kwargs).get_connections(conn_id='test')
+
+    def test_auth_type_kubernetes_with_unreadable_jwt_raises_error(self):
+        path = "/var/tmp/this_does_not_exist/334e918ef11987d3ef2f9553458ea09f"
+        kwargs = {
+            "auth_type": "kubernetes",
+            "kubernetes_role": "default",
+            "kubernetes_jwt_path": path,
+            "url": "http://127.0.0.1:8200",
+        }
+
+        if six.PY2:
+            error_ = IOError
+        else:
+            error_ = FileNotFoundError
+
+        with six.assertRaisesRegex(self, error_, path):
+            VaultBackend(**kwargs).get_connections(conn_id='test')