Enable TLS for Nagios UI

Blueprint: support-secure-communication

Change-Id: Iac010a698ed92cd3179dae8f9caf2eb6c0f4c1e0
This commit is contained in:
Swann Croiset 2016-06-15 18:11:27 +02:00
parent 51bffbc63c
commit 874c658ba1
11 changed files with 250 additions and 23 deletions

View File

@ -14,6 +14,9 @@
notice('fuel-plugin-lma-infrastructure-alerting: firewall.pp')
$nagios_ui = hiera_hash('lma::infrastructure_alerting::nagios_ui')
$apache_port = $nagios_ui['apache_port']
class {'::firewall':}
firewall { '000 accept all icmp requests':
@ -52,7 +55,7 @@ firewall { '114 corosync-input':
}
firewall { '300 nagios cgi':
port => hiera('lma::infrastructure_alerting::apache_port'),
port => $apache_port,
proto => 'tcp',
action => 'accept',
}

View File

@ -24,6 +24,34 @@ $alerting_vip = $network_metadata['vips']['infrastructure_alerting_mgmt_vip']
$alerting_ui_vip = $network_metadata['vips']['infrastructure_alerting_ui']['ipaddr']
$listen_address = get_network_role_property('infrastructure_alerting', 'ipaddr')
$plugin = hiera('lma_infrastructure_alerting')
$tls_enabled = $plugin['tls_enabled']
if $tls_enabled {
$nagios_ui_hostname = $plugin['nagios_hostname']
if $plugin['nagios_ssl_cert'] and $plugin['nagios_ssl_cert']['content'] {
$nagios_ui_ssl_cert = $plugin['nagios_ssl_cert']['content']
$nagios_ui_ssl_cert_path = "/etc/apache2/certs/${$plugin['nagios_ssl_cert']['name']}"
file { '/etc/apache2':
ensure => directory,
mode => '0755',
} ->
file { '/etc/apache2/certs':
ensure => directory,
mode => '0750',
} ->
file { $nagios_ui_ssl_cert_path:
ensure => present,
mode => '0700',
content => $nagios_ui_ssl_cert,
}
}
$ui_scheme = 'https'
} else {
$ui_scheme = 'http'
}
$kibana_port = hiera('lma::elasticsearch::kibana_port', 80)
$es_port = hiera('lma::elasticsearch::rest_port', 9200)
$grafana_port = hiera('lma::influxdb::grafana_port', 8000)
@ -34,15 +62,22 @@ lma::corosync_roles:
- infrastructure_alerting
- primary-infrastructure_alerting
lma::infrastructure_alerting::listen_address: <%= @listen_address %>
lma::infrastructure_alerting::apache_port: 8001
lma::infrastructure_alerting::vip: <%= @alerting_vip %>
lma::infrastructure_alerting::vip_ui: <%= @alerting_ui_vip %>
lma::infrastructure_alerting::vip_ns: infrastructure_alerting
lma::infrastructure_alerting::kibana_port: <%= @kibana_port %>
lma::infrastructure_alerting::es_port: <%= @es_port %>
lma::infrastructure_alerting::grafana_port: <%= @grafana_port %>
lma::infrastructure_alerting::influxdb_port: <%= @influxdb_port %>
lma::infrastructure_alerting::cluster_ip: 127.0.0.1
lma::infrastructure_alerting::nagios_ui:
vip: <%= @alerting_ui_vip %>
apache_port: 8001
scheme: <%= @ui_scheme %>
tls_enabled: <%= @tls_enabled %>
<% if @tls_enabled -%>
hostname: <%= @nagios_ui_hostname %>
ssl_cert_path: <%= @nagios_ui_ssl_cert_path %>
<% end -%>
')
file { $hiera_file:

View File

@ -43,9 +43,13 @@ if $notify_warning == false and
$notify_unknown = $plugin['notify_unknown']
$notify_recovery = $plugin['notify_recovery']
}
$apache_port = hiera('lma::infrastructure_alerting::apache_port')
$nagios_vip = hiera('lma::infrastructure_alerting::vip')
$nagios_ui_vip = hiera('lma::infrastructure_alerting::vip_ui')
$nagios_ui = hiera_hash('lma::infrastructure_alerting::nagios_ui')
$nagios_ui_vip = $nagios_ui['vip']
$apache_port = $nagios_ui['apache_port']
$tls_enabled = $nagios_ui['tls_enabled']
$lma_collector = hiera_hash('lma_collector', {})
@ -63,10 +67,14 @@ if $lma_collector['gse_cluster_node'] {
# Install and configure nagios server for StackLight
class { 'lma_infra_alerting::nagios':
http_password => $password,
http_port => $apache_port,
nagios_ui_address => $nagios_ui_vip,
nagios_address => $nagios_vip,
http_password => $password,
http_port => $apache_port,
nagios_ui_address => $nagios_ui_vip,
nagios_address => $nagios_vip,
ui_tls_enabled => $tls_enabled,
ui_certificate_filename => $nagios_ui['ssl_cert_path'],
ui_certificate_hostname => $nagios_ui['hostname'],
}
class { 'lma_infra_alerting::nagios::vhost':

View File

@ -16,11 +16,23 @@ notice('fuel-plugin-lma-infrastructure-alerting: nagios_dashboard_url.pp')
$deployment_id = hiera('deployment_id')
$master_ip = hiera('master_ip')
$vip = hiera('lma::infrastructure_alerting::vip_ui')
$port = hiera('lma::infrastructure_alerting::apache_port')
$nagios_ui = hiera_hash('lma::infrastructure_alerting::nagios_ui')
$vip = $nagios_ui['vip']
$scheme = $nagios_ui['scheme']
$tls_enabled = $nagios_ui['tls_enabled']
$port = $nagios_ui['apache_port']
if $tls_enabled {
$host_name = $nagios_ui['hostname']
$link = "${scheme}://${$host_name}:${port}/"
$text = "Dashboard for visualizing alerts (${host_name}: ${vip})"
} else {
$link = "${scheme}://${vip}:${port}/"
$text = 'Dashboard for visualizing alerts'
}
$nagios_link_data = "{\"title\":\"Nagios\",\
\"description\":\"Dashboard for visualizing alerts\",\
\"url\":\"http://${vip}:${port}/\"}"
\"description\":\"${text}\",\
\"url\":\"${link}\"}"
$nagios_link_created_file = '/var/cache/nagios_link_created'
exec { 'notify_nagios_url':

View File

@ -0,0 +1,26 @@
# 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-lma-infrastructure-alerting: validate_certificate.pp')
$nagios_ui = hiera('lma::infrastructure_alerting::nagios_ui')
$certificate = $nagios_ui['ssl_cert']
$certificate_path = $nagios_ui['ssl_cert_path']
$common_name = $nagios_ui['hostname']
if $nagios_ui['tls_enabled'] {
if validate_ssl_certificate($certificate_path, $common_name) {
notice("Certificate ${certificate_path} for '${common_name}' is valid")
}
}

View File

@ -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 content 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

View File

@ -23,6 +23,9 @@ class lma_infra_alerting::nagios (
$http_port,
$nagios_ui_address,
$nagios_address,
$ui_tls_enabled = false,
$ui_certificate_filename = undef,
$ui_certificate_hostname = undef,
) inherits lma_infra_alerting::params {
include nagios::params
@ -48,12 +51,15 @@ class lma_infra_alerting::nagios (
}
class { '::nagios::cgi':
user => $http_user,
password => $http_password,
http_port => $http_port,
vhost_listen_ip => $nagios_ui_address,
wsgi_vhost_listen_ip => $nagios_address,
require => Class[nagios],
user => $http_user,
password => $http_password,
http_port => $http_port,
vhost_listen_ip => $nagios_ui_address,
wsgi_vhost_listen_ip => $nagios_address,
ui_tls_enabled => $ui_tls_enabled,
ui_certificate_filename => $ui_certificate_filename,
ui_certificate_hostname => $ui_certificate_hostname,
require => Class[nagios],
}
$cron_bin = $lma_infra_alerting::params::update_configuration_script

View File

@ -23,15 +23,24 @@ class nagios::cgi (
$password = $nagios::params::cgi_password,
$htpasswd_file = $nagios::params::cgi_htpasswd_file,
$http_port = $nagios::params::cgi_http_port,
$ui_tls_enabled = false,
$ui_certificate_filename = undef,
$ui_certificate_hostname = undef,
$wsgi_process_service_checks_location = '/status',
$wsgi_process_service_checks_script = '/usr/local/bin/nagios-process-service-checks.wsgi',
$wsgi_processes = 2,
$wsgi_threads = 15,
) inherits nagios::params {
validate_integer($wsgi_processes)
validate_integer($wsgi_threads)
if $ui_tls_enabled {
$apache_modules = ['php', 'cgi', 'authn_file', 'auth_basic', 'authz_user', 'wsgi', 'ssl']
} else {
$apache_modules = ['php', 'cgi', 'authn_file', 'auth_basic', 'authz_user', 'wsgi']
}
## Configure apache
class { 'apache':
# be good citizen by not erasing other configurations
@ -40,7 +49,7 @@ class nagios::cgi (
default_vhost => false,
# prerequists for Nagios CGI
mpm_module => 'prefork',
default_mods => ['php', 'cgi', 'authn_file', 'auth_basic', 'authz_user', 'wsgi'],
default_mods => $apache_modules,
# allow to use the Puppet user resource later in the manifest
manage_group => false,
manage_user => false,

View File

@ -4,7 +4,21 @@
# ************************************
<VirtualHost <%= @vhost_listen_ip %>:<%= @http_port %>>
<% if @ui_tls_enabled -%>
ServerName <%= @ui_certificate_hostname %>
SSLEngine on
SSLCertificateFile "<%= @ui_certificate_filename %>"
## Configuration from mozilla.github.io/server-side-tls/ssl-config-generator/
# For Apache 2.4.7 with "modern" profile.
Header always set Strict-Transport-Security "max-age=15768000"
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256
SSLHonorCipherOrder on
SSLCompression off
<% else -%>
ServerName nagios-ui
<% end -%>
DocumentRoot "/usr/share/nagios3/htdocs"
# Alias for UI

View File

@ -3,7 +3,7 @@
type: group
version: 2.0.0
role: [primary-infrastructure_alerting]
tasks: &common_tasks
tasks:
- hiera
- setup_repositories
- fuel_pkgs
@ -13,6 +13,7 @@
- netconfig
- hosts
- lma-alerting-hiera
- lma-alerting-validate-certificate
- lma-alerting-firewall
- lma-alerting-cluster
- lma-alerting-vip
@ -26,7 +27,19 @@
type: group
version: 2.0.0
role: [infrastructure_alerting]
tasks: *common_tasks
tasks:
- hiera
- setup_repositories
- fuel_pkgs
- globals
- tools
- logging
- netconfig
- hosts
- lma-alerting-hiera
- lma-alerting-firewall
- lma-alerting-cluster
- lma-alerting-vip
required_for: [deploy_end]
requires: [deploy_start, primary-infrastructure_alerting]
parameters:
@ -45,6 +58,19 @@
puppet_modules: puppet/modules:/etc/puppet/modules
timeout: 120
- id: lma-alerting-validate-certificate
type: puppet
version: 2.0.0
requires: [lma-alerting-hiera]
required_for: [logging, lma-alerting-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: lma-alerting-firewall
type: puppet
version: 2.0.0

View File

@ -101,3 +101,30 @@ attributes:
weight: 52
type: "password"
restrictions: *no_auth
tls_enabled:
value: false
label: 'Enable TLS for Nagios'
description: ''
weight: 60
type: "checkbox"
nagios_hostname:
value: 'nagios.fuel.local'
label: 'DNS hostname for Nagios UI'
description: 'Your DNS entries should point to this name'
weight: 61
type: "text"
restrictions:
- condition: "settings:lma_infrastructure_alerting.tls_enabled.value == false"
action: "hide"
nagios_ssl_cert:
value: ''
label: 'Certificate for Nagios UI'
description: 'Certificate and private key data, concatenated into a single file'
weight: 62
type: "file"
restrictions:
- condition: "settings:lma_infrastructure_alerting.tls_enabled.value == false"
action: "hide"