2014-10-17 15:13:17 +02:00
/******************************************************************************
* Icinga 2 *
2015-01-22 12:00:23 +01:00
* Copyright ( C ) 2012 - 2015 Icinga Development Team ( http : //www.icinga.org) *
2014-10-17 15:13:17 +02:00
* *
* This program is free software ; you can redistribute it and / or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation ; either version 2 *
* of the License , or ( at your option ) any later version . *
* *
* This program is distributed in the hope that it will be useful , *
* but WITHOUT ANY WARRANTY ; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the *
* GNU General Public License for more details . *
* *
* You should have received a copy of the GNU General Public License *
* along with this program ; if not , write to the Free Software Foundation *
* Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 , USA . *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-10-31 11:38:16 +01:00
# include "cli/nodewizardcommand.hpp"
# include "cli/nodeutility.hpp"
2014-10-30 16:19:51 +01:00
# include "cli/pkiutility.hpp"
# include "cli/featureutility.hpp"
2014-10-19 14:21:12 +02:00
# include "base/logger.hpp"
2014-10-30 16:19:51 +01:00
# include "base/console.hpp"
2014-10-17 15:13:17 +02:00
# include "base/application.hpp"
2014-10-30 16:19:51 +01:00
# include "base/tlsutility.hpp"
2014-12-14 11:33:45 +01:00
# include "base/scriptglobal.hpp"
2014-12-15 10:16:06 +01:00
# include "base/exception.hpp"
2014-10-17 15:13:17 +02:00
# include <boost/foreach.hpp>
# include <boost/algorithm/string/join.hpp>
# include <boost/algorithm/string/replace.hpp>
2014-10-30 16:19:51 +01:00
# include <boost/algorithm/string/case_conv.hpp>
2014-10-18 21:06:28 +02:00
# include <iostream>
2014-10-30 16:19:51 +01:00
# include <string>
2014-10-17 15:13:17 +02:00
# include <fstream>
# include <vector>
using namespace icinga ;
namespace po = boost : : program_options ;
2014-10-31 11:38:16 +01:00
REGISTER_CLICOMMAND ( " node/wizard " , NodeWizardCommand ) ;
2014-10-17 15:13:17 +02:00
2014-10-31 11:38:16 +01:00
String NodeWizardCommand : : GetDescription ( void ) const
2014-10-17 15:13:17 +02:00
{
2014-10-31 11:53:44 +01:00
return " Wizard for Icinga 2 node setup. " ;
2014-10-17 15:13:17 +02:00
}
2014-10-31 11:38:16 +01:00
String NodeWizardCommand : : GetShortDescription ( void ) const
2014-10-17 15:13:17 +02:00
{
2014-10-31 11:53:44 +01:00
return " wizard for node setup " ;
2014-10-17 15:13:17 +02:00
}
2014-10-31 11:38:16 +01:00
ImpersonationLevel NodeWizardCommand : : GetImpersonationLevel ( void ) const
2014-10-30 20:34:33 +01:00
{
return ImpersonateRoot ;
}
2014-10-31 11:38:16 +01:00
int NodeWizardCommand : : GetMaxArguments ( void ) const
2014-10-30 20:34:33 +01:00
{
return - 1 ;
}
2014-10-17 15:13:17 +02:00
/**
2014-10-31 11:53:44 +01:00
* The entry point for the " node wizard " CLI command .
2014-10-17 15:13:17 +02:00
*
* @ returns An exit status .
*/
2014-10-31 11:38:16 +01:00
int NodeWizardCommand : : Run ( const boost : : program_options : : variables_map & vm , const std : : vector < std : : string > & ap ) const
2014-10-17 15:13:17 +02:00
{
2014-10-22 19:26:31 +02:00
/*
* The wizard will get all information from the user ,
* and then call all required functions .
*/
2014-11-02 20:17:57 +01:00
std : : cout < < ConsoleColorTag ( Console_Bold | Console_ForegroundBlue ) < < " Welcome to the Icinga 2 Setup Wizard! \n "
2014-10-22 19:26:31 +02:00
< < " \n "
< < " We'll guide you through all required configuration details. \n "
< < " \n "
2014-11-02 20:17:57 +01:00
< < " \n \n " < < ConsoleColorTag ( Console_Normal ) ;
2014-10-22 19:26:31 +02:00
//TODO: Add sort of bash completion to path input?
2014-10-31 11:53:44 +01:00
/* 0. master or node setup?
2014-10-22 19:26:31 +02:00
* 1. Ticket
* 2. Master information for autosigning
* 3. Trusted cert location
* 4. CN to use ( defaults to FQDN )
* 5. Local CA
* 6. New self signed certificate
* 7. Request signed certificate from master
* 8. copy key information to / etc / icinga2 / pki
* 9. enable ApiListener feature
* 10. generate zones . conf with endpoints and zone objects
* 11. set NodeName = cn in constants . conf
* 12. reload icinga2 , or tell the user to
*/
2014-10-30 16:19:51 +01:00
std : : string answer ;
2014-10-31 11:53:44 +01:00
bool is_node_setup = true ;
2014-10-30 16:19:51 +01:00
2014-11-02 20:17:57 +01:00
std : : cout < < ConsoleColorTag ( Console_Bold ) < < " Please specify if this is a satellite setup "
< < " ('n' installs a master setup) " < < ConsoleColorTag ( Console_Normal ) < < " [Y/n]: " ;
2014-10-30 16:19:51 +01:00
std : : getline ( std : : cin , answer ) ;
boost : : algorithm : : to_lower ( answer ) ;
2014-10-30 18:21:15 +01:00
String choice = answer ;
2014-10-30 16:19:51 +01:00
2014-10-30 18:21:15 +01:00
if ( choice . Contains ( " n " ) )
2014-10-31 11:53:44 +01:00
is_node_setup = false ;
2014-10-30 16:19:51 +01:00
2014-10-31 11:53:44 +01:00
if ( is_node_setup ) {
/* node setup part */
2014-10-31 11:38:16 +01:00
std : : cout < < " Starting the Node setup routine... \n " ;
2014-10-30 16:19:51 +01:00
/* CN */
2014-11-02 20:17:57 +01:00
std : : cout < < ConsoleColorTag ( Console_Bold ) < < " Please specifiy the common name (CN) " < < ConsoleColorTag ( Console_Normal ) < < " [ " < < Utility : : GetFQDN ( ) < < " ]: " ;
2014-10-30 16:19:51 +01:00
std : : getline ( std : : cin , answer ) ;
boost : : algorithm : : to_lower ( answer ) ;
if ( answer . empty ( ) )
answer = Utility : : GetFQDN ( ) ;
String cn = answer ;
cn . Trim ( ) ;
2014-11-02 20:17:57 +01:00
std : : cout < < ConsoleColorTag ( Console_Bold ) < < " Please specifiy the local zone name " < < ConsoleColorTag ( Console_Normal ) < < " [ " < < cn < < " ]: " ;
2014-10-31 22:21:36 +01:00
std : : getline ( std : : cin , answer ) ;
boost : : algorithm : : to_lower ( answer ) ;
if ( answer . empty ( ) )
answer = cn ;
String local_zone = answer ;
local_zone . Trim ( ) ;
2014-10-30 16:19:51 +01:00
std : : vector < std : : string > endpoints ;
String endpoint_buffer ;
2014-11-02 20:17:57 +01:00
std : : cout < < ConsoleColorTag ( Console_Bold ) < < " Please specify the master endpoint(s) this node should connect to: " < < ConsoleColorTag ( Console_Normal ) < < " \n " ;
2014-10-30 16:19:51 +01:00
String master_endpoint_name ;
wizard_endpoint_loop_start :
2014-11-13 15:25:15 +01:00
std : : cout < < ConsoleColorTag ( Console_Bold ) < < " Master Common Name " < < ConsoleColorTag ( Console_Normal ) < < " (CN from your master setup): " ;
2014-10-30 16:19:51 +01:00
std : : getline ( std : : cin , answer ) ;
boost : : algorithm : : to_lower ( answer ) ;
2015-02-11 15:47:45 +01:00
if ( answer . empty ( ) ) {
2014-10-30 16:19:51 +01:00
Log ( LogWarning , " cli " , " Master CN is required! Please retry. " ) ;
goto wizard_endpoint_loop_start ;
}
endpoint_buffer = answer ;
endpoint_buffer . Trim ( ) ;
2014-11-02 20:17:57 +01:00
std : : cout < < ConsoleColorTag ( Console_Bold ) < < " Please fill out the master connection information: " < < ConsoleColorTag ( Console_Normal ) < < " \n " ;
2014-11-13 15:25:15 +01:00
std : : cout < < ConsoleColorTag ( Console_Bold ) < < " Master endpoint host " < < ConsoleColorTag ( Console_Normal ) < < " (optional, your master's IP address or FQDN): " ;
2014-10-30 16:19:51 +01:00
std : : getline ( std : : cin , answer ) ;
boost : : algorithm : : to_lower ( answer ) ;
if ( ! answer . empty ( ) ) {
String tmp = answer ;
tmp . Trim ( ) ;
endpoint_buffer + = " , " + tmp ;
master_endpoint_name = tmp ; //store the endpoint name for later
}
2014-11-02 20:17:57 +01:00
std : : cout < < ConsoleColorTag ( Console_Bold ) < < " Master endpoint port " < < ConsoleColorTag ( Console_Normal ) < < " (optional) []: " ;
2014-10-30 16:19:51 +01:00
std : : getline ( std : : cin , answer ) ;
boost : : algorithm : : to_lower ( answer ) ;
if ( ! answer . empty ( ) ) {
String tmp = answer ;
tmp . Trim ( ) ;
endpoint_buffer + = " , " + answer ;
}
endpoints . push_back ( endpoint_buffer ) ;
2014-11-02 20:17:57 +01:00
std : : cout < < ConsoleColorTag ( Console_Bold ) < < " Add more master endpoints? " < < ConsoleColorTag ( Console_Normal ) < < " [y/N] " ;
2014-10-30 16:19:51 +01:00
std : : getline ( std : : cin , answer ) ;
boost : : algorithm : : to_lower ( answer ) ;
2014-10-30 18:21:15 +01:00
String choice = answer ;
2014-10-30 16:19:51 +01:00
2014-10-30 18:21:15 +01:00
if ( choice . Contains ( " y " ) | | choice . Contains ( " j " ) )
goto wizard_endpoint_loop_start ;
2014-10-30 16:19:51 +01:00
2014-11-02 20:17:57 +01:00
std : : cout < < ConsoleColorTag ( Console_Bold ) < < " Please specify the master connection for CSR auto-signing " < < ConsoleColorTag ( Console_Normal ) < < " (defaults to master endpoint host): \n " ;
2014-10-30 16:19:51 +01:00
wizard_master_host :
2014-11-02 20:17:57 +01:00
std : : cout < < ConsoleColorTag ( Console_Bold ) < < " Host " < < ConsoleColorTag ( Console_Normal ) < < " [ " < < master_endpoint_name < < " ]: " ;
2014-10-30 16:19:51 +01:00
std : : getline ( std : : cin , answer ) ;
boost : : algorithm : : to_lower ( answer ) ;
if ( answer . empty ( ) & & ! master_endpoint_name . IsEmpty ( ) )
answer = master_endpoint_name ;
if ( answer . empty ( ) & & master_endpoint_name . IsEmpty ( ) )
goto wizard_master_host ;
String master_host = answer ;
master_host . Trim ( ) ;
2014-11-02 20:17:57 +01:00
std : : cout < < ConsoleColorTag ( Console_Bold ) < < " Port " < < ConsoleColorTag ( Console_Normal ) < < " [5665]: " ;
2014-10-30 16:19:51 +01:00
std : : getline ( std : : cin , answer ) ;
boost : : algorithm : : to_lower ( answer ) ;
if ( answer . empty ( ) )
answer = " 5665 " ;
String master_port = answer ;
master_port . Trim ( ) ;
2014-10-30 20:34:33 +01:00
/* workaround for fetching the master cert */
String pki_path = PkiUtility : : GetPkiPath ( ) ;
2014-10-31 11:53:44 +01:00
String node_cert = pki_path + " / " + cn + " .crt " ;
String node_key = pki_path + " / " + cn + " .key " ;
2014-10-30 16:19:51 +01:00
2014-10-30 20:34:33 +01:00
if ( ! Utility : : MkDirP ( pki_path , 0700 ) ) {
Log ( LogCritical , " cli " )
< < " Could not create local pki directory ' " < < pki_path < < " '. " ;
return 1 ;
}
2014-12-14 11:33:45 +01:00
String user = ScriptGlobal : : Get ( " RunAsUser " ) ;
String group = ScriptGlobal : : Get ( " RunAsGroup " ) ;
2014-10-30 20:34:33 +01:00
if ( ! Utility : : SetFileOwnership ( pki_path , user , group ) ) {
Log ( LogWarning , " cli " )
< < " Cannot set ownership for user ' " < < user < < " ' group ' " < < group < < " ' on file ' " < < pki_path < < " '. Verify it yourself! " ;
}
2015-02-07 20:44:25 +01:00
if ( Utility : : PathExists ( node_key ) )
2015-02-09 14:04:00 +01:00
NodeUtility : : CreateBackupFile ( node_key , true ) ;
2015-02-07 20:44:25 +01:00
if ( Utility : : PathExists ( node_cert ) )
2015-02-09 14:04:00 +01:00
NodeUtility : : CreateBackupFile ( node_cert ) ;
2015-02-07 20:44:25 +01:00
2014-10-31 11:53:44 +01:00
if ( PkiUtility : : NewCert ( cn , node_key , Empty , node_cert ) > 0 ) {
2014-10-30 16:19:51 +01:00
Log ( LogCritical , " cli " )
< < " Failed to create new self-signed certificate for CN ' " < < cn < < " '. Please try again. " ;
return 1 ;
}
2014-10-30 20:34:33 +01:00
/* fix permissions: root -> icinga daemon user */
2014-10-31 11:53:44 +01:00
if ( ! Utility : : SetFileOwnership ( node_key , user , group ) ) {
2014-10-30 20:34:33 +01:00
Log ( LogWarning , " cli " )
2014-10-31 11:53:44 +01:00
< < " Cannot set ownership for user ' " < < user < < " ' group ' " < < group < < " ' on file ' " < < node_key < < " '. Verify it yourself! " ;
2014-10-30 20:34:33 +01:00
}
2014-10-30 16:19:51 +01:00
//save-cert and store the master certificate somewhere
2014-11-02 20:17:57 +01:00
Log ( LogInformation , " cli " , " Generating self-signed certifiate: " ) ;
2014-10-30 16:19:51 +01:00
2014-11-02 20:17:57 +01:00
Log ( LogInformation , " cli " )
< < " Fetching public certificate from master ( "
2014-10-30 16:19:51 +01:00
< < master_host < < " , " < < master_port < < " ): \n " ;
String trusted_cert = PkiUtility : : GetPkiPath ( ) + " /trusted-master.crt " ;
2015-02-07 20:44:25 +01:00
if ( Utility : : PathExists ( trusted_cert ) )
2015-02-09 14:04:00 +01:00
NodeUtility : : CreateBackupFile ( trusted_cert ) ;
2015-02-07 20:44:25 +01:00
2014-10-31 11:53:44 +01:00
if ( PkiUtility : : SaveCert ( master_host , master_port , node_key , node_cert , trusted_cert ) > 0 ) {
2014-10-30 16:19:51 +01:00
Log ( LogCritical , " cli " )
< < " Failed to fetch trusted master certificate. Please try again. " ;
return 1 ;
}
2014-11-02 20:17:57 +01:00
Log ( LogInformation , " cli " )
< < " Stored trusted master certificate in ' " < < trusted_cert < < " '. \n " ;
2014-10-30 16:19:51 +01:00
wizard_ticket :
2014-11-02 20:17:57 +01:00
std : : cout < < ConsoleColorTag ( Console_Bold ) < < " Please specify the request ticket generated on your Icinga 2 master. " < < ConsoleColorTag ( Console_Normal ) < < " \n "
2015-02-05 10:30:30 +01:00
< < " (Hint: # icinga2 pki ticket --cn ' " < < cn < < " '): " ;
2014-10-30 16:19:51 +01:00
std : : getline ( std : : cin , answer ) ;
boost : : algorithm : : to_lower ( answer ) ;
if ( answer . empty ( ) )
goto wizard_ticket ;
String ticket = answer ;
ticket . Trim ( ) ;
2014-11-02 20:17:57 +01:00
Log ( LogInformation , " cli " )
< < " Processing self-signed certificate request. Ticket ' " < < ticket < < " '. \n " ;
2014-10-30 16:19:51 +01:00
2014-11-13 15:25:15 +01:00
String target_ca = pki_path + " /ca.crt " ;
2015-02-07 20:44:25 +01:00
if ( Utility : : PathExists ( target_ca ) )
2015-02-09 14:04:00 +01:00
NodeUtility : : CreateBackupFile ( target_ca ) ;
2015-02-07 20:44:25 +01:00
if ( Utility : : PathExists ( node_cert ) )
2015-02-09 14:04:00 +01:00
NodeUtility : : CreateBackupFile ( node_cert ) ;
2015-02-07 20:44:25 +01:00
2014-11-13 15:25:15 +01:00
if ( PkiUtility : : RequestCertificate ( master_host , master_port , node_key , node_cert , target_ca , trusted_cert , ticket ) > 0 ) {
2014-10-30 16:19:51 +01:00
Log ( LogCritical , " cli " )
< < " Failed to fetch signed certificate from master ' " < < master_host < < " , "
< < master_port < < " '. Please try again. " ;
2015-01-08 17:09:31 +01:00
goto wizard_ticket ;
2014-10-30 16:19:51 +01:00
}
2014-10-30 20:34:33 +01:00
/* fix permissions (again) when updating the signed certificate */
2014-10-31 11:53:44 +01:00
if ( ! Utility : : SetFileOwnership ( node_cert , user , group ) ) {
2014-10-30 20:34:33 +01:00
Log ( LogWarning , " cli " )
2014-10-31 11:53:44 +01:00
< < " Cannot set ownership for user ' " < < user < < " ' group ' " < < group < < " ' on file ' " < < node_cert < < " '. Verify it yourself! " ;
2014-10-30 20:34:33 +01:00
}
2014-10-30 16:19:51 +01:00
/* apilistener config */
2014-11-02 20:17:57 +01:00
std : : cout < < ConsoleColorTag ( Console_Bold ) < < " Please specify the API bind host/port " < < ConsoleColorTag ( Console_Normal ) < < " (optional): \n " ;
std : : cout < < ConsoleColorTag ( Console_Bold ) < < " Bind Host " < < ConsoleColorTag ( Console_Normal ) < < " []: " ;
2014-10-30 16:19:51 +01:00
std : : getline ( std : : cin , answer ) ;
boost : : algorithm : : to_lower ( answer ) ;
String bind_host = answer ;
bind_host . Trim ( ) ;
std : : cout < < " Bind Port []: " ;
std : : getline ( std : : cin , answer ) ;
boost : : algorithm : : to_lower ( answer ) ;
String bind_port = answer ;
bind_port . Trim ( ) ;
2014-11-02 20:17:57 +01:00
/* disable the notifications feature on client nodes */
Log ( LogInformation , " cli " , " Disabling the Notification feature. " ) ;
std : : vector < std : : string > disable ;
disable . push_back ( " notification " ) ;
FeatureUtility : : DisableFeatures ( disable ) ;
2014-11-02 19:38:35 +01:00
Log ( LogInformation , " cli " , " Enabling the Apilistener feature. " ) ;
2014-10-30 16:19:51 +01:00
std : : vector < std : : string > enable ;
enable . push_back ( " api " ) ;
FeatureUtility : : EnableFeatures ( enable ) ;
String apipath = FeatureUtility : : GetFeaturesAvailablePath ( ) + " /api.conf " ;
2014-10-31 11:38:16 +01:00
NodeUtility : : CreateBackupFile ( apipath ) ;
2014-10-30 16:19:51 +01:00
String apipathtmp = apipath + " .tmp " ;
std : : ofstream fp ;
fp . open ( apipathtmp . CStr ( ) , std : : ofstream : : out | std : : ofstream : : trunc ) ;
fp < < " /** \n "
< < " * The API listener is used for distributed monitoring setups. \n "
< < " */ \n "
< < " object ApiListener \" api \" { \n "
< < " cert_path = SysconfDir + \" /icinga2/pki/ \" + NodeName + \" .crt \" \n "
< < " key_path = SysconfDir + \" /icinga2/pki/ \" + NodeName + \" .key \" \n "
< < " ca_path = SysconfDir + \" /icinga2/pki/ca.crt \" \n " ;
if ( ! bind_host . IsEmpty ( ) )
fp < < " bind_host = \" " < < bind_host < < " \" \n " ;
if ( ! bind_port . IsEmpty ( ) )
fp < < " bind_port = " < < bind_port < < " \n " ;
fp < < " \n "
< < " ticket_salt = TicketSalt \n "
< < " } \n " ;
fp . close ( ) ;
# ifdef _WIN32
_unlink ( apipath . CStr ( ) ) ;
# endif /* _WIN32 */
if ( rename ( apipathtmp . CStr ( ) , apipath . CStr ( ) ) < 0 ) {
BOOST_THROW_EXCEPTION ( posix_error ( )
< < boost : : errinfo_api_function ( " rename " )
< < boost : : errinfo_errno ( errno )
< < boost : : errinfo_file_name ( apipathtmp ) ) ;
}
/* apilistener config */
2014-11-02 19:38:35 +01:00
Log ( LogInformation , " cli " , " Generating local zones.conf. " ) ;
2014-10-30 16:19:51 +01:00
2014-10-31 22:21:36 +01:00
NodeUtility : : GenerateNodeIcingaConfig ( endpoints , cn , local_zone ) ;
2014-10-30 16:19:51 +01:00
if ( cn ! = Utility : : GetFQDN ( ) ) {
Log ( LogWarning , " cli " )
< < " CN ' " < < cn < < " ' does not match the default FQDN ' " < < Utility : : GetFQDN ( ) < < " '. Requires update for NodeName constant in constants.conf! " ;
}
2014-11-02 19:38:35 +01:00
Log ( LogInformation , " cli " , " Updating constants.conf. " ) ;
2014-10-30 16:19:51 +01:00
2014-11-02 19:38:35 +01:00
String constants_file = Application : : GetSysconfDir ( ) + " /icinga2/constants.conf " ;
NodeUtility : : CreateBackupFile ( constants_file ) ;
2014-10-30 16:19:51 +01:00
2014-10-31 11:38:16 +01:00
NodeUtility : : UpdateConstant ( " NodeName " , cn ) ;
2015-02-05 10:33:40 +01:00
NodeUtility : : UpdateConstant ( " ZoneName " , local_zone ) ;
2014-10-30 16:19:51 +01:00
} else {
/* master setup */
2014-11-02 20:17:57 +01:00
std : : cout < < ConsoleColorTag ( Console_Bold ) < < " Starting the Master setup routine... \n " ;
2014-10-30 16:19:51 +01:00
/* CN */
2014-11-02 20:17:57 +01:00
std : : cout < < ConsoleColorTag ( Console_Bold ) < < " Please specifiy the common name " < < ConsoleColorTag ( Console_Normal ) < < " (CN) [ " < < Utility : : GetFQDN ( ) < < " ]: " ;
2014-10-30 16:19:51 +01:00
std : : getline ( std : : cin , answer ) ;
boost : : algorithm : : to_lower ( answer ) ;
if ( answer . empty ( ) )
answer = Utility : : GetFQDN ( ) ;
String cn = answer ;
cn . Trim ( ) ;
if ( PkiUtility : : NewCa ( ) > 0 ) {
Log ( LogWarning , " cli " , " Found CA, skipping and using the existing one. " ) ;
}
String pki_path = PkiUtility : : GetPkiPath ( ) ;
if ( ! Utility : : MkDirP ( pki_path , 0700 ) ) {
Log ( LogCritical , " cli " )
< < " Could not create local pki directory ' " < < pki_path < < " '. " ;
return 1 ;
}
2014-12-14 11:33:45 +01:00
String user = ScriptGlobal : : Get ( " RunAsUser " ) ;
String group = ScriptGlobal : : Get ( " RunAsGroup " ) ;
2014-10-30 20:34:33 +01:00
if ( ! Utility : : SetFileOwnership ( pki_path , user , group ) ) {
Log ( LogWarning , " cli " )
< < " Cannot set ownership for user ' " < < user < < " ' group ' " < < group < < " ' on file ' " < < pki_path < < " '. Verify it yourself! " ;
}
2014-10-30 16:19:51 +01:00
String key = pki_path + " / " + cn + " .key " ;
String csr = pki_path + " / " + cn + " .csr " ;
2014-11-02 17:45:51 +01:00
Log ( LogInformation , " cli " )
< < " Generating new CSR in ' " < < csr < < " '. " ;
2015-02-07 20:44:25 +01:00
if ( Utility : : PathExists ( key ) )
2015-02-09 14:04:00 +01:00
NodeUtility : : CreateBackupFile ( key , true ) ;
2015-02-07 20:44:25 +01:00
if ( Utility : : PathExists ( csr ) )
2015-02-09 14:04:00 +01:00
NodeUtility : : CreateBackupFile ( csr ) ;
2015-02-07 20:44:25 +01:00
2014-10-30 16:19:51 +01:00
if ( PkiUtility : : NewCert ( cn , key , csr , " " ) > 0 ) {
2014-11-02 17:45:51 +01:00
Log ( LogCritical , " cli " , " Failed to create certificate signing request. " ) ;
2014-10-30 16:19:51 +01:00
return 1 ;
}
/* Sign the CSR with the CA key */
String cert = pki_path + " / " + cn + " .crt " ;
2014-11-02 17:45:51 +01:00
Log ( LogInformation , " cli " )
< < " Signing CSR with CA and writing certificate to ' " < < cert < < " '. " ;
2015-02-07 20:44:25 +01:00
if ( Utility : : PathExists ( cert ) )
2015-02-09 14:04:00 +01:00
NodeUtility : : CreateBackupFile ( cert ) ;
2015-02-07 20:44:25 +01:00
2014-10-30 16:19:51 +01:00
if ( PkiUtility : : SignCsr ( csr , cert ) ! = 0 ) {
Log ( LogCritical , " cli " , " Could not sign CSR. " ) ;
return 1 ;
}
/* Copy CA certificate to /etc/icinga2/pki */
2014-10-30 20:34:33 +01:00
String ca_path = PkiUtility : : GetLocalCaPath ( ) ;
String ca = ca_path + " /ca.crt " ;
String ca_key = ca_path + " /ca.key " ;
2014-11-02 19:38:35 +01:00
String serial = ca_path + " /serial.txt " ;
2014-10-30 16:19:51 +01:00
String target_ca = pki_path + " /ca.crt " ;
Log ( LogInformation , " cli " )
< < " Copying CA certificate to ' " < < target_ca < < " '. " ;
2015-02-07 20:44:25 +01:00
if ( Utility : : PathExists ( target_ca ) )
NodeUtility : : CreateBackupFile ( target_ca ) ;
2014-10-30 16:19:51 +01:00
/* does not overwrite existing files! */
Utility : : CopyFile ( ca , target_ca ) ;
2014-10-30 20:34:33 +01:00
/* fix permissions: root -> icinga daemon user */
2015-02-07 20:44:25 +01:00
std : : vector < String > files ;
files . push_back ( ca_path ) ;
files . push_back ( ca ) ;
files . push_back ( ca_key ) ;
files . push_back ( serial ) ;
files . push_back ( target_ca ) ;
files . push_back ( key ) ;
files . push_back ( csr ) ;
files . push_back ( cert ) ;
BOOST_FOREACH ( const String & file , files ) {
if ( ! Utility : : SetFileOwnership ( file , user , group ) ) {
Log ( LogWarning , " cli " )
< < " Cannot set ownership for user ' " < < user < < " ' group ' " < < group < < " ' on file ' " < < file < < " '. Verify it yourself! " ;
}
2014-10-30 20:34:33 +01:00
}
2014-10-30 16:19:51 +01:00
2014-10-31 11:38:16 +01:00
NodeUtility : : GenerateNodeMasterIcingaConfig ( cn ) ;
2014-10-30 16:19:51 +01:00
/* apilistener config */
2014-11-02 20:17:57 +01:00
std : : cout < < ConsoleColorTag ( Console_Bold ) < < " Please specify the API bind host/port (optional): \n " ;
std : : cout < < ConsoleColorTag ( Console_Bold ) < < " Bind Host " < < ConsoleColorTag ( Console_Normal ) < < " []: " ;
2014-10-30 16:19:51 +01:00
std : : getline ( std : : cin , answer ) ;
boost : : algorithm : : to_lower ( answer ) ;
String bind_host = answer ;
bind_host . Trim ( ) ;
2014-11-02 20:17:57 +01:00
std : : cout < < ConsoleColorTag ( Console_Bold ) < < " Bind Port " < < ConsoleColorTag ( Console_Normal ) < < " []: " ;
2014-10-30 16:19:51 +01:00
std : : getline ( std : : cin , answer ) ;
boost : : algorithm : : to_lower ( answer ) ;
String bind_port = answer ;
bind_port . Trim ( ) ;
2014-11-02 17:45:51 +01:00
Log ( LogInformation , " cli " , " Enabling the APIlistener feature. " ) ;
2014-10-30 16:19:51 +01:00
std : : vector < std : : string > enable ;
enable . push_back ( " api " ) ;
FeatureUtility : : EnableFeatures ( enable ) ;
String apipath = FeatureUtility : : GetFeaturesAvailablePath ( ) + " /api.conf " ;
2014-10-31 11:38:16 +01:00
NodeUtility : : CreateBackupFile ( apipath ) ;
2014-10-30 16:19:51 +01:00
String apipathtmp = apipath + " .tmp " ;
std : : ofstream fp ;
fp . open ( apipathtmp . CStr ( ) , std : : ofstream : : out | std : : ofstream : : trunc ) ;
fp < < " /** \n "
< < " * The API listener is used for distributed monitoring setups. \n "
< < " */ \n "
< < " object ApiListener \" api \" { \n "
< < " cert_path = SysconfDir + \" /icinga2/pki/ \" + NodeName + \" .crt \" \n "
< < " key_path = SysconfDir + \" /icinga2/pki/ \" + NodeName + \" .key \" \n "
< < " ca_path = SysconfDir + \" /icinga2/pki/ca.crt \" \n " ;
if ( ! bind_host . IsEmpty ( ) )
fp < < " bind_host = \" " < < bind_host < < " \" \n " ;
if ( ! bind_port . IsEmpty ( ) )
fp < < " bind_port = " < < bind_port < < " \n " ;
fp < < " \n "
< < " ticket_salt = TicketSalt \n "
< < " } \n " ;
fp . close ( ) ;
# ifdef _WIN32
_unlink ( apipath . CStr ( ) ) ;
# endif /* _WIN32 */
if ( rename ( apipathtmp . CStr ( ) , apipath . CStr ( ) ) < 0 ) {
BOOST_THROW_EXCEPTION ( posix_error ( )
< < boost : : errinfo_api_function ( " rename " )
< < boost : : errinfo_errno ( errno )
< < boost : : errinfo_file_name ( apipathtmp ) ) ;
}
/* update constants.conf with NodeName = CN + TicketSalt = random value */
if ( cn ! = Utility : : GetFQDN ( ) ) {
Log ( LogWarning , " cli " )
< < " CN ' " < < cn < < " ' does not match the default FQDN ' " < < Utility : : GetFQDN ( ) < < " '. Requires update for NodeName constant in constants.conf! " ;
}
Log ( LogInformation , " cli " , " Updating constants.conf. " ) ;
2014-11-02 17:45:51 +01:00
String constants_file = Application : : GetSysconfDir ( ) + " /icinga2/constants.conf " ;
NodeUtility : : CreateBackupFile ( constants_file ) ;
2014-10-30 16:19:51 +01:00
2014-10-31 11:38:16 +01:00
NodeUtility : : UpdateConstant ( " NodeName " , cn ) ;
2014-10-30 16:19:51 +01:00
String salt = RandomString ( 16 ) ;
2014-10-31 11:38:16 +01:00
NodeUtility : : UpdateConstant ( " TicketSalt " , salt ) ;
2014-10-30 16:19:51 +01:00
}
2014-11-02 17:45:51 +01:00
std : : cout < < " Done. \n \n " ;
std : : cout < < " Now restart your Icinga 2 daemon to finish the installation! \n \n " ;
2014-10-30 16:19:51 +01:00
2014-10-17 15:13:17 +02:00
return 0 ;
}