From a970f7dcf978fb7761fb21ea621b9bdb3899ecbd Mon Sep 17 00:00:00 2001 From: Andrew Jaffie Date: Fri, 27 Jul 2018 18:25:33 -0400 Subject: [PATCH 1/8] Implemented cli command + documentation. --- doc/06-distributed-monitoring.md | 8 ++++ doc/11-cli-commands.md | 1 + lib/cli/CMakeLists.txt | 1 + lib/cli/caremovecommand.cpp | 72 ++++++++++++++++++++++++++++++++ lib/cli/caremovecommand.hpp | 47 +++++++++++++++++++++ 5 files changed, 129 insertions(+) create mode 100644 lib/cli/caremovecommand.cpp create mode 100644 lib/cli/caremovecommand.hpp diff --git a/doc/06-distributed-monitoring.md b/doc/06-distributed-monitoring.md index dca0aea95..41e0468fd 100644 --- a/doc/06-distributed-monitoring.md +++ b/doc/06-distributed-monitoring.md @@ -451,6 +451,14 @@ information/cli: Signed certificate for 'CN = icinga2-client2.localdomain'. > `ca list` cannot be used as historical inventory. Certificate > signing requests older than 1 week are automatically deleted. +You can also remove an undesired CSR using the `ca remove` command using the +syntax as the `ca sign` command. + +``` +[root@pym ~]# icinga2 ca remove 5c31ca0e2269c10363a97e40e3f2b2cd56493f9194d5b1852541b835970da46e +information/cli: Certificate 5c31ca0e2269c10363a97e40e3f2b2cd56493f9194d5b1852541b835970da46e removed. +``` + ## Client/Satellite Setup This section describes the setup of a satellite and/or client connected to an diff --git a/doc/11-cli-commands.md b/doc/11-cli-commands.md index dff5bc390..f9197f0ee 100644 --- a/doc/11-cli-commands.md +++ b/doc/11-cli-commands.md @@ -21,6 +21,7 @@ Usage: Supported commands: * api setup (setup for API) * ca list (lists all certificate signing requests) + * ca remove (removes an outstanding certificate request) * ca sign (signs an outstanding certificate request) * console (Icinga debug console) * daemon (starts Icinga 2) diff --git a/lib/cli/CMakeLists.txt b/lib/cli/CMakeLists.txt index 7a5e91887..980429171 100644 --- a/lib/cli/CMakeLists.txt +++ b/lib/cli/CMakeLists.txt @@ -5,6 +5,7 @@ set(cli_SOURCES apisetupcommand.cpp apisetupcommand.hpp apisetuputility.cpp apisetuputility.hpp calistcommand.cpp calistcommand.hpp + caremovecommand.cpp caremovecommand.hpp casigncommand.cpp casigncommand.hpp clicommand.cpp clicommand.hpp consolecommand.cpp consolecommand.hpp diff --git a/lib/cli/caremovecommand.cpp b/lib/cli/caremovecommand.cpp new file mode 100644 index 000000000..ab6e0f811 --- /dev/null +++ b/lib/cli/caremovecommand.cpp @@ -0,0 +1,72 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/) * + * * + * 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. * + ******************************************************************************/ + +#include "cli/caremovecommand.hpp" +#include "remote/apilistener.hpp" +#include "base/logger.hpp" +#include "base/application.hpp" +#include "base/tlsutility.hpp" + +using namespace icinga; + +REGISTER_CLICOMMAND("ca/remove", CARemoveCommand); + +String CARemoveCommand::GetDescription() const +{ + return "Removes an outstanding certificate request."; +} + +String CARemoveCommand::GetShortDescription() const +{ + return "removes an outstanding certificate request"; +} + +int CARemoveCommand::GetMinArguments() const +{ + return 1; +} + +ImpersonationLevel CARemoveCommand::GetImpersonationLevel() const +{ + return ImpersonateIcinga; +} + +/** + * The entry point for the "ca remove" CLI command. + * + * @returns An exit status. + */ +int CARemoveCommand::Run(const boost::program_options::variables_map& vm, const std::vector& ap) const +{ + String requestFile = ApiListener::GetCertificateRequestsDir() + "/" + ap[0] + ".json"; + + if (!Utility::PathExists(requestFile)) { + Log(LogCritical, "cli") + << "No request exists for fingerprint '" << ap[0] << "'."; + return 1; + } + + if(remove(requestFile.CStr()) != 0) + return 1; + + Log(LogInformation, "cli") + << "Certificate " << ap[0] << " removed."; + + return 0; +} diff --git a/lib/cli/caremovecommand.hpp b/lib/cli/caremovecommand.hpp new file mode 100644 index 000000000..fabfd6974 --- /dev/null +++ b/lib/cli/caremovecommand.hpp @@ -0,0 +1,47 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/) * + * * + * 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. * + ******************************************************************************/ + +#ifndef CAREMOVECOMMAND_H +#define CAREMOVECOMMAND_H + +#include "cli/clicommand.hpp" + +namespace icinga +{ + +/** + * The "ca remove" command. + * + * @ingroup cli + */ +class CARemoveCommand final : public CLICommand +{ +public: + DECLARE_PTR_TYPEDEFS(CARemoveCommand); + + String GetDescription() const override; + String GetShortDescription() const override; + int GetMinArguments() const override; + ImpersonationLevel GetImpersonationLevel() const override; + int Run(const boost::program_options::variables_map& vm, const std::vector& ap) const override; +}; + +} + +#endif /* CASIGNCOMMAND_H */ From 429f1ed317598e6f13f07832ef7e3c297c496871 Mon Sep 17 00:00:00 2001 From: Andrew Jaffie Date: Wed, 8 Aug 2018 11:34:37 -0400 Subject: [PATCH 2/8] Ignore repeated requests from client after using ca remove command --- lib/cli/caremovecommand.cpp | 2 +- lib/remote/jsonrpcconnection-pki.cpp | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/cli/caremovecommand.cpp b/lib/cli/caremovecommand.cpp index ab6e0f811..a174d9e57 100644 --- a/lib/cli/caremovecommand.cpp +++ b/lib/cli/caremovecommand.cpp @@ -61,7 +61,7 @@ int CARemoveCommand::Run(const boost::program_options::variables_map& vm, const << "No request exists for fingerprint '" << ap[0] << "'."; return 1; } - + Utility::SaveJsonFile(ApiListener::GetCertificateRequestsDir() + "/" + ap[0] + ".removed", 700, Utility::LoadJsonFile(requestFile)); if(remove(requestFile.CStr()) != 0) return 1; diff --git a/lib/remote/jsonrpcconnection-pki.cpp b/lib/remote/jsonrpcconnection-pki.cpp index 9b537d138..27a21a6b3 100644 --- a/lib/remote/jsonrpcconnection-pki.cpp +++ b/lib/remote/jsonrpcconnection-pki.cpp @@ -129,6 +129,12 @@ Value RequestCertificateHandler(const MessageOrigin::Ptr& origin, const Dictiona return result; } + } else if (Utility::PathExists(requestDir + "/" + certFingerprint + ".removed")) { + Log(LogInformation, "JsonRpcConnection") + << "Certificate for CN " << cn << " has been removed. Ignoring signing request."; + result->Set("status_code", 1); + result->Set("error", "Ticket for CN " + cn + " declined by administrator."); + return result; } std::shared_ptr newcert; From 6aa2e0c36b264704664e131706e3156f680bdf92 Mon Sep 17 00:00:00 2001 From: Andrew Jaffie Date: Wed, 8 Aug 2018 12:09:41 -0400 Subject: [PATCH 3/8] Added ca restore command+docs to undo effects of ca remove --- doc/06-distributed-monitoring.md | 2 + doc/11-cli-commands.md | 3 ++ lib/cli/CMakeLists.txt | 1 + lib/cli/carestorecommand.cpp | 73 ++++++++++++++++++++++++++++++++ lib/cli/carestorecommand.hpp | 47 ++++++++++++++++++++ 5 files changed, 126 insertions(+) create mode 100644 lib/cli/carestorecommand.cpp create mode 100644 lib/cli/carestorecommand.hpp diff --git a/doc/06-distributed-monitoring.md b/doc/06-distributed-monitoring.md index 41e0468fd..fd1b1fd60 100644 --- a/doc/06-distributed-monitoring.md +++ b/doc/06-distributed-monitoring.md @@ -458,6 +458,8 @@ syntax as the `ca sign` command. [root@pym ~]# icinga2 ca remove 5c31ca0e2269c10363a97e40e3f2b2cd56493f9194d5b1852541b835970da46e information/cli: Certificate 5c31ca0e2269c10363a97e40e3f2b2cd56493f9194d5b1852541b835970da46e removed. ``` +If you want to restore a certificate you have removed, you can use `ca restore`. + ## Client/Satellite Setup diff --git a/doc/11-cli-commands.md b/doc/11-cli-commands.md index f9197f0ee..ca5e227c4 100644 --- a/doc/11-cli-commands.md +++ b/doc/11-cli-commands.md @@ -21,6 +21,7 @@ Usage: Supported commands: * api setup (setup for API) * ca list (lists all certificate signing requests) + * ca restore (restores a removed certificate request) * ca remove (removes an outstanding certificate request) * ca sign (signs an outstanding certificate request) * console (Icinga debug console) @@ -186,6 +187,8 @@ Usage: Supported commands: * ca list (lists all certificate signing requests) * ca sign (signs an outstanding certificate request) + * ca restore (restores a removed certificate request) + * ca remove (removes an outstanding certificate request) Global options: -h [ --help ] show this help message diff --git a/lib/cli/CMakeLists.txt b/lib/cli/CMakeLists.txt index 980429171..a87ee0e39 100644 --- a/lib/cli/CMakeLists.txt +++ b/lib/cli/CMakeLists.txt @@ -5,6 +5,7 @@ set(cli_SOURCES apisetupcommand.cpp apisetupcommand.hpp apisetuputility.cpp apisetuputility.hpp calistcommand.cpp calistcommand.hpp + carestorecommand.cpp carestorecommand.hpp caremovecommand.cpp caremovecommand.hpp casigncommand.cpp casigncommand.hpp clicommand.cpp clicommand.hpp diff --git a/lib/cli/carestorecommand.cpp b/lib/cli/carestorecommand.cpp new file mode 100644 index 000000000..0a232a84d --- /dev/null +++ b/lib/cli/carestorecommand.cpp @@ -0,0 +1,73 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/) * + * * + * 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. * + ******************************************************************************/ + +#include "cli/carestorecommand.hpp" +#include "remote/apilistener.hpp" +#include "base/logger.hpp" +#include "base/application.hpp" +#include "base/tlsutility.hpp" + +using namespace icinga; + +REGISTER_CLICOMMAND("ca/restore", CARestoreCommand); + +String CARestoreCommand::GetDescription() const +{ + return "Restores a previously removed certificate request."; +} + +String CARestoreCommand::GetShortDescription() const +{ + return "restores a removed certificate request"; +} + +int CARestoreCommand::GetMinArguments() const +{ + return 1; +} + +ImpersonationLevel CARestoreCommand::GetImpersonationLevel() const +{ + return ImpersonateIcinga; +} + +/** + * The entry point for the "ca restore" CLI command. + * + * @returns An exit status. + */ +int CARestoreCommand::Run(const boost::program_options::variables_map& vm, const std::vector& ap) const +{ + String requestFile = ApiListener::GetCertificateRequestsDir() + "/" + ap[0] + ".removed"; + + if (!Utility::PathExists(requestFile)) { + Log(LogCritical, "cli") + << "No removed request exists for fingerprint '" << ap[0] << "'."; + return 1; + } + Utility::SaveJsonFile(ApiListener::GetCertificateRequestsDir() + "/" + ap[0] + ".json", 700, Utility::LoadJsonFile(requestFile)); + if(remove(requestFile.CStr()) != 0) + return 1; + + Log(LogInformation, "cli") + << "Certificate " << ap[0] << " restored, you can now sign it using:\n" + << "\"icinga2 ca sign " << ap[0] << "\""; + + return 0; +} diff --git a/lib/cli/carestorecommand.hpp b/lib/cli/carestorecommand.hpp new file mode 100644 index 000000000..9f2378500 --- /dev/null +++ b/lib/cli/carestorecommand.hpp @@ -0,0 +1,47 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/) * + * * + * 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. * + ******************************************************************************/ + +#ifndef CARESTORECOMMAND_H +#define CARESTORECOMMAND_H + +#include "cli/clicommand.hpp" + +namespace icinga +{ + +/** + * The "ca restore" command. + * + * @ingroup cli + */ +class CARestoreCommand final : public CLICommand +{ +public: + DECLARE_PTR_TYPEDEFS(CARestoreCommand); + + String GetDescription() const override; + String GetShortDescription() const override; + int GetMinArguments() const override; + ImpersonationLevel GetImpersonationLevel() const override; + int Run(const boost::program_options::variables_map& vm, const std::vector& ap) const override; +}; + +} + +#endif /* CASIGNCOMMAND_H */ From d95feb4950162d8e44fe17b53ef71058876d2ddb Mon Sep 17 00:00:00 2001 From: Andrew Jaffie Date: Wed, 8 Aug 2018 14:59:58 -0400 Subject: [PATCH 4/8] Log messages now use CN, file permissions fixed, ca remove now will not remove CSR's that have already been signed. --- lib/cli/CMakeLists.txt | 2 +- lib/cli/caremovecommand.cpp | 17 +++++++++++++++-- lib/cli/carestorecommand.cpp | 13 +++++++++++-- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/lib/cli/CMakeLists.txt b/lib/cli/CMakeLists.txt index a87ee0e39..38756b5ce 100644 --- a/lib/cli/CMakeLists.txt +++ b/lib/cli/CMakeLists.txt @@ -5,8 +5,8 @@ set(cli_SOURCES apisetupcommand.cpp apisetupcommand.hpp apisetuputility.cpp apisetuputility.hpp calistcommand.cpp calistcommand.hpp - carestorecommand.cpp carestorecommand.hpp caremovecommand.cpp caremovecommand.hpp + carestorecommand.cpp carestorecommand.hpp casigncommand.cpp casigncommand.hpp clicommand.cpp clicommand.hpp consolecommand.cpp consolecommand.hpp diff --git a/lib/cli/caremovecommand.cpp b/lib/cli/caremovecommand.cpp index a174d9e57..b833750f9 100644 --- a/lib/cli/caremovecommand.cpp +++ b/lib/cli/caremovecommand.cpp @@ -61,12 +61,25 @@ int CARemoveCommand::Run(const boost::program_options::variables_map& vm, const << "No request exists for fingerprint '" << ap[0] << "'."; return 1; } - Utility::SaveJsonFile(ApiListener::GetCertificateRequestsDir() + "/" + ap[0] + ".removed", 700, Utility::LoadJsonFile(requestFile)); + + Dictionary::Ptr request = Utility::LoadJsonFile(requestFile); + std::shared_ptr certRequest = StringToCertificate(request->Get("cert_request")); + + if (!certRequest) { + Log(LogCritical, "cli", "Certificate request is invalid. Could not parse X.509 certificate for the 'cert_request' attribute."); + return 1; + } + if (request->Contains("cert_response")) { + Log(LogCritical, "cli", "Certificate request already signed, you cannot remove it."); + return 1; + } + + Utility::SaveJsonFile(ApiListener::GetCertificateRequestsDir() + "/" + ap[0] + ".removed", 0600, request); if(remove(requestFile.CStr()) != 0) return 1; Log(LogInformation, "cli") - << "Certificate " << ap[0] << " removed."; + << "Certificate for CN " << GetCertificateCN(certRequest) << " removed."; return 0; } diff --git a/lib/cli/carestorecommand.cpp b/lib/cli/carestorecommand.cpp index 0a232a84d..8a01acb91 100644 --- a/lib/cli/carestorecommand.cpp +++ b/lib/cli/carestorecommand.cpp @@ -61,12 +61,21 @@ int CARestoreCommand::Run(const boost::program_options::variables_map& vm, const << "No removed request exists for fingerprint '" << ap[0] << "'."; return 1; } - Utility::SaveJsonFile(ApiListener::GetCertificateRequestsDir() + "/" + ap[0] + ".json", 700, Utility::LoadJsonFile(requestFile)); + + Dictionary::Ptr request = Utility::LoadJsonFile(requestFile); + std::shared_ptr certRequest = StringToCertificate(request->Get("cert_request")); + + if (!certRequest) { + Log(LogCritical, "cli", "Certificate request is invalid. Could not parse X.509 certificate for the 'cert_request' attribute."); + return 1; + } + + Utility::SaveJsonFile(ApiListener::GetCertificateRequestsDir() + "/" + ap[0] + ".json", 0600, request); if(remove(requestFile.CStr()) != 0) return 1; Log(LogInformation, "cli") - << "Certificate " << ap[0] << " restored, you can now sign it using:\n" + << "Certificate " << GetCertificateCN(certRequest) << " restored, you can now sign it using:\n" << "\"icinga2 ca sign " << ap[0] << "\""; return 0; From a35828a6ff4f223bdfb3a33462d14c82d8b220ba Mon Sep 17 00:00:00 2001 From: Michael Friedrich Date: Fri, 10 May 2019 17:33:28 +0200 Subject: [PATCH 5/8] CLI: Update ca remove/restore commands from my review --- lib/cli/caremovecommand.cpp | 40 ++++++++++++---------------------- lib/cli/caremovecommand.hpp | 21 ++---------------- lib/cli/carestorecommand.cpp | 42 ++++++++++++------------------------ lib/cli/carestorecommand.hpp | 21 ++---------------- lib/cli/casigncommand.cpp | 2 +- 5 files changed, 33 insertions(+), 93 deletions(-) diff --git a/lib/cli/caremovecommand.cpp b/lib/cli/caremovecommand.cpp index b833750f9..30f1bf1dd 100644 --- a/lib/cli/caremovecommand.cpp +++ b/lib/cli/caremovecommand.cpp @@ -1,27 +1,10 @@ -/****************************************************************************** - * Icinga 2 * - * Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/) * - * * - * 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. * - ******************************************************************************/ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ #include "cli/caremovecommand.hpp" -#include "remote/apilistener.hpp" #include "base/logger.hpp" #include "base/application.hpp" #include "base/tlsutility.hpp" +#include "remote/apilistener.hpp" using namespace icinga; @@ -54,11 +37,12 @@ ImpersonationLevel CARemoveCommand::GetImpersonationLevel() const */ int CARemoveCommand::Run(const boost::program_options::variables_map& vm, const std::vector& ap) const { - String requestFile = ApiListener::GetCertificateRequestsDir() + "/" + ap[0] + ".json"; + String fingerPrint = ap[0]; + String requestFile = ApiListener::GetCertificateRequestsDir() + "/" + fingerPrint + ".json"; if (!Utility::PathExists(requestFile)) { Log(LogCritical, "cli") - << "No request exists for fingerprint '" << ap[0] << "'."; + << "No request exists for fingerprint '" << fingerPrint << "'."; return 1; } @@ -69,17 +53,21 @@ int CARemoveCommand::Run(const boost::program_options::variables_map& vm, const Log(LogCritical, "cli", "Certificate request is invalid. Could not parse X.509 certificate for the 'cert_request' attribute."); return 1; } + + String cn = GetCertificateCN(certRequest); + if (request->Contains("cert_response")) { - Log(LogCritical, "cli", "Certificate request already signed, you cannot remove it."); + Log(LogCritical, "cli") + << "Certificate request for CN '" << cn << "' already signed, removal is not possible."; return 1; } - Utility::SaveJsonFile(ApiListener::GetCertificateRequestsDir() + "/" + ap[0] + ".removed", 0600, request); - if(remove(requestFile.CStr()) != 0) - return 1; + Utility::SaveJsonFile(ApiListener::GetCertificateRequestsDir() + "/" + fingerPrint + ".removed", 0600, request); + + Utility::Remove(requestFile); Log(LogInformation, "cli") - << "Certificate for CN " << GetCertificateCN(certRequest) << " removed."; + << "Certificate request for CN " << cn << " removed."; return 0; } diff --git a/lib/cli/caremovecommand.hpp b/lib/cli/caremovecommand.hpp index fabfd6974..2da92d39e 100644 --- a/lib/cli/caremovecommand.hpp +++ b/lib/cli/caremovecommand.hpp @@ -1,21 +1,4 @@ -/****************************************************************************** - * Icinga 2 * - * Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/) * - * * - * 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. * - ******************************************************************************/ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ #ifndef CAREMOVECOMMAND_H #define CAREMOVECOMMAND_H @@ -44,4 +27,4 @@ public: } -#endif /* CASIGNCOMMAND_H */ +#endif /* CAREMOVECOMMAND_H */ diff --git a/lib/cli/carestorecommand.cpp b/lib/cli/carestorecommand.cpp index 8a01acb91..75ab2149e 100644 --- a/lib/cli/carestorecommand.cpp +++ b/lib/cli/carestorecommand.cpp @@ -1,27 +1,10 @@ -/****************************************************************************** - * Icinga 2 * - * Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/) * - * * - * 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. * - ******************************************************************************/ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ #include "cli/carestorecommand.hpp" -#include "remote/apilistener.hpp" #include "base/logger.hpp" #include "base/application.hpp" #include "base/tlsutility.hpp" +#include "remote/apilistener.hpp" using namespace icinga; @@ -54,29 +37,32 @@ ImpersonationLevel CARestoreCommand::GetImpersonationLevel() const */ int CARestoreCommand::Run(const boost::program_options::variables_map& vm, const std::vector& ap) const { - String requestFile = ApiListener::GetCertificateRequestsDir() + "/" + ap[0] + ".removed"; + String fingerPrint = ap[0]; + String removedRequestFile = ApiListener::GetCertificateRequestsDir() + "/" + fingerPrint + ".removed"; - if (!Utility::PathExists(requestFile)) { + if (!Utility::PathExists(removedRequestFile)) { Log(LogCritical, "cli") - << "No removed request exists for fingerprint '" << ap[0] << "'."; + << "Cannot find removed fingerprint '" << fingerPrint << "', bailing out."; return 1; } - Dictionary::Ptr request = Utility::LoadJsonFile(requestFile); + Dictionary::Ptr request = Utility::LoadJsonFile(removedRequestFile); std::shared_ptr certRequest = StringToCertificate(request->Get("cert_request")); if (!certRequest) { Log(LogCritical, "cli", "Certificate request is invalid. Could not parse X.509 certificate for the 'cert_request' attribute."); + /* Purge the file when we know that it is broken. */ + Utility::Remove(removedRequestFile); return 1; } - Utility::SaveJsonFile(ApiListener::GetCertificateRequestsDir() + "/" + ap[0] + ".json", 0600, request); - if(remove(requestFile.CStr()) != 0) - return 1; + Utility::SaveJsonFile(ApiListener::GetCertificateRequestsDir() + "/" + fingerPrint + ".json", 0600, request); + + Utility::Remove(removedRequestFile); Log(LogInformation, "cli") - << "Certificate " << GetCertificateCN(certRequest) << " restored, you can now sign it using:\n" - << "\"icinga2 ca sign " << ap[0] << "\""; + << "Restored certificate request for CN '" << GetCertificateCN(certRequest) << "', sign it with:\n" + << "\"icinga2 ca sign " << fingerPrint << "\""; return 0; } diff --git a/lib/cli/carestorecommand.hpp b/lib/cli/carestorecommand.hpp index 9f2378500..74a27dff6 100644 --- a/lib/cli/carestorecommand.hpp +++ b/lib/cli/carestorecommand.hpp @@ -1,21 +1,4 @@ -/****************************************************************************** - * Icinga 2 * - * Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/) * - * * - * 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. * - ******************************************************************************/ +/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ #ifndef CARESTORECOMMAND_H #define CARESTORECOMMAND_H @@ -44,4 +27,4 @@ public: } -#endif /* CASIGNCOMMAND_H */ +#endif /* CASTORECOMMAND_H */ diff --git a/lib/cli/casigncommand.cpp b/lib/cli/casigncommand.cpp index a6b547d98..368b378f0 100644 --- a/lib/cli/casigncommand.cpp +++ b/lib/cli/casigncommand.cpp @@ -1,10 +1,10 @@ /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ #include "cli/casigncommand.hpp" -#include "remote/apilistener.hpp" #include "base/logger.hpp" #include "base/application.hpp" #include "base/tlsutility.hpp" +#include "remote/apilistener.hpp" using namespace icinga; From b32d818d1b5908d8fdb5bfd9c09c44d51ea3789a Mon Sep 17 00:00:00 2001 From: Michael Friedrich Date: Fri, 10 May 2019 17:57:42 +0200 Subject: [PATCH 6/8] CLI: Allow to list removed CSRs with 'ca list' --- doc/11-cli-commands.md | 1 + lib/cli/calistcommand.cpp | 3 ++- lib/remote/pkiutility.cpp | 15 +++++++++++---- lib/remote/pkiutility.hpp | 2 +- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/doc/11-cli-commands.md b/doc/11-cli-commands.md index ca5e227c4..d05079a08 100644 --- a/doc/11-cli-commands.md +++ b/doc/11-cli-commands.md @@ -236,6 +236,7 @@ Command options: --all List all certificate signing requests, including signed. Note: Old requests are automatically cleaned by Icinga after 1 week. + --removed List all removed CSRs (for use with 'ca restore') --json encode output as JSON Report bugs at diff --git a/lib/cli/calistcommand.cpp b/lib/cli/calistcommand.cpp index 829086b98..64962ca5d 100644 --- a/lib/cli/calistcommand.cpp +++ b/lib/cli/calistcommand.cpp @@ -29,6 +29,7 @@ void CAListCommand::InitParameters(boost::program_options::options_description& { visibleDesc.add_options() ("all", "List all certificate signing requests, including signed. Note: Old requests are automatically cleaned by Icinga after 1 week.") + ("removed", "List all removed CSRs (for use with 'ca restore')") ("json", "encode output as JSON"); } @@ -39,7 +40,7 @@ void CAListCommand::InitParameters(boost::program_options::options_description& */ int CAListCommand::Run(const boost::program_options::variables_map& vm, const std::vector& ap) const { - Dictionary::Ptr requests = PkiUtility::GetCertificateRequests(); + Dictionary::Ptr requests = PkiUtility::GetCertificateRequests(vm.count("removed")); if (vm.count("json")) std::cout << JsonEncode(requests); diff --git a/lib/remote/pkiutility.cpp b/lib/remote/pkiutility.cpp index 350b99361..3fddd1a67 100644 --- a/lib/remote/pkiutility.cpp +++ b/lib/remote/pkiutility.cpp @@ -18,6 +18,7 @@ #include #include #include +#include using namespace icinga; @@ -368,8 +369,9 @@ static void CollectRequestHandler(const Dictionary::Ptr& requests, const String& Dictionary::Ptr result = new Dictionary(); - String fingerprint = Utility::BaseName(requestFile); - fingerprint = fingerprint.SubStr(0, fingerprint.GetLength() - 5); + namespace fs = boost::filesystem; + fs::path file(requestFile.Begin(), requestFile.End()); + String fingerprint = file.stem().string(); String certRequestText = request->Get("cert_request"); result->Set("cert_request", certRequestText); @@ -414,14 +416,19 @@ static void CollectRequestHandler(const Dictionary::Ptr& requests, const String& requests->Set(fingerprint, result); } -Dictionary::Ptr PkiUtility::GetCertificateRequests() +Dictionary::Ptr PkiUtility::GetCertificateRequests(bool removed) { Dictionary::Ptr requests = new Dictionary(); String requestDir = ApiListener::GetCertificateRequestsDir(); + String ext = "json"; + + if (removed) + ext = "removed"; if (Utility::PathExists(requestDir)) - Utility::Glob(requestDir + "/*.json", std::bind(&CollectRequestHandler, requests, _1), GlobFile); + Utility::Glob(requestDir + "/*." + ext, std::bind(&CollectRequestHandler, requests, _1), GlobFile); return requests; } + diff --git a/lib/remote/pkiutility.hpp b/lib/remote/pkiutility.hpp index cc5e67061..50d47e01a 100644 --- a/lib/remote/pkiutility.hpp +++ b/lib/remote/pkiutility.hpp @@ -29,7 +29,7 @@ public: const String& certfile, const String& cafile, const std::shared_ptr& trustedcert, const String& ticket = String()); static String GetCertificateInformation(const std::shared_ptr& certificate); - static Dictionary::Ptr GetCertificateRequests(); + static Dictionary::Ptr GetCertificateRequests(bool removed = false); private: PkiUtility(); From 65c8d43157d1e2aa21880840862d9c1d4b27dac9 Mon Sep 17 00:00:00 2001 From: Michael Friedrich Date: Fri, 7 Jun 2019 10:33:35 +0200 Subject: [PATCH 7/8] Add function docs for CA CLI commands --- lib/cli/calistcommand.cpp | 18 +++++++++++++++++- lib/cli/caremovecommand.cpp | 20 ++++++++++++++++++++ lib/cli/carestorecommand.cpp | 20 ++++++++++++++++++++ lib/cli/casigncommand.cpp | 22 +++++++++++++++++++++- 4 files changed, 78 insertions(+), 2 deletions(-) diff --git a/lib/cli/calistcommand.cpp b/lib/cli/calistcommand.cpp index 64962ca5d..f693ad72f 100644 --- a/lib/cli/calistcommand.cpp +++ b/lib/cli/calistcommand.cpp @@ -14,16 +14,32 @@ namespace po = boost::program_options; REGISTER_CLICOMMAND("ca/list", CAListCommand); +/** + * Provide a long CLI description sentence. + * + * @return text + */ String CAListCommand::GetDescription() const { return "Lists pending certificate signing requests."; } +/** + * Provide a short CLI description. + * + * @return text + */ String CAListCommand::GetShortDescription() const { return "lists pending certificate signing requests"; } +/** + * Initialize available CLI parameters. + * + * @param visibleDesc Register visible parameters. + * @param hiddenDesc Register hidden parameters. + */ void CAListCommand::InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const { @@ -36,7 +52,7 @@ void CAListCommand::InitParameters(boost::program_options::options_description& /** * The entry point for the "ca list" CLI command. * - * @returns An exit status. + * @return An exit status. */ int CAListCommand::Run(const boost::program_options::variables_map& vm, const std::vector& ap) const { diff --git a/lib/cli/caremovecommand.cpp b/lib/cli/caremovecommand.cpp index 30f1bf1dd..d8944944e 100644 --- a/lib/cli/caremovecommand.cpp +++ b/lib/cli/caremovecommand.cpp @@ -10,21 +10,41 @@ using namespace icinga; REGISTER_CLICOMMAND("ca/remove", CARemoveCommand); +/** + * Provide a long CLI description sentence. + * + * @return text + */ String CARemoveCommand::GetDescription() const { return "Removes an outstanding certificate request."; } +/** + * Provide a short CLI description. + * + * @return text + */ String CARemoveCommand::GetShortDescription() const { return "removes an outstanding certificate request"; } +/** + * Define minimum arguments without key parameter. + * + * @return number of arguments + */ int CARemoveCommand::GetMinArguments() const { return 1; } +/** + * Impersonate as Icinga user. + * + * @return impersonate level + */ ImpersonationLevel CARemoveCommand::GetImpersonationLevel() const { return ImpersonateIcinga; diff --git a/lib/cli/carestorecommand.cpp b/lib/cli/carestorecommand.cpp index 75ab2149e..502036830 100644 --- a/lib/cli/carestorecommand.cpp +++ b/lib/cli/carestorecommand.cpp @@ -10,21 +10,41 @@ using namespace icinga; REGISTER_CLICOMMAND("ca/restore", CARestoreCommand); +/** + * Provide a long CLI description sentence. + * + * @return text + */ String CARestoreCommand::GetDescription() const { return "Restores a previously removed certificate request."; } +/** + * Provide a short CLI description. + * + * @return text + */ String CARestoreCommand::GetShortDescription() const { return "restores a removed certificate request"; } +/** + * Define minimum arguments without key parameter. + * + * @return number of arguments + */ int CARestoreCommand::GetMinArguments() const { return 1; } +/** + * Impersonate as Icinga user. + * + * @return impersonate level + */ ImpersonationLevel CARestoreCommand::GetImpersonationLevel() const { return ImpersonateIcinga; diff --git a/lib/cli/casigncommand.cpp b/lib/cli/casigncommand.cpp index 368b378f0..96d2c2c87 100644 --- a/lib/cli/casigncommand.cpp +++ b/lib/cli/casigncommand.cpp @@ -10,21 +10,41 @@ using namespace icinga; REGISTER_CLICOMMAND("ca/sign", CASignCommand); +/** + * Provide a long CLI description sentence. + * + * @return text + */ String CASignCommand::GetDescription() const { return "Signs an outstanding certificate request."; } +/** + * Provide a short CLI description. + * + * @return text + */ String CASignCommand::GetShortDescription() const { return "signs an outstanding certificate request"; } +/** + * Define minimum arguments without key parameter. + * + * @return number of arguments + */ int CASignCommand::GetMinArguments() const { return 1; } +/** + * Impersonate as Icinga user. + * + * @return impersonate level + */ ImpersonationLevel CASignCommand::GetImpersonationLevel() const { return ImpersonateIcinga; @@ -33,7 +53,7 @@ ImpersonationLevel CASignCommand::GetImpersonationLevel() const /** * The entry point for the "ca sign" CLI command. * - * @returns An exit status. + * @return An exit status. */ int CASignCommand::Run(const boost::program_options::variables_map& vm, const std::vector& ap) const { From 3554579d0dd96369c59dcd1ad4703f027878f14a Mon Sep 17 00:00:00 2001 From: Michael Friedrich Date: Fri, 7 Jun 2019 10:37:19 +0200 Subject: [PATCH 8/8] Add upgrading docs for ca remove/restore CLI commands --- doc/16-upgrading-icinga-2.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/16-upgrading-icinga-2.md b/doc/16-upgrading-icinga-2.md index a0b016e3d..39d35a5ab 100644 --- a/doc/16-upgrading-icinga-2.md +++ b/doc/16-upgrading-icinga-2.md @@ -164,6 +164,16 @@ or with sudo. You can use the new `--all` parameter to show all signing requests. Note that Icinga automatically purges signed requests older than 1 week. +#### New: CA Remove/Restore The deprecated `concurrent_checks` attribute in the [checker feature](09-object-types.md#objecttype-checkercomponent)