Manually Importing Fortanix Data Security Manager keys into Cloud Providers

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. Requisite: Download SDKMS CLI from here.

Google Cloud

GCS (Cloud Storage)

For GCS, actual base64 customer keys are needed to be provided for every upload and download of objects to GCS.

1. 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

2. Export this key on your application environment.

$ python sdkms-cli export-object --name Google-Cloud-Master-Key

3. Add the following option to the GSUtil section of GSUtil boto configuration file:

encryption_key = [YOUR_ENCRYPTION_KEY]
decryption_key1 = [YOUR_ENCRYPTION_KEY]

4. 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]

5. GCS browser shows that the object is customer encrypted.

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.

1. 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

2. 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

3. 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

4. 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

5. Set the key data in GCE as a wrapped key

6. The disk says that it's encrypted with customer keys.

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:

1. Create a 256-bit AES key in Fortanix DSM withEXPORT key operation enabled.

$ python sdkms-cli create-key --obj-type AES --key-size 256 --name AWS-Master-Key --exportable

2. Initiate creation of key of external origin in KMS.

3. Download the zip containing the wrapping key and import token.

4. 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

5. Wrap SDKMS 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

 

6. Upload this wrapped key and the downloaded token to complete the import.

7. Use this imported key for server-side encryption in AWS Services. In S3 for example, one can enable this during bucket creation itself.

AWS

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=https://sdkms.fortanix.com
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 SDKMS
sdkms-cli app-login
 
# Generate Key in SDKMS
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 SDKMS
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 SDKMS key with wrapping key obtained from SDKMS
blobfile=$(mktemp)
sdkms-cli wrap-key --wrapping-kid $wrapping_kid --kid $kid --alg RSA --mode OAEP_MGF1_SHA256 --out $wrapped_blob
 
# Logout from SDKMS
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

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.

1. 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
 

2. 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.

Alibaba

1. Create an external key in Alibaba.

1a. Create a new key by selecting key material source as “External”.

Alibaba-1a.png

1b. Newly created key should show up with status as “Pending Import” and key material source as “External”.

Alibaba-1b.png

2. 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

Alibaba-2.png

3. Import Alibaba public key into Fortanix DSM.

Import the public key from previous step into Fortanix DSM as RSA key.

Alibaba-3.png

4. Create Customer Master Key in Fortanix DSM.

Create a new AES key and make sure to select the “exportable” option.

Alibaba-4.png

5. Wrap customer master key with Alibaba public key.

5a. Use sdkms-cli to wrap the newly created AES key (customer master key) with imported Alibaba public key.

$ sdkms-cli wrap-key --kid <customer master key> --alg RSA --mode OAEP_MGF1_SHA1 --wrapping-kid <Alibaba public key> --out alibabawrap.key 

5b. Apply base64 encoding on the wrap key.

$ openssl enc -e -base64 -A -in alibabawrap.key -out alibabawrapbase64.key

6. 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-6.png

7. Alibaba KMS should have external key enabled now.

With successful import your external key should be "Enabled" now.

Alibaba-7.png

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.

Prerequisite

1. Salesforce account with permission to below settings.

a. Name Credentials
b. Certificate & Key Management
c. Key Management

2. SDKMS account with appropriate permissions to create groups, app, security object and plugin.

Fortanix DSM Setup

Step 1: Create Group in Fortanix DSM

1. Log in to Fortanix Fortanix DSM (https://sdkms.fortanix.com)

2. Click on the left navigation bar to navigate to “Groups”

SalesforceBYOKSdkms-Step1.2.png

3. Click on (+) icon to create new group.

SalesforceBYOKSdkms-Step1.3.png

Step 2: Create an APP in Fortanix Fortanix DSM.

1. Click on left navigation bar to navigate to “Apps”

SalesforceBYOKSdkms-Step2.1.png

2. Click on (+) icon to create new app.

3. Enter desired information (refer below screenshot) and select above created group and click save.

SalesforceBYOKSdkms-Step2.3.png

4. Navigate to Apps dashboard to see newly created app.

5. Click on copy API key. It will open a model window.

6. Go to USERNAME/PASSWORD tab in model window.

SalesforceBYOKSdkms-Step2.6.png

7. Copy and Save username / password. Details will be required later to configure “Named Credentials” in salesforce later.

Step 3: Create plugin in Fortanix DSM

1. Click on “Plugins” tab on left navigation panel.

2. Click on (+) button to create new plugin.

3. Enter <plugin name>

SalesforceBYOKSdkms-Step3.3.png

4. Select “Group” created in Step 1.

5. Copy and paste code 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

6. Copy and save UUID of plugin created for future configuration.

Step 4: Generate and Download Self Signed Certificate in Salesforce

1. Login to Salesforce. Go to “Setup”.

2. Create a (Self Signed) certificate under Security >> Certificate and Key Management with below setting.

3. Disable Exportable Private key.

4. Check box to “Use Platform Encryption.

SalesforceBYOKSdkms-Step4.4.png

Please refer Salesforce documentation for more info on “Certificate and Key Management”.

5. Once certificate is created, please download it.

SalesforceBYOKSdkms-Step4.5.png

Download certificate and save to your desired location.

Step 5: Import Certificate to Fortanix Fortanix DSM

1. log in to Fortanix DSM.

2. Click on the left navigation bar to navigate to the “Security Objects” tab.

SalesforceBYOKSdkms-Step5.2.png

3. Click on (+) button to create new Security object.

4. Enter the name of the security object and select the Group created in Step 1.

5. Click the “IMPORT” button.

SalesforceBYOKSdkms-Step5.5.png

6. Choose the value format as “BASE 64”.

7. Choose the Security Object type as “Certificate”.

8. Click the “Upload a file” button to upload the converted certificate in Step 4.5.

9. Click the IMPORT button to import the certificate into Fortanix DSM as a security object.

SalesforceBYOKSdkms-Step5.9.png

Salesforce Setup

Step 6: Define Name Credential in Salesforce

1. Log in to Salesforce. Go to “Setup”.

2. Click on “Named Credentials” under Security in the left navigation bar.

SalesforceBYOKSdkms-Step6.2.png

Click the button: New Named Credential. It will open a screen to create a Name Credential.

SalesforceBYOKSdkms-Step6.2.1.png

3. Enter details for the named credential

a. Enter the Label & Name of your choice b. Enter URL as below (uuid: uuid of plugin created in SDKMS setup Step 3 )https://www.sdkms.fortanix.com/sys/v1/plugins/invoke/uuid

c. Select Identity Type as “Named Principal” and Authentication protocol as “Password Authentication”.

d. Enter username and password of Fortanix DSM created in Fortanix DSM  setup Step 2 and click Save.

SalesforceBYOKSdkms-Step6.3.png

Steps to generate encryption keys and import them to Salesforce

We can generate as many keys as we want with SDKMS 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.

Step 1: Generate JWE Token (BYOK Cache only KEY) using the plugin.

1. Go to plugin created in Step 3 of Fortanix DSM Setup.

2. Click on “ADD TEST INPUT” on the right-hand side.

3. Enter the below payload in the text box

{
"cert" : <uuid of certificate imported in SDKMS>,
"name": "<unique name of key eg: salesforce_ency_key_v1>"
}

4. Click “RUN TEST”.

SalesforceBYOKSdkms_TokenUsingPluginStep1_4.png

5. Plugin generates security objects (AES encryption key and meta information) in Fortanix DSM and returns their UUID.

Copy the value of the “opq_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:

a) AES Encryption key UUID (dek)
b) 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.

6. "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.

7. Go to Security Objects screen to see newly created object.

SalesforceBYOKSdkms_TokenUsingPluginStep1_7.png

Step 2: Configure Salesforce to use Fortanix DSM to fetch Cache-only Key at runtime.

1. Go to Setup >> Security >> Platform Encryption >> Key Management.

SalesforceBYOKSdkms_TokenUsingPluginStep2_1.png>

2. Click the Bring Your Own Key button.

SalesforceBYOKSdkms_TokenUsingPluginStep2_2.png

3. 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).

4. Select the “Use a Cache-Only Key” radio button.

5. Select “Named Credential” created with the Fortanix DSM endpoint.

6. Enter BYOK Id (opq_key_identifier) generated by the Fortanix DSMplugin in the previous step.

7. Click save

SalesforceBYOKSdkms_TokenUsingPluginStep2_7.png

8. Once the configuration is saved, Salesforce will call Fortanix DSM to fetch the JWE token and decrypt it with the private key of the certificate.

9. You can see the newly imported key on the “Key Management” screen.

SalesforceBYOKSdkms_TokenUsingPluginStep2_9.png

Step 3: Verify Key Import in Fortanix Fortanix DSM Event logs

1. Logs are generated in Fortanix Fortanix DSM while fetching encryption keys during setup (after step 2.9).

2. Go to Event logs in Fortanix DSM to verify (refer to the below screenshot).

3. Logs are also generated later when Salesforce calls Fortanix DSM to fetch encryption keys at runtime.

SalesforceBYOKSdkms_TokenUsingPluginStep3_3.png

 

Comments

Please sign in to leave a comment.

Was this article helpful?
0 out of 0 found this helpful