Deploying a Windows EC2 Instance with Hashicorp Terraform and Vault to AWS
As part of demonstrating our products to customers, I tend to reprovision EC2 instances to show how easy it is to mount data in AWS to Cloud Block Store. After doing this manually a little too often, I figured why not automate it? Check out this blog on how I use Terraform to deploy a EC2 instance and configure it for in-guest iSCSI.
Overview
If you are not familiar with the Pure Cloud Block Store, it is a purpose build block storage system that currently sits in AWS. There are many benefits and use cases you can find out here.
Today customers wonder once the data is in the Pure Cloud Block Store, how can they rapidly stand up a system and gain access to this data? This blog will cover a piece of automation I am now using to stand up an EC2 instance, configure it with iSCSI and get access to my data.
In a future post, i’ll dive much deeper into the Cloud Block Store architecture and configuration. For this post I wanted to focus on the basic deployment of automating t he deployment of the EC2 instance.
Pre-Requisites
- This is used to store the AWS access and secret key securely.
- This is used to automate the provisioning using a Terraform .TF file.
- This is the infrastructure to run the EC2 virtual machines.
Setup and Addition of AWS Secrets to Vault
Since I am running this on MacOS. I used brew to install Vault
1brew tap hashicorp/tap
2brew install hashicorp/tap/vault
Once Vault is installed, you can run the server locally. This will provide you the environment variable to use and provide the unseal key and root token.
Since I am using this for a lab, I am using the built in vault dev server. This should not be used for production!
1vault server -dev
To add your AWS secret key and access key to the vault, run the following command
1export VAULT_ADDR='http://127.0.0.1:8200'
2vault kv put secret/<secretname> secret_key=<secretkey> access_key=<accesskey>
Terraform Manifest Configuration
Download the sample manifest from GitHub and update the variables for your environment. This includes the Vault Token and Secret Name, and the AWS Region, AMI, Instance Type, VPC Security Groups, Subnet ID, KeyPair and Instance Name.
1provider "vault" {
2 address = "http://localhost:8200"
3 token = "<unsealtokenfromvault>"
4}
5
6data "vault_generic_secret" "aws_auth" {
7 path = "secret/<keyname>"
8}
9
10provider "aws" {
11 region = "us-west-2"
12 access_key = data.vault_generic_secret.aws_auth.data["access_key"]
13 secret_key = data.vault_generic_secret.aws_auth.data["secret_key"]
14}
15
16resource "aws_instance" "example" {
17 ami = "ami-id"
18 instance_type = "t2.micro"
19 vpc_security_group_ids = ["sg-id","sg-id2","sg-id3"]
20 get_password_data = true
21 subnet_id = "subnet-id"
22 key_name = "<secretkey>"
23 tags = {
24 Name = "<vmname>"
25 }
26 user_data = <<EOF
27 <powershell>
28 net user terraform Password1! /add /y
29 net localgroup administrators terraform /add
30 Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
31 Install-Module -Name PureStoragePowerShellSDK -Force
32 if (((Get-WindowsFeature Multipath-io).InstallState) -like "Available") {
33 Set-Service -Name msiscsi -StartupType Automatic
34 Start-Service -Name msiscsi
35 Set-InitiatorPort -NodeAddress (Get-InitiatorPort).NodeAddress -NewNodeAddress "iqn.1991-05.com.<customiqnname>"
36 Add-WindowsFeature -Name 'Multipath-IO' -Restart
37 }
38 if (((Get-WindowsFeature Multipath-io).InstallState) -like "Installed") {
39 if ((Get-IscsiTargetPortal).TargetPortalAddress -notcontains "<ct0-ip-iscsi-target>"){
40 New-IscsiTargetPortal -TargetPortalAddress <ct0-ip-iscsi-target>
41 Get-IscsiTarget | Connect-IscsiTarget -InitiatorPortalAddress (Get-NetIPAddress |Where-Object {$_.InterfaceAlias -like "Ethernet" -and $_.AddressFamily -like "IPv4"}).IPAddress -IsMultipathEnabled $true -IsPersistent $true -TargetPortalAddress <ct0-ip-iscsi-target>
42 }
43 if ((Get-IscsiTargetPortal).TargetPortalAddress -notcontains "<ct1-ip-iscsi-target>"){
44 New-IscsiTargetPortal -TargetPortalAddress <ct1-ip-iscsi-target>
45 Get-IscsiTarget | Connect-IscsiTarget -InitiatorPortalAddress (Get-NetIPAddress |Where-Object {$_.InterfaceAlias -like "Ethernet" -and $_.AddressFamily -like "IPv4"}).IPAddress -IsMultipathEnabled $true -IsPersistent $true -TargetPortalAddress <ct1-ip-iscsi-target>
46 }
47 if (((Get-MSDSMAutomaticClaimSettings).iSCSI) -ne "True") {
48 Enable-MSDSMAutomaticClaim -BusType iSCSI -Confirm:$false
49 }
50 if (((Get-MSDSMAutomaticClaimSettings).iSCSI) -notcontains "PURE") {
51 New-MSDSMSupportedHw -VendorId PURE -ProductId FlashArray
52 }
53 if (Get-MSDSMGlobalDefaultLoadBalancePolicy -ne "LQD") {
54 Set-MSDSMGlobalDefaultLoadBalancePolicy -Policy LQD
55 }
56 if (((Get-MPIOSetting).CustomPathRecoveryTime) -ne "20") {
57 Set-MPIOSetting -NewPathRecoveryInterval 20
58 }
59 if (((Get-MPIOSetting).UseCustomPathRecoveryTime) -ne "Enabled") {
60 Set-MPIOSetting -CustomPathRecovery Enabled
61 }
62 if (((Get-MPIOSetting).PDORemovePeriod) -ne "30") {
63 Set-MPIOSetting -NewPDORemovePeriod 30
64 }
65 if (((Get-MPIOSetting).DiskTimeoutValue) -ne "60") {
66 Set-MPIOSetting -NewDiskTimeout 60
67 }
68 if (((Get-MPIOSetting).PathVerificationState) -ne "Enabled") {
69 Set-MPIOSetting -NewPathVerificationState Enabled
70 }
71 if ((((Get-Disk).OperationalStatus) -contains "Offline") -and ((((Get-Disk).FriendlyName) -eq "PURE FlashArray"))) {
72 Get-Disk | ? {$_.OperationalStatus -eq "Offline"} | Set-Disk -IsOffline $false
73 }
74 if (((Get-Disk | ? {$_.IsReadOnly -eq "True"}).IsReadOnly) -and ((((Get-Disk).FriendlyName) -eq "PURE FlashArray"))) {
75 Get-Disk | ? {$_.IsReadOnly -eq "True"} | Set-Disk -IsReadOnly $false
76 }
77 }
78 </powershell>
79 <persist>true</persist>
80 EOF
81}
82
83output "public_dns" {
84 value = ["${aws_instance.example.*.public_dns}"]
85}
86output "public_ip" {
87 value = ["${aws_instance.example.*.public_ip}"]
88}
Run the Terraform Manifest
Run terraform init to install any needed providers, terraform plan to make sure all the connectivity is working and then terraform apply to deploy!
1terraform init
2terraform plan
3terraform apply
If everything is successful your EC2 instance should be deployed in ~ 2minutes and after a reboot or two will be fully configured and running!
Viewing your Pure Cloud Block Store data
In my example I already had a host provisioned with the custom IQN on my Pure Cloud Block Store, this allowed the data to be automatically mounted and utilized in my EC2 instance. As Pure Storage has a widely supported Powershell module you can easily provision new hosts, volumes or even mount existing replicated snapshots to your instance. Stay tuned to an upcoming post where I dive into the options to bring your replicated data to life in AWS!
Closing
Hopefully this helped you get started with automating EC2 instance deployment with Terraform!
Any questions or comments? Leave them below.
comments powered by DisqusSee Also
- Using Terraform to Provision your Pure Storage Infrastructure
- Using Terraform to Deploy the Pure1 VM Analytics Collector
- Using Terraform to Deploy the VMware Event Broker Appliance
- Using Terraform to Deploy the VMware Nested ESXi Appliance
- Using Terraform to Deploy the Site Recovery Manager 8.3 Appliance