Skip to content
This repository was archived by the owner on Feb 11, 2022. It is now read-only.

Commit 1c96cf3

Browse files
committed
ISSUE #423: Support using EC2-generated password as the WinRM password
Adds a winrm_info provider capability to support using the EC2 GetPasswordData API as a means of getting the WinRM password. If the winrm.password is set to :aws, go fetch the AWS password data for the machine, decrypt the user-specified private key, and set it as the winrm.password
1 parent 988be1f commit 1c96cf3

File tree

6 files changed

+121
-0
lines changed

6 files changed

+121
-0
lines changed

README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,41 @@ Vagrant.configure("2") do |config|
279279
end
280280
```
281281

282+
### Windows WinRM passwords
283+
284+
Want to use the EC2-generated Administrator password as the WinRM password for your Windows images? Use `:aws` as the WinRM password, and it will be fetched and decrypted using your private key.
285+
286+
```ruby
287+
Vagrant.configure("2") do |config|
288+
# ... other stuff
289+
290+
config.vm.communicator = "winrm"
291+
config.winrm.username = "Administrator"
292+
293+
config.vm.provider "aws" do |aws, override|
294+
# Indicate that the password should be fetched and decrypted from AWS
295+
override.winrm.password = :aws
296+
297+
# private_key_path needed to decrypt the password
298+
override.ssh.private_key_path = '~/mykey.pem'
299+
300+
# keypair name corresponding to private_key_path
301+
aws.keypair_name = "mykey"
302+
303+
# Use a security group that allows WinRM port inbound (port 5985)
304+
aws.security_groups = ['some_security_group_that_allows_winrm_inbound']
305+
306+
# Enable WinRM on the instance
307+
aws.user_data = <<-USERDATA
308+
<powershell>
309+
Enable-PSRemoting -Force
310+
netsh advfirewall firewall add rule name="WinRM HTTP" dir=in localport=5985 protocol=TCP action=allow
311+
</powershell>
312+
USERDATA
313+
end
314+
end
315+
```
316+
282317
## Development
283318

284319
To work on the `vagrant-aws` plugin, clone this repository out, and use

lib/vagrant-aws/action.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,14 @@ def self.action_reload
184184
end
185185
end
186186

187+
def self.action_get_winrm_password
188+
Vagrant::Action::Builder.new.tap do |b|
189+
b.use ConfigValidate
190+
b.use ConnectAWS
191+
b.use GetWinRMPassword
192+
end
193+
end
194+
187195
# The autoload farm
188196
action_root = Pathname.new(File.expand_path("../action", __FILE__))
189197
autoload :ConnectAWS, action_root.join("connect_aws")
@@ -204,6 +212,7 @@ def self.action_reload
204212
autoload :WarnNetworks, action_root.join("warn_networks")
205213
autoload :ElbRegisterInstance, action_root.join("elb_register_instance")
206214
autoload :ElbDeregisterInstance, action_root.join("elb_deregister_instance")
215+
autoload :GetWinRMPassword, action_root.join("get_winrm_password")
207216
end
208217
end
209218
end
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
require "fog"
2+
require "log4r"
3+
4+
module VagrantPlugins
5+
module AWS
6+
module Action
7+
# This action connects to AWS, verifies credentials work, and
8+
# puts the AWS connection object into the `:aws_compute` key
9+
# in the environment.
10+
class GetWinRMPassword
11+
def initialize(app, env)
12+
@app = app
13+
@logger = Log4r::Logger.new("vagrant_aws::action::get_winrm_password")
14+
end
15+
16+
def call(env)
17+
machine = env[:machine]
18+
19+
if machine.config.winrm.password == :aws && machine.config.ssh.private_key_path
20+
machine.ui.info(I18n.t("vagrant_aws.getting_winrm_password"))
21+
22+
aws = env[:aws_compute]
23+
response = aws.get_password_data(machine.id)
24+
password_data = response.body['passwordData']
25+
26+
if password_data
27+
password_data_bytes = Base64.decode64(password_data)
28+
29+
# Try to decrypt the password data using each one of the private key files
30+
# set by the user until we hit one that decrypts successfully
31+
machine.config.ssh.private_key_path.each do |private_key_path|
32+
private_key_path = File.expand_path private_key_path
33+
34+
@logger.info("Decrypting password data using #{private_key_path}")
35+
rsa = OpenSSL::PKey::RSA.new File.read private_key_path
36+
begin
37+
machine.config.winrm.password = rsa.private_decrypt password_data_bytes
38+
@logger.info("Successfully decrypted password data using #{private_key_path}")
39+
rescue OpenSSL::PKey::RSAError
40+
@logger.warn("Failed to decrypt password data using #{private_key_path}")
41+
next
42+
end
43+
44+
break
45+
end
46+
end
47+
end
48+
49+
@app.call(env)
50+
end
51+
end
52+
end
53+
end
54+
end

lib/vagrant-aws/capability.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
require "vagrant/action/builder"
2+
3+
module VagrantPlugins
4+
module AWS
5+
module Capability
6+
class WinRMInfo
7+
def self.winrm_info(machine)
8+
machine.action("get_winrm_password")
9+
return {}
10+
end
11+
end
12+
end
13+
end
14+
end

lib/vagrant-aws/plugin.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ class Plugin < Vagrant.plugin("2")
3434
Provider
3535
end
3636

37+
provider_capability(:aws, :winrm_info) do
38+
setup_logging
39+
40+
require_relative 'capability'
41+
Capability::WinRMInfo
42+
end
43+
3744
# This initializes the internationalization strings.
3845
def self.setup_i18n
3946
I18n.load_path << File.expand_path("locales/en.yml", AWS.source_root)

locales/en.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ en:
6262
will_not_destroy: |-
6363
The instance '%{name}' will not be destroyed, since the confirmation
6464
was declined.
65+
getting_winrm_password: |-
66+
Getting WinRM password from AWS...
6567
6668
config:
6769
access_key_id_required: |-

0 commit comments

Comments
 (0)