10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org).

## [v1.1.2](https://github.com/tragiccode/tragiccode-azure_key_vault/tree/v1.1.2) (2021-04-29)

[Full Changelog](https://github.com/tragiccode/tragiccode-azure_key_vault/compare/v1.1.1...v1.1.2)

### Fixed

- \(GH-39\) Normalize key names for hiera lookup [\#67](https://github.com/TraGicCode/tragiccode-azure_key_vault/pull/67) ([dowlingw](https://github.com/dowlingw))

## [v1.1.1](https://github.com/tragiccode/tragiccode-azure_key_vault/tree/v1.1.1) (2021-04-22)

[Full Changelog](https://github.com/tragiccode/tragiccode-azure_key_vault/compare/v1.1.0...v1.1.1)
Expand Down Expand Up @@ -35,7 +43,6 @@ All notable changes to this project will be documented in this file. The format
- \(GH-42\) Fix .empty? method missing on uri [\#45](https://github.com/TraGicCode/tragiccode-azure_key_vault/pull/45) ([TraGicCode](https://github.com/TraGicCode))
- \(GH-43\) Fix debug message [\#44](https://github.com/TraGicCode/tragiccode-azure_key_vault/pull/44) ([TraGicCode](https://github.com/TraGicCode))
- Fix typo in readme.md [\#29](https://github.com/TraGicCode/tragiccode-azure_key_vault/pull/29) ([lupyana](https://github.com/lupyana))
- Change log level from info to debug [\#10](https://github.com/TraGicCode/tragiccode-azure_key_vault/pull/10) ([TraGicCode](https://github.com/TraGicCode))

## [1.0.0](https://github.com/tragiccode/tragiccode-azure_key_vault/tree/1.0.0) (2018-10-25)

Expand Down Expand Up @@ -63,6 +70,7 @@ All notable changes to this project will be documented in this file. The format

### Fixed

- Change log level from info to debug [\#10](https://github.com/TraGicCode/tragiccode-azure_key_vault/pull/10) ([TraGicCode](https://github.com/TraGicCode))
- Add missing comma in readme.md [\#9](https://github.com/TraGicCode/tragiccode-azure_key_vault/pull/9) ([TraGicCode](https://github.com/TraGicCode))

## [0.2.0](https://github.com/tragiccode/tragiccode-azure_key_vault/tree/0.2.0) (2018-08-23)
Expand Down
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ Add a new entry to the `hierarchy` hash in `hiera.yaml` referencing the vault na
vault_name: production-vault
vault_api_version: '2016-10-01'
metadata_api_version: '2018-04-02'
key_replacement_token: '-'
```
To retrieve a secret in puppet code you can use the `lookup` function:
Expand Down Expand Up @@ -94,8 +95,23 @@ Alternatively a custom trusted fact can be included [in the certificate request]
vault_name: "%{trusted.extensions.pp_environment}"
vault_api_version: '2016-10-01'
metadata_api_version: '2018-04-02'
key_replacement_token: '-'
```

### A note on secret keys

KeyVault secret names can only contain the characters `0-9`, `a-z`, `A-Z`, and `-`.

When relying on automatic parameter lookup, this is almost always going to contain the module delimiter (`::`) or underscores.

This module will automatically convert the variable name to a valid value by replacing every invalid character with the `key_replacement_token` value, which defaults to `-`.

For example, the hiera variable `puppetdb::master::config::puppetdb_server` will automatically be converted to `puppetdb--master--config--puppetdb-server` before being queried up in KeyVault.

When troubleshooting, you can run hiera from the commandline with the `--explain` option to see the key name being used :

Using normalized KeyVault secret key for lookup: puppetdb--master--config--puppetdb-server

## How it's secure by default

In order to prevent accidental leakage of your secrets throughout all of the locations puppet stores information the returned value of the `azure_key_vault::secret` function & Hiera backend return a string wrapped in a Sensitive data type. Lets look at an example of what this means and why it's important. Below is an example of pulling a secret and trying to output the value in a notice function.
Expand Down
13 changes: 7 additions & 6 deletions REFERENCE.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
# Reference

<!-- DO NOT EDIT: This document was generated by Puppet Strings -->

## Table of Contents

**Functions**
### Functions

* [`azure_key_vault::lookup`](#azure_key_vaultlookup):
* [`azure_key_vault::lookup`](#azure_key_vaultlookup)
* [`azure_key_vault::secret`](#azure_key_vaultsecret): Retrieves secrets from Azure's Key Vault.

## Functions

### azure_key_vault::lookup
### <a name="azure_key_vaultlookup"></a>`azure_key_vault::lookup`

Type: Ruby 4.x API

The azure_key_vault::lookup function.

#### `azure_key_vault::lookup(Variant[String, Numeric] $secret_name, Struct[{vault_name => String, vault_api_version => String, metadata_api_version => String}] $options, Puppet::LookupContext $context)`
#### `azure_key_vault::lookup(Variant[String, Numeric] $secret_name, Struct[{vault_name => String, vault_api_version => String, metadata_api_version => String, Optional[key_replacement_token] => String}] $options, Puppet::LookupContext $context)`

The azure_key_vault::lookup function.

Expand All @@ -30,7 +31,7 @@ Data type: `Variant[String, Numeric]`

##### `options`

Data type: `Struct[{vault_name => String, vault_api_version => String, metadata_api_version => String}]`
Data type: `Struct[{vault_name => String, vault_api_version => String, metadata_api_version => String, Optional[key_replacement_token] => String}]`



Expand All @@ -40,7 +41,7 @@ Data type: `Puppet::LookupContext`



### azure_key_vault::secret
### <a name="azure_key_vaultsecret"></a>`azure_key_vault::secret`

Type: Ruby 4.x API

Expand Down
10 changes: 6 additions & 4 deletions lib/puppet/functions/azure_key_vault/lookup.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
Puppet::Functions.create_function(:'azure_key_vault::lookup') do
dispatch :lookup_key do
param 'Variant[String, Numeric]', :secret_name
param 'Struct[{vault_name => String, vault_api_version => String, metadata_api_version => String}]', :options
param 'Struct[{vault_name => String, vault_api_version => String, metadata_api_version => String, Optional[key_replacement_token] => String}]', :options
param 'Puppet::LookupContext', :context
end

def lookup_key(secret_name, options, context)
# This is a reserved key name in hiera
return context.not_found if secret_name == 'lookup_options'
return context.cached_value(secret_name) if context.cache_has_key(secret_name)
normalized_secret_name = TragicCode::Azure.normalize_object_name(secret_name, options['key_replacement_token'] || '-')
context.explain { " Using normalized KeyVault secret key for lookup: #{normalized_secret_name}" }
return context.cached_value(normalized_secret_name) if context.cache_has_key(normalized_secret_name)
access_token = context.cached_value('access_token')
if access_token.nil?
access_token = TragicCode::Azure.get_access_token(options['metadata_api_version'])
Expand All @@ -19,7 +21,7 @@ def lookup_key(secret_name, options, context)
begin
secret_value = TragicCode::Azure.get_secret(
options['vault_name'],
secret_name,
normalized_secret_name,
options['vault_api_version'],
access_token,
'',
Expand All @@ -30,6 +32,6 @@ def lookup_key(secret_name, options, context)
end
context.not_found if secret_value.nil?
return if secret_value.nil?
context.cache(secret_name, secret_value)
context.cache(normalized_secret_name, secret_value)
end
end
4 changes: 4 additions & 0 deletions lib/puppet_x/tragiccode/azure.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
module TragicCode
# Azure API functions
class Azure
def self.normalize_object_name(object_name, replacement)
object_name.gsub(%r{[^0-9a-zA-Z-]}, replacement)
end

def self.get_access_token(api_version)
uri = URI("http://169.254.169.254/metadata/identity/oauth2/token?api-version=#{api_version}&resource=https%3A%2F%2Fvault.azure.net")
req = Net::HTTP::Get.new(uri.request_uri)
Expand Down
2 changes: 1 addition & 1 deletion metadata.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tragiccode-azure_key_vault",
"version": "1.1.1",
"version": "1.1.2",
"author": "tragiccode",
"summary": "The azure_key_vault module allows you to easily fetch secrets securely within your puppet manifests.",
"license": "Apache-2.0",
Expand Down
18 changes: 15 additions & 3 deletions spec/functions/azure_key_vault_lookup_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

it { is_expected.not_to eq(nil) }

it 'only accepts 3 arguments' do
it 'accepts 3 required arguments' do
is_expected.to run.with_params.and_raise_error(ArgumentError, %r{expects 3 arguments}i)
end
it 'validates the :options hash' do
Expand All @@ -32,8 +32,8 @@
).and_raise_error(ArgumentError)
end
it 'uses the cache' do
expect(lookup_context).to receive(:cache_has_key).with('secret_name').and_return(true)
expect(lookup_context).to receive(:cached_value).with('secret_name').and_return('value')
expect(lookup_context).to receive(:cache_has_key).with('secret-name').and_return(true)
expect(lookup_context).to receive(:cached_value).with('secret-name').and_return('value')
is_expected.to run.with_params(
'secret_name', options, lookup_context
).and_return('value')
Expand All @@ -58,4 +58,16 @@
'lookup_options', options, lookup_context
)
end

it 'uses - as the default key_replacement_token' do
secret_name = 'profile::windows::sqlserver::sensitive_sql_user_password'
access_token_value = 'access_value'
secret_value = 'secret_value'
expect(TragicCode::Azure).to receive(:normalize_object_name).with(secret_name, '-')
expect(TragicCode::Azure).to receive(:get_access_token).and_return(access_token_value)
expect(TragicCode::Azure).to receive(:get_secret).and_return(secret_value)
is_expected.to run.with_params(
'profile::windows::sqlserver::sensitive_sql_user_password', options, lookup_context
).and_return(secret_value)
end
end
11 changes: 11 additions & 0 deletions spec/functions/tragic_code/azure_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
require 'spec_helper'

describe TragicCode::Azure do
context '.normalize_object_name' do
it 'returns a bearer token' do
original_var_name = 'puppetdb::master::config::puppetdb_server'
key_replacement_token = '-'

expected_key_value = 'puppetdb--master--config--puppetdb-server'

expect(described_class.normalize_object_name(original_var_name, key_replacement_token)).to eq(expected_key_value)
end
end

context '.get_access_token' do
it 'returns a bearer token' do
stub_request(:get, %r{169.254.169.254})
Expand Down