From 94619de8c358f6baa0c689fdf1e53360ffb34afb Mon Sep 17 00:00:00 2001 From: Jin Chi He Date: Tue, 27 Aug 2019 11:50:41 +0800 Subject: [PATCH] sdk client supports setting azure creds (#312) --- docs/samples/azure/README.md | 1 + python/kfserving/docs/KFServingClient.md | 14 ++++++++-- python/kfserving/kfserving/api/creds_utils.py | 28 +++++++++++++++++++ .../kfserving/api/kf_serving_client.py | 10 +++++-- .../kfserving/constants/constants.py | 3 ++ python/kfserving/test/azure_credentials.json | 6 ++++ python/kfserving/test/test_set_creds.py | 17 +++++++++++ 7 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 python/kfserving/test/azure_credentials.json diff --git a/docs/samples/azure/README.md b/docs/samples/azure/README.md index 30a1796c11c..e97dddf71f3 100644 --- a/docs/samples/azure/README.md +++ b/docs/samples/azure/README.md @@ -22,6 +22,7 @@ kind: Secret metadata: name: azcreds type: Opaque +data: AZ_CLIENT_ID: xxxxx AZ_CLIENT_SECRET: xxxxx AZ_SUBSCRIPTION_ID: xxxxx diff --git a/python/kfserving/docs/KFServingClient.md b/python/kfserving/docs/KFServingClient.md index 311483089e3..0c9fddec426 100644 --- a/python/kfserving/docs/KFServingClient.md +++ b/python/kfserving/docs/KFServingClient.md @@ -57,6 +57,16 @@ KFServing.set_credentials(storage_type='S3', s3_verify_ssl='0') ``` +Example for creating Azure credentials. +```python +from kfserving import KFServingClient + +KFServing = KFServingClient() +KFServing.set_credentials(storage_type='Azure', + namespace='kubeflow', + credentials_file='/path/azure_credentials.json') +``` + The created or patched `Secret` and `Service Account` will be shown as following: ``` INFO:kfserving.api.set_credentials:Created Secret: kfserving-secret-6tv6l in namespace kubeflow @@ -66,9 +76,9 @@ INFO:kfserving.api.set_credentials:Created (or Patched) Service account: kfservi ### Parameters Name | Type | Storage Type | Description ------------ | ------------- | ------------- | ------------- -storage_type | str | All |Required. Valid values: GCS or S3 | +storage_type | str | All |Required. Valid values: GCS, S3 or Azure | namespace | str | All |Optional. The kubernetes namespace. Defaults to current or default namespace.| -credentials_file | str | All |Optional. The path for the GCS or S3 credentials file. The default file for GCS is `~/.config/gcloud/application_default_credentials.json`, and default file for S3 is `~/.aws/credentials`. | +credentials_file | str | All |Optional. The path for the credentials file. The default file for GCS is `~/.config/gcloud/application_default_credentials.json`, see the [instructions](https://cloud.google.com/sdk/gcloud/reference/auth/application-default/login) on creating the GCS credentials file. For S3 is `~/.aws/credentials`, see the [instructions](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/setup-credentials.html) on creating the S3 credentials file. For Azure is `~/.azure/azure_credentials.json`, see the [instructions](https://docs.microsoft.com/en-us/azure/python/python-sdk-azure-authenticate#mgmt-auth-file) on creating the Azure credentials file. | service_account | str | All |Optional. The name of service account. Supports specifying the `service_account`, or using default Service Account `kfserving-service-credentials`. If the Service Account does not exist, the API will create it and attach the created Secret with the Service Account, if exists, only patch it to attach the created Secret.| s3_endpoint | str | S3 only |Optional. The S3 endpoint. | s3_region | str | S3 only|Optional. The S3 region By default, regional endpoint is used for S3.| | diff --git a/python/kfserving/kfserving/api/creds_utils.py b/python/kfserving/kfserving/api/creds_utils.py index 50a6ab7a211..babf5cc4c7e 100644 --- a/python/kfserving/kfserving/api/creds_utils.py +++ b/python/kfserving/kfserving/api/creds_utils.py @@ -112,6 +112,34 @@ def set_s3_credentials(namespace, credentials_file, service_account, s3_profile= service_account=service_account, secret_name=secret_name) +def set_azure_credentials(namespace, credentials_file, service_account): + ''' + Set Azure Credentails (secret and service account) with credentials file. + Args: + namespace(str): The kubernetes namespace. + credentials_file(str): The path for the Azure credentials file. + service_account(str): The name of service account. If the service_account + is specified, will attach created secret with the service account, + otherwise will create new one and attach with created secret. + ''' + + with open(expanduser(credentials_file)) as azure_creds_file: + azure_creds = json.load(azure_creds_file) + + data = { + 'AZ_CLIENT_ID': azure_creds['clientId'], + 'AZ_CLIENT_SECRET': azure_creds['clientSecret'], + 'AZ_SUBSCRIPTION_ID': azure_creds['subscriptionId'], + 'AZ_TENANT_ID': azure_creds['tenantId'], + } + + secret_name = create_secret( + namespace=namespace, data=data) + + set_service_account(namespace=namespace, + service_account=service_account, + secret_name=secret_name) + def create_secret(namespace, annotations=None, data=None, string_data=None): 'Create namespaced secret, and return the secret name.' diff --git a/python/kfserving/kfserving/api/kf_serving_client.py b/python/kfserving/kfserving/api/kf_serving_client.py index 93d25203c6c..ed1f8564e39 100644 --- a/python/kfserving/kfserving/api/kf_serving_client.py +++ b/python/kfserving/kfserving/api/kf_serving_client.py @@ -16,7 +16,7 @@ from ..constants import constants from ..utils import utils -from .creds_utils import set_gcs_credentials, set_s3_credentials +from .creds_utils import set_gcs_credentials, set_s3_credentials, set_azure_credentials class KFServingClient(object): @@ -62,8 +62,14 @@ def set_credentials(self, storage_type, namespace=None, credentials_file=None, credentials_file=credentials_file, service_account=service_account, **kwargs) + elif storage_type.lower() == 'azure': + if credentials_file is None: + credentials_file = constants.AZ_DEFAULT_CREDS_FILE + set_azure_credentials(namespace=namespace, + credentials_file=credentials_file, + service_account=service_account) else: - raise RuntimeError("Invalid storage_type: %s, only support GCS and S3\ + raise RuntimeError("Invalid storage_type: %s, only support GCS, S3 and Azure\ currently.\n" % storage_type) diff --git a/python/kfserving/kfserving/constants/constants.py b/python/kfserving/kfserving/constants/constants.py index e3691a90f47..233f5ff3dcb 100644 --- a/python/kfserving/kfserving/constants/constants.py +++ b/python/kfserving/kfserving/constants/constants.py @@ -18,3 +18,6 @@ # GCS credentials constants GCS_CREDS_FILE_DEFAULT_NAME = 'gcloud-application-credentials.json' GCS_DEFAULT_CREDS_FILE = '~/.config/gcloud/application_default_credentials.json' + +# Azure credentials constants +AZ_DEFAULT_CREDS_FILE = '~/.azure/azure_credentials.json' diff --git a/python/kfserving/test/azure_credentials.json b/python/kfserving/test/azure_credentials.json new file mode 100644 index 00000000000..bb0a2ecd68c --- /dev/null +++ b/python/kfserving/test/azure_credentials.json @@ -0,0 +1,6 @@ +{ + "clientId": "YTJhYjExYWYtMDFhYS00NzU5LTgzNDUtNzgwMzI4N2RiZD", + "clientSecret": "password", + "subscriptionId": "MzMzMzMzMzMtMzMzMy0zMzMzLTMzMzMtMzMzMzMz", + "tenantId": "QUJDREVGR0gtMTIzNC0xMjM0LTEyMzQtQUJDREVGR0hJSk" +} diff --git a/python/kfserving/test/test_set_creds.py b/python/kfserving/test/test_set_creds.py index 3b0d0e77552..dd7927f131b 100644 --- a/python/kfserving/test/test_set_creds.py +++ b/python/kfserving/test/test_set_creds.py @@ -93,3 +93,20 @@ def test_set_credentials_gcp(): created_secret_name = created_sa.secrets[0].name created_secret = get_created_secret(created_secret_name) assert created_secret.data[constants.GCS_CREDS_FILE_DEFAULT_NAME] == gcp_testing_creds + + +def test_azure_credentials(): + '''Test Azure credentials creating''' + KFServing = KFServingClient() + sa_name = constants.DEFAULT_SA_NAME + KFServing.set_credentials(storage_type='Azure', + namespace='kubeflow', + credentials_file='./azure_credentials.json', + sa_name=sa_name) + created_sa = get_created_sa(sa_name) + created_secret_name = created_sa.secrets[0].name + created_secret = get_created_secret(created_secret_name) + assert created_secret.data['AZ_CLIENT_ID'] == 'YTJhYjExYWYtMDFhYS00NzU5LTgzNDUtNzgwMzI4N2RiZD' + assert created_secret.data['AZ_CLIENT_SECRET'] == 'password' + assert created_secret.data['AZ_SUBSCRIPTION_ID'] == 'MzMzMzMzMzMtMzMzMy0zMzMzLTMzMzMtMzMzMzMz' + assert created_secret.data['AZ_TENANT_ID'] == 'QUJDREVGR0gtMTIzNC0xMjM0LTEyMzQtQUJDREVGR0hJSk'