Module: AWSUDO

Defined in:
lib/awsudo.rb

Constant Summary collapse

AWS_ROLES =
File.join(ENV['HOME'], '.aws-roles')

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.idp_login_urlObject (readonly)

Returns the value of attribute idp_login_url.



16
17
18
# File 'lib/awsudo.rb', line 16

def 
  
end

.saml_provider_nameObject (readonly)

Returns the value of attribute saml_provider_name.



16
17
18
# File 'lib/awsudo.rb', line 16

def saml_provider_name
  @saml_provider_name
end

Class Method Details

.assume_role(role) ⇒ Object



55
56
57
# File 'lib/awsudo.rb', line 55

def self.assume_role(role)
  assume_role_using_agent(role) rescue assume_role_using_password(role)
end

.assume_role_using_agent(role) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/awsudo.rb', line 35

def self.assume_role_using_agent(role)
  socket_name = ENV['AWS_AUTH_SOCK']
  credentials = UNIXSocket.open(socket_name) do |client|
    client.puts role
    response = client.gets
    raise "Connection closed by peer" if response.nil?
    JSON.parse(response.strip)
  end

  raise credentials['error'] if credentials['error']
  credentials
end

.assume_role_using_password(role) ⇒ Object



48
49
50
51
52
53
# File 'lib/awsudo.rb', line 48

def self.assume_role_using_password(role)
  username, password = get_federated_credentials
  saml_assertion = get_saml_assertion(username, password)
  role_arn = resolve_role(role)
  assume_role_with_saml(saml_assertion, role_arn).to_h
end

.assume_role_with_saml(saml_assertion, role_arn) ⇒ Object



83
84
85
86
87
88
89
90
# File 'lib/awsudo.rb', line 83

def self.assume_role_with_saml(saml_assertion, role_arn)
  principal_arn = "#{role_arn[/^arn:aws:iam::\d+:/]}saml-provider/#{saml_provider_name}"
  sts = Aws::STS::Client.new(credentials: Aws::Credentials.new('a', 'b', 'c'), region: 'us-east-1')
  sts.assume_role_with_saml(
    role_arn: role_arn,
    principal_arn: principal_arn, 
    saml_assertion: saml_assertion).credentials
end

.config(idp_login_url, saml_provider_name) ⇒ Object



19
20
21
22
# File 'lib/awsudo.rb', line 19

def self.config(, saml_provider_name)
   = 
  @saml_provider_name = saml_provider_name
end

.get_federated_credentialsObject



24
25
26
27
28
29
30
31
32
33
# File 'lib/awsudo.rb', line 24

def self.get_federated_credentials
  fd = IO.sysopen("/dev/tty", "w")
  console = IO.new(fd,"w")
  console.print "Login: "
  username = STDIN.gets.chomp
  console.print "Password: "
  password = STDIN.noecho(&:gets).chomp
  console.print "\n"
  [username, password]
end

.get_saml_assertion(username, password) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/awsudo.rb', line 59

def self.get_saml_assertion(username, password)
  uri = URI.parse()

  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = true
  http.verify_mode = OpenSSL::SSL::VERIFY_PEER

  req = Net::HTTP::Post.new(uri.request_uri)
  req.set_form_data({'username' => username, 'password' => password})
  res = http.request(req)

  raise "Authentication failed" if res['Location'].nil?
  uri = URI.parse(res['Location'])
  req = Net::HTTP::Get.new(uri.request_uri)
  req['Cookie'] = res['Set-Cookie']
  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = true
  http.verify_mode = OpenSSL::SSL::VERIFY_PEER
  res = http.request(req)

  doc = REXML::Document.new(res.body)
  REXML::XPath.first(doc, '/html/body/form/input[@name = "SAMLResponse"]/@value').to_s
end

.resolve_role(role, roles_filename = AWS_ROLES) ⇒ Object



92
93
94
95
96
97
98
99
100
# File 'lib/awsudo.rb', line 92

def self.resolve_role(role, roles_filename = AWS_ROLES)
  return role if role =~ /^arn:aws:iam::\d+:role\/\S+$/
  raise "`#{role}' is not a valid role" if role =~ /\s/
  line = File.readlines(roles_filename).find {|line| line =~ /^#{role}\s+arn:aws:iam::\d+:role\/\S+\s*$/ }
  raise "`#{role}' is not a valid role" if line.nil?
  role_arn = line.split(/\s+/)[1]
  raise "`#{role}' is not a valid role" if role_arn.nil?
  role_arn
end