Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(SUP-4373-system_store) Add CA bundle option #93

Merged
merged 2 commits into from
Aug 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- [Usage](#usage)
- [Installation](#installation)
- [Resource management](#resource-management)
- [SSL](#ssl)
- [Limitations](#limitations)
- [Supporting Content](#supporting-content)
- [Articles](#articles)
Expand Down Expand Up @@ -192,6 +193,22 @@ class my_profile::my_class{
)
```

### SSL

#### Defaults

The InfluxDB application and Puppet resources can be configured to use SSL. The [use_ssl](https://forge.puppet.com/modules/puppetlabs/influxdb/reference#use_ssl) parameter of the main class and all resources defaults to `true`, meaning SSL will be used in all communications. If you wish to disable it, setting `influxdb::use_ssl` to `false` will do so for the application. Passing `use_ssl` to resources will cause them to query the application without using SSL.

The certificates used in SSL communication default to those issued by the Puppet CA. The application will use the [ssl certificate](https://forge.puppet.com/modules/puppetlabs/influxdb/reference#ssl_cert_file) and [private key](https://forge.puppet.com/modules/puppetlabs/influxdb/reference#ssl_key_file) used by the Puppet agent on the local machine running InfluxDB. Applications that query InfluxDB, such as Telegraf and the resources in this module, need to provide a CA certificate issued by the same CA to be trusted. See the [puppet_operational_dashboards](https://forge.puppet.com/modules/puppetlabs/puppet_operational_dashboards/reference#puppet_operational_dashboardstelegrafagent) module for an example.

#### Configuration

If you wish to manage the certificate files yourself, you can set [manage_ssl](https://forge.puppet.com/modules/puppetlabs/influxdb/reference#manage_ssl). SSL will still be enabled and used by the resources, but the module will not manage the contents of the certificate files.

If you need to use certificates issued by a CA other than the Puppet CA, you can do so by using the [ssl_trust_store](https://www.puppet.com/docs/puppet/8/configuration.html#ssl-trust-store) option of the Puppet agent. First, set the [use_system_store](https://forge.puppet.com/modules/puppetlabs/influxdb/reference#use_system_store) parameter to `true` in the main class and all resources of this module.

Next, save your CA bundle to disk on the node managing your InfluxDB server. Set the `ssl_trust_store` option in its `puppet.conf` to contain the path to this file. This will cause all of the api calls made by this module to include your CA bundle.

## Limitations

This module is incompatible with InfluxDB 1.x. Migrating data from 1.x to 2.x must be done manually. For more information see [here](https://docs.influxdata.com/influxdb/v2.1/upgrade/v1-to-v2/).
Expand Down
16 changes: 12 additions & 4 deletions lib/puppet/functions/influxdb/retrieve_token.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,38 @@
param 'String', :uri
param 'String', :token_name
param 'String', :admin_token_file
param 'Boolean', :use_system_store
end

dispatch :retrieve_token do
param 'String', :uri
param 'String', :token_name
param 'Sensitive', :admin_token
param 'Boolean', :use_system_store
end

def retrieve_token_file(uri, token_name, admin_token_file)
def retrieve_token_file(uri, token_name, admin_token_file, use_system_store)
admin_token = File.read(admin_token_file)
retrieve_token(uri, token_name, admin_token)
retrieve_token(uri, token_name, admin_token, use_system_store)
rescue Errno::EISDIR, Errno::EACCES, Errno::ENOENT => e
Puppet.err("Unable to retrieve #{token_name}": e.message)
nil
end

def retrieve_token(uri, token_name, admin_token)
def retrieve_token(uri, token_name, admin_token, use_system_store)
if admin_token.is_a?(Puppet::Pops::Types::PSensitiveType::Sensitive)
admin_token = admin_token.unwrap
end

client = Puppet.runtime[:http]
client_options = if use_system_store
{ include_system_store: true }
else
{}
end

response = client.get(URI(uri + '/api/v2/authorizations'),
headers: { 'Authorization' => "Token #{admin_token}" })
headers: { 'Authorization' => "Token #{admin_token}", options: client_options })

if response.success?
body = JSON.parse(response.body)
Expand Down
2 changes: 1 addition & 1 deletion lib/puppet/provider/influxdb_bucket/influxdb_bucket.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def initialize
super
end

def canonicalize(_context, resources)
def canonicalize(context, resources)
init_attrs(resources)
resources
rescue StandardError => e
Expand Down
4 changes: 2 additions & 2 deletions lib/puppet/provider/influxdb_dbrp/influxdb_dbrp.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def initialize
super
end

def canonicalize(_context, resources)
def canonicalize(context, resources)
init_attrs(resources)
resources
rescue StandardError => e
Expand All @@ -22,7 +22,7 @@ def canonicalize(_context, resources)
nil
end

def get(_context, names = nil)
def get(context, names = nil)
init_auth if @auth.empty?
get_org_info if @org_hash.empty?
get_bucket_info if @bucket_hash.empty?
Expand Down
4 changes: 2 additions & 2 deletions lib/puppet/provider/influxdb_label/influxdb_label.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def initialize
super
end

def canonicalize(_context, resources)
def canonicalize(context, resources)
init_attrs(resources)
resources
rescue StandardError => e
Expand All @@ -20,7 +20,7 @@ def canonicalize(_context, resources)
nil
end

def get(_context, names = nil)
def get(context, names = nil)
init_auth if @auth.empty?
get_org_info if @org_hash.empty?
get_label_info if @label_hash.empty?
Expand Down
6 changes: 3 additions & 3 deletions lib/puppet/provider/influxdb_setup/influxdb_setup.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def initialize
super
end

def canonicalize(_context, resources)
def canonicalize(context, resources)
init_attrs(resources)
resources
rescue StandardError => e
Expand All @@ -20,7 +20,7 @@ def canonicalize(_context, resources)
nil
end

def get(_context)
def get(context)
response = influx_get('/api/v2/setup')[0]
[
{
Expand All @@ -29,7 +29,7 @@ def get(_context)
port: @port,
token: @token,
token_file: @token_file,
ensure: (response['allowed'] == true) ? 'absent' : 'present',
ensure: (response && response['allowed'] == true) ? 'absent' : 'present',
},
]
rescue StandardError => e
Expand Down
4 changes: 2 additions & 2 deletions lib/puppet/provider/influxdb_user/influxdb_user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def initialize
super
end

def canonicalize(_context, resources)
def canonicalize(context, resources)
init_attrs(resources)
resources
rescue StandardError => e
Expand All @@ -20,7 +20,7 @@ def canonicalize(_context, resources)
nil
end

def get(_context, names = nil)
def get(context, names = nil)
init_auth if @auth.empty?
get_user_info if @user_map.empty?

Expand Down
6 changes: 6 additions & 0 deletions lib/puppet/type/influxdb_auth.rb
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,12 @@
default: true,
behavior: :parameter,
},
use_system_store: {
type: 'Boolean',
desc: 'Whether to use the system store for SSL connections',
default: false,
behavior: :parameter,
},
force: {
type: 'Boolean',
desc: 'Recreate resource if immutable property changes',
Expand Down
8 changes: 7 additions & 1 deletion lib/puppet/type/influxdb_bucket.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@
desc: 'Whether to enable SSL for the InfluxDB service',
default: true,
behavior: :parameter,
}
},
use_system_store: {
type: 'Boolean',
desc: 'Whether to use the system store for SSL connections',
default: false,
behavior: :parameter,
},
},
)
8 changes: 7 additions & 1 deletion lib/puppet/type/influxdb_dbrp.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@
desc: 'Whether to enable SSL for the InfluxDB service',
default: true,
behavior: :parameter,
}
},
use_system_store: {
type: 'Boolean',
desc: 'Whether to use the system store for SSL connections',
default: false,
behavior: :parameter,
},
},
)
8 changes: 7 additions & 1 deletion lib/puppet/type/influxdb_label.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@
desc: 'Whether to enable SSL for the InfluxDB service',
default: true,
behavior: :parameter,
}
},
use_system_store: {
type: 'Boolean',
desc: 'Whether to use the system store for SSL connections',
default: false,
behavior: :parameter,
},
},
)
8 changes: 7 additions & 1 deletion lib/puppet/type/influxdb_org.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@
desc: 'Whether to enable SSL for the InfluxDB service',
default: true,
behavior: :parameter,
}
},
use_system_store: {
type: 'Boolean',
desc: 'Whether to use the system store for SSL connections',
default: false,
behavior: :parameter,
},
},
)
8 changes: 7 additions & 1 deletion lib/puppet/type/influxdb_setup.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@
desc: 'Whether to enable SSL for the InfluxDB service',
default: true,
behavior: :parameter,
}
},
use_system_store: {
type: 'Boolean',
desc: 'Whether to use the system store for SSL connections',
default: false,
behavior: :parameter,
},
},
)
8 changes: 7 additions & 1 deletion lib/puppet/type/influxdb_user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@
desc: 'Whether to enable SSL for the InfluxDB service',
default: true,
behavior: :parameter,
}
},
use_system_store: {
type: 'Boolean',
desc: 'Whether to use the system store for SSL connections',
default: false,
behavior: :parameter,
},
},
)
26 changes: 17 additions & 9 deletions lib/puppet_x/puppetlabs/influxdb/influxdb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ module Puppetlabs
# Mixin module to provide constants and instance methods for the providers
module PuppetlabsInfluxdb
class << self
attr_accessor :host, :port, :token_file, :use_ssl
attr_accessor :host, :port, :token_file, :use_ssl, :use_system_store, :cert_store, :ssl_context, :client_options
end

self.host = Facter.value(:networking)['fqdn']
self.port = 8086
self.use_ssl = true
self.use_system_store = false
self.token_file = if Facter.value('identity')['user'] == 'root'
'/root/.influxdb_token'
else
Expand All @@ -24,6 +25,7 @@ class << self

def initialize
@client ||= Puppet.runtime[:http]
@cert_store ||= OpenSSL::X509::Store.new
@org_hash = []
@telegraf_hash = []
@label_hash = []
Expand All @@ -37,17 +39,24 @@ def initialize
# Make class instance variables available as instance variables to whichever object calls this method
# For subclasses which call super, the instance variables will be part of their scope
def init_attrs(resources)
# TODO: Only one uri per resource type
# TODO: this can probably be refactored into a proper cache of resources
resources.each do |resource|
@host ||= resource[:host] ? resource[:host] : PuppetlabsInfluxdb.host
@port ||= resource[:port] ? resource[:port] : PuppetlabsInfluxdb.port
@use_ssl ||= (!resource[:use_ssl].nil?) ? resource[:use_ssl] : PuppetlabsInfluxdb.use_ssl
@use_system_store ||= resource[:use_system_store] ? resource[:use_system_store] : PuppetlabsInfluxdb.use_system_store
@token ||= resource[:token]
@token_file ||= resource[:token_file] ? resource[:token_file] : PuppetlabsInfluxdb.token_file
end

protocol = @use_ssl ? 'https' : 'http'
@influxdb_uri = "#{protocol}://#{@host}:#{@port}"

@client_options = if @use_system_store
{ include_system_store: true }
else
{}
end
end

def init_auth
Expand Down Expand Up @@ -75,7 +84,7 @@ def influx_get(name, results = [])
# Return the current data if there is no 'next' object
return results if name.nil?

response = @client.get(URI(@influxdb_uri + name), headers: @auth)
response = @client.get(URI(@influxdb_uri + name), headers: @auth, options: @client_options)
if response.success?
# Recursively append the results of calling the URL in the 'next' object to our array
body = JSON.parse(response.body)
Expand All @@ -99,28 +108,27 @@ def influx_get(name, results = [])
# end

def influx_post(name, body)
response = @client.post(URI(@influxdb_uri + name), body, headers: @auth.merge({ 'Content-Type' => 'application/json' }))
response = @client.post(URI(@influxdb_uri + name), body, headers: @auth.merge({ 'Content-Type' => 'application/json' }), options: @client_options)
raise Puppet::DevError, "Received HTTP code '#{response.code}' for post #{name} with message '#{response.reason}' '#{body}" unless response.success?

JSON.parse(response.body ? response.body : '{}')
end

def influx_put(name, body)
response = @client.put(URI(@influxdb_uri + name), body, headers: @auth.merge({ 'Content-Type' => 'application/json' }))
response = @client.put(URI(@influxdb_uri + name), body, headers: @auth.merge({ 'Content-Type' => 'application/json' }), options: @client_options)
raise Puppet::DevError, "Received HTTP code #{response.code} for put #{name} with message #{response.reason}" unless response.success?

JSON.parse(response.body ? response.body : '{}')
end

# Our HTTP class doesn't have a patch method, so we create the connection and use Net::HTTP manually
def influx_patch(name, body)
@client.connect(URI(@influxdb_uri)) do |conn|
@client.connect(URI(@influxdb_uri), options: @client_options) do |conn|
request = Net::HTTP::Patch.new(@influxdb_uri + name)
request['Content-Type'] = 'application/json'

request['Authorization'] = @auth[:Authorization]

request.body = body

response = conn.request(request)
raise Puppet::DevError, "Received HTTP code #{response.code} for patch #{name} with message #{response.reason}" unless response.is_a?(Net::HTTPSuccess)

Expand All @@ -129,7 +137,7 @@ def influx_patch(name, body)
end

def influx_delete(name)
response = @client.delete(URI(@influxdb_uri + name), headers: @auth)
response = @client.delete(URI(@influxdb_uri + name), headers: @auth, options: @client_options)
raise Puppet::DevError, "Received HTTP code #{response.code} for delete #{name} with message #{response.reason}" unless response.success?

JSON.parse(response.body ? response.body : '{}')
Expand Down
Loading