Whilst building a demo recently I had to store an oAuth client secret somewhere for Oracle Function to work properly. I immediately decided to store it in the Oracle Functions configurations section and thought all was well.
The below image shows the configuration section for my application and as you can see both the IDCS client id and client secret are stored.
However after a security review with my good friend (Olaf) we realised that whilst the data is relatively secure (i.e. Only someone who has access to the compartment could see it), its not really that secure as the oAuth secret is displayed in cleartext without any obfuscation. For stuff which is security related, e.g. oAuth Client Secrets, it would be nice to be able to store it "securely" in a way which is encrypted.
The answer to my problem is to use the Oracle Key Management service to encrypt the data (the oAuth Client ID), store this encrypted data in Oracle Functions and then at runtime reverse the process and decrypt the data on the fly.
Setting this up is relatively easy, first step to do is to navigate to the Oracle Key Management Service (Menu/Security/Key Management) and create a new KMS Vault.
Once the vault is created you can create a "key" in the vault. This "key" is not the encrypted data but the key to which is used to encrypt, and subsequently decrypt, the data.
Once the vault is created you need to note down the following data :
- The Key's OCID
- The Management Endpoint URL
Now we can encrypt our data using either code (Python/Java etc) or we can do this from the OCI CLI.
The below script encrypts the data can encrypt the data..
echo "Please enter the KMS Endpoint URL" read ENDPOINT echo "Please enter the KMS Key OCID" read KEY echo "Please enter the text you wish to encrypt" read PLAIN_TEXT echo "Encrypted Text" oci kms crypto encrypt --key-id "$KEY" --endpoint "$ENDPOINT" --plaintext "$( echo $PLAIN_TEXT | base64 -w0 )"
You must have a installed the OCI CLI for the above shell script to work
If you run this with your data you will be greeted with a JSON response containing the encrypted text.
Please enter the KMS Endpoint URL https://mycryptokms-crypto.kms.us-phoenix-1.oraclecloud.com Please enter the KMS Key OCID ocid1.key.oc1.phx.11111222.aaaaaabbbbbbbbbbdddddddddeeeeeeefffffff Please enter the text you wish to encrypt helo Encrypted Text { "data": { "ciphertext": "ITNi/++xxxxxx/gT/ssssss/Febc+zQ/wwwwwwwwww=" } }
You can now cut-n-paste the encrypted text (JSON attribute ciphertet) in the Function configuration using either the UI or using the command line.
e.g. Setting the configuration value via the command line
fn config app cloudnativesaas myEncryptedIDCSClientSecret ITNi/++xxxxxx/gT/ssssss/Febc+zQ/wwwwwwwwww
OK, now from within your function you need to query the KMS Service and get it to decrypt your encrypted key so you can use it in your code.
For this to work you will need to ensure that your application has the OCI library available, in my case I was using Java and the library was available using the maven repository. I used the following maven coordinates to allow my Java app to use the crypto services.
<dependency> <groupId>com.oracle.oci.sdk</groupId> <artifactId>oci-java-sdk-keymanagement</artifactId> <version>1.12.2</version> </dependency> <!-- Need the activation library if using Java 11 --> <dependency> <groupId>javax.activation</groupId> <artifactId>javax.activation-api</artifactId> <version>1.2.0</version> </dependency>
Here is a sample snippet of Java code which gets the encrypted value from functions configuration section and then calls the KMS services to decrypt it.
@FnConfiguration public ResourceServerConfig(RuntimeContext ctx) { // Config data for IDCS oAuth App IDCS_URL = ctx.getConfigurationByKey("idcs_app_url").orElse("NOTSET"); SCOPE_AUD = ctx.getConfigurationByKey("idcs_app_scopeid").orElse("NOTSET"); CLIENT_ID = ctx.getConfigurationByKey("idcs_app_clientid").orElse("NOTSET"); // KMS Key for IDCS Client Secret KMSEndpoint = ctx.getConfigurationByKey("kms_endpoint").orElse("NOTSET"); KMSKeyOCID = ctx.getConfigurationByKey("kms_idcs_secret_key").orElse("NOTSET"); EncryptedText = ctx.getConfigurationByKey("idcs_app_secret").orElse("NOTSET"); LOGGER.info("Decrypting key"); AbstractAuthenticationDetailsProvider provider = null; provider = ResourcePrincipalAuthenticationDetailsProvider.builder().build(); KmsCryptoClient cryptoClient = KmsCryptoClient.builder().endpoint(KMSEndpoint).build(provider); DecryptDataDetails decryptDataDetails = DecryptDataDetails.builder().keyId(KMSKeyOCID).ciphertext(EncryptedText).build(); DecryptRequest decryptRequest = DecryptRequest.builder().decryptDataDetails(decryptDataDetails).build(); DecryptResponse decryptResponse = cryptoClient.decrypt(decryptRequest); String decryptedDEK = decryptResponse.getDecryptedData().getPlaintext(); CLIENT_SECRET = new String (Base64.getDecoder().decode(decryptedDEK.getBytes())); LOGGER.info("oAuth Client Secret Decrypted"); }
The above snippet of code,queries all the parameters, including the client secret key out of the Functions configurations , calls the KMS Services to decrypt the keys and then sets the variables appropriately.
Finally for the above to work you need to ensure that the right permissions are granted at the OCI IAM level.
The Following IAM Security Policies need to be setup
Policy Type | Policy | Usage |
Policy | ALL {resource.type='fnfunc', resource.compartment.id='YOUR_COMPARTMENT_OCID'} | Dynamically defines all Function instances within the given compartment |
Policy | Allow dynamic-group FN_DYN_GRP to manage vaults in compartment |
Allow access the KMS Vaults |
Policy | Allow dynamic-group FN_DYN_GRP to manage keys in compartment |
Allow access the keys in KMS |
Policy | Allow dynamic-group FN_DYN_GRP to manage key-delegate in compartment |
| Allow access the key delegates in KMS | |
As per always when developing code think about security and always store your secret stuff "securely"!
25+ years of Oracle experience, specialising in Technical design and design authority of Oracle Technology solutions, specialising in integrating technology with Oracles SaaS products.
Extensive credible communication skills at all levels, from hard core developers to C-Level executives.
Specialities: Oracle Fusion Apps Integration, Oracle Cloud products, SaaS Integration architectures, Engaging with SIs & ISVs, Technical Enablement, Customer Design Reviews, advisory and project coaching.
TOGAF 9 Architect and Oracle Cloud Infrastructure Architect Certified
Previous Post