Amazon AWS Ubuntu cloud-init

Posted on Monday, January 21, 2013



 Ubuntu’s cloud releases (AMIs for AWS), which are listed at http://uec-images.ubuntu.com/releases/ [1],  include an ubuntu package called cloud-init.

Cloud-init,  https://help.ubuntu.com/community/CloudInit  [2], is a tool that will run a script during the initializing of an ec2 image in the amazon cloud.   It allows for custom deployment of an AMI as it is initialized.


I think the best way to learn a tool is to start using it.




Simple script test


Create a cloud-config script.  This is the script that can be fed into the instance as it initializes itself.   This script is run once when the EC2 instance is created not if/when it may reboot.



I am going to use a simple example here that runs command lines as the root user after the instance is created and boots up.

Here is the cloud-config file


#cloud-config
runcmd:
 - [ wget, "http://www.google.com", -O, /tmp/index.html ]
 - [ touch, /tmp/bob.txt ]


This just runs a few command line commands, wget and touch.


To use this script when creating an instance via the EC2 console you need to do the following.







From the EC2 web console click on Launch Instance






Select Class Wizard and click Continue





Select the Ubuntu 64 bit AMI





Click Continue








Paste the cloud-config text in the User Data:  area and click continue.





Click Continue





I gave mine a name “Test_10” so I can see it easily and click continue.





Choose your key-pair and click continue






Choose, or set up your security group and click Continue.   Rememner your security  group needs to have port 22 open if you expect to SSH to it.





Click Launch



Give it a minute or two to launch then ssh into your instance.  In my case my DNS address was 
ec2-174-129-94-111.compute-1.amazonaws.com



      > ssh -i .ec2/pats-keypair.pem ubuntu@ ec2-174-129-94-111.compute-1.amazonaws.com




Now run



      > ls -alh /tmp/





You should see the two files that the cloud-config script created.




Debugging


It took me several tries to get this simple cloud-config file working properly during which I found out were the log files for it are and a few other handy tools for debugging.

First the log file.  The log file for this is located at

/var/log/cloud-init.log

The cloud-config.txt file is also saved off at this location.

/var/lib/cloud/instance/cloud-config.txt


Another handy tool I used to help me debug a few things was the ec2 command line ec2-get-console-output

Assuming you have the ec2 command line commands installed on your system all you need is an instance id to run this.  


      > ec2-get-console-output i-47981a36


My instance was  i-47981a36

This gave me the console output and gave me some information and feedback on what the cloud-config output was.  Not perfect, but there was some useful information there.



Command line


As an alternative to using the ec2 web console to start an instance you cabn use the command line tools.  Here is an example of using the command line tools with a cloud-config file.


First make the cloud-config file.


      > vi cloud-config.txt


And place the same cloud-config data from the ec2 console example





      > ec2-run-instances ami-fd20ad94 -b /dev/sda1=:8:true -k pats-keypair -t t1.micro  -g default --availability-zone us-east-1a -f cloud-config.txt



Why not just use bash?


You could have done this simple command by passing it a bash file.

For example you could have created this bash file.



#!/bin/bash

wget http://www.google.com -O /tmp/index.html
touch /tmp/bob.txt


And pass it in when you create the instance and the results are the same as the cloud-config file.


To be honest I have not spent enough time using the cloud-config format to give all the whys.   I think you could get the job done with either bash or cloud-config but I think cloud-config has some better tools to do some typical thins you need done when creating a new instance.    I will use the rest of this document to show some examples I came up with for my own needs.


Adding Users


One thing I personally need, for my systems, is to add users to my own AMI images upon creation.  The idea being that I can set up an AMI, ready to go with all the installs I want but no users (beyond the default ubuntu user).   Then I can kick off a machine from that AMI and add users to it upon creation with their ssh keys.   This is important if you work for a company with people coming and going.  If a user leaves I can simply remove them from the cloud-config script.   (I would also have to update any running machine, or replace them)

For a prior small client I put the ssh keys in the AMI which was convenient, assuming no one joins or leaves the company.  The minute someone did I would have to update all the AMIs with new users/ssh keys.


Having said all that lets get into what I did to make this work.   First off it appears that Ubuntu 12.04 does not support the “users” cloud-config feature, so I had to user 12.10  (it took me a while to figure that one out.

Example location


An Ubuntu server has example files for cloud init in the following folder

/usr/share/doc/cloud-init/examples

Make sure to go here for ideas


Adding a user with a password


First you need a md5 crypted password.  The easiest way to do this is to download the whois package.


      > sudo apt-get install whois


Now run this to create an crypted password


      > mkpasswd -m sha-512





Here I enter the password “password”  and got the value

$6$VaL1/XcbO$QWjXoxu9Q8v5tDZAiFmvzgLGVsGj3SpYbP8//FCZaacDaJX1HqmzvpNMEPd7ag65e5zmu.kLDxpD8GcwtK4bx1

You need this value, well using your own password, to create a user with cloud-init and automatically set their password.


Alternatively you could rip out your current password from your /etc/shadow file

Run this command, but enter your username


      > sudo tail /etc/shadow | grep patman





And copy the hashed password between the first and second  colon “:”

 At any rate you have an encrypted password to use for your user. 


Here is a cloud-config file I attempted to use that did not work.  I am showing it here for a purpose so bear with me.



#cloud-config
# Add groups to the system
# The following example adds the ubuntu group with members foo and bar and
# the group cloud-users.
groups:
  - patman

# Add users to the system. Users are added after groups are added.
users:
  - default
  - name: patman
    gecos: Patrick Bailey
    primary-group: patman
    groups: admin
    passwd: $6$72xKa0rf$jTBvOqibuTMp7d3Tlvo6MP7MSv1V8IJpVUXvjlJos0KECsOnG5dFYTDAP9MadGhgaCCKNT0RFGKXj9fLlTwhW1


This first creates the group patman.  Then it creates the user patman and assigns his primary group to patman and adds him to the admin group.  Then gives him the passwd




I then used this command line command to instantiate a machine.


      > ec2-run-instances ami-7539b41c -b /dev/sda1=:8:true -k pats-keypair -t t1.micro  -g default --availability-zone us-east-1a -f cloud-config.txt


Notice the AMI is for a 12.10 Ubuntu AMI rather than a 12.04 one.


Logging into this instance  (make sure to use your dns location)


      >  ssh -i .work_ec2/pats-keypair.pem ubuntu@ec2-107-22-7-176.compute-1.amazonaws.com


Looking at the /etc/passwd file


      >  sudo vi /etc/passwd





I can see that the patman user was made.



If I look in the /etc/group file


      >  sudo vi /etc/group









I can see the patman group was made and that the patman user was added to the admin group.

But I cannot switch to the patman user using the password I gave it in the cloud-config file….

Looking in /etc/shadow you can see the issue


      >  sudo vi /etc/shadow









The password is there, but there is an exclamation point in front of it.



I found out from here http://linuxg.net/some-etcshadow-magic/ [4]  and here http://www.ducea.com/2007/12/05/howto-disable-a-user-account-in-linux/ [5] That an exclamation indicates it does not have a password.  If I remove the exclamation by hand and try again it works. 

It took me a long time to figure out this issue.   However that was not the only issue that had to be solved…

The following does not work either, but should


#cloud-config
# Add groups to the system
# The following example adds the ubuntu group with members foo and bar and
# the group cloud-users.
groups:
  - patman

# Add users to the system. Users are added after groups are added.
users:
  - default
  - name: patman
    gecos: Patrick Bailey
    primary-group: patman
    groups: admin
    lock-passwd: false
    passwd: $6$72xKa0rf$jTBvOqibuTMp7d3Tlvo6MP7MSv1V8IJpVUXvjlJos0KECsOnG5dFYTDAP9MadGhgaCCKNT0RFGKXj9fLlTwhW1






I had to dig into the actual cloud init code to figure out why this was not working.



      >   cd  /usr/share/pyshared/cloudinit/
      > sudo grep -rn lock_passwd *


Which got me to /usr/share/pyshared/cloudinit/distros/__init__.py line 267



      >   vi +267 /usr/share/pyshared/cloudinit/distros/__init__.py






The issue is this system line.  You need to add the “system” and set it to false to get it to work properly.   System, if set to true assumes it’s a system user and does not create a home directory.




Here is a cloud-config file that did work.


#cloud-config
# Add groups to the system
# The following example adds the ubuntu group with members foo and bar and
# the group cloud-users.
groups:
  - patman

# Add users to the system. Users are added after groups are added.
users:
  - default
  - name: patman
    gecos: Patrick Bailey
    primary-group: patman
    groups: admin
    passwd: $6$72xKa0rf$jTBvOqibuTMp7d3Tlvo6MP7MSv1V8IJpVUXvjlJos0KECsOnG5dFYTDAP9MadGhgaCCKNT0RFGKXj9fLlTwhW1

runcmd:
  - [passwd, patman, '-u']


Because of the issue you need to add a runcmd which in this case runs the command “passwd patman –u”  which will unlock the user patman’s password.







My Final user add code with ssh keys



#cloud-config
# Add groups to the system
# The following example adds the ubuntu group with members foo and bar and
# the group cloud-users.
groups:
  - patman

# Add users to the system. Users are added after groups are added.
users:
  - default
  - name: patman
    shell: /bin/bash
    gecos: Patrick Bailey
    primary-group: patman
    groups: admin
    passwd: $6$72xKa0rf$jTBvOqibuTMp7d3Tlvo6MP7MSv1V8IJpVUXvjlJos0KECsOnG5dFYTDAP9MadGhgaCCKNT0RFGKXj9fLlT
    ssh-import-id: None
    ssh-authorized-keys:
      - ssh-rsa AAAAB3NXXXXX
      - ssh-rsa AAAAB3XXXXXXX

runcmd:
  - [passwd, patman, '-u']


Here I added the shell command to designate my shell preference.
I set the ssh-import-id to None, this is a feature that imports ssh public keys from a site (not something I am familiar with).

Then I added the ssh-authorized-keys and added the actual public keys from my system.

Now I can happily run this to ssh to the machine after it has been initiated


      >   ssh patman@ec2-23-20-92-205.compute-1.amazonaws.com







Installing Apache


This example came from a video I found at http://www.youtube.com/watch?v=-zL3BdbKyGY [6]

You can use cloud-config to install packages.  In this example I update the apt tools and install apache2.



#cloud-config
apt_update: true
apt_upgrade: true

packages:
 - apache2


By using this script and if you have port 80 open for this server you

You should be able to open up its location and see that apache is running.








References

[1]  Ubuntu Cloud Images
       Visited 1/2013
[2]  Ubuntu CloudInit
       Visited 1/2013
[3]  cloud-init-dev/cloud-init/trunk
       Visited 1/2013
[4]  Some /etc/shadow Magic
       Visited 1/2013
[5]  HowTo Disable a User Account in Linux
       Visited 1/2013
[6]  Ubuntu Cloud-Init Technology
       Visited 1/2013





No comments:

Post a Comment