1.0 Overview
The steps in this article describe a very manual process for importing Fortanix DSM keys into cloud providers. If you are looking for more automation or orchestration, see Cloud Data Control.
Here we will go over several ways to export Fortanix DSM keys to major cloud providers that support BYOK for server-side encryption. Pre-requisite: Download DSM CLI from here.
2.0 Google Cloud
2.1 GCS (Cloud Storage)
For GCS, actual base64 customer keys are needed to be provided for every upload and download of objects to GCS.
Create a 256-bit AES key in Fortanix DSM with the
EXPORT
key operation enabled.$ python sdkms-cli create-key --obj-type AES --key-size 256 --name Google-Cloud-Master-Key --exportable
Export this key on your application environment.
$ python sdkms-cli export-object --name Google-Cloud-Master-Key
Add the following option to the
GSUtil
section of GSUtil boto configuration file:encryption_key = [YOUR_ENCRYPTION_KEY] decryption_key1 = [YOUR_ENCRYPTION_KEY]
Now you can upload and download objects in GCS with encryption with your own keys.
$ gsutil cp [LOCAL_OBJECT_LOCATION] gs://[DESTINATION_BUCKET_NAME]/ $ gsutil cp gs://[BUCKET_NAME]/[OBJECT_NAME] [OBJECT_DESTINATION]
GCS browser shows that the object is customer encrypted.
2.2 GCE (Compute Engine)
GCE supports import of customer keys wrapped by a Google public key. Since Fortanix DSM supports wrapping natively, actual material of the customer keys are never exposed.
Create a 256-bit AES key in Fortanix DSM with the
EXPORT
key operation enabled.$ python sdkms-cli create-key --obj-type AES --key-size 256 --name Google-Cloud-Master-Key --exportable
Fetch Google public key.
$ curl "https://cloud-certs.storage.googleapis.com/google-cloud-csek-ingress.pem" -o google-cloud-csek-ingress.pem $ openssl x509 -pubkey -noout -in google-cloud-csek-ingress.pem > google-cloud-csek-public.pem
Import the Google public key in Fortanix DSM.
$ python sdkms-cli import-key --obj-type RSA --in google-cloud-csek-public.pem --name Google-Cloud-Public-Key
Wrap Fortanix DSM master key with Google public key, using Fortanix DSM.
$ sdkms-cli wrap-key --kid (kid of master key) --alg RSA --mode OAEP_MGF1_SHA1 --wrapping-kid (kid of the Google public key) --out rsawrappedkey.txt $ openssl enc -base64 -in rsawrappedkey.txt | tr -d '\n' | sed -e '$a\' > rsawrappedbase64key.txt
Set the key data in GCE as a wrapped key
6. The disk says that it's encrypted with customer keys.
3.0 AWS
AWS KMS provides a wrapping key and a token in order to import customer keys. The steps are very similar to Google Cloud GCE setup:
Create a 256-bit AES key in Fortanix DSM with
EXPORT
key operation enabled.$ python sdkms-cli create-key --obj-type AES --key-size 256 --name AWS-Master-Key --exportable
Initiate creation of key of external origin in KMS.
Download the zip containing the wrapping key and import token.
Import the AWS wrapping key in Fortanix DSM.
$ python sdkms-cli import-key --obj-type RSA --in wrappingKey_fcb572d3-6680-449c-91ab-ac3a5c07dc09_080410435 --name AWS-Wrapping-Key
Wrap DSM master key with AWS wrapping key, using Fortanix DSM.
$ sdkms-cli wrap-key --kid (kid of master key) --alg RSA --mode OAEP_MGF1_SHA256 --wrapping-kid (kid of the AWS wrapping key) --out rsawrappedkey.txt
AWS KMS supports importing raw value of a key. If you require base-64 encoded value of the key, use the following command:
$ openssl enc -base64 -in rsawrappedkey.txt | tr -d '\n' | sed -e '$a\' > rsawrappedbase64key.txt
Upload this wrapped key and the downloaded token to complete the import.
Use this imported key for server-side encryption in AWS Services. In S3 for example, one can enable this during bucket creation itself.
4.0 AWS Automated
Use the following script to automate BYOK in AWS
#!/bin/bash
# Install aws cli, sdkms-cli before running this script
# Setup environment variable and temporary files for storing key material
export FORTANIX_API_ENDPOINT=<FORTANIX_DSM_URL> #For example: https://amer.smrtkey.io
wrappingkey_file=$(mktemp)
import_token_file=$(mktemp)
wrapped_blob=$(mktemp)
# run aws configure and enter your access key, secret key, region, and default output format (text)
aws configure
# Create external key in AWS
aws_kid=$(aws kms create-key --origin EXTERNAL | awk '{print $6}')
# Get description of key
aws kms describe-key --key-id $aws_kid
# Get import parameters for external key created in AWS
params=$(aws kms get-parameters-for-import --key-id $aws_kid --wrapping-algorithm RSAES_OAEP_SHA_256 --wrapping-key-spec RSA_2048)
echo $params | awk '{print $4}' | base64 -D > $wrappingkey_file
echo $params | awk '{print $1}' | base64 -D > $import_token_file
# Login to DSM
sdkms-cli app-login
# Generate Key in DSM
key_name="AWS Key"$RANDOM
kid=$(sdkms-cli create-key --name "$key_name" --obj-type AES --key-size 256 --exportable -f)
# Import public key to DSM
wrapping_key_name="AWS wrapping key"$RANDOM
wrapping_kid=$(sdkms-cli import-key --in $wrappingkey_file --der --name "$wrapping_key_name" --obj-type RSA)
# Wrap DSMkey with wrapping key obtained from DSM
blobfile=$(mktemp)
sdkms-cli wrap-key --wrapping-kid $wrapping_kid --kid $kid --alg RSA --mode OAEP_MGF1_SHA256 --out $wrapped_blob
# Logout from DSM
sdkms-cli app-logout
# Import key to AWS
aws kms import-key-material --key-id $aws_kid --encrypted-key-material fileb://$wrapped_blob --import-token fileb://$import_token_file --expiration-model KEY_MATERIAL_DOES_NOT_EXPIRE
# Get description of key
aws kms describe-key --key-id $aws_kid
# Cleanup
rm $wrappingkey_file $import_token_file $wrapped_blob
5.0 Azure
Azure Key Vault supports the direct import of key material. Generate an exportable AES key in Fortanix DSM and export its value to upload the key to Azure.
Create a 256-bit AES key in Fortanix DSM with the
EXPORT
key operation enabled.$ python sdkms-cli create-key --obj-type AES --key-size 256 --name Azure-Cloud-Master-Key --exportable
Export this key on your application environment.
$ python sdkms-cli export-object --name Azure-Cloud-Master-Key
You have to choose to upload your key either as a software or hardware key depending on your requirement.
6.0 Alibaba
Create an external key in Alibaba.
Create a new key by selecting key material source as “External”.
Newly created key should show up with status as “Pending Import” and key material source as “External”.
Download key encryption material.
Download the key encryption material, you will need it for key wrapping in Fortanix DSM and key importing into Alibaba.Public key
Import Token
Import Alibaba public key into Fortanix DSM.
Import the public key from previous step into Fortanix DSM as RSA key.
Create Customer Master Key in Fortanix DSM.
Create a new AES key and make sure to select the “exportable” option.
Wrap customer master key with Alibaba public key.
Use sdkms-cli to wrap the newly created AES key (customer master key) with imported Alibaba public key.
$ sdkms-cli wrap-key --kid --alg RSA --mode OAEP_MGF1_SHA1 --wrapping-kid --out alibabawrap.key
Apply base64 encoding on the wrap key.
$ openssl enc -e -base64 -A -in alibabawrap.key -out alibabawrapbase64.key
Upload key into Alibaba KMS.
Import the encoded wrap key into Alibaba. You will also need the import token which we downloaded from Alibaba in Step 2.
Alibaba KMS should have external key enabled now.
With successful import your external key should be "Enabled" now.
7.0 Salesforce
Salesforce's Shield Platform Encryption is introducing a new pilot feature called Cache-Only Keys. This capability enhances the existing Bring Your Own Key (BYOK) capability by allowing customers to host their key material in a wrapped format which Salesforce will fetch as required. While this will be cached in an encrypted form, Salesforce will not retain or persist the key material in any system of record or backups.
Fortanix Fortanix DSM can be used as HSM backed Software-as-a-service(SAAS) for Fortanix - Salesforce Cache only BYOK solution. This guide explains how to use Fortanix Fortanix DSM to securely generate encryption key and configure in Salesforce’s Shield Platform.
8.0 Prerequisite
Salesforce account with permission to below settings.
Name Credentials
Certificate & Key Management
Key Management
DSM account with appropriate permissions to create groups, application (app), Security-object and plugin.
9.0 Fortanix DSM Setup
9.1 Create a Group in Fortanix DSM
Log in to Fortanix Fortanix DSM (for example: https://amer.smartkey.io)
Click the left navigation bar to navigate to the Groups menu item.
On the Groups page, click on (+) icon to create new group.
9.2 Create an App in Fortanix DSM
Click the DSM left navigation bar to navigate to the Apps menu item.
On the Apps page, click on the (+) icon to create a new app.
Enter desired information (refer below screenshot) and select above created group and click save.
Navigate to the Apps page to see the newly created app.
For the app created, click the copy API key. This will open a model window.
Go to USERNAME/PASSWORD tab in the View credentials window.
Copy and Save the username and password. These will be required later to configure “Named Credentials” in Salesforce later.
9.3 Create a Plugin in Fortanix DSM
Click the DSM left navigation bar to navigate to the Plugins menu item.
On the Plugins page, click the (+) button to create a new plugin.
Enter the plugin name.
Select the group created in Section 9.1: Create a Group in Fortanix DSM.
Copy and paste the plugin code and save. Show Plugin Code
-- start of plugin ----------------------------- -- start of helper methods ----------------------------- function Blob:base64_urlsafe() return (self:base64():gsub('+', '-'):gsub('/', '_'):gsub('=', '')) end function getNextKeyVersionLabelForVersion(name, version) avialableName = name .. '_V' .. version key = Sobject { name = avialableName } if not key then return avialableName else return getNextKeyVersionLabelForVersion(name, version+1); end end function getNextKeyVersionLabel(name) return getNextKeyVersionLabelForVersion(name, 1) end function createKey(keyname, isTransient) return Sobject.create { obj_type = 'AES', key_size = 256, key_ops = {'ENCRYPT ', 'DECRYPT', 'WRAPKEY', 'UNWRAPKEY', 'DERIVEKEY', 'EXPORT', 'APPMANAGEABLE'}, name = keyname, transient = isTransient } end function findOrCreateKey(kid, name) if not kid then cek = createKey(name, false) else cek = Sobject { kid = kid } end return cek; end function saveToOpaqueObject(name, value, desc) return Sobject.import { name = name, obj_type = 'OPAQUE', value = value, description = desc, transient = false }; end function validateInput(input) if not Sobject { kid = input.cert } then return 'Unable to generate Key data, Cert not found' end --check if dek uuid is passed, else perform already exist validation if not input.dek then if not input.name then return 'Pass uuid of existing key or name for new dek' end if Sobject { name = input.name } then return 'Key ['.. input.name .. '] already generated for input name [' .. input.name .. ']' end if Sobject { name = input.name .. '_meta_info'} then return 'Meta info ['.. input.name .. '_meta_info' .. '] already generated for input name [' .. input.name .. ']' end else --check if input.dek is valid and meta info not already generated for same dek = Sobject { kid = input.dek } if not dek then return 'Invalid dek [' .. input.dek .. ']' else if Sobject { name = dek.name .. '_meta_info' } then return 'Meta info ['.. dek.name .. '_meta_info' .. '] already generated for input dek uuid [' .. input.dek .. ']' end end end return nil end function generateKeyAndMetaData(input) errormsg = validateInput(input) if errormsg then return { error = errormsg } end -- use dek passed or generate new one dek = findOrCreateKey(input.dek, input.name) key_info = '{ "dek":"' .. dek.kid .. '", "cert": "' .. input.cert .. '"}'; opq_obj = saveToOpaqueObject( dek.name .. '_meta_info', Blob.from_bytes(key_info), 'DEK = ' .. dek.kid .. ', cert = ' .. input.cert ) return { opq_key_identifier = opq_obj.kid, dek = dek.kid}; end function generateJWEForKey(input, opq_key_identifier) -- Generate JWE token and return using meta info store in OPQ object -- -- Search for opaque object having BYOK key meta info if opq_key_identifier == nil then return 'Key identificer [opq_key_identifier] missing' else opq_meta_info = Sobject { kid = opq_key_identifier } end if not opq_meta_info then return 'Invalid key identificer passed ['.. opq_key_identifier ..']' end meta_info = json.decode(opq_meta_info.value:bytes()) dek = Sobject { kid = meta_info.dek } if not dek then return 'Invalid dek reference stored in metadata' end local salesforce_cert = Sobject { kid = meta_info.cert } if not salesforce_cert then return nil, 'Invalid cert stored in metadata' end --get next avialable name to avoid name conflict local keyname = getNextKeyVersionLabel(this_plugin().name); cek = createKey(keyname .. '_cek', true) local header = '{"alg":"RSA-OAEP","enc":"A256GCM","kid":"' .. opq_key_identifier .. '"}' -- header = Blob.from_bytes(header):base64_urlsafe() local wcek = assert(salesforce_cert:wrap { alg = 'RSA', subject = cek, mode = 'OAEP_MGF1_SHA1' }) local wdek = assert(cek:wrap { ad = Blob.from_bytes(header), --authentication data tag_len = 128, mode = 'GCM', subject = dek, alg = 'AES' }) local jweval = header .. '.' .. wcek.wrapped_key:base64_urlsafe() .. '.' .. wdek.iv:base64_urlsafe() .. '.' .. wdek.wrapped_key:base64_urlsafe() .. '.' .. wdek.tag:base64_urlsafe() return {kid= opq_key_identifier, jwe = jweval}; end ----------------------------- -- end of helper methods ---- ----------------------------- ----------------------------- -- start of main method ----------------------------- function run(input, url, method) -- Start Plugin called to generate a new BYOK Key if method == "POST" then -- Generate DEK and store in opq_obj along with other meta info for future API calls return generateKeyAndMetaData(input) else -- Generate JWE token and return using meta info store in OPQ object -- return generateJWEForKey(input, url.path[6]) end ----------------------------- -- End of main method ----------------------------- end -- end of plugin
Copy and save the UUID of plugin created for future configuration.
9.4 Generate and Download Self-Signed Certificate in Salesforce
Log in to Salesforce. Go to Setup.
Create a (Self Signed) certificate under Security >> Certificate and Key Management with below setting.
Disable Exportable Private Key.
Select the check box for Use Platform Encryption.
Please refer to the Salesforce documentation for more info on “Certificate and Key Management”.
After the certificate is created, download it.
Download the certificate and save to your desired location.
9.5 Import Certificate to Fortanix DSM
Log in to Fortanix DSM.
Click the DSM left navigation bar to navigate to the Security Objects menu item.
On the Security Objects page, click the (+) button to create a new security object.
Enter the name of the security object and select the group created in Section 9.1: Create a Group in Fortanix DSM.
Click the IMPORT button.
Choose the value format as BASE 64.
Choose the security object type as Certificate.
Click the UPLOAD A FILE button to upload the certificate downloaded in Section 9.4: Generate and Download Self-Signed Certificate in Salesforce, Step 5.
Click the IMPORT button to import the certificate into Fortanix DSM as a security object.
10.0 Salesforce Setup
10.1 Define Name Credential in Salesforce
Log in to Salesforce. Go to Setup.
Click Named Credentials under Security in the left navigation bar.
Click the button: New Named Credential. It will open a screen to create a Name Credential.
Enter details for the named credential
Enter the Label and Name of your choice
Enter URL as below (UUID of the plugin created in DSM setup Section 9.3: Create a Plugin in Fortanix DSM) https://<FORTANIX_DSM_URL>/sys/v1/plugins/invoke/<UUID>
Select Identity Type as Named Principal and Authentication Protocol as Password Authentication.
Enter the username and password of Fortanix DSM created in Fortanix DSM setup Section 9.2: Create an App in Fortanix DSM and click Save.
11.0 Steps to Generate Encryption Keys and Import them to Salesforce
We can generate as many keys as we want with DSM and configure them in Salesforce using the steps mentioned below. Whenever customer wants to rotate key, simply execute the plugin and generate a new key. The same needs to be configured in Salesforce afterwards.
11.1 Generate JWE Token (BYOK Cache only KEY) Using the Plugin.
Go to the plugin created in Section 9.3: Create a Plugin in Fortanix DSM.
Click the ADD TEST INPUT button on the right side.
Enter the below payload in the text box
{ "cert" : , "name": "" }
Click RUN TEST.
The plugin generates security objects (AES encryption key and meta information) in Fortanix DSM and returns their UUID.
Copy the value of theopq_key_identifier
field in the response body.
This would be required while setting up BYOK in Salesforce.dek
: is UUID of the AES encryption key generated by plugin and stored securely in Fortanix DSM. Salesforce will use it as the data encryption key.opq_key_identifier
: Fortanix DSM plugin also generates a security object of type “OPAQUE”. It contains meta information to generate response (JWE Token) required by Salesforce. Meta information has the following information:AES Encryption key UUID (
dek
)UUID of the certificate used.
When the Salesforce platform calls the Fortanix DSM plugin to fetch encryption keys. Plugin reads meta information from opaque object and processes dek key material and certificate used (while generating meta info and AES initially) to generate JWE token. The same is returned to salesforce in desired JSON format.
Refer to Salesforce documentation for more info on the JWE token.
dek
value is AES encryption key which generated by plugin and the key is stored in Fortanix DSM. The key material would be securely transferred to Salesforce as part of the JWE token.Go to the Security Objects page to see newly created key.
11.2: Configure Salesforce to Use Fortanix DSM to Fetch Cache-only Key at Runtime
Go to Setup >> Security >> Platform Encryption >> Key Management.
Click the Bring Your Own Key button.
Select the desired certificate to be used (it should be the same as the one used while executing the plugin to generate the encryption key and meta information).
Select the Use a Cache-Only Key radio button.
Select Named Credential created with the Fortanix DSM endpoint.
Enter the BYOK ID (
opq_key_identifier
) generated by the Fortanix DSM plugin in the previous Section 11.1: Generate JWE Token.Click Save.
After the configuration is saved, Salesforce will call Fortanix DSM to fetch the JWE token and decrypt it with the private key of the certificate.
You can see the newly imported key on the Key Management screen.
11.3: Verify Key Import in Fortanix Fortanix DSM Event Logs
Logs are generated in Fortanix Fortanix DSM while fetching encryption keys during setup.
Go to the Event Logs in Fortanix DSM to verify (refer to the below screenshot).
Logs are also generated later when Salesforce calls Fortanix DSM to fetch encryption keys at runtime.