Last Updated: February 25, 2016
·
1.18K
· brunochauvet

AWS Spot instance with AIM Role and Security Group

If you temporarily need an instance on AWS, you may opt for a spot instance to minimise your costs. Here is a ruby script to request a spot instance, assign AIM Role granting an S3 bucket read access and Security Group to allow SSH on the instance.

require 'aws-sdk'
require 'base64'

def request_spot_instance
    ec2 = AWS::EC2.new(:ec2_endpoint => "ec2.ap-southeast-2.amazonaws.com")
    iam = AWS::IAM.new

    sg = create_security_group(ec2)
    ip_arn = create_instance_profile(iam)

    spot_request = {
      spot_price: "0.0101",
      instance_count: 1,
      launch_specification: {
        image_id: 'ami-3b4bd301',
        key_name: 'my-keypair',
        instance_type: 'm3.medium',
        security_groups: [sg.name],
        user_data: Base64.encode64('#!/bin/bash\necho "Initialising instance"'),
        placement: {
          availability_zone: "ap-southeast-2a"
        },
        iam_instance_profile: {
          arn: ip_arn
        },
        block_device_mappings: [{
          device_name: "/dev/sda1",
          ebs: {
            volume_size: 30
          }
        }]
      }
    }

    response = ec2.client.request_spot_instances(spot_request)
  end

Find or create the security group

def create_security_group(ec2)
  sg_name = "MySecurityGroup"

  ec2.security_groups.each do |sg| 
    return sg if sg.name.eql?(sg_name)
  end

  sg = ec2.security_groups.create(sg_name)
  sg.authorize_ingress(:tcp, 22, '0.0.0.0/0')
  sg
end

Find or create the instance profile and AIM role

def create_instance_profile(iam)
  role_name = "S3Role"
  instance_profile_name = "S3InstanceProfile"

  iam.client.list_instance_profiles[:instance_profiles].each do |ip|
    return ip[:arn] if ip[:instance_profile_name].eql? instance_profile_name
  end

  policy = AWS::IAM::Policy.new
  policy.allow(:actions => ["s3:Get*","s3:List*"], :resources => 'arn:aws:s3:::myBucket*')

  assume_role_policy_document = '{"Version":"2008-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":["ec2.amazonaws.com"]},"Action":["sts:AssumeRole"]}]}'

  iam.client.create_role(
    :role_name => role_name,
    :assume_role_policy_document => assume_role_policy_document)

  iam.client.put_role_policy(
    :role_name => role_name,
    :policy_name => "AccessMyBucket",
    :policy_document => policy.to_json)

  resp = iam.client.create_instance_profile(
    :instance_profile_name => instance_profile_name)
  profile_arn = resp[:instance_profile][:arn]

  iam.client.add_role_to_instance_profile(
    :instance_profile_name => instance_profile_name,
    :role_name => role_name)

  profile_arn
end