Enable secure communication over HTTPS for Grafana
This patch configures HAProxy to terminate SSL connection when the support for SSL/TLS is enabled in StackLight. DocImpact Add support for TLS Change-Id: Idf59f92f00ed58f3ebce2e0421694ad7c2010fe9 Implements: blueprint support-secure-communication
This commit is contained in:
parent
a8a1c08aeb
commit
9c77c2f5fe
|
@ -19,12 +19,8 @@ $master_ip = hiera('master_ip')
|
|||
$vip = hiera('lma::influxdb::vip')
|
||||
$grafana_port = hiera('lma::influxdb::grafana_port')
|
||||
$influxdb_port = hiera('lma::influxdb::influxdb_port')
|
||||
$grafana_link_data = "{\"title\":\"Grafana\",\
|
||||
\"description\":\"Dashboard for visualizing metrics\",\
|
||||
\"url\":\"http://${vip}:${grafana_port}/\"}"
|
||||
$grafana_link_created_file = '/var/cache/grafana_link_created'
|
||||
$influxdb_grafana = hiera('influxdb_grafana')
|
||||
|
||||
$grafana_link_created_file = '/var/cache/grafana_link_created'
|
||||
$admin_username = $influxdb_grafana['grafana_username']
|
||||
$admin_password = $influxdb_grafana['grafana_userpass']
|
||||
$influxdb_username = $influxdb_grafana['influxdb_username']
|
||||
|
@ -32,7 +28,6 @@ $influxdb_password = $influxdb_grafana['influxdb_userpass']
|
|||
$influxdb_database = $influxdb_grafana['influxdb_dbname']
|
||||
|
||||
$lma_collector = hiera_hash('lma_collector', {})
|
||||
|
||||
$influxdb_mode = $lma_collector['influxdb_mode']
|
||||
$import_influxdb = $influxdb_mode ? {
|
||||
'local' => true,
|
||||
|
@ -45,6 +40,19 @@ $import_elasticsearch = $elasticsearch_mode ? {
|
|||
default => false,
|
||||
}
|
||||
|
||||
if hiera('lma::grafana::tls::enabled') {
|
||||
$protocol = 'https'
|
||||
$grafana_hostname = hiera('lma::grafana::tls::hostname')
|
||||
$grafana_link_data = "{\"title\":\"Grafana\",\
|
||||
\"description\":\"Dashboard for visualizing metrics (${grafana_hostname}: ${vip})\",\
|
||||
\"url\":\"${protocol}://${grafana_hostname}:${grafana_port}/\"}"
|
||||
} else {
|
||||
$protocol = 'http'
|
||||
$grafana_link_data = "{\"title\":\"Grafana\",\
|
||||
\"description\":\"Dashboard for visualizing metrics\",\
|
||||
\"url\":\"${protocol}://${vip}:${grafana_port}/\"}"
|
||||
}
|
||||
|
||||
grafana_datasource { 'lma':
|
||||
ensure => present,
|
||||
url => "http://${vip}:${influxdb_port}",
|
||||
|
@ -53,7 +61,7 @@ grafana_datasource { 'lma':
|
|||
database => $influxdb_database,
|
||||
access_mode => 'proxy',
|
||||
is_default => true,
|
||||
grafana_url => "http://${vip}:${grafana_port}",
|
||||
grafana_url => "${protocol}://${vip}:${grafana_port}",
|
||||
grafana_user => $admin_username,
|
||||
grafana_password => $admin_password,
|
||||
}
|
||||
|
@ -61,6 +69,7 @@ grafana_datasource { 'lma':
|
|||
class {'lma_monitoring_analytics::grafana_dashboards':
|
||||
admin_username => $admin_username,
|
||||
admin_password => $admin_password,
|
||||
protocol => $protocol,
|
||||
host => $vip,
|
||||
import_elasticsearch => $import_elasticsearch,
|
||||
import_influxdb => $import_influxdb,
|
||||
|
|
|
@ -19,6 +19,7 @@ $nodes_names = prefix(range(1, size($nodes_ips)), 'server_')
|
|||
$stats_port = '1000'
|
||||
$influxdb_port = hiera('lma::influxdb::influxdb_port')
|
||||
$grafana_port = hiera('lma::influxdb::grafana_port')
|
||||
$influxdb_grafana = hiera_hash('influxdb_grafana')
|
||||
|
||||
Openstack::Ha::Haproxy_service {
|
||||
balancermember_options => 'check',
|
||||
|
@ -46,15 +47,30 @@ openstack::ha::haproxy_service { 'influxdb':
|
|||
# client IP address will always reach the same server (as long as no server
|
||||
# goes down or up). This is needed to support sticky session and to be able
|
||||
# to authenticate.
|
||||
openstack::ha::haproxy_service { 'grafana':
|
||||
order => '801',
|
||||
listen_port => $grafana_port,
|
||||
balancermember_port => $grafana_port,
|
||||
haproxy_config_options => {
|
||||
'option' => ['httplog', 'dontlog-normal'],
|
||||
'balance' => 'source',
|
||||
'mode' => 'http',
|
||||
},
|
||||
if hiera('lma::grafana::tls::enabled') {
|
||||
openstack::ha::haproxy_service { 'grafana':
|
||||
order => '801',
|
||||
internal_ssl => true,
|
||||
internal_ssl_path => hiera('lma::grafana::tls::cert_file_path'),
|
||||
listen_port => $grafana_port,
|
||||
balancermember_port => $grafana_port,
|
||||
haproxy_config_options => {
|
||||
'option' => ['httplog', 'dontlog-normal'],
|
||||
'balance' => 'source',
|
||||
'mode' => 'http',
|
||||
},
|
||||
}
|
||||
} else {
|
||||
openstack::ha::haproxy_service { 'grafana':
|
||||
order => '801',
|
||||
listen_port => $grafana_port,
|
||||
balancermember_port => $grafana_port,
|
||||
haproxy_config_options => {
|
||||
'option' => ['httplog', 'dontlog-normal'],
|
||||
'balance' => 'source',
|
||||
'mode' => 'http',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
openstack::ha::haproxy_service { 'stats':
|
||||
|
|
|
@ -35,6 +35,32 @@ $leader_ip_address = $leader_ip_addresses[0]
|
|||
$influxdb_others = get_nodes_hash_by_roles($network_metadata, ['influxdb_grafana'])
|
||||
$others_ip_addresses = sort(values(get_node_to_ipaddr_map_by_network_role($influxdb_others, 'influxdb_vip')))
|
||||
|
||||
$tls_enabled = $influxdb_grafana['tls_enabled']
|
||||
if $tls_enabled {
|
||||
$grafana_hostname = $influxdb_grafana['grafana_hostname']
|
||||
$cert_base_dir = '/etc/haproxy'
|
||||
$cert_dir = "${cert_base_dir}/certs"
|
||||
$cert_file_path = "${cert_dir}/${influxdb_grafana['grafana_ssl_cert']['name']}"
|
||||
|
||||
file { $cert_base_dir:
|
||||
ensure => directory,
|
||||
mode => '0755'
|
||||
}
|
||||
|
||||
file { $cert_dir:
|
||||
ensure => directory,
|
||||
mode => '0700',
|
||||
require => File[$cert_base_dir]
|
||||
}
|
||||
|
||||
file { $cert_file_path:
|
||||
ensure => present,
|
||||
mode => '0400',
|
||||
content => $influxdb_grafana['grafana_ssl_cert']['content'],
|
||||
require => File[$cert_dir]
|
||||
}
|
||||
}
|
||||
|
||||
$calculated_content = inline_template('
|
||||
---
|
||||
lma::influxdb::data_dir: "/var/lib/influxdb"
|
||||
|
@ -51,6 +77,12 @@ lma::influxdb::vip: <%= @influxdb_vip %>
|
|||
lma::corosync_roles:
|
||||
- primary-influxdb_grafana
|
||||
- influxdb_grafana
|
||||
|
||||
lma::grafana::tls::enabled: <%= @tls_enabled %>
|
||||
<% if @tls_enabled -%>
|
||||
lma::grafana::tls::hostname: "<%= @grafana_hostname %>"
|
||||
lma::grafana::tls::cert_file_path: "<%= @cert_file_path %>"
|
||||
<% end -%>
|
||||
')
|
||||
|
||||
file { $hiera_file:
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
# Copyright 2016 Mirantis, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
notice('fuel-plugin-influxdb-grafana: validate_certificate.pp')
|
||||
|
||||
if hiera('lma::grafana::tls::enabled') {
|
||||
|
||||
$certificate = hiera('lma::grafana::tls::cert_file_path')
|
||||
$common_name = hiera('lma::grafana::tls::hostname')
|
||||
|
||||
# function validate_ssl_certificate() must be the value of a statement, so
|
||||
# we must use it in a statement.
|
||||
$not_used = validate_ssl_certificate($certificate, $common_name)
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
# Inspired by cert_date_valid.rb found at
|
||||
# https://github.com/camptocamp/puppet-openssl
|
||||
#
|
||||
# Function: validate_ssl_certificate()
|
||||
#
|
||||
# Checks SSL certificate date and CN validity. It also checks that the private
|
||||
# key is embedded into the certificate.
|
||||
#
|
||||
# It raises an exception if:
|
||||
# - the certificate has no private key
|
||||
# - the CN of the certificate and the CN provided as argument don't match
|
||||
# - the date is not found in the certificate
|
||||
#
|
||||
# It returns false if the certificate is expired or not yet valid
|
||||
# Otherwise it returns the number of seconds before the certificate expires
|
||||
#
|
||||
# Parameter:
|
||||
# - the file path of the SSL certificate
|
||||
# - the expected CN
|
||||
|
||||
module Puppet::Parser::Functions
|
||||
newfunction(:validate_ssl_certificate, :type => :rvalue) do |args|
|
||||
|
||||
require 'time'
|
||||
|
||||
certfile = args[0]
|
||||
|
||||
# Check that file is a valid x509 certificate
|
||||
err_msg = `openssl x509 -noout -in #{certfile}`
|
||||
raise "'#{certfile}' is not a valid certificate" unless err_msg.chomp() == ""
|
||||
|
||||
dates = `openssl x509 -dates -noout -in #{certfile}`.gsub("\n", '')
|
||||
subject = `openssl x509 -subject -noout -in #{certfile}`.gsub("\n", '')
|
||||
pk = `openssl rsa -check -noout -in #{certfile}`.gsub("\n",'')
|
||||
|
||||
cn = subject.match(/CN=([^\/]+)/)
|
||||
cn_found = cn[1] if cn
|
||||
certbegin = Time.parse(dates.gsub(/.*notBefore=(.+? GMT).*/, '\1'))
|
||||
certend = Time.parse(dates.gsub(/.*notAfter=(.+? GMT).*/, '\1'))
|
||||
now = Time.now.utc
|
||||
|
||||
raise "The certificate file doesn't contain the private key" unless pk == 'RSA key ok'
|
||||
raise "Found #{cn_found} as CN whereas '#{args[1]}' was expected" unless cn_found == args[1]
|
||||
raise "Dates not found in the certificate" unless dates.match(/not(Before|After)=/)
|
||||
|
||||
if (now > certend)
|
||||
Puppet.warning("Certificate has expired. End date: #{certend}")
|
||||
false
|
||||
elsif (now < certbegin)
|
||||
Puppet.warning("Certificate is not yet valid. Start date: #{certbegin}")
|
||||
false
|
||||
elsif (certend <= certbegin)
|
||||
Puppet.warning("Certificate will never be valid")
|
||||
false
|
||||
else
|
||||
# return the number of seconds before the certificate expires
|
||||
(certend - now).to_i
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -78,9 +78,11 @@ class Puppet::Provider::Grafana < Puppet::Provider
|
|||
request.basic_auth resource[:grafana_user], resource[:grafana_password]
|
||||
end
|
||||
|
||||
return Net::HTTP.start(self.grafana_host, self.grafana_port) do |http|
|
||||
http.request(request)
|
||||
end
|
||||
return Net::HTTP.start(self.grafana_host, self.grafana_port,
|
||||
:use_ssl => self.grafana_scheme == "https",
|
||||
:verify_mode => OpenSSL::SSL::VERIFY_NONE) do |http|
|
||||
http.request(request)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
class lma_monitoring_analytics::grafana_dashboards (
|
||||
$admin_username,
|
||||
$admin_password,
|
||||
$protocol = $lma_monitoring_analytics::params::protocol,
|
||||
$host = $lma_monitoring_analytics::params::grafana_domain,
|
||||
$port = $lma_monitoring_analytics::params::grafana_port,
|
||||
$import_influxdb = false,
|
||||
|
@ -25,7 +26,7 @@ class lma_monitoring_analytics::grafana_dashboards (
|
|||
|
||||
$dashboard_defaults = {
|
||||
ensure => present,
|
||||
grafana_url => "http://${host}:${port}",
|
||||
grafana_url => "${protocol}://${host}:${port}",
|
||||
grafana_user => $admin_username,
|
||||
grafana_password => $admin_password,
|
||||
}
|
||||
|
|
|
@ -22,4 +22,5 @@ class lma_monitoring_analytics::params {
|
|||
$grafana_domain = 'localhost'
|
||||
$grafana_address = ''
|
||||
$grafana_port = 8000
|
||||
$protocol = 'http'
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
- netconfig
|
||||
- hosts
|
||||
- influxdb-hiera
|
||||
- grafana-validate-certificate
|
||||
- influxdb-firewall
|
||||
- influxdb-cluster
|
||||
- influxdb-cluster-haproxy
|
||||
|
@ -67,6 +68,19 @@
|
|||
reexecute_on:
|
||||
- deploy_changes
|
||||
|
||||
- id: grafana-validate-certificate
|
||||
type: puppet
|
||||
version: 2.0.0
|
||||
requires: [influxdb-hiera]
|
||||
required_for: [influxdb-firewall]
|
||||
parameters:
|
||||
puppet_manifest: "puppet/manifests/validate_certificate.pp"
|
||||
puppet_modules: puppet/modules:/etc/puppet/modules
|
||||
timeout: 120
|
||||
# reexecute_on is needed for scale-down operations
|
||||
reexecute_on:
|
||||
- deploy_changes
|
||||
|
||||
- id: influxdb-firewall
|
||||
type: puppet
|
||||
version: 2.0.0
|
||||
|
|
|
@ -135,3 +135,32 @@ attributes:
|
|||
regex:
|
||||
source: '^[\S]{4,}$'
|
||||
error: "You must provide a password with at least 4 characters"
|
||||
|
||||
# TLS Settings: BEGIN
|
||||
tls_enabled:
|
||||
value: false
|
||||
label: 'Enable TLS for Grafana'
|
||||
description: ''
|
||||
weight: 140
|
||||
type: "checkbox"
|
||||
|
||||
grafana_hostname:
|
||||
value: 'grafana.fuel.local'
|
||||
label: 'DNS hostname for Grafana'
|
||||
description: 'Your DNS entries should point to this name.'
|
||||
weight: 150
|
||||
type: "text"
|
||||
restrictions:
|
||||
- condition: "settings:influxdb_grafana.tls_enabled.value == false"
|
||||
action: "hide"
|
||||
|
||||
grafana_ssl_cert:
|
||||
value: ''
|
||||
label: 'Certificate for Grafana'
|
||||
description: 'Certificate and private key data, concatenated into a single file.'
|
||||
weight: 160
|
||||
type: "file"
|
||||
restrictions:
|
||||
- condition: "settings:influxdb_grafana.tls_enabled.value == false"
|
||||
action: "hide"
|
||||
# TLS Settings: END
|
||||
|
|
Loading…
Reference in New Issue