From 6879f0978d859ed090cb0925dd0194451a6732cc Mon Sep 17 00:00:00 2001 From: Daniel Coelho Date: Fri, 16 Jul 2021 15:24:42 -0700 Subject: [PATCH 1/3] External Provider Integration Template App - AKV and file renames --- .../README.md | 2 +- .../kms_plugin_app/app.py | 8 +- .../kms_plugin_app/custom_akv.py | 105 ++++++++++++++++++ .../{custom2.py => custom_hcv.py} | 0 .../{custom.py => custom_softhsm.py} | 0 .../kms_plugin_app/requirements.txt | 2 + 6 files changed, 112 insertions(+), 5 deletions(-) create mode 100644 samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/custom_akv.py rename samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/{custom2.py => custom_hcv.py} (100%) rename samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/{custom.py => custom_softhsm.py} (100%) diff --git a/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/README.md b/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/README.md index c739cb9d6b..9ee8bc2afa 100644 --- a/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/README.md +++ b/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/README.md @@ -1,6 +1,6 @@ # SQL Server BDC Encryption at Rest -This folder contains the AppDeploy template application for integration with external key providers (such as HSMs, HashiCorp Vault, etc). +This folder contains the AppDeploy template application for integration with external key providers (such as HSMs, HashiCorp Vault, Azure Key Vault, etc). The folder kms_plugin_app should be downloaded as a zip file for usage in respect of the instructions at [External Key Providers](https://docs.microsoft.com/sql/big-data-cluster/encryption-at-rest-external-provider). diff --git a/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/app.py b/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/app.py index 72d14dd855..0d19cefd37 100644 --- a/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/app.py +++ b/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/app.py @@ -8,7 +8,7 @@ from constants import ConfigurationConstants, Operations import utils from json_objects import EncryptDecryptRequest -import custom2 +import custom def handler(operation, payload, pin, key_attributes, version): """ @@ -45,16 +45,16 @@ def get_key(json_key_attributes_dict, pin, version): """ Call in to the custom key store module to get the key. """ - return custom2.get_key(json_key_attributes_dict, pin, version) + return custom.get_key(json_key_attributes_dict, pin, version) def wrap_key(request, json_key_attributes_dict, pin, version): """ Call in to the custom key store module to encrypt. """ - return custom2.encrypt(request, json_key_attributes_dict, pin, version) + return custom.encrypt(request, json_key_attributes_dict, pin, version) def unwrap_key(request, json_key_attributes_dict, pin, version): """ Call in to the custom key store module to decrypt. """ - return custom2.decrypt(request, json_key_attributes_dict, pin, version) + return custom.decrypt(request, json_key_attributes_dict, pin, version) diff --git a/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/custom_akv.py b/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/custom_akv.py new file mode 100644 index 0000000000..b850754ddd --- /dev/null +++ b/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/custom_akv.py @@ -0,0 +1,105 @@ +# Placeholder for adding logic specific to application +# and backend key store. +# +import os +import json +import sys +from azure.identity import DefaultAzureCredential +from azure.keyvault.keys import KeyClient +from azure.keyvault.keys.crypto import CryptographyClient, EncryptionAlgorithm +# Append the current application path to sys path to be able to resolve local modules. +# +sys.path.append('.') +sys.path.append('./model') +from constants import ConfigurationConstants, Operations, CryptoConstants +import utils +from json_objects import EncryptDecryptRequest, JsonWebKeyResponse, EncryptDecryptResponse + + +def decrypt(request, json_key_attributes_dict, pin, version): + """ + This method will be called by the application entry point + for decrypting the payload. + request.value has the plaintext payload + request.alg contains the padding algorithm for encryption. + """ + set_env(json_key_attributes_dict, pin) + credential = DefaultAzureCredential() + key_vault_key = get_akv_key(json_key_attributes_dict, credential) + crypto_client = CryptographyClient(key_vault_key, credential=credential) + decrypted_payload = crypto_client.decrypt(EncryptionAlgorithm.rsa_oaep, request.value) + response = EncryptDecryptResponse(decrypted_payload.plaintext) + return response + +def encrypt(request, json_key_attributes_dict, pin, version): + """ + This method will be called by the application entry point + for encrypting the payload. + request.value has the plaintext payload + request.alg contains the padding algorithm for encryption. + """ + set_env(json_key_attributes_dict, pin) + credential = DefaultAzureCredential() + key_vault_key = get_akv_key(json_key_attributes_dict, credential) + crypto_client = CryptographyClient(key_vault_key, credential=credential) + encrypted_payload = crypto_client.encrypt(EncryptionAlgorithm.rsa_oaep, request.value) + response = EncryptDecryptResponse(encrypted_payload.ciphertext) + return response + +def get_key(json_key_attributes_dict, pin, version): + set_env(json_key_attributes_dict, pin) + credential = DefaultAzureCredential() + + key_vault_key = get_akv_key(json_key_attributes_dict, credential) + + # JsonWebKeyResponse expects integer inputs and converts them to byte array + # However AKV SDK already provides byte arrays for Exponent and Modulus. + # We will instantiate the object with a dummy value and then overwrite the + # exponent and module value. + # + dummy_val = 1 + key_response = JsonWebKeyResponse(1,1) + key_response.e = utils.urlsafe_b64encode_as_str(key_vault_key.key.e) + key_response.n = utils.urlsafe_b64encode_as_str(key_vault_key.key.n) + return key_response + +def get_akv_key(json_key_attributes_dict, credential): + """ + Gets the AKV key object. + """ + if "vault_url" in json_key_attributes_dict: + vault_url = json_key_attributes_dict["vault_url"] + else: + raise KeyError('vault_url was expected in the parameters but not found') + + if "keyname" in json_key_attributes_dict: + key_name = json_key_attributes_dict["keyname"] + else: + raise KeyError('keyname was expected in the parameters but not found') + if "keyversion" in json_key_attributes_dict: + key_version = json_key_attributes_dict["keyversion"] + else: + raise KeyError('keyversion was expected in the parameters but not found') + + key_client = KeyClient(vault_url=vault_url, credential=credential) + key_vault_key = key_client.get_key(key_name, key_version) + + return key_vault_key + +def set_env(json_key_attributes_dict, pin): + """ + Sets the environment variables for the MS identity credential lookup to work. + """ + if "azure_client_id" in json_key_attributes_dict: + key_version = json_key_attributes_dict["azure_client_id"] + else: + raise KeyError('azure_client_id was expected in the parameters but not found') + + if "azure_tenant_id" in json_key_attributes_dict: + key_version = json_key_attributes_dict["azure_tenant_id"] + else: + raise KeyError('azure_tenant_id was expected in the parameters but not found') + + os.environ["AZURE_CLIENT_ID"]=json_key_attributes_dict["azure_client_id"] + os.environ["AZURE_TENANT_ID"]=json_key_attributes_dict["azure_tenant_id"] + os.environ["AZURE_CLIENT_SECRET"]=pin diff --git a/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/custom2.py b/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/custom_hcv.py similarity index 100% rename from samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/custom2.py rename to samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/custom_hcv.py diff --git a/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/custom.py b/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/custom_softhsm.py similarity index 100% rename from samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/custom.py rename to samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/custom_softhsm.py diff --git a/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/requirements.txt b/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/requirements.txt index f12d87ffc3..da29fd0e60 100644 --- a/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/requirements.txt +++ b/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/requirements.txt @@ -2,3 +2,5 @@ pycrypto==2.6.1 pycryptodome==3.10.1 cryptography==3.2.1 hvac==0.10.11 +azure-identity==1.6.0 +azure-keyvault-keys==4.3.1 From f071f121c640d62041694391f512ee11db709921 Mon Sep 17 00:00:00 2001 From: Daniel Coelho Date: Fri, 16 Jul 2021 15:37:18 -0700 Subject: [PATCH 2/3] External Provider Integration Template App - AKV and file renames - one more fix --- .../kms_plugin_app/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/app.py b/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/app.py index 0d19cefd37..0a01586bd1 100644 --- a/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/app.py +++ b/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/app.py @@ -8,7 +8,7 @@ from constants import ConfigurationConstants, Operations import utils from json_objects import EncryptDecryptRequest -import custom +import custom_softhsm def handler(operation, payload, pin, key_attributes, version): """ From 965653b4be13d1c75366b63e94635a366f405293 Mon Sep 17 00:00:00 2001 From: Daniel Coelho Date: Fri, 16 Jul 2021 15:42:10 -0700 Subject: [PATCH 3/3] External Provider Integration Template App - AKV and file renames - last one --- .../kms_plugin_app/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/app.py b/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/app.py index 0a01586bd1..75ae49001b 100644 --- a/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/app.py +++ b/samples/features/sql-big-data-cluster/security/encryption-at-rest-external-key-provider/kms_plugin_app/app.py @@ -8,7 +8,7 @@ from constants import ConfigurationConstants, Operations import utils from json_objects import EncryptDecryptRequest -import custom_softhsm +import custom_softhsm as custom def handler(operation, payload, pin, key_attributes, version): """