hiera-cfn-metadata 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 079405345d2b1e39e29713feafb802b754eece8f
|
|
4
|
+
data.tar.gz: 97a40eb65e8b7324f48ef1d419d8eb8f8c2adbbe
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: de917f50c270aa0ae32fcc342e3697d55624afdb14536fe5fc88a7867ca62f0b37390cca3d1931f7b924d1534215c7b8d799f2cdd36e033202c19d7449e828d5
|
|
7
|
+
data.tar.gz: f1c9548b28d2c524d42a045f3b630b6eada42b7930e4354f608bde40432e096cc9f68599dbfc48c56b99e5ebdedf11c6b64d263d067335611d554684915196eb
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
require 'base64'
|
|
2
|
+
require 'net/http'
|
|
3
|
+
require 'time'
|
|
4
|
+
|
|
5
|
+
module Aws
|
|
6
|
+
class InstanceIdentityCredentials
|
|
7
|
+
|
|
8
|
+
include CredentialProvider
|
|
9
|
+
include RefreshingCredentials
|
|
10
|
+
|
|
11
|
+
# @api private
|
|
12
|
+
class Non200Response < RuntimeError; end
|
|
13
|
+
|
|
14
|
+
# These are the errors we trap when attempting to talk to the
|
|
15
|
+
# instance metadata service. Any of these imply the service
|
|
16
|
+
# is not present, no responding or some other non-recoverable
|
|
17
|
+
# error.
|
|
18
|
+
# @api private
|
|
19
|
+
FAILURES = [
|
|
20
|
+
Errno::EHOSTUNREACH,
|
|
21
|
+
Errno::ECONNREFUSED,
|
|
22
|
+
Errno::EHOSTDOWN,
|
|
23
|
+
Errno::ENETUNREACH,
|
|
24
|
+
SocketError,
|
|
25
|
+
Timeout::Error,
|
|
26
|
+
Non200Response,
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
# @param [Hash] options
|
|
30
|
+
# @option options [Integer] :retries (5) Number of times to retry
|
|
31
|
+
# when retrieving credentials.
|
|
32
|
+
# @option options [String] :ip_address ('169.254.169.254')
|
|
33
|
+
# @option options [Integer] :port (80)
|
|
34
|
+
# @option options [Float] :http_open_timeout (5)
|
|
35
|
+
# @option options [Float] :http_read_timeout (5)
|
|
36
|
+
# @option options [Numeric, Proc] :delay By default, failures are retried
|
|
37
|
+
# with exponential back-off, i.e. `sleep(1.2 ** num_failures)`. You can
|
|
38
|
+
# pass a number of seconds to sleep between failed attempts, or
|
|
39
|
+
# a Proc that accepts the number of failures.
|
|
40
|
+
# @option options [IO] :http_debug_output (nil) HTTP wire
|
|
41
|
+
# traces are sent to this object. You can specify something
|
|
42
|
+
# like $stdout.
|
|
43
|
+
def initialize options = {}
|
|
44
|
+
@from_identity = true
|
|
45
|
+
@retries = options[:retries] || 5
|
|
46
|
+
@ip_address = options[:ip_address] || '169.254.169.254'
|
|
47
|
+
@port = options[:port] || 80
|
|
48
|
+
@http_open_timeout = options[:http_open_timeout] || 5
|
|
49
|
+
@http_read_timeout = options[:http_read_timeout] || 5
|
|
50
|
+
@http_debug_output = options[:http_debug_output]
|
|
51
|
+
super
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# @return [Integer] The number of times to retry failed atttempts to
|
|
55
|
+
# fetch credentials from the instance metadata service. Defaults to 0.
|
|
56
|
+
attr_reader :retries
|
|
57
|
+
|
|
58
|
+
attr_reader :from_identity
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
def refresh
|
|
63
|
+
doc = get_instance_identity('document')
|
|
64
|
+
sig = get_instance_identity('signature')
|
|
65
|
+
@credentials = Credentials.new(
|
|
66
|
+
Base64.encode64(doc),
|
|
67
|
+
sig.delete("\n")
|
|
68
|
+
)
|
|
69
|
+
# Pretend that it expires in an hour
|
|
70
|
+
@expiration = Time.now + 60 * 60
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def get_instance_identity(path)
|
|
74
|
+
failed_attempts = 0
|
|
75
|
+
begin
|
|
76
|
+
open_connection do |conn|
|
|
77
|
+
path = "/latest/dynamic/instance-identity/#{path}"
|
|
78
|
+
profile_name = http_get(conn, path).lines.first.strip
|
|
79
|
+
http_get(conn, path + profile_name)
|
|
80
|
+
end
|
|
81
|
+
rescue *FAILURES
|
|
82
|
+
if failed_attempts < @retries
|
|
83
|
+
failed_attempts += 1
|
|
84
|
+
retry
|
|
85
|
+
else
|
|
86
|
+
'{}'
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def open_connection
|
|
92
|
+
http = Net::HTTP.new(@ip_address, @port, nil)
|
|
93
|
+
http.open_timeout = @http_open_timeout
|
|
94
|
+
http.read_timeout = @http_read_timeout
|
|
95
|
+
http.set_debug_output(@http_debug_output) if @http_debug_output
|
|
96
|
+
http.start
|
|
97
|
+
yield(http).tap { http.finish }
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def http_get(connection, path)
|
|
101
|
+
response = connection.request(Net::HTTP::Get.new(path))
|
|
102
|
+
if response.code.to_i == 200
|
|
103
|
+
response.body
|
|
104
|
+
else
|
|
105
|
+
raise Non200Response
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
end
|
|
110
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module Aws
|
|
2
|
+
module Plugins
|
|
3
|
+
class CfnRequestSigner < Seahorse::Client::Plugin
|
|
4
|
+
|
|
5
|
+
option(:signature_version) do |cfg|
|
|
6
|
+
cfg.api.metadata['signatureVersion']
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
class Handler < Seahorse::Client::Handler
|
|
10
|
+
def call(context)
|
|
11
|
+
if cfn_request?(context) and using_instance_identity?(context)
|
|
12
|
+
context.config.signature_version = 'cfn_v1'
|
|
13
|
+
end
|
|
14
|
+
@handler.call(context)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def cfn_request?(context)
|
|
20
|
+
context.config.api.metadata['endpointPrefix'] == 'cloudformation'
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def using_instance_identity?(context)
|
|
24
|
+
context.config.credentials.respond_to? :from_identity
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def add_handlers(handlers, config)
|
|
30
|
+
handlers.add(Handler, step: :sign)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require "time"
|
|
2
|
+
require "openssl"
|
|
3
|
+
|
|
4
|
+
module Aws
|
|
5
|
+
module Signers
|
|
6
|
+
class CfnV1 < Base
|
|
7
|
+
def sign(http_request)
|
|
8
|
+
http_request.headers["Authorization"] = authorization()
|
|
9
|
+
http_request
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def authorization
|
|
15
|
+
return "CFN_V1 #{document}:#{signature}"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def document
|
|
19
|
+
@credentials.access_key_id
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def signature
|
|
23
|
+
@credentials.secret_access_key
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Vault backend for Hiera
|
|
2
|
+
class Hiera
|
|
3
|
+
module Backend
|
|
4
|
+
class Cfn_metadata_backend
|
|
5
|
+
|
|
6
|
+
def initialize()
|
|
7
|
+
require 'aws-sdk-core'
|
|
8
|
+
require 'hiera-cfn-metadata'
|
|
9
|
+
|
|
10
|
+
@config = Config[:cfn_metadata]
|
|
11
|
+
stack = @config[:stack] || ENV['CFN_STACK']
|
|
12
|
+
resource = @config[:resource] || ENV['CFN_RESOURCE']
|
|
13
|
+
|
|
14
|
+
begin
|
|
15
|
+
cfn = Aws::CloudFormation::Client.new(
|
|
16
|
+
region: @config[:region] || ENV['AWS_REGION'],
|
|
17
|
+
credentials: Aws::InstanceIdentityCredentials.new(),
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
resp = cfn.describe_stack_resource({
|
|
21
|
+
stack_name: stack,
|
|
22
|
+
logical_resource_id: resource
|
|
23
|
+
})
|
|
24
|
+
raise resp.error if !resp.successful?
|
|
25
|
+
|
|
26
|
+
metadata = resp.stack_resource_detail.metadata
|
|
27
|
+
|
|
28
|
+
@datasources = JSON.parse(metadata)
|
|
29
|
+
p @datasources
|
|
30
|
+
|
|
31
|
+
rescue Exception => e
|
|
32
|
+
@datasources = nil
|
|
33
|
+
Hiera.warn("[hiera-cfn-metadata] Skipping backend. Configuration error: #{e}")
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def lookup(key, scope, order_override, resolution_type, context)
|
|
38
|
+
answer = nil
|
|
39
|
+
found = false
|
|
40
|
+
|
|
41
|
+
Hiera.debug("[hiera-cfn-metadata] Looking up #{key}")
|
|
42
|
+
|
|
43
|
+
Backend.datasources(scope, order_override) do |source|
|
|
44
|
+
Hiera.debug("[hiera-cfn-metadata] Looking for data source #{source}")
|
|
45
|
+
|
|
46
|
+
data = @datasources[source]
|
|
47
|
+
next if section.nil? or data.empty?
|
|
48
|
+
next unless data.include?(key)
|
|
49
|
+
found = true
|
|
50
|
+
|
|
51
|
+
# for array resolution we just append to the array whatever
|
|
52
|
+
# we find, we then goes onto the next file and keep adding to
|
|
53
|
+
# the array
|
|
54
|
+
#
|
|
55
|
+
# for priority searches we break after the first found data item
|
|
56
|
+
new_answer = Backend.parse_answer(data[key], scope, {}, context)
|
|
57
|
+
case resolution_type.is_a?(Hash) ? :hash : resolution_type
|
|
58
|
+
when :array
|
|
59
|
+
raise Exception, "[hiera-cfn-metadata] Hiera type mismatch for key '#{key}': expected Array and got #{new_answer.class}" unless new_answer.kind_of? Array or new_answer.kind_of? String
|
|
60
|
+
answer ||= []
|
|
61
|
+
answer << new_answer
|
|
62
|
+
when :hash
|
|
63
|
+
raise Exception, "[hiera-cfn-metadata] Hiera type mismatch for key '#{key}': expected Hash and got #{new_answer.class}" unless new_answer.kind_of? Hash
|
|
64
|
+
answer ||= {}
|
|
65
|
+
answer = Backend.merge_answer(new_answer, answer, resolution_type)
|
|
66
|
+
else
|
|
67
|
+
answer = new_answer
|
|
68
|
+
break
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
throw :no_such_key unless found
|
|
72
|
+
return answer
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require "aws-sdk-core"
|
|
2
|
+
require_relative "aws-sdk-core/instance_identity_credentials"
|
|
3
|
+
require_relative "aws-sdk-core/signers/cfn_v1"
|
|
4
|
+
require_relative "aws-sdk-core/plugins/cfn_request_signer"
|
|
5
|
+
|
|
6
|
+
# Add the CFN_V1 signer to the built-in list
|
|
7
|
+
default_signers = Aws::Plugins::RequestSigner::Handler.const_get(:SIGNERS)
|
|
8
|
+
default_signers['cfn_v1'] = Aws::Signers::CfnV1
|
|
9
|
+
Aws::Plugins::RequestSigner::Handler.const_set(:SIGNERS, default_signers)
|
|
10
|
+
|
|
11
|
+
# Insert the CFN request signer plugin before the standard request signer
|
|
12
|
+
# so we can alter the signature version in time
|
|
13
|
+
plugins = Aws::CloudFormation::Client.plugins.dup
|
|
14
|
+
plugins.insert(plugins.index(Aws::Plugins::RequestSigner), Aws::Plugins::CfnRequestSigner)
|
|
15
|
+
Aws::CloudFormation::Client.set_plugins(plugins)
|
metadata
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: hiera-cfn-metadata
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Jonathan Sokolowski
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2015-07-02 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: aws-sdk
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '2'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '2'
|
|
27
|
+
description: Hiera backend for retrieving CloudFormation resource metadata and parsing
|
|
28
|
+
it as a JSON data source
|
|
29
|
+
email: jonathan.sokolowski@gmail.com
|
|
30
|
+
executables: []
|
|
31
|
+
extensions: []
|
|
32
|
+
extra_rdoc_files: []
|
|
33
|
+
files:
|
|
34
|
+
- lib/aws-sdk-core/instance_identity_credentials.rb
|
|
35
|
+
- lib/aws-sdk-core/plugins/cfn_request_signer.rb
|
|
36
|
+
- lib/aws-sdk-core/signers/cfn_v1.rb
|
|
37
|
+
- lib/hiera-cfn-metadata.rb
|
|
38
|
+
- lib/hiera/backend/cfn_metadata_backend.rb
|
|
39
|
+
homepage: http://github.com/jsok/hiera-cfn-metadata
|
|
40
|
+
licenses:
|
|
41
|
+
- Apache-2.0
|
|
42
|
+
metadata: {}
|
|
43
|
+
post_install_message:
|
|
44
|
+
rdoc_options: []
|
|
45
|
+
require_paths:
|
|
46
|
+
- lib
|
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
48
|
+
requirements:
|
|
49
|
+
- - ">="
|
|
50
|
+
- !ruby/object:Gem::Version
|
|
51
|
+
version: '0'
|
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
53
|
+
requirements:
|
|
54
|
+
- - ">="
|
|
55
|
+
- !ruby/object:Gem::Version
|
|
56
|
+
version: '0'
|
|
57
|
+
requirements: []
|
|
58
|
+
rubyforge_project:
|
|
59
|
+
rubygems_version: 2.4.5
|
|
60
|
+
signing_key:
|
|
61
|
+
specification_version: 4
|
|
62
|
+
summary: Module for using CloudFormation resource metadata as a hiera backend
|
|
63
|
+
test_files: []
|