Encrypting PII + other data in RDS Database With AWS KMS & Secrets Manager - amazon-web-services

My needs - Read/Write Encrypted Data
I have a software application that can build webpages and emails and I need to encrypt content stored in the database (PII plus user generated content by financial/healthcare institutions).
I would like to use AWS KMS/AWS Secrets Manager to manage the hash so the hash is secured and keys that gate the hash are automatically rotated and managed by AWS. I'll use this hash to encrypt/decrypt data. Two way encryption is required.
My Question
It seems there are two options, and I'm not sure which is preferred and which is the proper way to use AWS for this:
Option 1 - Encrypt DB Access (Not preferred)
I could store all PII and encrypted data in a separate RDS DB, and simply gate API access with encryption provided by AWS Secrets Manger and KMS. This kinda stinks because the encrypted data relates to tables in the main DB. So hosting this data elsewhere is cumbersome to maintain.
Option 2 - Encrypt the data on a field level (!Preferred!)
I would prefer to store encrypted data in the DB directly. For instance a table may have 7 columns unencrypted, but the content column contains encrypted data. I then need to figure out a way to encrypt/decrypt this securely. I would need some sort hash that encrypts/decrypts the data. Storing in directly in PHP seems like a bad idea so could I use AWS KMS / Secrets Manager to do this?
Plan A -
I store a hash in Secrets Manager (Encrypted with KMS), so when the application wants to encrypt/decrypt content, it uses the required IAM user to get the hash from AWS Secrets Manager, encrypts/decrypts the content and then removes the hash from memory.
Plan B* -
I use KMS directly (No secrets manager) and pass encrypted/decrypted content to KMS directly and it encrypts/decrypts on the fly, never needing to expose or send the key it's using to perform these actions.
Thanks again for taking the time

Related

Doesn't bring your own key (BYOK) lose control of the key to cloud provider like AWS anyway?

My understanding is that by generating your own key and use that to encrypt stuff, it prevents a cloud provider from being able to read your data at rest. But before a cloud provider can use this customer managed key to encrypt/decrypt, it has to first have access to the key's plaintext. What stops a cloud provider from actually storing that plaintext and still has access to my data at rest?
Different cloud provider might have different approach to this, so I'm using AWS S3 as a reference here, which requires you to send the key in the request. https://docs.aws.amazon.com/AmazonS3/latest/userguide/ServerSideEncryptionCustomerKeys.html
In the SSE-C scenario you refer to, the user provides AWS the plaintext data and plaintext key (over https) and then AWS performs the encryption and discards the key. The benefit to the user is that the user does not have to perform cryptographic operations.
If there is a concern about AWS having access to plaintext data or keys, the user can encrypt the data on the client computer and then send the data to AWS already encrypted. This is the client-side encryption scenario.

Should I use Secrets Manager for storing customers' API keys?

I'm implementing a service that requires me to call my customers' API using their API keys. My customers will provide me with their API keys in their accounts.
When I'm calling my customers' API, I have to retrieve their API key before making the call. Since these are my customers' API keys and I want them to be kept safely, I'm considering keeping all of them in AWS Secrets Manager. I have roughly about 5,000 users (still growing) and I plan to store all their keys into a single secret in Secrets Manager. My application makes about a few millions calls to my customers API a month and it needs to retrieve the keys at high frequency and concurrency.
However, I'm not sure if this is the kind of use case for Secrets Manager because their docs sound to me like it was meant for just keeping secret information for the application and not for customers like a database. At the same time, storing encrypted keys in the database and having to decrypt them with a KMS key sounds like I may end up with roughly the same cost.
Is Secrets Manager meant for such a use case to store customers' sensitive information such as API keys? If not, what should I consider in my case?
50k api keys in a single secret is goinfg to be very unwieldy. Assuming a 40 byte token, you're looking at 2mb of data - SSM has a max data length for a value of 4096 bytes unless I'm mistaken.
To me it would make more sense to generate a key with KMS and use that key to encrypt customer API keys before writing them to a DynamoDB table (or even RDS if you so desire) When you need to use a customer API key, fetch it from dynamoDB, decrypt it with the KMS key, and then make use of it.
If you want automatic key rotation, SSM could be used to encrypt the key you use to encrypt the client API tokens. Your token decryption key would remain usable while the wrapping SSM entry would be reencrypted with a key rotation set by policy.
Finally, as Software Engineer suggested above, there is Vault.

Why doesn't AWS KMS encrypt/decrypt need data key?

I am reading AWS encrypt cli document from https://docs.aws.amazon.com/cli/latest/reference/kms/encrypt.html and https://docs.aws.amazon.com/cli/latest/reference/kms/decrypt.html. I found that I am able to encrypt/decrypt without creating a data key. When I read https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html, it says that I need to use KMS CMK to generate a data key which is used to encrypt my data.
So I am confused about whether I need a data key at all?
CMK is designed to encrypt/decrypt the data keys. Therefore, there is a limit of 4 KB on the amount of plaintext that can be encrypted in a direct call to the encrypt function. You can easily test this by passing in message larger than 4 KB.
These operations are designed to encrypt and decrypt data keys. They use an AWS KMS customer master key (CMK) in the encryption operations and they cannot accept more than 4 KB (4096 bytes) of data. Although you might use them to encrypt small amounts of data, such as a password or RSA key, they are not designed to encrypt application data.
You are likely using a default CMK that was created by another AWS service that uses KMS encryption.
Of course all encryption and decryption operations require a key. If you did not explicitly create one for your application, then you are using the current default key.
Ensure that KMS Customer Master Keys (CMKs) are used by your AWS services and resources instead of default KMS keys, in order to have full control over data encryption/decryption process and meet compliance requirements. A KMS default master key is used by an AWS service such as RDS, EBS, Lambda, Elastic Transcoder, Redshift, SES, SQS, CloudWatch, EFS, S3 or Workspaces when no other key is defined to encrypt a resource for that service. The default key cannot be modified to ensure its availability, durability and security. On the other side, a KMS Customer Master Key (CMK) provides the ability to create, rotate, disable, enable and audit the encryption key used to protect the data.
See https://www.cloudconformity.com/knowledge-base/aws/KMS/default-key-usage.html

Store third party API key in S3 bucket or Dynamod DB?

I am connecting my app to third party email service using the registered API key.
Since it is a sensitive information I would like to store it in some encrypted place and retrieve it from there.
As I am already using AWS Lambda, so for this use-case is it better to use Dynamo DB or S3 bucket to store the API key?
Parameter store is also a good option. It is possible to store encrypted data and more easy to manage than via Secret Manager.
https://aws.amazon.com/en/systems-manager/features/
For just storing API key, both S3 and DynamoDB are not the best option.
The simplest solution will be SecureString in ParameterStore.
Alternatively, you can use lambda encrypted environment variable if you want to encrypt with a specific KMS key. Then in your lambda code you decrypt the env variable.
If you do the second approach in many lambdas, then consider put this code for decryption in a lambda layer.
For my future projects, I would store secrets in the SSM ParameterStore and then make the secrets available to my lambdas as encrypted during the deployment phase. The lambdas can then use the KMS key to decrypt it during runtime.
The parameter store has a 120 requests per second limit, this way we can prevent us from hitting the limit.

Field level encryption using AWS KMS and AWS CloudHSM

There is a requirement to implement additional level of security for an application. Let's say there is a table with 10'000'000 users. The sensitive fields are user.first_name and user.last_name. We need to encrypt that data before storing it into the database and later decrypt on the application level to show it on the UI.
As far as I can see the recommended way to do it with KMS is:
Write Part
call KMS service to get data key
encrypt the fields using data key
on the application level persist user record with encrypted fields into the database
Read Part
retrieve the record with encrypted fields from the database
decrypt the fields using data key
show the data on the UI
I have a set of questions that i need to clarify:
Does it make sense to use a new data key for each user?
10'000'000 users means 10'000'000 different data keys , what is the best practice to store them and access them from the machine that is doing decryption?
Is it ok to have a single data key for the whole user table?
What is the best practice to store a single key securely on local machine?
What will happen when accidentally the data key will be lost? Are there any recovery procedures?
The exact solution to be implemented should be decided based on the organization policy and the regulatory needs. However, the following points would hopefully help you develop a solution:
You can create a separate data key for each field by using a pseudo random number generator. The data key will be used to encrypt the raw data and then the data key itself will be encrypted using a common "Customer Master Key" from KMS. The encrypted data key will then be stored along with the encrypted data (first name and last name, in your case).
During decryption, the encrypted data key (stored along with the encrypted data) will be first decrypted using the master key from KMS and then the data will be decrypted using the data key
KMS can be configured to rotate the master key automatically every year. However, KMS keeps track of the old keys so that the encryption done with the old keys can be decrypted in the future even after the master key is rotated
The master key in KMS will be replicated across multiple Availability zones and therefore it is highly available
If you have more stringent security requirements, you may consider CloudHSM which stores the key in dedicated hardware that is not shared with other AWS customers
You can also use a KMS custom key store backed by CloudHSM. However, in that case the automatic key rotation will not be available