
Flow Security Keys
Amazon Connect Encryption Setup and Lambda Decryption
Amazon Connect provides the ability to capture customer DTMF input and encrypt this for security and compliance reasons. This can be used to collect data of any type with common use case being collecting card numbers and CVV codes for payments. In this post we're going to show you how to get set-up to collect this information, encrypt it within the Contact Flow and then decrypt it with an AWS Lambda Function.
Each Amazon Connect instance provides a set of sample contact flows, one such flow is called Sample secure input with no agent. This blog extends this to flow to use encryption.
Part 1: Creating Certificates on macOS
Step 1: Setup Working Directory
1mkdir ~/amazon-connect-certs
2cd ~/amazon-connect-certs
Step 2: Generate Private Key
1openssl genrsa -out private_key.pem 2048
Step 3: Create X.509 Certificate
1openssl req -new -x509 -key private_key.pem -out certificate.pem -days 365 \
2 -subj "/C=UK/ST=England/L=London/O=MyOrganization/OU=IT/CN=amazon-connect-encryption"
Step 4: Extract Public Key
1openssl x509 -in certificate.pem -pubkey -noout > public_key.pem
Step 5: Verify Files Created
1ls -la *.pem
2# Should show: certificate.pem, private_key.pem, public_key.pem
Step 6: Upload Public Key to Amazon Connect
- Go to Amazon Connect Console → Flows → Flow Security keys
- Click Add key
- Copy and paste the public key
1cat public_key.pem
4. Click Add
This will key you a Key Id

Step 7: Store Private Key Securely
Create a parameter store item using secure string that has the private_key.pem contents. You can use the AWS Console or using CLI. Ensure that you replace {key-id} with the Key Id provided in the step above.
1aws ssm put-parameter \
2 --name "/amazon-connect/encryption/{key-id}/private-key" \
3 --description "Private key for Amazon Connect encryption" \
4 --value "$(cat private_key.pem)" \
5 --type "SecureString" \
6 --overwrite
Step 8: AWS Lambda
Ensure that you have deployed the ECR images as provided by the Blog ECR repo: This blog requires the connect-encryption function, and that this is deployed as per the README.
Make sure that you have added the AWS Lambda function to the Amazon Connect console:
- Go to Amazon Connect Console → Flows → AWS Lambda
- Choose connect-encryption and click Add Lambda Function
Step 9: Configure Connect Flow
I have used the Sample secure input with no agent flow and adapted this. You can access the flow here and then use 'import' and change it as follows.

- Update the Key Id
- In certificate field, paste the results from the command below and Save
1cat certificate.pem
3. Open the next Flow block, AWS Lambda. From the Function ARN dropdown select your AWS Lambda function, connect-encryption, and Save.
4. Publish the flow, assign a phone number and then test.
Part 2: Testing
Place a call into your Contact Flow. Enter a neter using DTMF when prompted. If successful you will hear the message "The encrypted customer..." If you hear "There was a problem..." Then you need to review the guide and look at the logs to help identify where the error might be.
Troubleshooting:
- Check the logs in CloudWatch for
- Amazon Connect
- Lambda function
Between the two you will be able to find where the issue is.
AWS Lambda Logs
Request
The below shows the encrypted entry
1{
2 "Details": {
3 "ContactData": {
4 "Attributes": {},
5 "AwsRegion": "eu-west-2",
6 "Channel": "VOICE",
7 "ContactId": "1dec6044-d140-4092-be55-c67956177378",
8 "CustomerEndpoint": {
9 "Address": "+440000000000",
10 "Type": "TELEPHONE_NUMBER"
11 },
12 "CustomerId": null,
13 "Description": null,
14 "InitialContactId": "1dec6044-0000-0000-0000-c67956177378",
15 "InitiationMethod": "INBOUND",
16 "InstanceARN": "arn:aws:connect:eu-west-2:674248749882:instance/695202c7-0000-0000-0000-7a0bf91dfd94",
17 "LanguageCode": "en-US",
18 "MediaStreams": {
19 "Customer": {
20 "Audio": null
21 }
22 },
23 "Name": null,
24 "PreviousContactId": "1dec6044-0000-0000-0000-c67956177378",
25 "Queue": null,
26 "References": {},
27 "RelatedContactId": null,
28 "SegmentAttributes": {
29 "connect:Purpose": {
30 "ValueArn": null,
31 "ValueInteger": null,
32 "ValueList": null,
33 "ValueMap": {
34 "contact-attributes-search": {
35 "ValueArn": null,
36 "ValueInteger": null,
37 "ValueList": null,
38 "ValueMap": null,
39 "ValueString": null
40 }
41 },
42 "ValueString": null
43 },
44 "connect:Subtype": {
45 "ValueArn": null,
46 "ValueInteger": null,
47 "ValueList": null,
48 "ValueMap": null,
49 "ValueString": "connect:Telephony"
50 }
51 },
52 "SystemEndpoint": {
53 "Address": "+440000000000",
54 "Type": "TELEPHONE_NUMBER"
55 },
56 "Tags": {
57 "aws:connect:instanceId": "695202c7-0000-0000-0000-7a0bf91dfd94",
58 "aws:connect:systemEndpoint": "+440000000000"
59 }
60 },
61 "Parameters": {
62 "key-id": "b1071b33-0944-47f3-945c-098f3725ac1d",
63 "my-secret-string": "AYADeMCUuxaDZI53u3qDEqfpwDUAXwABABVhd3MtY3J5cHRvLXB1YmxpYy1rZXkAREEzcGg4WXc1dU1vTXNjVVlLM1BpTlRBUUtWWWZMWmU2Z05iQkwrekU0aFZFc05GaHMrNWNGTkU0WHhXTzc1SFVRQT09AAEADUFtYXpvbkNvbm5lY3QAJGIxMDcxYjMzLTA5NDQtNDdmMy05NDVjLTA5OGYzNzI1YWMxZAEAsQy+1ukKe7P0fNUfcaxXY/LJC+ClQK9GQQ3xCkAh9b1lnUvAdEqSPeGLzlTpSITR/72Wb4HrO2+YQdfkq69UgfwiJf0XYbZw82pA6SEskhsYTtLvGIq8iOF1u67NY0/BEHmpUz3KGHJPYa6Li2WsynKmlxwCxi7ChB7M5tIXRoN63EjnfeqJ1kzPZtBNVUxxzMyYmOKPKDGpwrA/+wKXj/9sa00E1ik9qqqOOi6FlPqJm3CgY//4UMCmdyksjFb5v3ho4BcUj/Xc15TTqB4isYjqy2zNImViHfIDuRvXmA2yypEHPMJ6IIfQYdm53NglMhn3W9vM7irmbdQ/xkMM5AIAAAAADAAAEADsrpXUgoesZFoxRQj/wTJVdeMXhlHRXyRCVpmG/////wAAAAGcGYwjdd8MWua7xc4AAAAMrrvgHRxRlE6wEH60CLZ2pv5YHbyOcFitE5pg+QBnMGUCMG5Prxlwhm1VftdXLEWf190d1N7BrmyT4oOS7DW06vj9U96OgAxS6Js5mWvdlgVUxwIxAIkRV0f2KACNPUrFpaHMRhGU8ropqYXR2IQWpWyHfTY1nQ4ar1gVN7Hpg9DLp21ZGg=="
64 }
65 },
66 "Name": "ContactFlowEvent"
67}
Response
The response shows the unencrypted data*
1{
2 "status-code": 200,
3 "data": {
4 "success": true,
5 "message": "Data decrypted successfully",
6 "contactId": "1dec6044-d140-4092-be55-c67956177378",
7 "requestId": "9675ddc6-5cb4-4c50-8858-a0c5ce9c0a0d",
8 "decryptedData": "4444444444444444",
9 "dataLength": 16
10 }
11}
Important*: This lambda is for educational purposes. You should never write the unencrypted payload to the logs.
Key rotation
You notice that the certification created is valid for 365 days, this is the case as we passed the param -days 365 when creating the key.
Amazon Connect support 2 keys so that key rotation is supported.
This blog post has been created to support key rotation. For example the KeyId created is passed by the AWS Lambda block in Amazon Connect to the Lambda. This param is then used to retrieve the RSA PRIVATE KEY from the parameters store. Therefore we can create a 2nd KEY and allow both keys to work simultaneously and dynamically. Then retire the first key before it expires.
This process ensure seamless rollback and no downtime in deployments.
Multiple Encryption Requirements
You may have a requirement to support 2 or more encryption consumers, this is a problem due to the limitation of Amazon Connect only allowing 2 Key Ids. With just 2 you cannot support more than 2 and with those key rotation would require downtime.
Therefore the approach in this blog can be adopted to work around this limitation.
Effectively the connect-encryption lambda would become a middleware, decrypting the payload and re-encrypting it for the destination system, this allows you to scale to 10s or 100s of encryption consumers.
I hope you found this educational and useful!