diff --git a/README.md b/README.md index 4b1f831..bd01417 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ This repository provides examples demonstrating how to use Oracle Functions. | Run a SQL statement against Autonomous DB using DB Client |[sample](./samples/oci-adb-client-runsql-python)|| | Publish a notification using ONS |[sample](./samples/oci-ons-publish-python)| | Send an email using Email Delivery Service |[sample](./samples/oci-email-send-python)| -| Decrypt cipher using Vault keys |[sample](./samples/oci-vault-decrypt-python) +| Decrypt cipher using Vault keys |[sample](./samples/oci-vault-decrypt-python)||[sample](./samples/oci-vault-decrypt-dotnet)| | Get a secret from Vault |[sample](./samples/oci-vault-get-secret-python)||[sample](./samples/oci-vault-get-secret-dotnet)| | Write IAM policies that enables Functions in a tenancy to access resources in other tenancies ||[sample](./samples/oci-cross-tenancy-policies-java) | Trace a function with APM and add custom child spans using Zipkin |[sample](./samples/trace-functions-with-apm)| diff --git a/samples/oci-vault-decrypt-dotnet/Common/KmsCryptoClientHelper.cs b/samples/oci-vault-decrypt-dotnet/Common/KmsCryptoClientHelper.cs new file mode 100644 index 0000000..ac8fa08 --- /dev/null +++ b/samples/oci-vault-decrypt-dotnet/Common/KmsCryptoClientHelper.cs @@ -0,0 +1,30 @@ + +using System; +using System.Threading.Tasks; +using System.Text; + +using Oci.Common; +using Oci.Common.Auth; +using Oci.KeymanagementService; + + +namespace VaultDecrypt +{ + public class KmsCryptoClientHelper + { + public static KmsCryptoClient GetVaultDecryptClient(string crypto_endpoint) + { + try + { + return new KmsCryptoClient(ResourcePrincipalAuthenticationDetailsProvider.GetProvider(), new ClientConfiguration(), crypto_endpoint); + } + catch (Exception ex) + { + Console.WriteLine("Unable To Create Resource Principal Provider: {0}", ex.Message); + Console.WriteLine("Defaulting to Instance Provider"); + return new KmsCryptoClient(new InstancePrincipalsAuthenticationDetailsProvider(), new ClientConfiguration(), crypto_endpoint); + } + } + + } +} diff --git a/samples/oci-vault-decrypt-dotnet/Controller/GetSecretsHelper.cs b/samples/oci-vault-decrypt-dotnet/Controller/GetSecretsHelper.cs new file mode 100644 index 0000000..ed807a9 --- /dev/null +++ b/samples/oci-vault-decrypt-dotnet/Controller/GetSecretsHelper.cs @@ -0,0 +1,59 @@ + +using System; +using System.Threading.Tasks; +using System.Text; +using System.Collections.Generic; +using System.IO; +using Oci.Common.Model; +using Oci.Common; +using Oci.Common.Auth; +using Oci.KeymanagementService; +using Oci.KeymanagementService.Models; +using Oci.KeymanagementService.Requests; +using Oci.KeymanagementService.Responses; + + +namespace VaultDecrypt +{ + public class GetSecretsHelper + { + public static async Task getSecretValue(KmsCryptoClient client, string vault_key_ocid, string cipher) + + { + + try + { + + + // Create a request and dependent object(s). + var decryptDataDetails = new Oci.KeymanagementService.Models.DecryptDataDetails + { + Ciphertext = cipher, + KeyId = vault_key_ocid, + }; + + var decryptRequest = new Oci.KeymanagementService.Requests.DecryptRequest + { + DecryptDataDetails = decryptDataDetails, + }; + + + var response = await client.Decrypt(decryptRequest); + var value_b64 = response.DecryptedData.Plaintext; + byte[] secretValueDecoded = Convert.FromBase64String(value_b64); + string secretIdValue = Encoding.Default.GetString(secretValueDecoded); + return secretIdValue; + + } + + catch (OciException ex) + { + Console.WriteLine("Unable To Get Secret : {0}", ex.Message); + return "Failed " + ex.Message; + } + + } + + + } +} diff --git a/samples/oci-vault-decrypt-dotnet/Dockerfile b/samples/oci-vault-decrypt-dotnet/Dockerfile new file mode 100644 index 0000000..dc8e00c --- /dev/null +++ b/samples/oci-vault-decrypt-dotnet/Dockerfile @@ -0,0 +1,11 @@ +FROM fnproject/dotnet:3.1-1.0.4-dev as build-stage +WORKDIR /function +COPY . . +RUN dotnet sln add VaultDecrypt.csproj +RUN dotnet build VaultDecrypt.csproj -c Release +RUN dotnet publish VaultDecrypt.csproj -c Release -o out +FROM fnproject/dotnet:3.1-1.0.4 +WORKDIR /function +COPY --from=build-stage /function/out/ /function/ +ENTRYPOINT ["dotnet", "VaultDecrypt.dll"] +CMD ["VaultDecrypt:Function:function_handler"] \ No newline at end of file diff --git a/samples/oci-vault-decrypt-dotnet/Function.sln b/samples/oci-vault-decrypt-dotnet/Function.sln new file mode 100644 index 0000000..f87916a --- /dev/null +++ b/samples/oci-vault-decrypt-dotnet/Function.sln @@ -0,0 +1,17 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26124.0 +MinimumVisualStudioVersion = 15.0.26124.0 +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/samples/oci-vault-decrypt-dotnet/Models/InputMessage.cs b/samples/oci-vault-decrypt-dotnet/Models/InputMessage.cs new file mode 100644 index 0000000..aeb92f5 --- /dev/null +++ b/samples/oci-vault-decrypt-dotnet/Models/InputMessage.cs @@ -0,0 +1,13 @@ +using System; + +namespace VaultDecrypt +{ + + class InputMessage + { + public string cipher { get; set; } + + + } + +} diff --git a/samples/oci-vault-decrypt-dotnet/Models/SecretContent.cs b/samples/oci-vault-decrypt-dotnet/Models/SecretContent.cs new file mode 100644 index 0000000..26bed9d --- /dev/null +++ b/samples/oci-vault-decrypt-dotnet/Models/SecretContent.cs @@ -0,0 +1,14 @@ +using System; + +namespace VaultDecrypt +{ + + class SecretContent + { + + public string secret_content { get; set; } + + + } + +} diff --git a/samples/oci-vault-decrypt-dotnet/README.md b/samples/oci-vault-decrypt-dotnet/README.md new file mode 100644 index 0000000..96daec6 --- /dev/null +++ b/samples/oci-vault-decrypt-dotnet/README.md @@ -0,0 +1,130 @@ +# Function that decrypts a cipher text using Vault keys +This function decrypts a cipher text using a Vault key. As a best practice, we do not recommend to expose your secrets via a return value of a function. This sample just demonstrate to use Vault keys in a function. + +As you make your way through this tutorial, look out for this icon ![user input icon](./images/userinput.png). +Whenever you see it, it's time for you to perform an action. + + +## Prerequisites +Before you deploy this sample function, make sure you have run step A, B and C of the [Oracle Functions Quick Start Guide for Cloud Shell](https://www.oracle.com/webfolder/technetwork/tutorials/infographics/oci_functions_cloudshell_quickview/functions_quickview_top/functions_quickview/index.html) +* A - Set up your tenancy +* B - Create application +* C - Set up your Cloud Shell dev environment + + +## List Applications +Assuming your have successfully completed the prerequisites, you should see your +application in the list of applications. +``` +fn ls apps +``` + + +## Create or Update your Dynamic Group +In order to use other OCI Services, your function must be part of a dynamic group. For information on how to create a dynamic group, refer to the [documentation](https://docs.cloud.oracle.com/iaas/Content/Identity/Tasks/managingdynamicgroups.htm#To). + +When specifying the *Matching Rules*, we suggest matching all functions in a compartment with: +``` +ALL {resource.type = 'fnfunc', resource.compartment.id = 'ocid1.compartment.oc1..aaaaaxxxxx'} +``` +Please check the [Accessing Other Oracle Cloud Infrastructure Resources from Running Functions](https://docs.cloud.oracle.com/en-us/iaas/Content/Functions/Tasks/functionsaccessingociresources.htm) for other *Matching Rules* options. + + +## Create or Update IAM Policies +Create a new policy that allows the dynamic group to manage compute instances. We will grant `use` access to `keys` in the compartment. + +![user input icon](./images/userinput.png) + +Your policy should look something like this: +``` +Allow dynamic-group to use keys in compartment +``` + +For more information on how to create policies, check the [documentation](https://docs.cloud.oracle.com/iaas/Content/Identity/Concepts/policysyntax.htm). + + +## Review and customize the function +Review the following files in the current folder: +* the code of the function, [VaultDecrypt.cs](./VaultDecrypt.cs) +* its dependencies, [VaultDecrypt.csproj](./VaultDecrypt.csproj) +* the function metadata, [func.yaml](./func.yaml) + + +## Deploy the function +In Cloud Shell, run the *fn deploy* command to build the function and its dependencies as a Docker image, +push the image to OCIR, and deploy the function to Oracle Functions in your application. + +![user input icon](./images/userinput.png) +``` +fn -v deploy --app +``` + + +## Create the Vault key and a cipher text +![user input icon](./images/userinput.png) + +On the OCI console, navigate to *Security* > *Key Management*. If you don't already have a Vault created, create one. Create a key by clicking on `Create Key`. Provide a name for the key and click `Create Key`. + +In your vault, note the *Cryptographic Endpoint* and your key OCID. + +![Cryptographic Endpoint anf Key OCID](./images/vault.png) + +Set the `KEY_OCID` and `CRYPTOGRAPHIC_ENDPOINTT` environement variables with the OCID of your Vault key and the Vault Endpoint. For example: +``` +KEY_OCID='ocid1.key.oc1.phx.acdfdfna.abyxxxxxxxsqhycfq' +CRYPTOGRAPHIC_ENDPOINT='https://a5pdddfdfna-crypto.kms.us-phoenix-1.oraclecloud.com' +``` + +Set the `PLAIN_TEXT` environement variable with the text you will encrypt: +``` +PLAIN_TEXT="my text" +``` +Run the following command to get the encrypted version of your text: +``` +oci kms crypto encrypt --key-id "$KEY_OCID" --endpoint "$CRYPTOGRAPHIC_ENDPOINT" \ + --plaintext "$( echo -n $PLAIN_TEXT | base64 -b0 )" | jq -r .data.ciphertext +``` +The above command is for MacOS. For Linux, replace `base64 -b0` with `base64 -w0`. + +The command returns a Cipher text, you will use it to invoke your function. + + +## Set the function configuration values +The function requires the following configuration values to be set: +- key_ocid +- cryptographic_endpoint + +![user input icon](./images/userinput.png) + +Use the *fn CLI* to set the config value: +``` +fn config function key_ocid +fn config function cryptographic_endpoint +``` +e.g. +``` +fn config function myapp oci-vault-decrypt-dotnet key_ocid "ocid1.key.oc1.phx.a5pedhchaafna.abyhqljt63augu4nwptqrvaw7gymh7zp7ihvgayo72pehd3sqhfproiaycfq" +fn config function myapp oci-vault-decrypt-dotnet cryptographic_endpoint 'https://a5pedhchaafna-crypto.kms.us-phoenix-1.oraclecloud.com' +``` + + +## Invoke the function +The function requires the cipher to be specified in the payload to be invoked. "cipher-text" is encrypted text you generated in the section [Create the Vault key and a cipher text](#Create the Vault key and a cipher text) + +![user input icon](./images/userinput.png) +``` +echo '{"cipher": ""}' | fn invoke oci-vault-decrypt-dotnet +``` +e.g.: +``` +echo '{"cipher": "Ia+hS8+UYAEV8gr00ItHxsC1jhfslbzAA="}' | fn invoke myapp oci-vault-decrypt-dotnet +``` + +Upon success, the function should return the decrypted text: +{"secret_content":[{"secret_content":"my text"}]} + + +## Monitoring Functions + +Learn how to configure basic observability for your function using metrics, alarms and email alerts: +* [Basic Guidance for Monitoring your Functions](../basic-observability/functions.md) diff --git a/samples/oci-vault-decrypt-dotnet/VaultDecrypt.cs b/samples/oci-vault-decrypt-dotnet/VaultDecrypt.cs new file mode 100644 index 0000000..cf0c5d1 --- /dev/null +++ b/samples/oci-vault-decrypt-dotnet/VaultDecrypt.cs @@ -0,0 +1,42 @@ +using Fnproject.Fn.Fdk; +using System.Runtime.CompilerServices; +using System.Collections.Generic; +using System; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; +using Oci.KeymanagementService; +using Oci.KeymanagementService.Models; + +namespace VaultDecrypt +{ + class Function + { + public string function_handler(InputMessage input) + { + + Dictionary> output = new Dictionary>(); + var secret_details_list = new List(); + + string cipher = input.cipher; + string vault_key_ocid = Environment.GetEnvironmentVariable("key_ocid"); + string crypto_endpoint = Environment.GetEnvironmentVariable("cryptographic_endpoint"); + + + KmsCryptoClient client = KmsCryptoClientHelper.GetVaultDecryptClient(crypto_endpoint); + + Task secret_value = GetSecretsHelper.getSecretValue(client, vault_key_ocid, cipher); + + var secret_detail = new SecretContent(); + secret_detail.secret_content = secret_value.Result; + secret_details_list.Add(secret_detail); + + output.Add("secret_content", secret_details_list); + return System.Text.Json.JsonSerializer.Serialize(output); + + } + + static void Main(string[] args) { Fdk.Handle(args[0]); } + + } +} diff --git a/samples/oci-vault-decrypt-dotnet/VaultDecrypt.csproj b/samples/oci-vault-decrypt-dotnet/VaultDecrypt.csproj new file mode 100644 index 0000000..58c4680 --- /dev/null +++ b/samples/oci-vault-decrypt-dotnet/VaultDecrypt.csproj @@ -0,0 +1,17 @@ + + + + Exe + netcoreapp3.1 + + + + + + + + + + + + diff --git a/samples/oci-vault-decrypt-dotnet/func.yaml b/samples/oci-vault-decrypt-dotnet/func.yaml new file mode 100644 index 0000000..11f9e2e --- /dev/null +++ b/samples/oci-vault-decrypt-dotnet/func.yaml @@ -0,0 +1,8 @@ +schema_version: 20180708 +name: oci-vault-decrypt-dotnet +version: 0.0.90 +runtime: dotnet3.1 +build_image: fnproject/dotnet:3.1-1.0.4-dev +run_image: fnproject/dotnet:3.1-1.0.4 +cmd: VaultDecrypt:Function:function_handler +entrypoint: dotnet VaultDecrypt.dll diff --git a/samples/oci-vault-decrypt-dotnet/images/userinput.png b/samples/oci-vault-decrypt-dotnet/images/userinput.png new file mode 100644 index 0000000..ce6a202 Binary files /dev/null and b/samples/oci-vault-decrypt-dotnet/images/userinput.png differ diff --git a/samples/oci-vault-decrypt-dotnet/images/vault.png b/samples/oci-vault-decrypt-dotnet/images/vault.png new file mode 100644 index 0000000..c36177a Binary files /dev/null and b/samples/oci-vault-decrypt-dotnet/images/vault.png differ