Tag Archives: AWS

AWS KMS Encryption/Decryption Script

As a follow up to my blog post on Keeping Secrets in Chef with AWS Key Managment Service I wanted to post an updated script that can be used to encrypt/decrypt sensitive information. I’ve updated the following script to allow for a few parameters. Specifically:

-e --encrypt STRING (encrypt the specified string)
-d --decrypt STRING (decrypt the specified string)
-k --key KEY (full ARN or Key ID to be used to encrypt/decrypt)
-r --region REGION (region the key is located in)

You can find the script in my GitHub repo here, feel free to use it to encrypt/decrypt your sensitive information.


Keeping Secrets in Chef with AWS Key Management Service

Handling sensitive data in Chef can be a bit of a challenge. You can use encrypted data bags, but that can be trickty if you want a new node to access an existing encrypted data bag as you have to re-encrypt the data bag after the node has been bootstrapped. You can also use an external method of encryption/decryption (OpenSSL), but have to handle security around the keys themselves. Enter AWS Key Management Service. KMS is a service that you can use to store keys for encryption/decryption in AWS (EBS volume encryption, for instance) and can also be used as a sort of “Encryption as a Service”. I’ll show you how to do encryption of Chef secrets using KMS and a little Ruby. This works best if you’re Cheffing servers that will be running within AWS (as you can use IAM roles to provide greater security) but is not exclusive to servers running in AWS, you can use it anywhere. Here’s how it works.

At a high level we’ll do the following:

  1. Create a new KMS key
  2. Run Ruby script to encrypt some text
  3. Create a new server in EC2 with an IAM role allowing access to the KMS key
  4. Use the encrypted string in a Chef recipe

First off you’ll need a KMS key. As with many things in AWS there is a cost associated with this service. It’s $1.00 per key per month, plus some small charges for key usage. Check out the KMS pricing page for more details. KMS can be found as an option within IAM, it doesn’t have it’s own entry on the master AWS services list.

AWS Security & Identity

Click on Identity and Access Management and on the right side you’ll see an Encryption Keys link, click that and you’ll be taken to your KMS keys. There may already be a few there for usage of services within AWS, so leave those alone. You’ll need to create a new key for encryption/decryption within Chef. Note that once a key is created, it cannot be deleted, only disabled. You aren’t charged for disabled keys or for keys used created and used by AWS services themselves. Click the Create Key button to create a new key. This will take you through a few screens. Give it a name and a description, grant permissions to users/roles to administer the key, grant permissions to users/roles to use the key, and then create your new key. If you forget to add a user/role to either of those screens, you can always change that after key creation. Click on the key name after creation and you can see details on the key, and modify its options if you need.

So now you have a key, great! But how do we use it? Let’s take a look at some Ruby that can be used to encrypt/decrypt within KMS:

require 'aws-sdk-core'

key_id = 'arn:aws:kms:us-east-1:012345678901:key/01abc2d3-4e56-78f9-g01h-23ij45klm6n6'
kms = Aws::KMS::Client.new(region:'us-east-1')

# Get text from user
puts "Please enter the text you want to encrypt"
text = gets.chomp

# Encrypt entered text
encrypted = kms.encrypt({
key_id: key_id,
plaintext: text

# Display raw encrypted text
puts "Encrypted text raw:"
puts encrypted.ciphertext_blob

# Display Base64 encoded text
puts "Encrypted text Base64 encoded:"
puts Base64.encode64(encrypted.ciphertext_blob)

# Display Base64 strict encoded text
puts "Encrypted text Base64 strict encoded:"
puts Base64.strict_encode64(encrypted.ciphertext_blob)

# Decrypt the encrypted text
puts "Now lets decrypt that"
decrypted = kms.decrypt({
ciphertext_blob: encrypted.ciphertext_blob

# Display the decrypted text
puts "Here's the decrypted text:"
puts decrypted.plaintext

Open your editor of choice and paste this code in. Replace the key_id with the full ARN of the key you want to use, and ensure the region in the kms variable is set properly as well. This also assumes that you have your AWS keys set up locally with an account that has access to the KMS key for access through the API. Save this file as kms-test.rb and run it from the command line with the command ruby kms-test.rb. You should see something like the following:
kms output

Note the difference between the raw output, the Base64 and Base64 strict output. The Base64 strict encoded text is what we’ll want to use in Chef since it’s one long string with no carriage returns. This allows for easy storage in a Chef attribute, handy if we want to store a password for an account for example.

So how do we use this in Chef? Let’s say you have a recipe that you want to decrypt the password for use by a command.

First, you’re going to need an IAM role associated with your node. When you build a new node in AWS, ensure that it has the following IAM permissions (replace the ARN with the ARN of your KMS key):

  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": "principal",
    "Action": [
    "Resource": "arn:aws:kms:us-east-1:012345678901:key/01abc2d3-4e56-78f9-g01h-23ij45klm6n6" 

Now, if you store the Base64 strict encoded string (which you can get via the kms-test.rb script) in a node['my-cookbook']['password'] attribute, you can use the following Ruby in your recipe to access it and decrypt it from your new node.

pw = node['my-cookbook']['password']
key_id = node['my-cookbook']['kms_key']
kms = Aws::KMS::Client.new(region:'us-east-1')
pw = kms.decrypt({
     ciphertext_blob: Base64.strict_decode64(node['my-cookbook']['password'])

execute 'use-password' do
command "command that uses #{pw}"
sensitive true

This can be used without an IAM role (for instance if you want to use it outside of AWS) by updating the KMS object in the recipe with the following:

kms = Aws::KMS::Client.new(
        access_key_id: node['my-cookbook']['aws_access_key_id'],
        secret_access_key: node['my-cookbook']['aws_secret_access_key']

That said, storing keys locally on any system is much less secure than using IAM roles, so make sure you understand the risks and implications in doing so.

Using these techniques, you can easily store and retrieve sensitive data via KMS for use in Chef and whip up some more awesome!

AWS Certified Solutions Architect – Associate Exam Review

A couple of weeks ago I sat the Amazon Certified Solutions Architect – Associate exam and passed (woohoo!). I wanted to provide a bit of an overview of the exam itself and what I did to prepare.

The exam itself was 60 questions, with 80 minutes to answer all of them. I think i had 25 minutes or so when all was said and done, so it was ample enough time for me. All questions are multiple choice; no simulations were involved though there was some fill in the blank style questions with multiple choice answers. As you go through the exam you have the opportunity to mark each question for review, and can then review any question once you have answered all of them. I’d suggest taking advantage of this; I would mark questions that I was uncertain about, using context from other questions or a bit more time to think about it at the end. I think I marked 6 questions or so, and am pretty sure that I answered most of them correctly after changing my answers during the review period. Regardless, it’s a good practice to mark those that you’re unsure about so you can ponder on them a bit more as time allows at the end, but leaving an answer if you happen to not have that extra time buffer at the end.

As far as the questions themselves, per the testing agreement I cannot disclose any detailed specifics, but can give you some high level thoughts on what was covered. First and foremost, having solid experience with AWS will go a long way on this exam. Strong knowledge of EC2, VPC, S3 and IAM is good to have. The exam blueprint is a good place to start, but you’ll have much more success if you spend time in the console, building environments and playing around. Take the time to get very familiar with all the concepts in the blueprint and that will go a long way. Specifics on pricing for services were not covered in the exam, so you don’t need to know things like how much you’ll get charged per GB on ingress network traffic per VPC.

As far as preparation, along with hands on experience I took the AWS Certified Solutions Architect – Associate 2015 course on Udemy [1]. It’s a great course, starts out a bit slow if you’ve had any experience on AWS, but does a very good job of covering all the concepts you’d need to know in preparation for the exam. Ryan Kroonenburg is the instructor, and he’s got a Professional course that should be coming soon that I’m looking forward to. If you don’t have experience with AWS, get a free account and start playing around, you’ll need it if you take Ryan’s course.

All in all it wasn’t terribly difficult, but I’m glad that I took the time to prepare, as I’ve no doubt it contributed to my success. If you’re taking it, good luck!

[1] https://www.udemy.com/aws-certified-solutions-architect-associate-2015/