CloudExceptions::CloudException – 400: VPCIdNotSpecified: No default VPC for this user

When you launch a new EC2 instance in the AWS cloud from the command line or with other cloud management platforms, you may get the error message:

CloudExceptions::CloudException – 400: VPCIdNotSpecified: No default VPC for this user (RequestID: …)

This can happen when the specified Subnet Id is not a valid subnet in the selected availability zone (datacenter).

Create the AWS credentials file from a Chef Data Bag

When a process on a server instance needs access to an AWS account, the user who will execute the AWS CLI commands needs to be able to automatically authenticate in AWS.

For automatic AWS authentication, the AWS CLI creates two files in the .aws directory:

  • config and
  • credentials.

The location of this directory depends on the operating system and the type of user.

  • On Linux, the location is ~/.aws ( the user’s home directory )
  • On Windows, it is located at C:\Users\USER_NAME\.aws
  • On Windows, if the file was created by SYSTEM, the location is C:\Windows\System32\config\systemprofile\.aws

Store the AWS key values

To create these files, you need to store the AWS Access Key and Secret Key. The safest place for these values is an encrypted data bag. To automatically generate the AWS files, create a data bag file and name it the same as the “id” in the following structure:

  "MY_PROFiLE_1": {
    "region": "MY_REGION_1",
    "aws_access_key_id": "MY_ACCESSKEY_1",
    "aws_secret_access_key": "MY_SECRET_KEY_1"
  "MY_PROFiLE_2": {
    "region": "MY_REGION_2",
    "aws_access_key_id": "MY_ACCESSKEY_2",
    "aws_secret_access_key": "MY_SECRET_KEY_2"

To create and encrypt the data bag see my post on Chef Data Bags

Create the AWS authentication files

  1. In your Chef recipe, first install the AWS CLI and reboot the server, so the new path entry will be available for the Chef process.
  2. The following Chef code will create the AWS config and credential files. The script
    1. opens and decrypts the data bag,
    2. loads it into a hash table,
    3. iterates through the hash items,
    4. skips the “id” item,
    5. stores the AWS key values in a temporary file,
    6. executes the “aws configure” command to generate the AWS config and credential files.
  # Iterate through the data bag and create the credentials file

  puts "***** Creating the AWS credentials file"

  # Load the encrypted data bag into a hash
  aws_credentials = Chef::EncryptedDataBagItem.load('MY_DATA_BAG_NAME', 'MY_DATA_BAG_ITEM_NAME').to_hash

  # Iterate through the items, skip the "id"
  aws_credentials.each_pair do |key, value|

    # skip the "id"
    next if key == "id"

    # Add the credentials to the .aws/credentials file
    puts "Account #{key}, Region #{value['region']}"

    batch "add_aws_credentials_#{key}" do
      code <<-EOF echo #{value["aws_access_key_id"]}> input.txt
        echo #{value["aws_secret_access_key"]}>> input.txt
        echo #{value["region"]}>> input.txt
        echo.>> input.txt
        aws configure --profile #{key} < input.txt



Get AWS SSL Certificate resource ids from existing Load Balancers

To launch an Elastic Load Balancer ( ELB ) with an existing SSL certificate using Terraform, you need to specify the AWS certificate resource id. If you have already uploaded the certificate and attached it to an existing load balancer, the following AWS CLI command will display it in the command window. MY_PROFILE is the name of the profile in the square brackets [] in the ~/.aws/credentials file.

aws elb describe-load-balancers --region MY_AWS_REGION --profile MY_PROFILE |grep SSL

To get all information on the load balancers, just omit the grep command:

aws elb describe-load-balancers --region MY_AWS_REGION --profile MY_PROFILE

Convert PEM files to PPK to use them in PuTTY

When you create a key in AWS you can download it one time in PEM format. To use it in PuTTY, the free SSH and Telnet client, you have to convert it to PPK format.

To install PuTTY, see the Terminal Emulator section in Recommended utilities for your workstation

To convert a PEM file to PPK

  1. Open a terminal window in the folder of the PEM file
  2. Execute the following
    puttygen MYKEY.pem -o MYKEY.ppk


Error waiting for instance (i-…) to become ready: unexpected state ‘terminated’, wanted target ‘running’

When you launch a server instance with Terraform, sometimes the error message does not contain the underlying cause. When the cloud provider cannot complete the request, many times Terraform displays a generic error message:

Error waiting for instance (i-...) to become ready: unexpected state 'terminated', wanted target 'running'

To find the root cause of the error in AWS

  1. Log into the AWS console and navigate to the EC2 section,
  2. Search for the instance by the instance Id,
  3. You can find the error message at the bottom of the Description tab

In our specific case, it was Client.VolumeLimitExceeded: Volume limit exceeded

We had to increase the volume limit to be able to launch more large EC2 instances.

Upgrade a server on an AWS EC2 instance with minimum risk and downtime

When you need to upgrade an application on an AWS EC2 instance with minimum downtime, there are many options.

Upgrade an EC2 instance

  1. Stop the application, so users don’t make more changes,
  2. Create a backup of the database (snapshot of the RDS instance),
  3. Create a backup of the server (backup image of the EC2 instance),
  4. Upgrade the application on the server,
  5. Start the application,
  6. Test the new version of the application.

In case the upgrade fails, or the post-upgrade test fails

  1. Stop the application,
  2. If you use RightScale to launch servers:
    1. stop the RightLink service on the failed server to prevent RightScale auto terminating the restored server
      (When RightScale finds a new identical server instance, it automatically shuts it down to avoid multiple instances with the same identifier.)
    2. Terminate the failed server
  3. Stop the failed server,
  4. Restore the database from the pre-upgrade backup with a new name,
  5. Restore the server instance from the pre-upgrade backup,
  6. Start the restored server,
  7. Change the database address in the application’s config file to point to the restored database,
  8. Start the application,
  9. Test the restored version of the application.

To make the backup image of the AWS EC2 instance

  1. Open the AWS console and navigate to EC2, Running instances
  2. Find the server instance you want to backup
  3. Right-click the row of the instance and select Image, Create Image

  4. Name the image and click the Create Image button
  5. Save the image Id from the popup

Find the AWS AMI that a RightScale server template is using

When you use RightScale to launch servers in the cloud, you want to use the same base image to test your Chef cookbooks in Test Kitchen.

Packer by Hashicorp is a utility to create custom server images based on cloud images. You supply the image ID and other configuration parameters to create a new custom image.

To find the AMI ID of the base image of the RightScale Server Template

  1. Open the RightScale user interface in your browser,
  2. Select the RightScale account where the server template was created,
  3. In RightScale Cloud Management select  Design / ServerTemplates,
  4. Select the server template,
  5. Select Images,
  6. Select the MultiCloud image,
  7. Select Clouds,
  8. Select the image in the region you are working in,
  9. The Resource UID is the AMI ID of the image.

Migrate databases to and from AWS RDS instances

Amazon Web Services do not provide tools to migrate data to, from and between AWS RDS instances.

There is a free utility that can do the job.

SQL Server Management Studio (SSMS)

Install Microsoft SQL Server Management Studio (SSMS), because the utility uses libraries from it.

  1. Download the installer for free from

SQL Azure Migration Wizard


  1. Download the SQL Azure Migration Wizard from
  2. Unzip the downloaded ZIP file into a folder on your hard drive
  3. Create a shortcut in your Start Menu for SQLAzureMW.exe

Migrate a database

  1. Start the SQL Azure Migration Wizard by executing the SQLAzureMW.exe file
  2. Select Database in the Analyze / Migrate section and click Next

Connect to the source database

  1. On the Connect to Server page
    1. Enter the address of the database server
    2. Select SQL Server Authentication
    3. Enter the database owner login name and password
    4. If you keep Master DB selected, the next screen will show the list of databases to select from
    5. To save the username and password select Save Login Information
    6. Click Connect

  2. Select the database to connect to and click Next
  3. Leave Script all database objects selected and click Next
  4. On the Script Wizard Summary page click Next
  5. Click Yes to start the read process
  6. On the Results Summary page select Auto Scroll Display to see the scrolling results
  7. When the read is done click Next

Connect to the target database

  1. Enter the connection properties of the target database server
  2. Select the target database
    1. To migrate the data into a new database click the Create Database button
    2. On mirrored RDS instances we cannot drop and recreate databases. To migrate data into an existing database
      1. Use SQL Management Studio to drop the existing tables to avoid key conflicts
      2. Select the target database on this page
  3. Click Next
  4. Click Yes to start the write process
  5. When the write process is done click Exit


DevOps Engineering part 5. – Create an enterprise cookbook

In this exercise we will create a Chef cookbook for a corporation. It will be robust and include all the necessary elements to be used in a large enterprise. If your company already has established standards, as you progress with this tutorial, copy the appropriate file from an existing cookbook. If this is the first cookbook in your organization, or you don’t want to follow the current standards, copy the sample files from this page.

Create the cookbook

  • Navigate to the C:\Chef\…\cookbooks folder and open a Bash window
  • Create an empty cookbook
    chef generate cookbook COOKBOOK_NAME

    Chef creates a new sub-folder with the name of the cookbook.

  • Rename the new folder to cookbook-COOKBOOK_NAME to distinguish it in version control from other repository types.

Update the .gitignore file

The last line is the most important! We want to exclude sensitive information from source control.


# Bundler


# Ignore the unencrypted Data Bags

Update the metadata.rb file

Add your name, email address, and the version of the cookbook to the top of the metadata.rb file

maintainer 'YOUR_NAME'
maintainer_email 'YOUR_EMAIL_ADDRESS'
license 'All rights reserved'
description 'Installs/Configures THE_NAME_OF_THE_COOKBOOK'
long_description, ''))
version '1.0.0'

The expression in the long_description line refers to the file that GitHub can create when you set up a new repository. Place the cookbook related information into that file, so others who want to use your cookbook can easily find it.

Update the .kitchen.yml file to be able to test your cookbook.

If you want to test your cookbook in the Cloud, copy the following sections from an existing .kitchen.yml file of your organization. To learn Chef and launch instances with Vagrant on your workstation, the automatically created .kitchen.yml file is perfect.

  • driver
  • provisioner
  • platforms
  • a suite as an example

If your organization use tags to track instances in the Cloud,  update the tags section to reflect the values of the cookbook.

The following is a sample .kitchen.yml file with Windows and Linux platforms

name: ec2
aws_ssh_key_id: YOUR_AWS_SSH_KEY_NAME
region: THE_AWS_REGION # us-east-1
availability_zone: THE_AWS_AVAILIBILITY_ZONE # e
subnet_id: THE_SUBNET_ID
require_chef_omnibus: true
Name: TK_test
Environment: DEV
created-by: test-kitchen
associate_public_ip: false #This can be false if test instance is accessible by VPN or LAN
retryable_tries: 120
retryable_sleep: 5
# interface: dns #uncomment if test instance should be registered with DNS

name: chef_zero

- name: windows-2012r2
image_id: "A_WINDOWS_AMI_ID"
instance_type: INSTANCE_TYPE # t2.large #Can be changed to any AWS instance size
security_group_ids: [ "SECURITY_GROUP_ID_1", "SECURITY_GROUP_ID_2" ]
name: winrm
elevated: true # Required for the installation of some Windows features
connection_timeout: 10
connection_retries: 5

- name: rhel7
image_id: "A_LINUX_AMI_ID"
instance_type: INSTANCE_TYPE # t2.medium #Can be changed to any AWS instance size
- device_name: /dev/sda1
volume_type: standard
volume_size: 100
delete_on_termination: true
security_group_ids: [ "SECURITY_GROUP_ID_1", "SECURITY_GROUP_ID_2" ]
ssh_key: C:\Users\YOUR_USERNAME\.aws\YOUR_KEY_FILE_NAME.pem
connection_timeout: 10
connection_retries: 5
sudo: true

- name: windows_server
data_bags_path: "data_bags"
encrypted_data_bag_secret_key_path: "../../data_bags/DATABAG_SECRET_FILE_NAME"
- rhel7

Encrypted Data Bags

If you want to use encrypted data bags, ask your Chef administrator to send you the key file to encrypt and decrypt data bags. In the sample .kitchen.yml file above the DATABAG_SECRET_FILE is the placeholder for the key file name. Create a folder for the key at


on the same level where the cookbook and environment folders are.


This is a chicken and egg paradox. We don’t want to commit secrets into version control, so we need to encrypt them. But how can we place the secret encryption key on the server to decrypt the secrets? We will use Packer to create our own server images that will contain the secret key, so when Chef starts to run on the server, the key is going to be there.

Default recipe

We will place code in the default.rb file that is common to all recipes in the cookbook. All custom recipes will call the default recipe as the first step.

Update the header comments of the default.rb recipe with your name and company information

# Cookbook Name:: COOKBOOK_NAME
# Recipe:: default
# Copyright (c) 2015-2016 COMPANY_NAME, All Rights Reserved.

Custom recipe

Make a copy of the default.rb file and name it to describe the purpose of the instance (server.rb)

  • Update the name of the recipe in the header
  • Add the following line under the header to call the default recipe, even if it is currently empty
    include_recipe 'COOKBOOK_NAME::default'

Add the cookbook to GitHub

Create the local repository

  • In the Bash window execute the following commands
git init
git add .
git commit -m "Initial commit"

Add the repository to GitHub

In your web browser log into your GitHub account and create a new repository

  • Click the New Repository button
  • Name the repository the same as the name of the folder of the cookbook (cookbook-…)
  • Execute the lines in the section …or push an existing repository….  If you work on a Windows workstation make sure HTTPS is selected
    git remote add origin
    git push -u origin master
  • In the Collaborators & teams section of Settings select the group who will have access to the new repository

Test the cookbook

In the Bash window launch the instance with Test Kitchen

List the available instances

kitchen list

Launch the instance


If there are multiple suites or platforms in the .kitchen.yml file you need to type the unique part of the name of the instance to identify it.

Start a Remote Desktop connection to a Windows instance


If you work on a Macintosh workstation and testing a Windows server, the best way to remote into the server is

  1. Install Microsoft Remote Desktop for free from the Apple App Store (See the Remote Desktop Client section in Install the DevOps development tools on Macintosh,
  2. Execute the kitchen login STRING_UNIQUE_TO_THE_INSTANCE command in the terminal window,
  3. The Microsoft Remote Desktop window will pop up with the User account name and the IP address. If you click “Connect”, the remote connection opens with the default settings, that are may not optimal for your display. The “login” command already created a new entry in the Microsoft Remote Desktop app with the IP address of the instance. To use custom settings, click Cancel,
  4. Open the Microsoft Remote Desktop app, right click the last entry that contains the IP address, select Edit, and copy the IP address to the clipboard,
  5. Create a new connection with custom display settings and paste the IP address there. You can keep this generic connection to access the Test Kitchen instances, just update the IP address.
  6. Delete the automatically created connection

SSH into a Linux instance



  • USER_NAME is the value of username: in the .kitchen.yml file.
  • IP_ADDRESS is the IP of the instance. Get it from the “Waiting for SSH service on…” line of the Test Kitchen bash or command window, or from the .yml file in the .kitchen/logs folder of the cookbook.
  • PATH_TO_THE_SSH_KEY_FILE is the value of ssh_key: in the .kitchen.yml file.

Terminate the instance


Upload the cookbook to the Chef server

See Connect to the Chef server in Beginner’s Guide to DevOps Engineering part 4.


Infrastructure as code in Beginner’s Guide to DevOps Engineering part 6.


to the Tutorials page

DevOps Engineering part 3. – Working with AWS

Install the AWS EC2 drivers

Open a Bash or CMD window in the Chef cookbook folder

  • Install the kitchen-ec2 driver
    More info on the ec2 driver at

    chef gem install kitchen-ec2
  • Add the gem folder to the path
    • On Macintosh
      • Add the path to the ~/.zshrc or ~/.bash_profile file
      • Open a new terminal window for the change to take effect
  • Install the  chef-zero-scheduled-task plugin
    chef gem install chef-zero-scheduled-task
  • Install the latest vagrant plugin
    chef gem install kitchen-vagrant

Personalize your workstation

Set up your account in the AWS console

If you are not an AWS account administrator, ask your AWS account administrator to do the following for you

  • Create an account in AWS
  • Add the account to the appropriate user group
  • Generate a password with a request to change it at the first login
  • Generate an AWS Access Key ID and Secret Key
    • Using your browser log into the AWS console
    • In the upper right corner click your user id
    • In the drop down list select Security Credentials
    • On the left select Users
    • In the user list select you account
    • Select the Security Credentials tab
    • Click the Create Access Key button

AWS Command Line Interface

Install AWS CLI

On Macintosh

  • Instructions are at
    The steps are:

    • Install pip, the Python Package Manager
      • Download the pip installation script
        curl -O
      • Check the version of Python on your computer
        python --version
      • Run the pip install script. Set the Python version according to the installed version on your workstation
        sudo python2.7
      • Install the AWS CLI using pip
        sudo pip install awscli --ignore-installed six

On Windows



If you do not configure the AWS CLI you will get the following error message: ‘NoneType’ object has no attribute ‘get_frozen_credentials’

  • Open a Bash window and execute the following command to save your AWS credentials and default region in the ( C:\Users\YOUR_USER_NAME\.aws in Windows ) folder.
    aws configure
    • Answer the questions
      AWS Access Key ID [None]: YOUR AWS KEY
      AWS Secret Access Key [None]: YOUR AWS SECRET KEY
      Default region name [None]: us-east-1
      Default output format [None]: HIT ENTER FOR NONE

Close and reopen all open Bash and Command windows to reload the changed Path environment variable.

The configure command created the .aws folder with two files.

On Macintosh

Your AWS configuration folder is located at ~/.aws

Set the permissions on the folder

  • Open a terminal window and execute
    chmod -R 700 ~/.aws
  • The result should be

If you copy key files to the folder you may get the following error message:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @         WARNING: UNPROTECTED PRIVATE KEY FILE!          @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ Permissions 0755 for ‘/Users/YOUR_USERNAME/.aws/KEY_FILE_NAME.pem’ are too open. It is required that your private key files are NOT accessible by others. This private key will be ignored. Load key “/Users/YOUR_USERNAME/.aws/KEY_FILE_NAME.pem”: bad permissions USERNAME@SERVER_IP’s password: Permission denied, please try again.

To satisfy the security requirements set the permission on the key files to 700

chmod -R 700 ~/.aws/KEY_FILE_NAME.pem

On Windows

Your AWS configuration folder is located at C:\Users\YOUR_USER_NAME\.aws

Your  credentials file will look like this

 aws_access_key_id = MY_ACCESS_KEY
 aws_secret_access_key = MY_SECRET_KEY

Test Kitchen will use the keys from the [default] section to connect to AWS when we launch instances.

When you work with multiple AWS accounts you can add all of your keys to the credentials file. To use a specific key, add the profile option to your command line instructions. If you don’t specify the profile in your AWS commands, the AWS Command Line Interface will use the key from the default section.

 aws_access_key_id = MY_ACCESS_KEY_FOR_AWS01
 aws_secret_access_key = MY_SECRET_KEY_FOR_AWS01

 aws_access_key_id = MY_ACCESS_KEY_FOR_AWS02
 aws_secret_access_key = MY_SECRET_KEY_FOR_AWS02

 aws_access_key_id = MY_ACCESS_KEY_FOR_AWS01
 aws_secret_access_key = MY_SECRET_KEY_FOR_AWS01

The config file will look like this. If you don’t specify the region in the AWS command, the AWS Command Line utility will use the region from this file.

region = us-east-1

Collect the following information to be able to launch an instance in AWS


  • Your IAM user name
  • AWS Access Key and Secret Key
  • Region (us-east-1)
  • Availability zone (b)
  • VPC subnet ID
  • Security group ID
  • AWS key pair file
  • AMI ID


Generate an AWS key pair

  • Log into the AWS console
  • Select EC2
  • Under Network & Security select Key Pairs
  • In the upper right corner select the region
  • Click the Create Key Pair button
    Create your key pair with the following naming scheme:
    For example: USERID_aws01_us_east_1
  • Download the .pem private key file and save it in the (C:\Users\YOUR_USER_NAME\.aws on Windows) directory you created above during the AWS CLI configuration.

For more info visit Amazon EC2 Key Pairs

Set up your .kitchen.yml file

When you have created your cookbook, Chef already added a .kitchen.yml file that tells Test Kitchen how to launch a server instance on your workstation.

The default .kitchen.yml file only contains driver and provisioner information for Vargrant. To launch a server instance in AWS we need to add AWS specific instructions to the file. First modify the .kitchen.yml file to be ready for other drivers:

  name: chef_zero

  name: inspec

  - name: ubuntu-16.04
      name: vagrant

  - name: centos-7.2
      name: vagrant

  - name: default
      - recipe[test::default]
        - test/recipes

Make sure the empty lines are really empty. The .kitchen.yml file cannot have white space in a seemingly empty line.



Connect to the Chef server in Beginner’s Guide to DevOps Engineering part 4.


to the Tutorials page