AWS Contact Center

Creating a secure IVR solution with Amazon Connect

Creating a secure IVR solution with Amazon Connect

The contact flows in Amazon Connect can be used to create dynamic Interactive Voice Response (IVR) solutions. With Amazon Connect, organizations can gather appropriate personal information to customize the customer experience when they interact with their IVR. The personal information can include social security numbers, credit card information, and addresses. Because of compliance reasons, sensitive personal information must be encrypted in motion and when stored. Always encrypt personal information.

This blog post shows you how customers can use the Store customer input block in Amazon Connect to gather sensitive personal information, and automatically encrypt the data by using the customer’s own supplied encryption keys. This feature allows the customer to comply with encryption requirements.

To achieve this, Amazon Connect uses the AWS Encryption Software Development KIT (SDK) to encrypt customer provided data. The SDK uses an envelope encryption approach. This protects both the raw data and the data keys used to encrypt them. For more information about how the AWS Encryption SDK works, see Envelope Encryption.

This post shows the steps required to:

  1. Configure Amazon Connect to collect a credit card number.
  2. Encrypt the credit card digits.
  3. Send it to our backend AWS Lambda for decryption, using the customer supplied decryption key.

We will use the Amazon Connect contact flow shown in the following illustration:

Implementing the secure IVR

To implement our secure IVR, we must:

  1. Create new encryption and decryption keys, or import existing ones.
  2. Securely store the decryption key into AWS parameter store
  3. Create an AWS Lambda function to decrypt the collected digits
  4. Upload our public key to Amazon Connect to encrypt collected credit card digits.
  5. Create the contact flow described in the previous section.

Note

To implement the secure IVR, make sure that AWS Command Line Interface (AWS CLI) is installed, configured and pointed to the same region as your Amazon Connect instance. To verify that you can run “aws configure” from your Terminal window and verify that your default region name parameter has the correct value.

The Amazon Connect customer input encryption feature is designed to use the organization’s supplied public key to encrypt data. This allows the organization to use its private key to decrypt the data for further processing. Using a private key known only to the organization helps preserve the privacy that an organization requires. An organization can use either an existing key pair or create a new one. When the key information is available, the process remains the same.

If you are using your existing keys for this exercise, skip to step 2 of this section.

Step 1: Create the encryption and decryption keys

We will be leveraging OpenSSL for this step. If you are using a macOS computer, OpenSSL should already be installed. For information about installing OpenSSL, see this OpenSSL site.

Let’s use Terminal and the OpenSSL command line encryption utility to generate a self-signed certificate and private key. We create the private key and certificate in a single step. As a result, two files are generated:

  • A private key file: connect.private.key
  • A certificate file: connect.certificate.pem

When you run the following command, you are providing the usual necessary certificate request information; such as, country/region name, organization name, etc.

$ openssl req -x509 -sha256 -nodes -newkey rsa:4096 -keyout blog.connect.private.key -days 730 -out blog.connect.certificate.pem

Notice that we created a certificate valid for 2 years (730 days). It is important to remember that the certificate’s expiration date monitoring remains the responsibility of the organization.

Next, we extract the public key from the certificate file using the OpenSSL utility. The next command generates a file named blog.connect.public.key, which contains the encryption key that we need to upload to Amazon Connect.

$ openssl x509 -pubkey -noout -in blog.connect.certificate.pem > blog.connect.public.key

We now have three files to use for the next steps.

Step 2: Securely store the decryption private key into the AWS Parameter Store

This step helps to make sure that our decryption is stored securely. Moreover, the decryption is stored with traceability and access rights management using the power of IAM. By using this approach, we can manage the access to our private key by selectively granting access to processes and users. Also, it lets the system log every access of the private key for audit purposes.

The following command securely uploads our private key to the AWS Systems Manager Parameter Store. This saves the key to a parameter named CONNECT_INPUT_DECRYPTION_KEY. We can use that parameter to securely retrieve our private key from AWS Lambda at runtime.

$ aws ssm put-parameter --type SecureString --name CONNECT_INPUT_DECRYPTION_KEY --description "Private key for decryption of Amazon Connect collected data" --value "$(<blog.connect.private.key)"

To run the previous command, you must be an AWS user with access to AWS Systems Manager and the permissions to create parameters. Work with your AWS SysOps team to verify proper access.

The command uses the default key alias/aws/ssm to encrypt your private key. If you prefer to use a different  AWS KMS key for this, you could do so by adding the –key-id option to this command.

After you complete this step, you can then go to the Parameter Store in the AWS Systems Manager console. There, you should see the newly created parameter for your private key as shown in the following screenshot. If you do not see the key, it is most like a permissions issue which can be fixed by reviewing the output on your terminal window.

Step 3: Use AWS CloudFormation to create the Lambda function for decryption

In this step, we use AWS CloudFormation to automatically create the IAM role and the AWS Lambda function. The function is used to perform the decryption of the credit card number.

To create the Lambda function for decryption:

  1. Login to your AWS console.
  2. Confirm that the AWS Region selected has the Amazon Connect service available.
  3. Click on the button below “Launch Stack”

  1. On the AWS CloudFormation page, modify the stack name if you prefer a different one. You can keep the other options as default.
  2. Because this template uses transforms to take advantage of the AWS Serverless Application Model (AWS SAM), choose Create Change Set (shown in the following screenshot) to perform the necessary declaration changes.

When this procedure is completed, the output should print the value for your AWS Lambda resource name (ARN). Copy the ARN and save it for the next step.

  1. Now let’s make sure that our Amazon Connect instance has access to this newly created AWS Lambda Function by following sub steps A and B below:
  2. In the Amazon Connect console, choose Contact Flows and scroll to the bottom of the page in the AWS Lambda section.
  3. On the Function drop-down menu, select the DecryptCustomerInput function and click on “+Add Lambda Function”, as shown in the following screenshot:

 

Step 4: Upload our public key to Amazon Connect.

In this step, we upload our encryption key, so Amazon Connect knows to use it when we want to encrypt customer input.

  1. Open the Amazon Connect console,
  2. Open your instance, and in the left pane, choose Contact Flows.
  3. Choose Add Key, and paste the content of your public key file blog.connect.public.key. You can use any text editor to open the file and copy its content.
  4. Choose Add to save the public key, as shown in the following example. You now have a key ID generated for your public key. Copy it and save it in the next step.

Step 5: Create a contact flow to collect digits and encrypt them.

In this step, download the contact flow we will use from this location. Save it to a file. We Following the steps below, you will import your saved file and modify it so that Amazon Connect knows which key we use to encrypt the credit card number.

  1. Open the Amazon Connect console.
  2. Click on Overview, then choose Login as administrator.
  3. On the Routing menu on the left side, choose Contact Flows to show the list of contact flows.
  4. Click on Create Contact flow.
  5. From the drop-down menu next to the Save button on the right side, as shown in the following screenshot, choose Import flow. This loads the flow that was downloaded at the beginning of this step.

  1. After the import completes, choose the Store customer input block and enter the key ID that you created in step 3, and the content of your blog.connect.certificate.pem file, as shown in the following example:

  1. Next, let’s point our contact flow’s Invoke AWS Lambda function block to our DecryptCustomerInput To do so, update the Function ARN field with the value returned from the CloudFormation stack. You can use the following screenshot example as a guide.

  1. Save and publish the contact flow, as we are done with all changes.
  2. Attach the contact flow to your test phone number, as shown in the following example. For more information about setting up a phone number, see Claiming Phone Numbers.

  1. Dial the test phone number to go through the flow. After the call is completed, check the Amazon CloudWatch Logs to confirm the digits that we entered are encrypted and passed to our AWS Lambda function for decryption.

Note

To confirm that the decryption works as expected, we also log the deciphered text. However, avoid doing this in a production environment to ensure that sensitive data is not leaked through the log files.

The following extracts show the information that is stored in both the Contact Flow logs and the AWS Lambda function logs.

Contact flow logs

Collected input

{
    "ContactFlowModuleType": "StoreUserInput",
    "ContactFlowId": "arn:aws:connect:us-east-1:098145436134:instance/1f5e58e8-4c0e-414d-bf3e-2bb5411a8799/contact-flow/6845a578-1226-458d-910f-6549251f3471",
    "Timestamp": "2018-12-06T01:44:20.143Z",
    "ContactId": "c4955beb-1aaf-4be9-a77e-44affab094a6",
    "Results": "AYADeChksVCWzXiOV5r3lqTOgNwAXwABABVhd3MtY3J5cHRvLXB1YmxpYy1rZXkAREF2QXlYMzJOZ1ByTFdZRkNGUEo1K1RsM1l2RE9IZ2IvZzV6Z0h5RnVJTmpudHpVcTl1VlI5OEljOHRjb2RSS3RSQT09AAEADUFtYXpvbkNvbm5lY3QAJGEyNWMzNWY4LThiZTYtNDgwOS1iYjQ2LWU5Yjk2NDAyMjY0ZgIALWU7lQ/BvMDejcjotBY41kwqFZh+mmlY6Uob+VpwlinLWTKoxo+4alK7cLOgXLHp8sEKbaZFvR+HIsjJYccpgS6e8KIljfrpFrz+/xAIxt9oE3u0RCN11/SW7gcZ93fZryKoF77ki1RdMlNFRkram5Sb2IPQ43X4YhdFD/GUEKKFb6EBwwsglOE+KYstJFUJ7hc0AAILpGQDPA+EelymG8BF7CBlpZByvxPQH66Dnh4ypw3ANfW0Tg5dwHDC0+78RYOqnVVJohQ0g9SlqH5oGx/08CeTNfnvICvPdd//9Le51xu8mddqYEZJHBLOMkecIbiQo51eD2d99aaN4Byv3wYsFx7ENBdqcD1khiAHAsJdc570VJbKgrmbLu99359BABiWjlcBIF8ss6Vul13FgCbsQGQT9RaRud6BR+xv4KZekI3xJhTgcxP/BDoi6ITQxR+bq+Go0IbX4Lv5MDTZ+dl+FiTV1Yeyr6apWpeeRgJUVDptaoiPwWIP8SPdxtJs479fz+kN8JEWg16PZD16WiRjS+nO6zwyxjTOpoUImbOMSBqXIdiKIPcEH00aI1LwjUemQoFE1oQeYI+aSVYUdK1vLjNHfW8mzJxUSN7++uT4Ano2xfehza13i71ERHTo83a4Dn+pQkwjmU04lE5pL+da6V1Bk/tlpoZmNn2FAcgCAAAAAAwAABAASYbegRD39l1dwH1s7o3QmAYAONZqZhBArr50hv////8AAAAB/JtEZVJ2Ns41DlxjAAAACvSX4W1TeTUFi/mExfmasoTIhIBQcEigWL9uAGcwZQIwS24mN0dgkK5Iu77iZ/tGbzm//+vSMt4QFhOGNMMPBhRUXg0oZ/W8bLEe7tS2JQ1oAjEA3hRWm6FZvEuOeR+HGrkb22Woe05qYG3Dxbjl2ajUy0FtjQ2FTBYY9T7AX8S3RSjV"
}

AWS Lambda invocation

{
    "ContactFlowModuleType": "InvokeExternalResource",
    "ContactId": "c4955beb-1aaf-4be9-a77e-44affab094a6",
    "Parameters": {
        "FunctionArn": "arn:aws:lambda:us-east-1:098145436134:function:ConnectEncryption",
        "Parameters": {
            "EncryptedCreditCard": "AYADeChksVCWzXiOV5r3lqTOgNwAXwABABVhd3MtY3J5cHRvLXB1YmxpYy1rZXkAREF2QXlYMzJOZ1ByTFdZRkNGUEo1K1RsM1l2RE9IZ2IvZzV6Z0h5RnVJTmpudHpVcTl1VlI5OEljOHRjb2RSS3RSQT09AAEADUFtYXpvbkNvbm5lY3QAJGEyNWMzNWY4LThiZTYtNDgwOS1iYjQ2LWU5Yjk2NDAyMjY0ZgIALWU7lQ/BvMDejcjotBY41kwqFZh+mmlY6Uob+VpwlinLWTKoxo+4alK7cLOgXLHp8sEKbaZFvR+HIsjJYccpgS6e8KIljfrpFrz+/xAIxt9oE3u0RCN11/SW7gcZ93fZryKoF77ki1RdMlNFRkram5Sb2IPQ43X4YhdFD/GUEKKFb6EBwwsglOE+KYstJFUJ7hc0AAILpGQDPA+EelymG8BF7CBlpZByvxPQH66Dnh4ypw3ANfW0Tg5dwHDC0+78RYOqnVVJohQ0g9SlqH5oGx/08CeTNfnvICvPdd//9Le51xu8mddqYEZJHBLOMkecIbiQo51eD2d99aaN4Byv3wYsFx7ENBdqcD1khiAHAsJdc570VJbKgrmbLu99359BABiWjlcBIF8ss6Vul13FgCbsQGQT9RaRud6BR+xv4KZekI3xJhTgcxP/BDoi6ITQxR+bq+Go0IbX4Lv5MDTZ+dl+FiTV1Yeyr6apWpeeRgJUVDptaoiPwWIP8SPdxtJs479fz+kN8JEWg16PZD16WiRjS+nO6zwyxjTOpoUImbOMSBqXIdiKIPcEH00aI1LwjUemQoFE1oQeYI+aSVYUdK1vLjNHfW8mzJxUSN7++uT4Ano2xfehza13i71ERHTo83a4Dn+pQkwjmU04lE5pL+da6V1Bk/tlpoZmNn2FAcgCAAAAAAwAABAASYbegRD39l1dwH1s7o3QmAYAONZqZhBArr50hv////8AAAAB/JtEZVJ2Ns41DlxjAAAACvSX4W1TeTUFi/mExfmasoTIhIBQcEigWL9uAGcwZQIwS24mN0dgkK5Iu77iZ/tGbzm//+vSMt4QFhOGNMMPBhRUXg0oZ/W8bLEe7tS2JQ1oAjEA3hRWm6FZvEuOeR+HGrkb22Woe05qYG3Dxbjl2ajUy0FtjQ2FTBYY9T7AX8S3RSjV"
        },
        "TimeLimit": "8000"
    },
    "ContactFlowId": "arn:aws:connect:us-east-1:098145436134:instance/1f5e58e8-4c0e-414d-bf3e-2bb5411a8799/contact-flow/6845a578-1226-458d-910f-6549251f3471",
    "Timestamp": "2018-12-06T01:44:20.208Z",
    "ExternalResults": {
        "body": "Successfully Decryption",
        "statusCode": "200"
    }
}

AWS Lambda Logs

body: { frames: [], lastFrame: { seq: 1, text: '4444444444444444' } },

In this case, the entered digits were 4444444444444444.

 

Conclusion

That’s it!

In this post we covered how you can use Amazon Connect’s Encryption feature to collect digits from a caller and encrypt them using your own supplied key pair. We have also covered how you can use AWS Systems Managers to securely store your decryption key.

With this, you can now build a secured IVR using Amazon Connect.

Please let us know what you built with this.