Aws Kms



  1. Aws Kms Vs Cloudhsm

Access to AWS KMS requires credentials that AWS can use to authenticate your requests. The credentials must have permissions to access AWS resources, such.

CloudhsmAws kms cli

March 12, 2021

AWS KMS is an incredible offering by AWS that manages encryptionkeys, automatic rotation and secure storage. With rotation enabled,AWS will generate a new encryption key once a year without deletingthe previous keys. Any cipher generated by old keys can still bedecrypted. We don’t have access to the actual key, which meanswe can’t leak it.

  1. AWS Key Management Service (AWS KMS) is a managed service that makes it easy for you to create and control customer master keys (CMKs), the encryption keys used to encrypt your data.
  2. An AWS KMS CMK for each secret Each secret is associated with an AWS managed or customer managed customer master key (CMK). Customer managed CMKs allow authorized users to control access to the CMK through policies and grants, manage.
  3. AWS KMS supports symmetric and asymmetric CMKs. A symmetric CMK represents a 256-bit key that is used for encryption and decryption. An asymmetric CMK represents an RSA key pair that is used for encryption and decryption or signing and verification (but not both), or an elliptic curve (ECC) key pair that is used for signing and verification.

Laravel ships an Encrypter class that uses AES for encryption.Replacing Laravel’s implementation with KMS takes only a simpleKmsEncrypter and a Service Provider.

The Service Provider

I just sent out a pull request to introduce a StringEncrypterinterface into Laravel so that this process can be simplified.https://github.com/laravel/framework/pull/36578

The Service Provider can look like this:

Notice how we’re instantiating a KmsClient inside the KmsEncrypterfactory callback. That gives us the chance of delegating howwe should resolve KmsClient to a separate process. One wayof doing that could be like this:

KmsEncrypter

Here’s how KmsEncrypter would look like:

Let’s dissect this class. First we have the KmsClient thatalready carries every configuration necessary to interactwith AWS KMS. Whether you use environment variable with AWSCredentials or let your AWS service assume role with permissionto interact with KMS, AWS SDK will handle the authentication.Then we have the key which should be the ARN of the AWS KMS keyor Alias of the key to be used. Finally we have context. Contextis a non-secret information (e.g. it will be plain text on CloudTrail)that allows you to bind your encryption with a specific signingcontext. If the exact same context is not provided when tryingto decrypt a specific cipher text, then the decryption will notwork. For instance, you may choose to use your service name asthe context of your encryption so that if other services accidentallytries to decrypt your cipher texts, it won’t just work. The developerwould have to make a conscious decision to specify another service’scontext when trying to decrypt cross-service data.

For ease of use, we can base64_encode() the cipher text and thenbase64_decode before decryption so that it’s easier to passthe data around. If you’re interested in learning more aboutbase64_encode, check out my post on Should I encrypt, hash or encode?.

Kms

Eloquent

Since the ServiceProvider is replacing the binding behind encrypteron Laravel’s service provider, we’re free to use Eloquent’scast feature to encrypt/decrypt attributes automatically.

This way whenever we try to save something into the password orclient_secret attributes, Eloquent will use KmsEncrypter toencrypt the data being stored and when we’re accessing the attribute,Eloquent Mutators will kick in and decrypt it.

Tests

For my automation tests, I decided to use a NullEncrypter implementationso that I don’t need to integrate directly with AWS KMS to runtests. Here’s how a NullEncrypter could look like:

On test could, we could then replace the binding like this:

Watch out for your storage service

During the development of this implementation, I first wrote a produtfeature without encryption and handed the APIs over to the frontendteam so that they could get started. I then started implementingAWS KMS encryption. I noticed that anytime my code would try todecrypt a cipher text, it would throw an exception saying

The reason I was getting this error was not because of the keynor the context. It was actually because I was interacting witha legacy database with strict=false and a password field oftype varchar(191). What would then happen was that the cipher textwould go above 191 characters and MySQL would truncate the datadown to 191 characters. Losing part of a cipher text means thatwe did not guarantee the integrity of the message and we canno longer decrypt it. Increasing the field size mitigated theissue.

Why don’t we inform the key to the decrypt API call to AWS?

When AWS encrypts a payload, it puts inside the cipher text anidentifier for which key was used for encryption. That way evenif we don’t know which key was used for encryption, AWS can stilldecrypt it as long as you have the complete cipher text and thecontext. This probably facilitates AWS’s job when rotating keys.When the key reaches 1 year of life, AWS will generate a brand newone and start using it for any new encryption. It won’t get ridof the old key, though. So if you make an API call asking fordecryption with a cipher text older than 1 year, AWS can stillfind the identifier for the key used and decrypt it.

Defining a Key with CloudFormation

The following template defines a MyEncryptionKey resource anda MyEncryptionKeyAlias resource. It will also output the aliasalongside the Key ARN. The Key ARN can be used to attach to an IAMRole that will need kms:Encrypt* and kms:Decrypt*. The Aliascan be used as an Environment Variable for your compute resourceso that it can be accessed by Laravel and injected into theKmsEncrypter class.

Aws

Conclusion

AWS KMS offering is great for the enterprise world. We will neverleak keys, they will be rotated automatically and it costs penniesfor the benefit that they bring. Laravel’s Encrypter and StringEncrypterinterfaces makes it easy to swap the implementation and offer agreat DX to work with encryption be it directly or via Eloquent.All in all it’s a great service, easy to use and designed to offersafety.

It’s important to note that I’m not rolling my own encryption here.I’m swapping Laravel’s Encrypter class with one that uses AWS KMS.In other words, AWS KMS is responsible for encryption/decryptionof the data and we should never roll our own encryption algorithms.

Follow me on Twitter tostay tuned with my latest work.

Kms

Cheers.

Aws Kms Vs Cloudhsm

Marco Aurélio Deleu
Writing bad code for 10 years. Passionate about Laravel and AWS.