hiera-cfn-metadata 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []