Vagrant AWS Provider: Difference between revisions

From NovaOrdis Knowledge Base
Jump to navigation Jump to search
 
(4 intermediate revisions by the same user not shown)
Line 2: Line 2:


* https://github.com/mitchellh/vagrant-aws
* https://github.com/mitchellh/vagrant-aws
* https://www.vagrantup.com/docs/plugins/providers.html#example-provider-aws


=Internal=
=Internal=
Line 9: Line 10:
=Overview=
=Overview=


Vagrant AWS Provider is a plugin that adds an AWS provider to Vagrant, allowing it to control and provision machines in EC2 and VPC.
Vagrant AWS Provider is a Vagrant [[Vagrant_Concepts#Plugin|plugin]] that adds an AWS [[Vagrant_Concepts#Provider|provider]]  to Vagrant, allowing it to control and provision machines in EC2 and VPC.


=Installation=
=Installation=
Line 15: Line 16:
  vagrant plugin install vagrant-aws
  vagrant plugin install vagrant-aws
  vagrant box add dummy https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box
  vagrant box add dummy https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box
=Vagrantfile Example=
This is an example. More details about Vagrantfile syntax in: {{Internal|Vagrantfile|Vagrantfile}}
<syntaxhighlight lang='ruby'>
# frozen_string_literal: true
#
# Configuration
#
#
# It is assumed that the environment was already configured with AWS authentication (.aws/credentials or AWS
# environment variables). The VM will be created in the configured account/region.
#
ENVIRONMENT_NAME = "infra-playground"
BASTION_HOST = '1.2.3.4'
AWS_KEYPAIR = 'infra-playground'
SSH_PRIVATE_KEY = "~/.ssh/#{AWS_KEYPAIR}.pem"
SSH_CONFIG_FILE = "#{ENV['HOME']}/.ssh/dev/infra-worker"
#
# This is required by AWS CLI as part of instance provisioning call. It must the ID of the private subnet
# the instance will be attached to. If using environments, this subnet should be the default private subnet
# of the environment.
#
SUBNET_ID = 'subnet-000000000000000'
#
# This is required by AWS CLI as part of instance provisioning call. It must the ID of the security
# group that will protect the access to the instance. Access must be configuring depending on the instance
# requirements. At minimum, it should allow inbound ssh access.
#
SECURITY_GROUP_ID = 'sg-000000000000000'
#
# The AMI of the infra-worker image created by Packer
#
AMI_ID = ENV['AMI_ID'] || 'ami-0000000000000000'
INSTANCE_TYPE = 'm5.4xlarge'
VOLUME_SIZE_GB = 50
#
# Install vagrant plugin
#
# @param: plugin type: Array[String] desc: The desired plugin to install
def ensure_plugins(plugins)
  logger = Vagrant::UI::Colored.new
  result = false
  plugins.each do |p|
    pm = Vagrant::Plugin::Manager.new(
      Vagrant::Plugin::Manager.user_plugins_file
    )
    plugin_hash = pm.installed_plugins
    next if plugin_hash.key?(p)
    result = true
    logger.warn("Installing plugin #{p}")
    pm.install_plugin(p)
  end
  if result
    logger.warn('Re-run vagrant up now that plugins are installed')
    exit
  end
end
def aws_config(name)
  value = `aws configure get #{name}`.strip
  raise ArgumentError, "aws #{name} config must be set; use 'aws configure set #{name} <value>'" if value.empty?
  value
end
def username
  ENV['USER'] || 'anonymous'
end
def hostname
  "infra-worker-#{username}"
end
#
# Create and configure the AWS instance(s)
#
Vagrant.configure('2') do |config|
  ensure_plugins(%w[vagrant-aws])
  config.vm.define :infra_worker do |t|
  end
  config.vm.hostname = hostname
  #
  # Use dummy AWS box
  #
  config.vm.box = 'dummy'
  config.vm.synced_folder '.', '/vagrant', disabled: true
  #
  # Specify AWS provider configuration
  #
  config.vm.provider 'aws' do |aws, override|
    #
    # Specify SSH keypair to use, which should match SSH_PRIVATE_KEY
    #
    aws.keypair_name = AWS_KEYPAIR
    aws.instance_type = INSTANCE_TYPE
    aws.associate_public_ip = false
    aws.elastic_ip = false
    #
    # Launch configuration
    #
    aws.ami = AMI_ID
    aws.subnet_id = SUBNET_ID
    aws.security_groups = [SECURITY_GROUP_ID]
    aws.block_device_mapping = [{ 'DeviceName' => '/dev/xvda', 'Ebs.VolumeSize' => VOLUME_SIZE_GB }]
    aws.tags = {
      'Name' => hostname,
      'Created by' => username,
      'Environment' => ENVIRONMENT_NAME
    }
    #
    # Specify username and private key path
    #
    config.ssh.forward_agent = true
    override.ssh.username = 'ec2-user'
    override.ssh.private_key_path = SSH_PRIVATE_KEY
    override.ssh.proxy_command = "ssh -o ExitOnForwardFailure=yes -W %h:%p -i #{override.ssh.private_key_path} %r@#{BASTION_HOST}"
  end
  config.trigger.after [:up] do |t|
    t.info = "Writing ssh config to #{SSH_CONFIG_FILE}"
    t.run = { path: '../_common_tools_and_config/bin/configure-ssh-access', args: [SSH_CONFIG_FILE.to_s] }
  end
end
</syntaxhighlight>
Companion ssh configuration script <code>configure-ssh-access'</code>
<syntaxhighlight lang='bash'>
#!/usr/bin/env bash
function usage() {
cat << EOF
Write the output of "vagrant ssh-config" to the configuration file specified as first argument.
This script is invoked as part of the "vagrant up" sequence. Various Vagrantfiles that mention
it have the path to it hardcoded.
EOF
}
function main() {
    local ssh_config_file=$1
    [[ -z ${ssh_config_file} ]] && { echo "a ssh configuration file must be specified" 1>&2; exit 1; }
    mkdir -p $(dirname ${ssh_config_file})
    #
    # Ruby won't allow for "-" in host name so we convert it here. "Host a_b" will be converted to "Host a-b".
    #
    vagrant ssh-config | sed -e 's/^\(Host.*\)_\(.*\)/\1-\2/' > ${ssh_config_file}
}
main "$@"
</syntaxhighlight>
=Configuration=
==Configuring the Instance Profile==
Use <code>iam_instance_profile_arn</code> (the ARN of the [[Amazon_AWS_Security_Concepts#Instance_Profile|IAM instance profile]] to associate with the instance) or <code>iam_instance_profile_name</code> (the name of the [[Amazon_AWS_Security_Concepts#Instance_Profile|IAM instance profile]]  to associate with the instance).

Latest revision as of 21:50, 19 November 2019

External

Internal

Overview

Vagrant AWS Provider is a Vagrant plugin that adds an AWS provider to Vagrant, allowing it to control and provision machines in EC2 and VPC.

Installation

vagrant plugin install vagrant-aws
vagrant box add dummy https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box

Vagrantfile Example

This is an example. More details about Vagrantfile syntax in:

Vagrantfile
# frozen_string_literal: true

#
# Configuration
#

#
# It is assumed that the environment was already configured with AWS authentication (.aws/credentials or AWS
# environment variables). The VM will be created in the configured account/region.
#

ENVIRONMENT_NAME = "infra-playground"
BASTION_HOST = '1.2.3.4'
AWS_KEYPAIR = 'infra-playground'
SSH_PRIVATE_KEY = "~/.ssh/#{AWS_KEYPAIR}.pem"
SSH_CONFIG_FILE = "#{ENV['HOME']}/.ssh/dev/infra-worker"

#
# This is required by AWS CLI as part of instance provisioning call. It must the ID of the private subnet
# the instance will be attached to. If using environments, this subnet should be the default private subnet
# of the environment.
#
SUBNET_ID = 'subnet-000000000000000'

#
# This is required by AWS CLI as part of instance provisioning call. It must the ID of the security
# group that will protect the access to the instance. Access must be configuring depending on the instance
# requirements. At minimum, it should allow inbound ssh access.
#
SECURITY_GROUP_ID = 'sg-000000000000000'

#
# The AMI of the infra-worker image created by Packer
#
AMI_ID = ENV['AMI_ID'] || 'ami-0000000000000000'

INSTANCE_TYPE = 'm5.4xlarge'
VOLUME_SIZE_GB = 50

#
# Install vagrant plugin
#
# @param: plugin type: Array[String] desc: The desired plugin to install
def ensure_plugins(plugins)
  logger = Vagrant::UI::Colored.new
  result = false
  plugins.each do |p|
    pm = Vagrant::Plugin::Manager.new(
      Vagrant::Plugin::Manager.user_plugins_file
    )
    plugin_hash = pm.installed_plugins
    next if plugin_hash.key?(p)

    result = true
    logger.warn("Installing plugin #{p}")
    pm.install_plugin(p)
  end
  if result
    logger.warn('Re-run vagrant up now that plugins are installed')
    exit
  end
end

def aws_config(name)
  value = `aws configure get #{name}`.strip
  raise ArgumentError, "aws #{name} config must be set; use 'aws configure set #{name} <value>'" if value.empty?
  value
end

def username
  ENV['USER'] || 'anonymous'
end

def hostname
  "infra-worker-#{username}"
end

#
# Create and configure the AWS instance(s)
#
Vagrant.configure('2') do |config|

  ensure_plugins(%w[vagrant-aws])

  config.vm.define :infra_worker do |t|
  end

  config.vm.hostname = hostname
  #
  # Use dummy AWS box
  #
  config.vm.box = 'dummy'
  config.vm.synced_folder '.', '/vagrant', disabled: true

  #
  # Specify AWS provider configuration
  #
  config.vm.provider 'aws' do |aws, override|
    #
    # Specify SSH keypair to use, which should match SSH_PRIVATE_KEY
    #
    aws.keypair_name = AWS_KEYPAIR
    aws.instance_type = INSTANCE_TYPE
    aws.associate_public_ip = false
    aws.elastic_ip = false

    #
    # Launch configuration
    #
    aws.ami = AMI_ID
    aws.subnet_id = SUBNET_ID
    aws.security_groups = [SECURITY_GROUP_ID]
    aws.block_device_mapping = [{ 'DeviceName' => '/dev/xvda', 'Ebs.VolumeSize' => VOLUME_SIZE_GB }]
    aws.tags = {
      'Name' => hostname,
      'Created by' => username,
      'Environment' => ENVIRONMENT_NAME
    }

    #
    # Specify username and private key path
    # 
    config.ssh.forward_agent = true
    override.ssh.username = 'ec2-user'
    override.ssh.private_key_path = SSH_PRIVATE_KEY
    override.ssh.proxy_command = "ssh -o ExitOnForwardFailure=yes -W %h:%p -i #{override.ssh.private_key_path} %r@#{BASTION_HOST}"
  end

  config.trigger.after [:up] do |t|
    t.info = "Writing ssh config to #{SSH_CONFIG_FILE}"
    t.run = { path: '../_common_tools_and_config/bin/configure-ssh-access', args: [SSH_CONFIG_FILE.to_s] }
  end
end

Companion ssh configuration script configure-ssh-access'


#!/usr/bin/env bash

function usage() {

cat << EOF

Write the output of "vagrant ssh-config" to the configuration file specified as first argument.
This script is invoked as part of the "vagrant up" sequence. Various Vagrantfiles that mention
it have the path to it hardcoded.
EOF

}
function main() {

    local ssh_config_file=$1

    [[ -z ${ssh_config_file} ]] && { echo "a ssh configuration file must be specified" 1>&2; exit 1; }

    mkdir -p $(dirname ${ssh_config_file})

    #
    # Ruby won't allow for "-" in host name so we convert it here. "Host a_b" will be converted to "Host a-b".
    #
    vagrant ssh-config | sed -e 's/^\(Host.*\)_\(.*\)/\1-\2/' > ${ssh_config_file}
}

main "$@"

Configuration

Configuring the Instance Profile

Use iam_instance_profile_arn (the ARN of the IAM instance profile to associate with the instance) or iam_instance_profile_name (the name of the IAM instance profile to associate with the instance).