API: Implement 'generate-ticket' action and update distributed monitoring docs

fixes #12433
This commit is contained in:
Michael Friedrich 2016-08-15 14:32:41 +02:00
parent 2e8d3d3934
commit d341783a51
4 changed files with 81 additions and 5 deletions

View File

@ -1105,6 +1105,31 @@ Example:
]
}
### <a id="icinga2-api-actions-generate-ticket"></a> generate-ticket
Generates a PKI ticket for [CSR auto-signing](6-distributed-monitoring.md#distributed-monitoring-setup-csr-auto-signing).
This can be used in combination with satellite/client setups requesting this ticket number.
Send a `POST` request to the URL endpoint `/v1/actions/generate-ticket`.
Parameter | Type | Description
--------------|-----------|--------------
cn | string | **Required.** The host's common name for which the ticket should be geenerated.
Example:
$ curl -k -s -u root:icinga -H 'Accept: application/json' -X POST 'https://localhost:5665/v1/actions/generate-ticket' \
-d '{ "cn": "icinga2-client1.localdomain" }' | python -m json.tool
{
"results": [
{
"code": 200.0,
"status": "Generated PKI ticket '4f75d2ecd253575fe9180938ebff7cbca262f96e' for common name 'icinga2-client1.localdomain'.",
"ticket": "4f75d2ecd253575fe9180938ebff7cbca262f96e"
}
]
}
## <a id="icinga2-api-event-streams"></a> Event Streams

View File

@ -215,11 +215,21 @@ existing master node setup. If you haven't done so already please [run the maste
Icinga 2 on the master node must be running and accepting connections on port `5665`.
### <a id="distributed-monitoring-setup-csr-auto-signing"></a> CSR Auto-Signing
The `node wizard` cli command will setup a satellite/client using CSR auto-signing. This
involves that the setup wizard sends a certificate signing request (CSR) to the
master node.
There is a security mechanism in place which requires the client to send in a valid
ticket for CSR auto-signing. This ticket must be generated on the master beforehand.
ticket for CSR auto-signing.
This ticket must be generated beforehand. The `ticket_salt` attribute for the [ApiListener](9-object-types.md#objecttype-apilistener)
must be properly configured in order to make this work.
There are two possible ways to retrieve the ticket:
* [CLI command](11-cli-commands.md#cli-command-pki) executed on the master node
* [REST API](12-icinga2-api.md#icinga2-api) request against the master node
Required information:
@ -231,7 +241,23 @@ Example for the client `icinga2-client1.localdomain` generating a ticket on the
`icinga2-master1.localdomain`:
[root@icinga2-master1.localdomain /]# icinga2 pki ticket --cn icinga2-client1.localdomain
4f75d2ecd253575fe9180938ebff7cbca262f96e
Querying the [Icinga 2 API](12-icinga2-api.md#icinga2-api) on the master requires an [ApiUser](12-icinga2-api.md#icinga2-api-authentication)
object with at least the `actions/generate-ticket`.
[root@icinga2-master1.localdomain /]# vim /etc/icinga2/conf.d/api-users.conf
object ApiUser "client-pki-ticket" {
password = "bea11beb7b810ea9ce6ea" //change this
permissions = [ "actions/generate-ticket" ]
}
[root@icinga2-master1.localdomain /]# systemctl restart icinga2
Retrieve the ticket on the client node `icinga2-client1.localdomain` with curl for example:
[root@icinga2-client1.localdomain /]# curl -k -s -u client-pki-ticket:bea11beb7b810ea9ce6ea -H 'Accept: application/json' \
-X POST 'https://icinga2-master1.localdomain:5665/v1/actions/generate-ticket' -d '{ "cn": "icinga2-client1.localdomain" }'
Store that ticket number for the satellite/client setup below.
@ -251,7 +277,7 @@ Required information:
Add more master endpoints | **Optional.** If you have multiple master nodes configured, add them here.
Master connection for CSR auto-signing | **Required.** The master node's IP address or FQDN and port where the client should request a certificate from. Defaults to the master endpoint host.
Certificate information | **Required.** Verify that the connecting host really is the requested master node.
Request ticket | **Required.** Paste the previously generated ticket number from the master node here.
Request ticket | **Required.** Paste the previously generated [ticket number](6-distributed-monitoring.md#distributed-monitoring-setup-csr-auto-signing).
API bind host | **Optional.** Allows to specify the address where the ApiListener is bound to. For advanced usage only.
API bind port | **Optional.** Allows to specify the port where the ApiListener is bound to. For advanced usage only (requires changing the default port 5665 everywhere).
Accept config | **Optional.** Whether this node accepts configuration sync from the master node (required for [config sync mode](6-distributed-monitoring.md#distributed-monitoring-top-down-config-sync). Defaults to 'n'.
@ -1605,7 +1631,7 @@ Add the disk check using command endpoint checks (details in the
### <a id="distributed-monitoring-windows-nscp"></a> Windows Client and NSClient++
The [Windows setup](#distributed-monitoring-setup-client-windows) already allows
The [Windows setup](6-distributed-monitoring.md#distributed-monitoring-setup-client-windows) already allows
you to install the NSClient++ package. In addition to the Windows plugins you can
also use the [nscp-local commands](10-icinga-template-library.md#nscp-plugin-check-commands)
provided by the Icinga Template Library (ITL).
@ -1805,7 +1831,7 @@ Required information:
* The client common name (CN). Use the FQDN, e.g. `icinga2-node2.localdomain`.
* The master host and zone name. Pass that to `pki save-cert` as `--host` parameter for example.
* Optional: Master endpoint host and port information for the `--endpoint` parameter.
* The client ticket number generated on the master (`icinga2 pki ticket --cn icinga2-node2.localdomain`)
* The client [ticket number](6-distributed-monitoring.md#distributed-monitoring-setup-csr-auto-signing)
Generate a new local self-signed certificate.

View File

@ -26,6 +26,7 @@
#include "icinga/eventcommand.hpp"
#include "icinga/notificationcommand.hpp"
#include "remote/apiaction.hpp"
#include "remote/apilistener.hpp"
#include "remote/httputility.hpp"
#include "base/utility.hpp"
#include "base/convert.hpp"
@ -45,6 +46,7 @@ REGISTER_APIACTION(schedule_downtime, "Service;Host", &ApiActions::ScheduleDownt
REGISTER_APIACTION(remove_downtime, "Service;Host;Downtime", &ApiActions::RemoveDowntime);
REGISTER_APIACTION(shutdown_process, "", &ApiActions::ShutdownProcess);
REGISTER_APIACTION(restart_process, "", &ApiActions::RestartProcess);
REGISTER_APIACTION(generate_ticket, "", &ApiActions::GenerateTicket);
Dictionary::Ptr ApiActions::CreateResult(int code, const String& status,
const Dictionary::Ptr& additional)
@ -372,3 +374,25 @@ Dictionary::Ptr ApiActions::RestartProcess(const ConfigObject::Ptr& object,
return ApiActions::CreateResult(200, "Restarting Icinga 2.");
}
Dictionary::Ptr ApiActions::GenerateTicket(const ConfigObject::Ptr&,
const Dictionary::Ptr& params)
{
if (!params->Contains("cn"))
return ApiActions::CreateResult(404, "Option 'cn' is required");
String cn = HttpUtility::GetLastParameter(params, "cn");
ApiListener::Ptr listener = ApiListener::GetInstance();
String salt = listener->GetTicketSalt();
if (salt.IsEmpty())
return ApiActions::CreateResult(500, "Ticket salt is not configured in ApiListener object");
String ticket = PBKDF2_SHA1(cn, salt, 50000);
Dictionary::Ptr additional = new Dictionary();
additional->Set("ticket", ticket);
return ApiActions::CreateResult(200, "Generated PKI ticket '" + ticket + "' for common name '"
+ cn + "'.", additional);
}

View File

@ -45,6 +45,7 @@ public:
static Dictionary::Ptr RemoveDowntime(const ConfigObject::Ptr& object, const Dictionary::Ptr& params);
static Dictionary::Ptr ShutdownProcess(const ConfigObject::Ptr& object, const Dictionary::Ptr& params);
static Dictionary::Ptr RestartProcess(const ConfigObject::Ptr& object, const Dictionary::Ptr& params);
static Dictionary::Ptr GenerateTicket(const ConfigObject::Ptr& object, const Dictionary::Ptr& params);
private:
static Dictionary::Ptr CreateResult(int code, const String& status, const Dictionary::Ptr& additional = Dictionary::Ptr());