2019-02-25 14:48:22 +01:00
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
2014-10-17 15:13:17 +02:00
2014-10-31 11:38:16 +01:00
# include "cli/nodesetupcommand.hpp"
# include "cli/nodeutility.hpp"
2014-10-21 18:24:35 +02:00
# include "cli/featureutility.hpp"
2015-06-25 11:00:25 +02:00
# include "cli/apisetuputility.hpp"
2017-09-05 14:21:30 +02:00
# include "remote/apilistener.hpp"
2017-09-05 14:44:56 +02:00
# include "remote/pkiutility.hpp"
2014-10-19 14:21:12 +02:00
# include "base/logger.hpp"
2014-10-21 18:24:35 +02:00
# include "base/console.hpp"
2014-10-17 15:13:17 +02:00
# include "base/application.hpp"
2014-10-23 15:05:12 +02: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/algorithm/string/join.hpp>
# include <boost/algorithm/string/replace.hpp>
2014-10-21 21:33:21 +02:00
2014-10-18 21:06:28 +02:00
# include <iostream>
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/setup " , NodeSetupCommand ) ;
2014-10-17 15:13:17 +02:00
2018-01-04 04:25:35 +01:00
String NodeSetupCommand : : GetDescription ( ) const
2014-10-17 15:13:17 +02:00
{
2014-10-31 11:53:44 +01:00
return " Sets up an Icinga 2 node. " ;
2014-10-17 15:13:17 +02:00
}
2018-01-04 04:25:35 +01:00
String NodeSetupCommand : : GetShortDescription ( ) const
2014-10-17 15:13:17 +02:00
{
2014-10-31 11:53:44 +01:00
return " set up node " ;
2014-10-17 15:13:17 +02:00
}
2014-10-31 11:38:16 +01:00
void NodeSetupCommand : : InitParameters ( boost : : program_options : : options_description & visibleDesc ,
2017-12-19 15:50:05 +01:00
boost : : program_options : : options_description & hiddenDesc ) const
2014-10-17 15:13:17 +02:00
{
visibleDesc . add_options ( )
2014-10-18 21:06:28 +02:00
( " zone " , po : : value < std : : string > ( ) , " The name of the local zone " )
2014-10-23 04:38:54 +02:00
( " endpoint " , po : : value < std : : vector < std : : string > > ( ) , " Connect to remote endpoint; syntax: cn[,host,port] " )
2018-04-06 19:18:19 +02:00
( " parent_host " , po : : value < std : : string > ( ) , " The name of the parent host for auto-signing the csr; syntax: host[,port] " )
( " parent_zone " , po : : value < std : : string > ( ) , " The name of the parent zone " )
2014-10-18 21:06:28 +02:00
( " listen " , po : : value < std : : string > ( ) , " Listen on host,port " )
2017-10-16 18:38:18 +02:00
( " ticket " , po : : value < std : : string > ( ) , " Generated ticket number for this request (optional) " )
2020-02-13 16:09:16 +01:00
( " trustedcert " , po : : value < std : : string > ( ) , " Trusted parent certificate file as connection verification (received via 'pki save-cert') " )
2014-10-18 21:06:28 +02:00
( " cn " , po : : value < std : : string > ( ) , " The certificate's common name " )
2020-02-13 16:09:16 +01:00
( " accept-config " , " Accept config from parent node " )
( " accept-commands " , " Accept commands from parent node " )
2017-11-15 18:42:29 +01:00
( " master " , " Use setup for a master instance " )
2018-05-08 16:06:10 +02:00
( " global_zones " , po : : value < std : : vector < std : : string > > ( ) , " The names of the additional global zones to 'global-templates' and 'director-global'. " )
2018-05-02 17:42:30 +02:00
( " disable-confd " , " Disables the conf.d directory during the setup " ) ;
2015-11-25 18:58:52 +01:00
hiddenDesc . add_options ( )
2018-04-06 19:18:19 +02:00
( " master_zone " , po : : value < std : : string > ( ) , " DEPRECATED: The name of the master zone " )
( " master_host " , po : : value < std : : string > ( ) , " DEPRECATED: The name of the master host for auto-signing the csr; syntax: host[,port] " ) ;
2014-10-17 15:13:17 +02:00
}
2014-10-31 11:38:16 +01:00
std : : vector < String > NodeSetupCommand : : GetArgumentSuggestions ( const String & argument , const String & word ) const
2014-10-21 18:24:35 +02:00
{
2014-10-22 15:36:39 +02:00
if ( argument = = " key " | | argument = = " cert " | | argument = = " trustedcert " )
2014-10-21 18:24:35 +02:00
return GetBashCompletionSuggestions ( " file " , word ) ;
else if ( argument = = " host " )
return GetBashCompletionSuggestions ( " hostname " , word ) ;
else if ( argument = = " port " )
return GetBashCompletionSuggestions ( " service " , word ) ;
else
return CLICommand : : GetArgumentSuggestions ( argument , word ) ;
}
2018-01-04 04:25:35 +01:00
ImpersonationLevel NodeSetupCommand : : GetImpersonationLevel ( ) const
2014-10-24 15:29:46 +02:00
{
2019-01-04 15:29:25 +01:00
return ImpersonateIcinga ;
2014-10-24 15:29:46 +02:00
}
2014-10-17 15:13:17 +02:00
/**
2014-10-31 11:53:44 +01:00
* The entry point for the " node setup " CLI command .
2014-10-17 15:13:17 +02:00
*
* @ returns An exit status .
*/
2014-10-31 11:38:16 +01:00
int NodeSetupCommand : : Run ( const boost : : program_options : : variables_map & vm , const std : : vector < std : : string > & ap ) const
2014-10-17 15:13:17 +02:00
{
if ( ! ap . empty ( ) ) {
2014-10-19 17:52:17 +02:00
Log ( LogWarning , " cli " )
2017-12-19 15:50:05 +01:00
< < " Ignoring parameters: " < < boost : : algorithm : : join ( ap , " " ) ;
2014-10-17 15:13:17 +02:00
}
2014-10-23 04:23:22 +02:00
if ( vm . count ( " master " ) )
2014-10-21 18:24:35 +02:00
return SetupMaster ( vm , ap ) ;
2014-10-23 04:23:22 +02:00
else
2014-10-31 11:38:16 +01:00
return SetupNode ( vm , ap ) ;
2014-10-17 15:13:17 +02:00
}
2014-10-18 21:06:28 +02:00
2014-10-31 11:38:16 +01:00
int NodeSetupCommand : : SetupMaster ( const boost : : program_options : : variables_map & vm , const std : : vector < std : : string > & ap )
2014-10-18 21:06:28 +02:00
{
2014-10-23 03:35:01 +02:00
/* Ignore not required parameters */
2014-10-22 19:27:21 +02:00
if ( vm . count ( " ticket " ) )
2014-10-31 11:38:16 +01:00
Log ( LogWarning , " cli " , " Master for Node setup: Ignoring --ticket " ) ;
2014-10-23 03:35:01 +02:00
2014-10-22 19:27:21 +02:00
if ( vm . count ( " endpoint " ) )
2014-10-31 11:38:16 +01:00
Log ( LogWarning , " cli " , " Master for Node setup: Ignoring --endpoint " ) ;
2014-10-23 03:35:01 +02:00
2014-10-22 19:27:21 +02:00
if ( vm . count ( " trustedcert " ) )
2014-10-31 11:38:16 +01:00
Log ( LogWarning , " cli " , " Master for Node setup: Ignoring --trustedcert " ) ;
2014-10-22 19:27:21 +02:00
2017-12-19 15:50:05 +01:00
String cn = Utility : : GetFQDN ( ) ;
2014-10-21 21:33:21 +02:00
2017-12-19 15:50:05 +01:00
if ( vm . count ( " cn " ) )
cn = vm [ " cn " ] . as < std : : string > ( ) ;
2014-10-21 18:24:35 +02:00
2018-04-06 17:29:37 +02:00
/* Setup command hardcodes this as FQDN */
String endpointName = cn ;
/* Allow to specify zone name. */
String zoneName = " master " ;
if ( vm . count ( " zone " ) )
zoneName = vm [ " zone " ] . as < std : : string > ( ) ;
2015-07-08 15:32:47 +02:00
/* check whether the user wants to generate a new certificate or not */
2017-09-06 17:33:54 +02:00
String existingPath = ApiListener : : GetCertsDir ( ) + " / " + cn + " .crt " ;
2015-07-08 15:32:47 +02:00
Log ( LogInformation , " cli " )
2017-12-19 15:50:05 +01:00
< < " Checking in existing certificates for common name ' " < < cn < < " '... " ;
2015-07-08 15:32:47 +02:00
2017-09-06 17:33:54 +02:00
if ( Utility : : PathExists ( existingPath ) ) {
2015-07-08 15:32:47 +02:00
Log ( LogWarning , " cli " )
2017-12-19 15:50:05 +01:00
< < " Certificate ' " < < existingPath < < " ' for CN ' " < < cn < < " ' already exists. Not generating new certificate. " ;
2015-07-08 15:32:47 +02:00
} else {
Log ( LogInformation , " cli " )
2017-12-19 15:50:05 +01:00
< < " Certificates not yet generated. Running 'api setup' now. " ;
2015-07-08 15:32:47 +02:00
ApiSetupUtility : : SetupMasterCertificates ( cn ) ;
}
Log ( LogInformation , " cli " , " Generating master configuration for Icinga 2. " ) ;
2015-10-22 15:56:27 +02:00
ApiSetupUtility : : SetupMasterApiUser ( ) ;
2015-07-08 15:32:47 +02:00
if ( ! FeatureUtility : : CheckFeatureEnabled ( " api " ) ) {
2015-10-22 15:56:27 +02:00
ApiSetupUtility : : SetupMasterEnableApi ( ) ;
2015-07-08 15:32:47 +02:00
} else {
Log ( LogInformation , " cli " )
2017-12-19 15:50:05 +01:00
< < " 'api' feature already enabled. \n " ;
2015-07-08 15:32:47 +02:00
}
2015-11-25 17:41:03 +01:00
/* write zones.conf and update with zone + endpoint information */
2014-10-22 08:06:06 +02:00
Log ( LogInformation , " cli " , " Generating zone and object configuration. " ) ;
2014-10-21 18:24:35 +02:00
2018-03-12 20:23:21 +01:00
std : : vector < String > globalZones { " global-templates " , " director-global " } ;
2018-02-26 08:34:45 +01:00
std : : vector < std : : string > setupGlobalZones ;
2017-11-15 18:42:29 +01:00
if ( vm . count ( " global_zones " ) )
2018-02-26 08:34:45 +01:00
setupGlobalZones = vm [ " global_zones " ] . as < std : : vector < std : : string > > ( ) ;
2017-11-15 18:42:29 +01:00
2019-03-08 14:07:29 +01:00
for ( decltype ( setupGlobalZones . size ( ) ) i = 0 ; i < setupGlobalZones . size ( ) ; i + + ) {
2017-11-15 18:42:29 +01:00
if ( std : : find ( globalZones . begin ( ) , globalZones . end ( ) , setupGlobalZones [ i ] ) ! = globalZones . end ( ) ) {
Log ( LogCritical , " cli " )
< < " The global zone ' " < < setupGlobalZones [ i ] < < " ' is already specified. " ;
return 1 ;
}
}
globalZones . insert ( globalZones . end ( ) , setupGlobalZones . begin ( ) , setupGlobalZones . end ( ) ) ;
2018-04-06 17:29:37 +02:00
/* Generate master configuration. */
NodeUtility : : GenerateNodeMasterIcingaConfig ( endpointName , zoneName , globalZones ) ;
2014-10-21 16:04:20 +02:00
2018-04-06 17:29:37 +02:00
/* Update the ApiListener config. */
2014-10-28 21:13:15 +01:00
Log ( LogInformation , " cli " , " Updating the APIListener feature. " ) ;
2014-10-21 16:04:20 +02:00
2014-10-28 21:13:15 +01:00
String apipath = FeatureUtility : : GetFeaturesAvailablePath ( ) + " /api.conf " ;
2014-10-31 11:38:16 +01:00
NodeUtility : : CreateBackupFile ( apipath ) ;
2014-10-28 21:13:15 +01:00
2016-02-22 16:47:41 +01:00
std : : fstream fp ;
2016-02-24 13:55:25 +01:00
String tempApiPath = Utility : : CreateTempFile ( apipath + " .XXXXXX " , 0644 , fp ) ;
2014-10-28 21:13:15 +01:00
fp < < " /** \n "
2017-12-19 15:50:05 +01:00
< < " * The API listener is used for distributed monitoring setups. \n "
< < " */ \n "
< < " object ApiListener \" api \" { \n " ;
2014-10-28 21:13:15 +01:00
if ( vm . count ( " listen " ) ) {
2018-01-04 18:24:45 +01:00
std : : vector < String > tokens = String ( vm [ " listen " ] . as < std : : string > ( ) ) . Split ( " , " ) ;
2014-10-28 21:13:15 +01:00
if ( tokens . size ( ) > 0 )
fp < < " bind_host = \" " < < tokens [ 0 ] < < " \" \n " ;
if ( tokens . size ( ) > 1 )
fp < < " bind_port = " < < tokens [ 1 ] < < " \n " ;
}
2018-10-01 16:24:37 +02:00
fp < < " \n " ;
if ( vm . count ( " accept-config " ) )
fp < < " accept_config = true \n " ;
else
fp < < " accept_config = false \n " ;
if ( vm . count ( " accept-commands " ) )
fp < < " accept_commands = true \n " ;
else
fp < < " accept_commands = false \n " ;
2014-10-28 21:13:15 +01:00
fp < < " \n "
2017-12-19 15:50:05 +01:00
< < " ticket_salt = TicketSalt \n "
< < " } \n " ;
2014-10-28 21:13:15 +01:00
fp . close ( ) ;
2019-04-10 13:44:13 +02:00
Utility : : RenameFile ( tempApiPath , apipath ) ;
2014-10-22 19:27:21 +02:00
2014-10-23 03:35:01 +02:00
/* update constants.conf with NodeName = CN + TicketSalt = random value */
2019-05-06 10:19:56 +02:00
if ( endpointName ! = Utility : : GetFQDN ( ) ) {
2014-10-23 03:35:01 +02:00
Log ( LogWarning , " cli " )
2019-05-06 10:19:56 +02:00
< < " CN/Endpoint name ' " < < endpointName < < " ' does not match the default FQDN ' " < < Utility : : GetFQDN ( ) < < " '. Requires update for NodeName constant in constants.conf! " ;
2014-10-23 03:35:01 +02:00
}
2019-05-06 10:19:56 +02:00
NodeUtility : : UpdateConstant ( " NodeName " , endpointName ) ;
NodeUtility : : UpdateConstant ( " ZoneName " , zoneName ) ;
2014-10-23 15:05:12 +02:00
String salt = RandomString ( 16 ) ;
2014-10-31 11:38:16 +01:00
NodeUtility : : UpdateConstant ( " TicketSalt " , salt ) ;
2014-10-21 16:04:20 +02:00
2014-10-21 18:24:35 +02:00
Log ( LogInformation , " cli " )
2017-12-19 15:50:05 +01:00
< < " Edit the api feature config file ' " < < apipath < < " ' and set a secure 'ticket_salt' attribute. " ;
2014-10-21 18:24:35 +02:00
2018-05-02 17:42:30 +02:00
if ( vm . count ( " disable-confd " ) ) {
2018-04-18 20:22:04 +02:00
/* Disable conf.d inclusion */
2018-05-08 16:06:10 +02:00
if ( NodeUtility : : UpdateConfiguration ( " \" conf.d \" " , false , true ) ) {
2018-05-04 11:38:30 +02:00
Log ( LogInformation , " cli " )
< < " Disabled conf.d inclusion " ;
2018-05-08 16:06:10 +02:00
} else {
2018-05-04 11:38:30 +02:00
Log ( LogWarning , " cli " )
< < " Tried to disable conf.d inclusion but failed, possibly it's already disabled. " ;
2018-05-08 16:06:10 +02:00
}
2014-10-21 21:33:21 +02:00
2018-04-18 20:22:04 +02:00
/* Include api-users.conf */
2018-05-08 16:06:10 +02:00
String apiUsersFilePath = ApiSetupUtility : : GetApiUsersConfPath ( ) ;
if ( Utility : : PathExists ( apiUsersFilePath ) ) {
2018-04-18 20:22:04 +02:00
NodeUtility : : UpdateConfiguration ( " \" conf.d/api-users.conf \" " , true , false ) ;
2018-05-08 16:06:10 +02:00
} else {
2018-04-18 20:22:04 +02:00
Log ( LogWarning , " cli " )
2018-07-21 10:38:09 +02:00
< < " Included file doesn't exist " < < apiUsersFilePath ;
2018-05-08 16:06:10 +02:00
}
2018-04-18 20:22:04 +02:00
}
/* tell the user to reload icinga2 */
2014-10-22 08:06:06 +02:00
Log ( LogInformation , " cli " , " Make sure to restart Icinga 2. " ) ;
2014-10-21 18:24:35 +02:00
return 0 ;
2014-10-18 21:06:28 +02:00
}
2014-10-31 11:38:16 +01:00
int NodeSetupCommand : : SetupNode ( const boost : : program_options : : variables_map & vm , const std : : vector < std : : string > & ap )
2014-10-18 21:06:28 +02:00
{
2017-10-16 18:38:18 +02:00
/* require at least one endpoint. Ticket is optional. */
2014-10-23 04:23:22 +02:00
if ( ! vm . count ( " endpoint " ) ) {
Log ( LogCritical , " cli " , " You need to specify at least one endpoint (--endpoint). " ) ;
return 1 ;
}
2014-10-21 18:24:35 +02:00
2014-10-31 22:21:36 +01:00
if ( ! vm . count ( " zone " ) ) {
Log ( LogCritical , " cli " , " You need to specify the local zone (--zone). " ) ;
return 1 ;
}
2018-04-06 19:18:19 +02:00
/* Deprecation warnings. TODO: Remove in 2.10.0. */
if ( vm . count ( " master_zone " ) )
Log ( LogWarning , " cli " , " The 'master_zone' parameter has been deprecated. Use 'parent_zone' instead. " ) ;
if ( vm . count ( " master_host " ) )
Log ( LogWarning , " cli " , " The 'master_host' parameter has been deprecated. Use 'parent_host' instead. " ) ;
2017-10-16 18:38:18 +02:00
String ticket ;
2014-10-21 18:24:35 +02:00
2017-10-16 18:38:18 +02:00
if ( vm . count ( " ticket " ) )
ticket = vm [ " ticket " ] . as < std : : string > ( ) ;
if ( ticket . IsEmpty ( ) ) {
Log ( LogInformation , " cli " )
2017-12-19 15:50:05 +01:00
< < " Requesting certificate without a ticket. " ;
2017-10-16 18:38:18 +02:00
} else {
Log ( LogInformation , " cli " )
2017-12-19 15:50:05 +01:00
< < " Requesting certificate with ticket ' " < < ticket < < " '. " ;
2017-10-16 18:38:18 +02:00
}
2014-10-21 16:04:20 +02:00
2018-04-06 19:49:01 +02:00
/* Decide whether to directly connect to the parent node for CSR signing, or leave it to the user. */
bool connectToParent = false ;
String parentHost ;
String parentPort = " 5665 " ;
std : : shared_ptr < X509 > trustedParentCert ;
2014-10-21 21:33:21 +02:00
2018-04-06 19:49:01 +02:00
/* TODO: remove master_host in 2.10.0. */
if ( ! vm . count ( " master_host " ) & & ! vm . count ( " parent_host " ) ) {
connectToParent = false ;
2014-10-21 21:33:21 +02:00
2018-04-06 19:49:01 +02:00
Log ( LogWarning , " cli " )
< < " Node to master/satellite connection setup skipped. Please configure your parent node to \n "
< < " connect to this node by setting the 'host' attribute for the node Endpoint object. \n " ;
} else {
connectToParent = true ;
2018-04-06 19:18:19 +02:00
2018-04-06 19:49:01 +02:00
String parentHostInfo ;
2018-04-06 19:18:19 +02:00
2018-04-06 19:49:01 +02:00
if ( vm . count ( " parent_host " ) )
parentHostInfo = vm [ " parent_host " ] . as < std : : string > ( ) ;
else if ( vm . count ( " master_host " ) ) /* TODO: Remove in 2.10.0. */
parentHostInfo = vm [ " master_host " ] . as < std : : string > ( ) ;
2014-10-21 21:33:21 +02:00
2018-04-06 19:49:01 +02:00
std : : vector < String > tokens = parentHostInfo . Split ( " , " ) ;
2014-10-21 21:33:21 +02:00
2018-04-06 19:49:01 +02:00
if ( tokens . size ( ) = = 1 | | tokens . size ( ) = = 2 )
parentHost = tokens [ 0 ] ;
2014-10-21 21:33:21 +02:00
2018-04-06 19:49:01 +02:00
if ( tokens . size ( ) = = 2 )
parentPort = tokens [ 1 ] ;
2014-10-21 21:33:21 +02:00
2018-04-06 19:49:01 +02:00
Log ( LogInformation , " cli " )
< < " Verifying parent host connection information: host ' " < < parentHost < < " ', port ' " < < parentPort < < " '. " ;
2014-10-21 21:33:21 +02:00
2014-10-21 18:24:35 +02:00
}
2014-10-23 03:35:01 +02:00
/* retrieve CN and pass it (defaults to FQDN) */
2014-10-21 18:24:35 +02:00
String cn = Utility : : GetFQDN ( ) ;
if ( vm . count ( " cn " ) )
cn = vm [ " cn " ] . as < std : : string > ( ) ;
2014-10-21 16:04:20 +02:00
2014-10-21 18:24:35 +02:00
Log ( LogInformation , " cli " )
2017-12-19 15:50:05 +01:00
< < " Using the following CN (defaults to FQDN): ' " < < cn < < " '. " ;
2014-10-21 18:24:35 +02:00
2014-10-23 03:35:01 +02:00
/* pki request a signed certificate from the master */
2018-04-06 19:18:19 +02:00
String certsDir = ApiListener : : GetCertsDir ( ) ;
Utility : : MkDirP ( certsDir , 0700 ) ;
2014-10-30 20:34:33 +01:00
2018-08-09 15:37:23 +02:00
String user = Configuration : : RunAsUser ;
String group = Configuration : : RunAsGroup ;
2014-10-30 20:34:33 +01:00
2018-04-06 19:18:19 +02:00
if ( ! Utility : : SetFileOwnership ( certsDir , user , group ) ) {
2014-10-30 20:34:33 +01:00
Log ( LogWarning , " cli " )
2018-04-06 19:18:19 +02:00
< < " Cannot set ownership for user ' " < < user < < " ' group ' " < < group < < " ' on file ' " < < certsDir < < " '. Verify it yourself! " ;
2014-10-30 20:34:33 +01:00
}
2018-04-06 19:18:19 +02:00
String key = certsDir + " / " + cn + " .key " ;
String cert = certsDir + " / " + cn + " .crt " ;
String ca = certsDir + " /ca.crt " ;
2015-08-24 15:11:49 +02:00
2015-02-09 14:19:26 +01:00
if ( Utility : : PathExists ( key ) )
NodeUtility : : CreateBackupFile ( key , true ) ;
if ( Utility : : PathExists ( cert ) )
NodeUtility : : CreateBackupFile ( cert ) ;
2014-10-22 21:49:41 +02:00
if ( PkiUtility : : NewCert ( cn , key , String ( ) , cert ) ! = 0 ) {
Log ( LogCritical , " cli " , " Failed to generate new self-signed certificate. " ) ;
2014-10-22 15:29:54 +02:00
return 1 ;
}
2014-10-21 18:24:35 +02:00
2014-10-30 20:34:33 +01:00
/* fix permissions: root -> icinga daemon user */
2016-02-23 08:41:48 +01:00
if ( ! Utility : : SetFileOwnership ( key , user , group ) ) {
Log ( LogWarning , " cli " )
2017-12-19 15:50:05 +01:00
< < " Cannot set ownership for user ' " < < user < < " ' group ' " < < group < < " ' on file ' " < < key < < " '. Verify it yourself! " ;
2014-10-30 20:34:33 +01:00
}
2018-04-06 19:49:01 +02:00
/* Send a signing request to the parent immediately, or leave it to the user. */
if ( connectToParent ) {
/* In contrast to `node wizard` the user must manually fetch
* the trustedParentCert to prove the trust relationship ( fetched with ' pki save - cert ' ) .
*/
if ( ! vm . count ( " trustedcert " ) ) {
Log ( LogCritical , " cli " )
< < " Please pass the trusted cert retrieved from the parent node (master or satellite) \n "
2020-02-13 16:09:16 +01:00
< < " (Hint: 'icinga2 pki save-cert --host <parenthost> --port <5665> --key local.key --cert local.crt --trustedcert trusted-parent.crt'). " ;
2018-04-06 19:49:01 +02:00
return 1 ;
}
2014-10-21 18:24:35 +02:00
2020-02-13 19:40:32 +01:00
String trustedCert = vm [ " trustedcert " ] . as < std : : string > ( ) ;
try {
2020-02-14 07:56:23 +01:00
trustedParentCert = GetX509Certificate ( trustedCert ) ;
2020-02-13 19:40:32 +01:00
} catch ( const std : : exception & ) {
Log ( LogCritical , " cli " )
< < " Can't read trusted cert at ' " < < trustedCert < < " '. " ;
return 1 ;
}
2018-04-06 19:49:01 +02:00
2020-02-13 16:09:16 +01:00
try {
if ( IsCa ( trustedParentCert ) ) {
Log ( LogCritical , " cli " )
< < " The trusted parent certificate is NOT a client certificate. It seems you passed the 'ca.crt' CA certificate via '--trustedcert' parameter. " ;
return 1 ;
}
} catch ( const std : : exception & ) {
/* Swallow the error and do not run the check on unsupported OpenSSL platforms. */
}
2018-04-06 19:49:01 +02:00
Log ( LogInformation , " cli " )
< < " Verifying trusted certificate file ' " < < vm [ " trustedcert " ] . as < std : : string > ( ) < < " '. " ;
Log ( LogInformation , " cli " , " Requesting a signed certificate from the parent Icinga node. " ) ;
if ( PkiUtility : : RequestCertificate ( parentHost , parentPort , key , cert , ca , trustedParentCert , ticket ) > 0 ) {
Log ( LogCritical , " cli " )
< < " Failed to fetch signed certificate from parent Icinga node ' "
< < parentHost < < " , "
< < parentPort < < " '. Please try again. " ;
return 1 ;
}
} else {
/* We cannot retrieve the parent certificate.
* Tell the user to manually copy the ca . crt file
2018-07-31 11:59:09 +02:00
* into DataDir + " /certs "
2018-04-06 19:49:01 +02:00
*/
Log ( LogWarning , " cli " )
< < " \n No connection to the parent node was specified. \n \n "
< < " Please copy the public CA certificate from your master/satellite \n "
< < " into ' " < < ca < < " ' before starting Icinga 2. \n " ;
if ( Utility : : PathExists ( ca ) ) {
Log ( LogInformation , " cli " )
< < " \n Found public CA certificate in ' " < < ca < < " '. \n "
< < " Please verify that it is the same as on your master/satellite. \n " ;
}
2014-10-22 21:49:41 +02:00
}
2014-10-21 21:33:21 +02:00
2016-02-23 08:41:48 +01:00
if ( ! Utility : : SetFileOwnership ( ca , user , group ) ) {
Log ( LogWarning , " cli " )
2017-12-19 15:50:05 +01:00
< < " Cannot set ownership for user ' " < < user < < " ' group ' " < < group < < " ' on file ' " < < ca < < " '. Verify it yourself! " ;
2016-02-23 08:41:48 +01:00
}
2014-10-30 20:34:33 +01:00
/* fix permissions (again) when updating the signed certificate */
if ( ! Utility : : SetFileOwnership ( cert , user , group ) ) {
Log ( LogWarning , " cli " )
2017-12-19 15:50:05 +01:00
< < " Cannot set ownership for user ' " < < user < < " ' group ' " < < group < < " ' on file ' " < < cert < < " '. Verify it yourself! " ;
2014-10-30 20:34:33 +01:00
}
2014-11-02 20:17:57 +01:00
/* disable the notifications feature */
Log ( LogInformation , " cli " , " Disabling the Notification feature. " ) ;
2017-11-23 09:58:05 +01:00
FeatureUtility : : DisableFeatures ( { " notification " } ) ;
2014-11-02 20:17:57 +01:00
2014-10-28 21:13:15 +01:00
/* enable the ApiListener config */
2014-10-21 16:04:20 +02:00
2014-11-02 20:17:57 +01:00
Log ( LogInformation , " cli " , " Updating the ApiListener feature. " ) ;
2014-10-21 18:24:35 +02:00
2017-11-23 09:58:05 +01:00
FeatureUtility : : EnableFeatures ( { " api " } ) ;
2014-10-21 21:33:21 +02:00
2014-10-28 21:13:15 +01:00
String apipath = FeatureUtility : : GetFeaturesAvailablePath ( ) + " /api.conf " ;
2014-10-31 11:38:16 +01:00
NodeUtility : : CreateBackupFile ( apipath ) ;
2014-10-28 21:13:15 +01:00
2016-02-22 16:47:41 +01:00
std : : fstream fp ;
2016-02-24 13:55:25 +01:00
String tempApiPath = Utility : : CreateTempFile ( apipath + " .XXXXXX " , 0644 , fp ) ;
2014-10-28 21:13:15 +01:00
fp < < " /** \n "
2017-12-19 15:50:05 +01:00
< < " * The API listener is used for distributed monitoring setups. \n "
< < " */ \n "
< < " object ApiListener \" api \" { \n " ;
2014-10-28 21:13:15 +01:00
if ( vm . count ( " listen " ) ) {
2018-01-04 18:24:45 +01:00
std : : vector < String > tokens = String ( vm [ " listen " ] . as < std : : string > ( ) ) . Split ( " , " ) ;
2014-10-28 21:13:15 +01:00
if ( tokens . size ( ) > 0 )
fp < < " bind_host = \" " < < tokens [ 0 ] < < " \" \n " ;
if ( tokens . size ( ) > 1 )
fp < < " bind_port = " < < tokens [ 1 ] < < " \n " ;
}
2015-06-18 19:13:10 +02:00
fp < < " \n " ;
2015-03-27 14:11:21 +01:00
if ( vm . count ( " accept-config " ) )
2015-06-18 19:13:10 +02:00
fp < < " accept_config = true \n " ;
2015-03-27 14:11:21 +01:00
else
2015-06-18 19:13:10 +02:00
fp < < " accept_config = false \n " ;
2015-03-27 14:11:21 +01:00
if ( vm . count ( " accept-commands " ) )
2015-06-18 19:13:10 +02:00
fp < < " accept_commands = true \n " ;
2015-03-27 14:11:21 +01:00
else
2015-06-18 19:13:10 +02:00
fp < < " accept_commands = false \n " ;
2014-10-21 21:33:21 +02:00
2014-10-28 21:13:15 +01:00
fp < < " \n "
2017-12-19 15:50:05 +01:00
< < " } \n " ;
2014-10-21 21:33:21 +02:00
2014-10-28 21:13:15 +01:00
fp . close ( ) ;
2014-10-21 21:33:21 +02:00
2019-04-10 13:44:13 +02:00
Utility : : RenameFile ( tempApiPath , apipath ) ;
2014-10-21 16:04:20 +02:00
2018-04-06 19:18:19 +02:00
/* Generate zones configuration. */
2014-10-22 08:06:06 +02:00
Log ( LogInformation , " cli " , " Generating zone and object configuration. " ) ;
2014-10-21 18:24:35 +02:00
2018-04-06 19:18:19 +02:00
/* Setup command hardcodes this as FQDN */
String endpointName = cn ;
/* Allow to specify zone name. */
String zoneName = vm [ " zone " ] . as < std : : string > ( ) ;
/* Allow to specify the parent zone name. */
String parentZoneName = " master " ;
if ( vm . count ( " parent_zone " ) )
parentZoneName = vm [ " parent_zone " ] . as < std : : string > ( ) ;
2018-03-12 20:23:21 +01:00
std : : vector < String > globalZones { " global-templates " , " director-global " } ;
2018-02-26 08:34:45 +01:00
std : : vector < std : : string > setupGlobalZones ;
2017-11-15 18:42:29 +01:00
if ( vm . count ( " global_zones " ) )
2018-02-26 08:34:45 +01:00
setupGlobalZones = vm [ " global_zones " ] . as < std : : vector < std : : string > > ( ) ;
2017-11-15 18:42:29 +01:00
2019-03-08 14:07:29 +01:00
for ( decltype ( setupGlobalZones . size ( ) ) i = 0 ; i < setupGlobalZones . size ( ) ; i + + ) {
2017-11-15 18:42:29 +01:00
if ( std : : find ( globalZones . begin ( ) , globalZones . end ( ) , setupGlobalZones [ i ] ) ! = globalZones . end ( ) ) {
Log ( LogCritical , " cli " )
< < " The global zone ' " < < setupGlobalZones [ i ] < < " ' is already specified. " ;
return 1 ;
}
}
globalZones . insert ( globalZones . end ( ) , setupGlobalZones . begin ( ) , setupGlobalZones . end ( ) ) ;
2018-04-06 19:18:19 +02:00
/* Generate node configuration. */
NodeUtility : : GenerateNodeIcingaConfig ( endpointName , zoneName , parentZoneName , vm [ " endpoint " ] . as < std : : vector < std : : string > > ( ) , globalZones ) ;
2014-10-21 21:33:21 +02:00
2014-10-23 03:35:01 +02:00
/* update constants.conf with NodeName = CN */
2019-05-06 10:19:56 +02:00
if ( endpointName ! = Utility : : GetFQDN ( ) ) {
2014-10-22 15:29:54 +02:00
Log ( LogWarning , " cli " )
2019-05-06 10:19:56 +02:00
< < " CN/Endpoint name ' " < < endpointName < < " ' does not match the default FQDN ' "
< < Utility : : GetFQDN ( ) < < " '. Requires an update for the NodeName constant in constants.conf! " ;
2014-10-22 15:29:54 +02:00
}
2014-10-21 21:33:21 +02:00
2019-05-06 10:19:56 +02:00
NodeUtility : : UpdateConstant ( " NodeName " , endpointName ) ;
NodeUtility : : UpdateConstant ( " ZoneName " , zoneName ) ;
2014-10-21 21:33:21 +02:00
2017-10-16 18:38:18 +02:00
if ( ! ticket . IsEmpty ( ) ) {
String ticketPath = ApiListener : : GetCertsDir ( ) + " /ticket " ;
2017-08-29 11:57:16 +02:00
2017-10-16 18:38:18 +02:00
String tempTicketPath = Utility : : CreateTempFile ( ticketPath + " .XXXXXX " , 0600 , fp ) ;
2017-08-29 11:57:16 +02:00
2017-10-16 18:38:18 +02:00
if ( ! Utility : : SetFileOwnership ( tempTicketPath , user , group ) ) {
Log ( LogWarning , " cli " )
2017-12-19 15:50:05 +01:00
< < " Cannot set ownership for user ' " < < user
< < " ' group ' " < < group
< < " ' on file ' " < < tempTicketPath < < " '. Verify it yourself! " ;
2017-10-16 18:38:18 +02:00
}
2017-08-29 11:57:16 +02:00
2017-10-16 18:38:18 +02:00
fp < < ticket ;
2017-08-29 11:57:16 +02:00
2017-10-16 18:38:18 +02:00
fp . close ( ) ;
2014-10-21 16:04:20 +02:00
2019-04-10 13:44:13 +02:00
Utility : : RenameFile ( tempTicketPath , ticketPath ) ;
2017-08-29 11:57:16 +02:00
}
2018-04-06 19:49:01 +02:00
/* If no parent connection was made, the user must supply the ca.crt before restarting Icinga 2.*/
if ( ! connectToParent ) {
Log ( LogWarning , " cli " )
< < " No connection to the parent node was specified. \n \n "
< < " Please copy the public CA certificate from your master/satellite \n "
< < " into ' " < < ca < < " ' before starting Icinga 2. \n " ;
} else {
Log ( LogInformation , " cli " , " Make sure to restart Icinga 2. " ) ;
}
2014-10-21 16:04:20 +02:00
2018-05-02 17:42:30 +02:00
if ( vm . count ( " disable-confd " ) ) {
2018-04-18 20:22:04 +02:00
/* Disable conf.d inclusion */
NodeUtility : : UpdateConfiguration ( " \" conf.d \" " , false , true ) ;
}
/* tell the user to reload icinga2 */
Log ( LogInformation , " cli " , " Make sure to restart Icinga 2. " ) ;
2014-10-21 18:24:35 +02:00
return 0 ;
2014-10-18 21:06:28 +02:00
}