Skip to content

Commit

Permalink
Merge pull request #6500 from ajaffie/feature/cli-ca-remove-6049
Browse files Browse the repository at this point in the history
Implemented `ca remove` cli command + documentation.
  • Loading branch information
Michael Friedrich committed Jun 7, 2019
2 parents 1997878 + 3554579 commit ee4c5c5
Show file tree
Hide file tree
Showing 13 changed files with 327 additions and 9 deletions.
10 changes: 10 additions & 0 deletions doc/06-distributed-monitoring.md
Expand Up @@ -451,6 +451,16 @@ information/cli: Signed certificate for 'CN = icinga2-client2.localdomain'.
> `ca list` cannot be used as historical inventory. Certificate > `ca list` cannot be used as historical inventory. Certificate
> signing requests older than 1 week are automatically deleted. > 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.
```
If you want to restore a certificate you have removed, you can use `ca restore`.


## Client/Satellite Setup <a id="distributed-monitoring-setup-satellite-client"></a> ## Client/Satellite Setup <a id="distributed-monitoring-setup-satellite-client"></a>


This section describes the setup of a satellite and/or client connected to an This section describes the setup of a satellite and/or client connected to an
Expand Down
5 changes: 5 additions & 0 deletions doc/11-cli-commands.md
Expand Up @@ -21,6 +21,8 @@ Usage:
Supported commands: Supported commands:
* api setup (setup for API) * api setup (setup for API)
* ca list (lists all certificate signing requests) * 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) * ca sign (signs an outstanding certificate request)
* console (Icinga debug console) * console (Icinga debug console)
* daemon (starts Icinga 2) * daemon (starts Icinga 2)
Expand Down Expand Up @@ -185,6 +187,8 @@ Usage:
Supported commands: Supported commands:
* ca list (lists all certificate signing requests) * ca list (lists all certificate signing requests)
* ca sign (signs an outstanding certificate request) * ca sign (signs an outstanding certificate request)
* ca restore (restores a removed certificate request)
* ca remove (removes an outstanding certificate request)
Global options: Global options:
-h [ --help ] show this help message -h [ --help ] show this help message
Expand Down Expand Up @@ -232,6 +236,7 @@ Command options:
--all List all certificate signing requests, including --all List all certificate signing requests, including
signed. Note: Old requests are automatically signed. Note: Old requests are automatically
cleaned by Icinga after 1 week. cleaned by Icinga after 1 week.
--removed List all removed CSRs (for use with 'ca restore')
--json encode output as JSON --json encode output as JSON
Report bugs at <https://github.com/Icinga/icinga2> Report bugs at <https://github.com/Icinga/icinga2>
Expand Down
10 changes: 10 additions & 0 deletions doc/16-upgrading-icinga-2.md
Expand Up @@ -164,6 +164,16 @@ or with sudo.
You can use the new `--all` parameter to show all signing requests. You can use the new `--all` parameter to show all signing requests.
Note that Icinga automatically purges signed requests older than 1 week. Note that Icinga automatically purges signed requests older than 1 week.


#### New: CA Remove/Restore <a id="upgrading-to-2-11-cli-commands-ca-remove-restore></a>

`ca remove` allows you to remove pending signing requests. Once the
master receives a CSR, and it is marked as removed, the request is
denied.

`ca restore` allows you to restore a removed signing request. You
can list removed signing requests with the new `--removed` parameter
for `ca list`.

### Configuration <a id="upgrading-to-2-11-configuration"></a> ### Configuration <a id="upgrading-to-2-11-configuration"></a>


The deprecated `concurrent_checks` attribute in the [checker feature](09-object-types.md#objecttype-checkercomponent) The deprecated `concurrent_checks` attribute in the [checker feature](09-object-types.md#objecttype-checkercomponent)
Expand Down
2 changes: 2 additions & 0 deletions lib/cli/CMakeLists.txt
Expand Up @@ -5,6 +5,8 @@ set(cli_SOURCES
apisetupcommand.cpp apisetupcommand.hpp apisetupcommand.cpp apisetupcommand.hpp
apisetuputility.cpp apisetuputility.hpp apisetuputility.cpp apisetuputility.hpp
calistcommand.cpp calistcommand.hpp calistcommand.cpp calistcommand.hpp
caremovecommand.cpp caremovecommand.hpp
carestorecommand.cpp carestorecommand.hpp
casigncommand.cpp casigncommand.hpp casigncommand.cpp casigncommand.hpp
clicommand.cpp clicommand.hpp clicommand.cpp clicommand.hpp
consolecommand.cpp consolecommand.hpp consolecommand.cpp consolecommand.hpp
Expand Down
21 changes: 19 additions & 2 deletions lib/cli/calistcommand.cpp
Expand Up @@ -14,32 +14,49 @@ namespace po = boost::program_options;


REGISTER_CLICOMMAND("ca/list", CAListCommand); REGISTER_CLICOMMAND("ca/list", CAListCommand);


/**
* Provide a long CLI description sentence.
*
* @return text
*/
String CAListCommand::GetDescription() const String CAListCommand::GetDescription() const
{ {
return "Lists pending certificate signing requests."; return "Lists pending certificate signing requests.";
} }


/**
* Provide a short CLI description.
*
* @return text
*/
String CAListCommand::GetShortDescription() const String CAListCommand::GetShortDescription() const
{ {
return "lists pending certificate signing requests"; 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, void CAListCommand::InitParameters(boost::program_options::options_description& visibleDesc,
boost::program_options::options_description& hiddenDesc) const boost::program_options::options_description& hiddenDesc) const
{ {
visibleDesc.add_options() visibleDesc.add_options()
("all", "List all certificate signing requests, including signed. Note: Old requests are automatically cleaned by Icinga after 1 week.") ("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"); ("json", "encode output as JSON");
} }


/** /**
* The entry point for the "ca list" CLI command. * 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<std::string>& ap) const int CAListCommand::Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const
{ {
Dictionary::Ptr requests = PkiUtility::GetCertificateRequests(); Dictionary::Ptr requests = PkiUtility::GetCertificateRequests(vm.count("removed"));


if (vm.count("json")) if (vm.count("json"))
std::cout << JsonEncode(requests); std::cout << JsonEncode(requests);
Expand Down
93 changes: 93 additions & 0 deletions lib/cli/caremovecommand.cpp
@@ -0,0 +1,93 @@
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */

#include "cli/caremovecommand.hpp"
#include "base/logger.hpp"
#include "base/application.hpp"
#include "base/tlsutility.hpp"
#include "remote/apilistener.hpp"

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;
}

/**
* 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<std::string>& ap) const
{
String fingerPrint = ap[0];
String requestFile = ApiListener::GetCertificateRequestsDir() + "/" + fingerPrint + ".json";

if (!Utility::PathExists(requestFile)) {
Log(LogCritical, "cli")
<< "No request exists for fingerprint '" << fingerPrint << "'.";
return 1;
}

Dictionary::Ptr request = Utility::LoadJsonFile(requestFile);
std::shared_ptr<X509> 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;
}

String cn = GetCertificateCN(certRequest);

if (request->Contains("cert_response")) {
Log(LogCritical, "cli")
<< "Certificate request for CN '" << cn << "' already signed, removal is not possible.";
return 1;
}

Utility::SaveJsonFile(ApiListener::GetCertificateRequestsDir() + "/" + fingerPrint + ".removed", 0600, request);

Utility::Remove(requestFile);

Log(LogInformation, "cli")
<< "Certificate request for CN " << cn << " removed.";

return 0;
}
30 changes: 30 additions & 0 deletions lib/cli/caremovecommand.hpp
@@ -0,0 +1,30 @@
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */

#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<std::string>& ap) const override;
};

}

#endif /* CAREMOVECOMMAND_H */
88 changes: 88 additions & 0 deletions lib/cli/carestorecommand.cpp
@@ -0,0 +1,88 @@
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */

#include "cli/carestorecommand.hpp"
#include "base/logger.hpp"
#include "base/application.hpp"
#include "base/tlsutility.hpp"
#include "remote/apilistener.hpp"

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;
}

/**
* 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<std::string>& ap) const
{
String fingerPrint = ap[0];
String removedRequestFile = ApiListener::GetCertificateRequestsDir() + "/" + fingerPrint + ".removed";

if (!Utility::PathExists(removedRequestFile)) {
Log(LogCritical, "cli")
<< "Cannot find removed fingerprint '" << fingerPrint << "', bailing out.";
return 1;
}

Dictionary::Ptr request = Utility::LoadJsonFile(removedRequestFile);
std::shared_ptr<X509> 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() + "/" + fingerPrint + ".json", 0600, request);

Utility::Remove(removedRequestFile);

Log(LogInformation, "cli")
<< "Restored certificate request for CN '" << GetCertificateCN(certRequest) << "', sign it with:\n"
<< "\"icinga2 ca sign " << fingerPrint << "\"";

return 0;
}
30 changes: 30 additions & 0 deletions lib/cli/carestorecommand.hpp
@@ -0,0 +1,30 @@
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */

#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<std::string>& ap) const override;
};

}

#endif /* CASTORECOMMAND_H */

0 comments on commit ee4c5c5

Please sign in to comment.