mirror of
https://github.com/Icinga/icinga2.git
synced 2025-07-26 07:04:37 +02:00
Implement support for migrating certificates to /var/lib/icinga2/certs
This commit includes documentation too. Signed-off-by: Michael Friedrich <michael.friedrich@icinga.com>
This commit is contained in:
parent
c514ff061a
commit
f2d437e96c
@ -175,11 +175,11 @@ By default Icinga 2 uses the following files and directories:
|
|||||||
/usr/lib\*/icinga2 | Libraries and the Icinga 2 binary (use `find /usr -type f -name icinga2` to locate the binary path).
|
/usr/lib\*/icinga2 | Libraries and the Icinga 2 binary (use `find /usr -type f -name icinga2` to locate the binary path).
|
||||||
/usr/share/doc/icinga2 | Documentation files that come with Icinga 2.
|
/usr/share/doc/icinga2 | Documentation files that come with Icinga 2.
|
||||||
/usr/share/icinga2/include | The Icinga Template Library and plugin command configuration.
|
/usr/share/icinga2/include | The Icinga Template Library and plugin command configuration.
|
||||||
|
/var/lib/icinga2 | Icinga 2 state file, cluster log, master CA, node certificates and configuration files (cluster, api).
|
||||||
/var/run/icinga2 | PID file.
|
/var/run/icinga2 | PID file.
|
||||||
/var/run/icinga2/cmd | Command pipe and Livestatus socket.
|
/var/run/icinga2/cmd | Command pipe and Livestatus socket.
|
||||||
/var/cache/icinga2 | status.dat/objects.cache, icinga2.debug files
|
/var/cache/icinga2 | status.dat/objects.cache, icinga2.debug files
|
||||||
/var/spool/icinga2 | Used for performance data spool files.
|
/var/spool/icinga2 | Used for performance data spool files.
|
||||||
/var/lib/icinga2 | Icinga 2 state file, cluster log, local CA and configuration files (cluster, api).
|
|
||||||
/var/log/icinga2 | Log file location and compat/ directory for the CompatLogger feature.
|
/var/log/icinga2 | Log file location and compat/ directory for the CompatLogger feature.
|
||||||
|
|
||||||
FreeBSD uses slightly different paths:
|
FreeBSD uses slightly different paths:
|
||||||
@ -194,11 +194,11 @@ By default Icinga 2 uses the following files and directories:
|
|||||||
/usr/local/lib/icinga2 | Libraries and the Icinga 2 binary.
|
/usr/local/lib/icinga2 | Libraries and the Icinga 2 binary.
|
||||||
/usr/local/share/doc/icinga2 | Documentation files that come with Icinga 2.
|
/usr/local/share/doc/icinga2 | Documentation files that come with Icinga 2.
|
||||||
/usr/local/share/icinga2/include | The Icinga Template Library and plugin command configuration.
|
/usr/local/share/icinga2/include | The Icinga Template Library and plugin command configuration.
|
||||||
|
/var/lib/icinga2 | Icinga 2 state file, cluster log, master CA, node certificates and configuration files (cluster, api).
|
||||||
/var/run/icinga2 | PID file.
|
/var/run/icinga2 | PID file.
|
||||||
/var/run/icinga2/cmd | Command pipe and Livestatus socket.
|
/var/run/icinga2/cmd | Command pipe and Livestatus socket.
|
||||||
/var/cache/icinga2 | status.dat/objects.cache, icinga2.debug files
|
/var/cache/icinga2 | status.dat/objects.cache, icinga2.debug files
|
||||||
/var/spool/icinga2 | Used for performance data spool files.
|
/var/spool/icinga2 | Used for performance data spool files.
|
||||||
/var/lib/icinga2 | Icinga 2 state file, cluster log, local CA and configuration files (cluster, api).
|
|
||||||
/var/log/icinga2 | Log file location and compat/ directory for the CompatLogger feature.
|
/var/log/icinga2 | Log file location and compat/ directory for the CompatLogger feature.
|
||||||
|
|
||||||
## Setting up Check Plugins <a id="setting-up-check-plugins"></a>
|
## Setting up Check Plugins <a id="setting-up-check-plugins"></a>
|
||||||
@ -877,5 +877,6 @@ popular addons is available in the
|
|||||||
Ensure to include the following in your backups:
|
Ensure to include the following in your backups:
|
||||||
|
|
||||||
* Configuration files in `/etc/icinga2`
|
* Configuration files in `/etc/icinga2`
|
||||||
* Runtime files in `/var/lib/icinga2` (the master's CA is stored here as well)
|
* Certificate files in `/var/lib/icinga2/ca` (Master CA key pair) and `/var/lib/icinga2/certs` (node certificates)
|
||||||
|
* Runtime files in `/var/lib/icinga2`
|
||||||
* Optional: IDO database backup
|
* Optional: IDO database backup
|
||||||
|
@ -553,6 +553,11 @@ The setup wizard will ensure that the following steps are taken:
|
|||||||
|
|
||||||
You can verify that the certificate files are stored in the `/var/lib/icinga2/certs` directory.
|
You can verify that the certificate files are stored in the `/var/lib/icinga2/certs` directory.
|
||||||
|
|
||||||
|
> **Note**
|
||||||
|
>
|
||||||
|
> The certificate location changed in v2.8 to `/var/lib/icinga2/certs`. Please read the [upgrading chapter](16-upgrading-icinga-2.md#upgrading-to-2-8-certificate-paths)
|
||||||
|
> for more details.
|
||||||
|
|
||||||
> **Note**
|
> **Note**
|
||||||
>
|
>
|
||||||
> If the client is not directly connected to the certificate signing master,
|
> If the client is not directly connected to the certificate signing master,
|
||||||
@ -2358,6 +2363,11 @@ Sign the CSR with the previously created CA:
|
|||||||
|
|
||||||
[root@icinga2-master1.localdomain /root]# icinga2 pki sign-csr --csr icinga2-master1.localdomain.csr --cert icinga2-master1.localdomain
|
[root@icinga2-master1.localdomain /root]# icinga2 pki sign-csr --csr icinga2-master1.localdomain.csr --cert icinga2-master1.localdomain
|
||||||
|
|
||||||
|
> **Note**
|
||||||
|
>
|
||||||
|
> The certificate location changed in v2.8 to `/var/lib/icinga2/certs`. Please read the [upgrading chapter](16-upgrading-icinga-2.md#upgrading-to-2-8-certificate-paths)
|
||||||
|
> for more details.
|
||||||
|
|
||||||
Copy the host's certificate files and the public CA certificate to `/var/lib/icinga2/certs`:
|
Copy the host's certificate files and the public CA certificate to `/var/lib/icinga2/certs`:
|
||||||
|
|
||||||
[root@icinga2-master1.localdomain /root]# mkdir -p /var/lib/icinga2/certs
|
[root@icinga2-master1.localdomain /root]# mkdir -p /var/lib/icinga2/certs
|
||||||
@ -2444,7 +2454,12 @@ host/port you can specify it like this:
|
|||||||
|
|
||||||
#### Node Setup with Satellites/Clients <a id="distributed-monitoring-automation-cli-node-setup-satellite-client"></a>
|
#### Node Setup with Satellites/Clients <a id="distributed-monitoring-automation-cli-node-setup-satellite-client"></a>
|
||||||
|
|
||||||
Make sure that the `/var/lib/icinga2/certs` exists and is owned by the `icinga`
|
> **Note**
|
||||||
|
>
|
||||||
|
> The certificate location changed in v2.8 to `/var/lib/icinga2/certs`. Please read the [upgrading chapter](16-upgrading-icinga-2.md#upgrading-to-2-8-certificate-paths)
|
||||||
|
> for more details.
|
||||||
|
|
||||||
|
Make sure that the `/var/lib/icinga2/certs` directory exists and is owned by the `icinga`
|
||||||
user (or the user Icinga 2 is running as).
|
user (or the user Icinga 2 is running as).
|
||||||
|
|
||||||
[root@icinga2-client1.localdomain /]# mkdir -p /var/lib/icinga2/certs
|
[root@icinga2-client1.localdomain /]# mkdir -p /var/lib/icinga2/certs
|
||||||
@ -2499,7 +2514,7 @@ Pass the following details to the `node setup` CLI command:
|
|||||||
Accept config | **Optional.** Whether this node accepts configuration sync from the master node (required for [config sync mode](06-distributed-monitoring.md#distributed-monitoring-top-down-config-sync)).
|
Accept config | **Optional.** Whether this node accepts configuration sync from the master node (required for [config sync mode](06-distributed-monitoring.md#distributed-monitoring-top-down-config-sync)).
|
||||||
Accept commands | **Optional.** Whether this node accepts command execution messages from the master node (required for [command endpoint mode](06-distributed-monitoring.md#distributed-monitoring-top-down-command-endpoint)).
|
Accept commands | **Optional.** Whether this node accepts command execution messages from the master node (required for [command endpoint mode](06-distributed-monitoring.md#distributed-monitoring-top-down-command-endpoint)).
|
||||||
|
|
||||||
Example:
|
Example for Icinga 2 v2.8:
|
||||||
|
|
||||||
[root@icinga2-client1.localdomain /]# icinga2 node setup --ticket ead2d570e18c78abf285d6b85524970a0f69c22d \
|
[root@icinga2-client1.localdomain /]# icinga2 node setup --ticket ead2d570e18c78abf285d6b85524970a0f69c22d \
|
||||||
--cn icinga2-client1.localdomain \
|
--cn icinga2-client1.localdomain \
|
||||||
|
@ -41,9 +41,8 @@ Example:
|
|||||||
|
|
||||||
```
|
```
|
||||||
object ApiListener "api" {
|
object ApiListener "api" {
|
||||||
cert_path = LocalStateDir + "/lib/icinga2/certs/" + NodeName + ".crt"
|
accept_commands = true
|
||||||
key_path = LocalStateDir + "/lib/icinga2/certs/" + NodeName + ".key"
|
accept_config = true
|
||||||
ca_path = LocalStateDir + "/lib/icinga2/certs/ca.crt"
|
|
||||||
|
|
||||||
ticket_salt = TicketSalt
|
ticket_salt = TicketSalt
|
||||||
}
|
}
|
||||||
@ -53,9 +52,9 @@ Configuration Attributes:
|
|||||||
|
|
||||||
Name | Type | Description
|
Name | Type | Description
|
||||||
--------------------------------------|-----------------------|----------------------------------
|
--------------------------------------|-----------------------|----------------------------------
|
||||||
cert\_path | String | **Required.** Path to the public key.
|
cert\_path | String | **Deprecated.** Path to the public key.
|
||||||
key\_path | String | **Required.** Path to the private key.
|
key\_path | String | **Deprecated.** Path to the private key.
|
||||||
ca\_path | String | **Required.** Path to the CA certificate file.
|
ca\_path | String | **Deprecated.** Path to the CA certificate file.
|
||||||
ticket\_salt | String | **Optional.** Private key for [CSR auto-signing](06-distributed-monitoring.md#distributed-monitoring-setup-csr-auto-signing). **Required** for a signing master instance.
|
ticket\_salt | String | **Optional.** Private key for [CSR auto-signing](06-distributed-monitoring.md#distributed-monitoring-setup-csr-auto-signing). **Required** for a signing master instance.
|
||||||
crl\_path | String | **Optional.** Path to the CRL file.
|
crl\_path | String | **Optional.** Path to the CRL file.
|
||||||
bind\_host | String | **Optional.** The IP address the api listener should be bound to. Defaults to `0.0.0.0`.
|
bind\_host | String | **Optional.** The IP address the api listener should be bound to. Defaults to `0.0.0.0`.
|
||||||
@ -69,6 +68,20 @@ Configuration Attributes:
|
|||||||
access\_control\_allow\_headers | String | **Optional.** Used in response to a preflight request to indicate which HTTP headers can be used when making the actual request. Defaults to `Authorization`. [(MDN docs)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Access-Control-Allow-Headers)
|
access\_control\_allow\_headers | String | **Optional.** Used in response to a preflight request to indicate which HTTP headers can be used when making the actual request. Defaults to `Authorization`. [(MDN docs)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Access-Control-Allow-Headers)
|
||||||
access\_control\_allow\_methods | String | **Optional.** Used in response to a preflight request to indicate which HTTP methods can be used when making the actual request. Defaults to `GET, POST, PUT, DELETE`. [(MDN docs)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Access-Control-Allow-Methods)
|
access\_control\_allow\_methods | String | **Optional.** Used in response to a preflight request to indicate which HTTP methods can be used when making the actual request. Defaults to `GET, POST, PUT, DELETE`. [(MDN docs)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Access-Control-Allow-Methods)
|
||||||
|
|
||||||
|
The ApiListener type expects its certificate files to be in the following locations:
|
||||||
|
|
||||||
|
Type | Location
|
||||||
|
---------------------|-------------------------------------
|
||||||
|
Private key | `LocalStateDir + "/lib/icinga2/certs/" + NodeName + ".key"`
|
||||||
|
Certificate file | `LocalStateDir + "/lib/icinga2/certs/" + NodeName + ".crt"`
|
||||||
|
CA certificate file | `LocalStateDir + "/lib/icinga2/certs/ca.crt"`
|
||||||
|
|
||||||
|
If the deprecated attributes `cert_path`, `key_path` and/or `ca_path` are specified Icinga 2
|
||||||
|
copies those files to the new location in `LocalStateDir + "/lib/icinga2/certs"` unless the
|
||||||
|
file(s) there are newer.
|
||||||
|
|
||||||
|
Please check the [upgrading chapter](16-upgrading-icinga-2.md#upgrading-to-2-8-certificate-paths) for more details.
|
||||||
|
|
||||||
## ApiUser <a id="objecttype-apiuser"></a>
|
## ApiUser <a id="objecttype-apiuser"></a>
|
||||||
|
|
||||||
ApiUser objects are used for authentication against the [Icinga 2 API](12-icinga2-api.md#icinga2-api-authentication).
|
ApiUser objects are used for authentication against the [Icinga 2 API](12-icinga2-api.md#icinga2-api-authentication).
|
||||||
|
@ -10,19 +10,103 @@ are scheme updates for the IDO database.
|
|||||||
The default certificate path was changed from `/etc/icinga2/pki` to
|
The default certificate path was changed from `/etc/icinga2/pki` to
|
||||||
`/var/lib/icinga2/certs`.
|
`/var/lib/icinga2/certs`.
|
||||||
|
|
||||||
|
Old Path | New Path
|
||||||
|
---------------------------------------------------|---------------------------------------------------
|
||||||
|
`/etc/icinga2/pki/icinga2-client1.localdomain.crt` | `/var/lib/icinga2/certs/icinga2-client1.localdomain.crt`
|
||||||
|
`/etc/icinga2/pki/icinga2-client1.localdomain.key` | `/var/lib/icinga2/certs/icinga2-client1.localdomain.key`
|
||||||
|
`/etc/icinga2/pki/ca.crt` | `/var/lib/icinga2/certs/ca.crt`
|
||||||
|
|
||||||
This applies to Windows clients in the same way: `%ProgramData%\etc\icinga2\pki`
|
This applies to Windows clients in the same way: `%ProgramData%\etc\icinga2\pki`
|
||||||
was moved to `%ProgramData%`\var\lib\icinga2\certs`.
|
was moved to `%ProgramData%\var\lib\icinga2\certs`.
|
||||||
|
|
||||||
|
Old Path | New Path
|
||||||
|
----------------------------------------------------------------|----------------------------------------------------------------
|
||||||
|
`%ProgramData%\etc\icinga2\pki\icinga2-client1.localdomain.crt` | `%ProgramData%\var\lib\icinga2\certs\icinga2-client1.localdomain.crt`
|
||||||
|
`%ProgramData%\etc\icinga2\pki\icinga2-client1.localdomain.key` | `%ProgramData%\var\lib\icinga2\certs\icinga2-client1.localdomain.key`
|
||||||
|
`%ProgramData%\etc\icinga2\pki\ca.crt` | `%ProgramData%\var\lib\icinga2\certs\ca.crt`
|
||||||
|
|
||||||
|
|
||||||
|
> **Note**
|
||||||
|
>
|
||||||
|
> The default expected path for client certificates is `/var/lib/icinga2/certs/ + NodeName + {.crt,.key}`.
|
||||||
|
> The `NodeName` constant is usually the FQDN and certificate common name (CN). Check the [conventions](06-distributed-monitoring.md#distributed-monitoring-conventions)
|
||||||
|
> section inside the Distributed Monitoring chapter.
|
||||||
|
|
||||||
The [setup CLI commands](06-distributed-monitoring.md#distributed-monitoring-setup-master) and the
|
The [setup CLI commands](06-distributed-monitoring.md#distributed-monitoring-setup-master) and the
|
||||||
default [ApiListener configuration](06-distributed-monitoring.md#distributed-monitoring-apilistener)
|
default [ApiListener configuration](06-distributed-monitoring.md#distributed-monitoring-apilistener)
|
||||||
have been adjusted to these paths too.
|
have been adjusted to these paths too.
|
||||||
|
|
||||||
|
The [ApiListener](09-object-types.md#objecttype-apilistener) object attributes `cert_path`, `key_path`
|
||||||
|
and `ca_path` have been deprecated and removed from the example configuration.
|
||||||
|
|
||||||
|
#### Migration Path <a id="upgrading-to-2-8-certificate-paths-migration-path"></a>
|
||||||
|
|
||||||
|
> **Note**
|
||||||
|
>
|
||||||
|
> Icinga 2 automatically migrates the certificates to the new default location if they
|
||||||
|
> are configured and detected in `/etc/icinga2/pki`.
|
||||||
|
|
||||||
|
During startup, the migration kicks in and ensures to copy the certificates to the new
|
||||||
|
location. This will also happen if someone updates the certificate files in `/etc/icinga2/pki`
|
||||||
|
to ensure that the new certificate location always has the latest files.
|
||||||
|
|
||||||
|
This has been implemented in the Icinga 2 binary to ensure it works on both Linux/Unix
|
||||||
|
and the Windows platform.
|
||||||
|
|
||||||
|
If you are not using the built-in CLI commands and setup wizards to deploy the client certificates,
|
||||||
|
please ensure to update your deployment tools/scripts. This mainly affects
|
||||||
|
|
||||||
|
* Puppet modules
|
||||||
|
* Ansible playbooks
|
||||||
|
* Chef cookbooks
|
||||||
|
* Salt recipes
|
||||||
|
* Custom scripts, e.g. Windows Powershell or self-made implementations
|
||||||
|
|
||||||
|
In order to support a smooth migration between versions older than 2.8 and future releases,
|
||||||
|
the built-in certificate migration path is planned to exist as long as the deprecated
|
||||||
|
`ApiListener` object attributes exist.
|
||||||
|
|
||||||
|
You are safe to use the existing configuration paths inside the `api` feature. If you plan your migration,
|
||||||
|
look at the following example taken from the Director Linux deployment script for clients.
|
||||||
|
|
||||||
|
* Ensure that the default certificate path is changed from `/etc/icinga2/pki` to `/var/lib/icinga2/certs`.
|
||||||
|
|
||||||
|
```
|
||||||
|
-ICINGA2_SSL_DIR="${ICINGA2_CONF_DIR}/pki"
|
||||||
|
+ICINGA2_SSL_DIR="${ICINGA2_STATE_DIR}/lib/icinga2/certs"
|
||||||
|
```
|
||||||
|
|
||||||
|
* Remove the ApiListener configuration attributes.
|
||||||
|
|
||||||
|
```
|
||||||
|
object ApiListener "api" {
|
||||||
|
- cert_path = SysconfDir + "/icinga2/pki/${ICINGA2_NODENAME}.crt"
|
||||||
|
- key_path = SysconfDir + "/icinga2/pki/${ICINGA2_NODENAME}.key"
|
||||||
|
- ca_path = SysconfDir + "/icinga2/pki/ca.crt"
|
||||||
|
accept_commands = true
|
||||||
|
accept_config = true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Test the script with a fresh client installation before putting it into production.
|
||||||
|
|
||||||
|
> **Tip**
|
||||||
|
>
|
||||||
|
> Please support module and script developers in their migration. If you find
|
||||||
|
> any project which would require these changes, create an issue or a patchset in a PR
|
||||||
|
> and help them out. Thanks in advance!
|
||||||
|
|
||||||
|
|
||||||
### Removed Bottom Up Client Mode <a id="upgrading-to-2-8-removed-bottom-up-client-mode"></a>
|
### Removed Bottom Up Client Mode <a id="upgrading-to-2-8-removed-bottom-up-client-mode"></a>
|
||||||
|
|
||||||
This client mode was deprecated in 2.6 and was removed in 2.8.
|
This client mode was deprecated in 2.6 and was removed in 2.8.
|
||||||
|
|
||||||
The node CLI command does not provide `list` or `update-config` anymore.
|
The node CLI command does not provide `list` or `update-config` anymore.
|
||||||
|
|
||||||
|
> **Note**
|
||||||
|
>
|
||||||
|
> The old migration guide can be found on [GitHub](https://github.com/Icinga/icinga2/blob/v2.7.0/doc/06-distributed-monitoring.md#bottom-up-migration-to-top-down-).
|
||||||
|
|
||||||
The clients don't need to have a local `conf.d` directory included.
|
The clients don't need to have a local `conf.d` directory included.
|
||||||
The setup wizards for Linux and Windows attempt to disable this by default.
|
The setup wizards for Linux and Windows attempt to disable this by default.
|
||||||
|
|
||||||
@ -31,6 +115,7 @@ You are advised to [migrate](https://github.com/Icinga/icinga2/issues/4798)
|
|||||||
any existing configuration to the "top down" mode with the help of the
|
any existing configuration to the "top down" mode with the help of the
|
||||||
Icinga Director or config management tools such as Puppet, Ansible, etc.
|
Icinga Director or config management tools such as Puppet, Ansible, etc.
|
||||||
|
|
||||||
|
|
||||||
### Removed Classic UI Config Package <a id="upgrading-to-2-8-removed-classicui-config-package"></a>
|
### Removed Classic UI Config Package <a id="upgrading-to-2-8-removed-classicui-config-package"></a>
|
||||||
|
|
||||||
The config meta package `classicui-config` and the configuration files
|
The config meta package `classicui-config` and the configuration files
|
||||||
|
@ -3,9 +3,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
object ApiListener "api" {
|
object ApiListener "api" {
|
||||||
cert_path = LocalStateDir + "/lib/icinga2/certs/" + NodeName + ".crt"
|
//accept_config = false
|
||||||
key_path = LocalStateDir + "/lib/icinga2/certs/" + NodeName + ".key"
|
//accept_commands = false
|
||||||
ca_path = LocalStateDir + "/lib/icinga2/certs/ca.crt"
|
|
||||||
|
|
||||||
ticket_salt = TicketSalt
|
ticket_salt = TicketSalt
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ abstract class Function
|
|||||||
{
|
{
|
||||||
[config] String "name";
|
[config] String "name";
|
||||||
[config] bool side_effect_free;
|
[config] bool side_effect_free;
|
||||||
[config] bool deprecated;
|
[config] bool "deprecated";
|
||||||
[config] Array::Ptr arguments;
|
[config] Array::Ptr arguments;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -39,7 +39,8 @@ enum FieldAttribute
|
|||||||
FARequired = 256,
|
FARequired = 256,
|
||||||
FANavigation = 512,
|
FANavigation = 512,
|
||||||
FANoUserModify = 1024,
|
FANoUserModify = 1024,
|
||||||
FANoUserView = 2048
|
FANoUserView = 2048,
|
||||||
|
FADeprecated = 4096,
|
||||||
};
|
};
|
||||||
|
|
||||||
class Type;
|
class Type;
|
||||||
|
@ -816,6 +816,10 @@ void Utility::CollectPaths(const String& path, std::vector<String>& paths)
|
|||||||
paths.push_back(path);
|
paths.push_back(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copies a source file to a target location.
|
||||||
|
* Caller must ensure that the target's base directory exists and is writable.
|
||||||
|
*/
|
||||||
void Utility::CopyFile(const String& source, const String& target)
|
void Utility::CopyFile(const String& source, const String& target)
|
||||||
{
|
{
|
||||||
std::ifstream ifs(source.CStr(), std::ios::binary);
|
std::ifstream ifs(source.CStr(), std::ios::binary);
|
||||||
|
@ -173,10 +173,7 @@ int NodeSetupCommand::SetupMaster(const boost::program_options::variables_map& v
|
|||||||
fp << "/**\n"
|
fp << "/**\n"
|
||||||
<< " * The API listener is used for distributed monitoring setups.\n"
|
<< " * The API listener is used for distributed monitoring setups.\n"
|
||||||
<< " */\n"
|
<< " */\n"
|
||||||
<< "object ApiListener \"api\" {\n"
|
<< "object ApiListener \"api\" {\n";
|
||||||
<< " cert_path = LocalStateDir + \"/lib/icinga2/certs/\" + NodeName + \".crt\"\n"
|
|
||||||
<< " key_path = LocalStateDir + \"/lib/icinga2/certs/\" + NodeName + \".key\"\n"
|
|
||||||
<< " ca_path = LocalStateDir + \"/lib/icinga2/certs/ca.crt\"\n";
|
|
||||||
|
|
||||||
if (vm.count("listen")) {
|
if (vm.count("listen")) {
|
||||||
std::vector<String> tokens;
|
std::vector<String> tokens;
|
||||||
@ -378,10 +375,7 @@ int NodeSetupCommand::SetupNode(const boost::program_options::variables_map& vm,
|
|||||||
fp << "/**\n"
|
fp << "/**\n"
|
||||||
<< " * The API listener is used for distributed monitoring setups.\n"
|
<< " * The API listener is used for distributed monitoring setups.\n"
|
||||||
<< " */\n"
|
<< " */\n"
|
||||||
<< "object ApiListener \"api\" {\n"
|
<< "object ApiListener \"api\" {\n";
|
||||||
<< " cert_path = LocalStateDir + \"/lib/icinga2/certs/\" + NodeName + \".crt\"\n"
|
|
||||||
<< " key_path = LocalStateDir + \"/lib/icinga2/certs/\" + NodeName + \".key\"\n"
|
|
||||||
<< " ca_path = LocalStateDir + \"/lib/icinga2/certs/ca.crt\"\n";
|
|
||||||
|
|
||||||
if (vm.count("listen")) {
|
if (vm.count("listen")) {
|
||||||
std::vector<String> tokens;
|
std::vector<String> tokens;
|
||||||
|
@ -472,10 +472,6 @@ wizard_ticket:
|
|||||||
<< " * The API listener is used for distributed monitoring setups.\n"
|
<< " * The API listener is used for distributed monitoring setups.\n"
|
||||||
<< " */\n"
|
<< " */\n"
|
||||||
<< "object ApiListener \"api\" {\n"
|
<< "object ApiListener \"api\" {\n"
|
||||||
<< " cert_path = LocalStateDir + \"/lib/icinga2/certs/\" + NodeName + \".crt\"\n"
|
|
||||||
<< " key_path = LocalStateDir + \"/lib/icinga2/certs/\" + NodeName + \".key\"\n"
|
|
||||||
<< " ca_path = LocalStateDir + \"/lib/icinga2/certs/ca.crt\"\n"
|
|
||||||
<< "\n"
|
|
||||||
<< " accept_config = " << acceptConfig << "\n"
|
<< " accept_config = " << acceptConfig << "\n"
|
||||||
<< " accept_commands = " << acceptCommands << "\n";
|
<< " accept_commands = " << acceptCommands << "\n";
|
||||||
|
|
||||||
@ -629,10 +625,7 @@ int NodeWizardCommand::MasterSetup(void) const
|
|||||||
fp << "/**\n"
|
fp << "/**\n"
|
||||||
<< " * The API listener is used for distributed monitoring setups.\n"
|
<< " * The API listener is used for distributed monitoring setups.\n"
|
||||||
<< " */\n"
|
<< " */\n"
|
||||||
<< "object ApiListener \"api\" {\n"
|
<< "object ApiListener \"api\" {\n";
|
||||||
<< " cert_path = LocalStateDir + \"/lib/icinga2/certs/\" + NodeName + \".crt\"\n"
|
|
||||||
<< " key_path = LocalStateDir + \"/lib/icinga2/certs/\" + NodeName + \".key\"\n"
|
|
||||||
<< " ca_path = LocalStateDir + \"/lib/icinga2/certs/ca.crt\"\n";
|
|
||||||
|
|
||||||
if (!bindHost.IsEmpty())
|
if (!bindHost.IsEmpty())
|
||||||
fp << " bind_host = \"" << bindHost << "\"\n";
|
fp << " bind_host = \"" << bindHost << "\"\n";
|
||||||
|
@ -75,6 +75,34 @@ String ApiListener::GetCertificateRequestsDir(void)
|
|||||||
return Application::GetLocalStateDir() + "/lib/icinga2/certificate-requests/";
|
return Application::GetLocalStateDir() + "/lib/icinga2/certificate-requests/";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String ApiListener::GetDefaultCertPath(void)
|
||||||
|
{
|
||||||
|
return GetCertsDir() + "/" + ScriptGlobal::Get("NodeName") + ".crt";
|
||||||
|
}
|
||||||
|
|
||||||
|
String ApiListener::GetDefaultKeyPath(void)
|
||||||
|
{
|
||||||
|
return GetCertsDir() + "/" + ScriptGlobal::Get("NodeName") + ".key";
|
||||||
|
}
|
||||||
|
|
||||||
|
String ApiListener::GetDefaultCaPath(void)
|
||||||
|
{
|
||||||
|
return GetCertsDir() + "/ca.crt";
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApiListener::CopyCertificateFile(const String& oldCertPath, const String& newCertPath)
|
||||||
|
{
|
||||||
|
struct stat st1, st2;
|
||||||
|
|
||||||
|
if (!oldCertPath.IsEmpty() && stat(oldCertPath.CStr(), &st1) >= 0 && (stat(newCertPath.CStr(), &st2) < 0 || st1.st_mtime > st2.st_mtime)) {
|
||||||
|
Log(LogWarning, "ApiListener")
|
||||||
|
<< "Copying '" << oldCertPath << "' certificate file to '" << newCertPath << "'";
|
||||||
|
|
||||||
|
Utility::MkDirP(Utility::DirName(newCertPath), 0700);
|
||||||
|
Utility::CopyFile(oldCertPath, newCertPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ApiListener::OnConfigLoaded(void)
|
void ApiListener::OnConfigLoaded(void)
|
||||||
{
|
{
|
||||||
if (m_Instance)
|
if (m_Instance)
|
||||||
@ -82,20 +110,37 @@ void ApiListener::OnConfigLoaded(void)
|
|||||||
|
|
||||||
m_Instance = this;
|
m_Instance = this;
|
||||||
|
|
||||||
|
String defaultCertPath = GetDefaultCertPath();
|
||||||
|
String defaultKeyPath = GetDefaultKeyPath();
|
||||||
|
String defaultCaPath = GetDefaultCaPath();
|
||||||
|
|
||||||
|
/* Migrate certificate location < 2.8 to the new default path. */
|
||||||
|
String oldCertPath = GetCertPath();
|
||||||
|
String oldKeyPath = GetKeyPath();
|
||||||
|
String oldCaPath = GetCaPath();
|
||||||
|
|
||||||
|
CopyCertificateFile(oldCertPath, defaultCertPath);
|
||||||
|
CopyCertificateFile(oldKeyPath, defaultKeyPath);
|
||||||
|
CopyCertificateFile(oldCaPath, defaultCaPath);
|
||||||
|
|
||||||
|
if (!oldCertPath.IsEmpty() && !oldKeyPath.IsEmpty() && !oldCaPath.IsEmpty()) {
|
||||||
|
Log(LogWarning, "ApiListener", "Please read the upgrading documentation for v2.8: https://www.icinga.com/docs/icinga2/latest/doc/16-upgrading-icinga-2/");
|
||||||
|
}
|
||||||
|
|
||||||
/* set up SSL context */
|
/* set up SSL context */
|
||||||
boost::shared_ptr<X509> cert;
|
boost::shared_ptr<X509> cert;
|
||||||
try {
|
try {
|
||||||
cert = GetX509Certificate(GetCertPath());
|
cert = GetX509Certificate(defaultCertPath);
|
||||||
} catch (const std::exception&) {
|
} catch (const std::exception&) {
|
||||||
BOOST_THROW_EXCEPTION(ScriptError("Cannot get certificate from cert path: '"
|
BOOST_THROW_EXCEPTION(ScriptError("Cannot get certificate from cert path: '"
|
||||||
+ GetCertPath() + "'.", GetDebugInfo()));
|
+ defaultCertPath + "'.", GetDebugInfo()));
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
SetIdentity(GetCertificateCN(cert));
|
SetIdentity(GetCertificateCN(cert));
|
||||||
} catch (const std::exception&) {
|
} catch (const std::exception&) {
|
||||||
BOOST_THROW_EXCEPTION(ScriptError("Cannot get certificate common name from cert path: '"
|
BOOST_THROW_EXCEPTION(ScriptError("Cannot get certificate common name from cert path: '"
|
||||||
+ GetCertPath() + "'.", GetDebugInfo()));
|
+ defaultCertPath + "'.", GetDebugInfo()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Log(LogInformation, "ApiListener")
|
Log(LogInformation, "ApiListener")
|
||||||
@ -109,10 +154,10 @@ void ApiListener::UpdateSSLContext(void)
|
|||||||
boost::shared_ptr<SSL_CTX> context;
|
boost::shared_ptr<SSL_CTX> context;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
context = MakeSSLContext(GetCertPath(), GetKeyPath(), GetCaPath());
|
context = MakeSSLContext(GetDefaultCertPath(), GetDefaultKeyPath(), GetDefaultCaPath());
|
||||||
} catch (const std::exception&) {
|
} catch (const std::exception&) {
|
||||||
BOOST_THROW_EXCEPTION(ScriptError("Cannot make SSL context for cert path: '"
|
BOOST_THROW_EXCEPTION(ScriptError("Cannot make SSL context for cert path: '"
|
||||||
+ GetCertPath() + "' key path: '" + GetKeyPath() + "' ca path: '" + GetCaPath() + "'.", GetDebugInfo()));
|
+ GetDefaultCertPath() + "' key path: '" + GetDefaultKeyPath() + "' ca path: '" + GetDefaultCaPath() + "'.", GetDebugInfo()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!GetCrlPath().IsEmpty()) {
|
if (!GetCrlPath().IsEmpty()) {
|
||||||
@ -420,7 +465,7 @@ void ApiListener::NewClientHandlerInternal(const Socket::Ptr& client, const Stri
|
|||||||
identity = GetCertificateCN(cert);
|
identity = GetCertificateCN(cert);
|
||||||
} catch (const std::exception&) {
|
} catch (const std::exception&) {
|
||||||
Log(LogCritical, "ApiListener")
|
Log(LogCritical, "ApiListener")
|
||||||
<< "Cannot get certificate common name from cert path: '" << GetCertPath() << "'.";
|
<< "Cannot get certificate common name from cert path: '" << GetDefaultCertPath() << "'.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,6 +104,10 @@ public:
|
|||||||
static bool IsHACluster(void);
|
static bool IsHACluster(void);
|
||||||
static String GetFromZoneName(const Zone::Ptr& fromZone);
|
static String GetFromZoneName(const Zone::Ptr& fromZone);
|
||||||
|
|
||||||
|
static String GetDefaultCertPath(void);
|
||||||
|
static String GetDefaultKeyPath(void);
|
||||||
|
static String GetDefaultCaPath(void);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void OnConfigLoaded(void) override;
|
virtual void OnConfigLoaded(void) override;
|
||||||
virtual void OnAllConfigLoaded(void) override;
|
virtual void OnAllConfigLoaded(void) override;
|
||||||
@ -157,6 +161,8 @@ private:
|
|||||||
static void LogGlobHandler(std::vector<int>& files, const String& file);
|
static void LogGlobHandler(std::vector<int>& files, const String& file);
|
||||||
void ReplayLog(const JsonRpcConnection::Ptr& client);
|
void ReplayLog(const JsonRpcConnection::Ptr& client);
|
||||||
|
|
||||||
|
static void CopyCertificateFile(const String& oldCertPath, const String& newCertPath);
|
||||||
|
|
||||||
/* filesync */
|
/* filesync */
|
||||||
static ConfigDirInformation LoadConfigDir(const String& dir);
|
static ConfigDirInformation LoadConfigDir(const String& dir);
|
||||||
static Dictionary::Ptr MergeConfigUpdate(const ConfigDirInformation& config);
|
static Dictionary::Ptr MergeConfigUpdate(const ConfigDirInformation& config);
|
||||||
|
@ -28,9 +28,9 @@ namespace icinga
|
|||||||
|
|
||||||
class ApiListener : ConfigObject
|
class ApiListener : ConfigObject
|
||||||
{
|
{
|
||||||
[config, required] String cert_path;
|
[config, deprecated] String cert_path;
|
||||||
[config, required] String key_path;
|
[config, deprecated] String key_path;
|
||||||
[config, required] String ca_path;
|
[config, deprecated] String ca_path;
|
||||||
[config] String crl_path;
|
[config] String crl_path;
|
||||||
[config] String cipher_list {
|
[config] String cipher_list {
|
||||||
default {{{ return "ALL:!LOW:!WEAK:!MEDIUM:!EXP:!NULL"; }}}
|
default {{{ return "ALL:!LOW:!WEAK:!MEDIUM:!EXP:!NULL"; }}}
|
||||||
|
@ -56,7 +56,7 @@ Value RequestCertificateHandler(const MessageOrigin::Ptr& origin, const Dictiona
|
|||||||
cert = StringToCertificate(certText);
|
cert = StringToCertificate(certText);
|
||||||
|
|
||||||
ApiListener::Ptr listener = ApiListener::GetInstance();
|
ApiListener::Ptr listener = ApiListener::GetInstance();
|
||||||
boost::shared_ptr<X509> cacert = GetX509Certificate(listener->GetCaPath());
|
boost::shared_ptr<X509> cacert = GetX509Certificate(listener->GetDefaultCaPath());
|
||||||
|
|
||||||
String cn = GetCertificateCN(cert);
|
String cn = GetCertificateCN(cert);
|
||||||
|
|
||||||
@ -183,7 +183,7 @@ Value RequestCertificateHandler(const MessageOrigin::Ptr& origin, const Dictiona
|
|||||||
* a certificate it wouldn't be able to use to connect to us anyway) */
|
* a certificate it wouldn't be able to use to connect to us anyway) */
|
||||||
if (!VerifyCertificate(cacert, newcert)) {
|
if (!VerifyCertificate(cacert, newcert)) {
|
||||||
Log(LogWarning, "JsonRpcConnection")
|
Log(LogWarning, "JsonRpcConnection")
|
||||||
<< "The CA in '" << listener->GetCaPath() << "' does not match the CA which Icinga uses "
|
<< "The CA in '" << listener->GetDefaultCaPath() << "' does not match the CA which Icinga uses "
|
||||||
<< "for its own cluster connections. This is most likely a configuration problem.";
|
<< "for its own cluster connections. This is most likely a configuration problem.";
|
||||||
goto delayed_request;
|
goto delayed_request;
|
||||||
}
|
}
|
||||||
@ -285,7 +285,7 @@ Value UpdateCertificateHandler(const MessageOrigin::Ptr& origin, const Dictionar
|
|||||||
if (!listener)
|
if (!listener)
|
||||||
return Empty;
|
return Empty;
|
||||||
|
|
||||||
boost::shared_ptr<X509> oldCert = GetX509Certificate(listener->GetCertPath());
|
boost::shared_ptr<X509> oldCert = GetX509Certificate(listener->GetDefaultCertPath());
|
||||||
boost::shared_ptr<X509> newCert = StringToCertificate(cert);
|
boost::shared_ptr<X509> newCert = StringToCertificate(cert);
|
||||||
|
|
||||||
String cn = GetCertificateCN(newCert);
|
String cn = GetCertificateCN(newCert);
|
||||||
@ -328,7 +328,7 @@ Value UpdateCertificateHandler(const MessageOrigin::Ptr& origin, const Dictionar
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Update CA certificate. */
|
/* Update CA certificate. */
|
||||||
String caPath = listener->GetCaPath();
|
String caPath = listener->GetDefaultCaPath();
|
||||||
|
|
||||||
Log(LogInformation, "JsonRpcConnection")
|
Log(LogInformation, "JsonRpcConnection")
|
||||||
<< "Updating CA certificate in '" << caPath << "'.";
|
<< "Updating CA certificate in '" << caPath << "'.";
|
||||||
@ -350,7 +350,7 @@ Value UpdateCertificateHandler(const MessageOrigin::Ptr& origin, const Dictionar
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Update signed certificate. */
|
/* Update signed certificate. */
|
||||||
String certPath = listener->GetCertPath();
|
String certPath = listener->GetDefaultCertPath();
|
||||||
|
|
||||||
Log(LogInformation, "JsonRpcConnection")
|
Log(LogInformation, "JsonRpcConnection")
|
||||||
<< "Updating client certificate for CN '" << cn << "' in '" << certPath << "'.";
|
<< "Updating client certificate for CN '" << cn << "' in '" << certPath << "'.";
|
||||||
|
@ -149,6 +149,7 @@ bool TypeQueryHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& requ
|
|||||||
attributeInfo->Set("navigation", static_cast<bool>(field.Attributes & FANavigation));
|
attributeInfo->Set("navigation", static_cast<bool>(field.Attributes & FANavigation));
|
||||||
attributeInfo->Set("no_user_modify", static_cast<bool>(field.Attributes & FANoUserModify));
|
attributeInfo->Set("no_user_modify", static_cast<bool>(field.Attributes & FANoUserModify));
|
||||||
attributeInfo->Set("no_user_view", static_cast<bool>(field.Attributes & FANoUserView));
|
attributeInfo->Set("no_user_view", static_cast<bool>(field.Attributes & FANoUserView));
|
||||||
|
attributeInfo->Set("deprecated", static_cast<bool>(field.Attributes & FADeprecated));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,6 +147,7 @@ protected { yylval->num = FAGetProtected | FASetProtected; return T_FIELD_ATTR
|
|||||||
no_storage { yylval->num = FANoStorage; return T_FIELD_ATTRIBUTE; }
|
no_storage { yylval->num = FANoStorage; return T_FIELD_ATTRIBUTE; }
|
||||||
no_user_modify { yylval->num = FANoUserModify; return T_FIELD_ATTRIBUTE; }
|
no_user_modify { yylval->num = FANoUserModify; return T_FIELD_ATTRIBUTE; }
|
||||||
no_user_view { yylval->num = FANoUserView; return T_FIELD_ATTRIBUTE; }
|
no_user_view { yylval->num = FANoUserView; return T_FIELD_ATTRIBUTE; }
|
||||||
|
deprecated { yylval->num = FADeprecated; return T_FIELD_ATTRIBUTE; }
|
||||||
navigation { return T_NAVIGATION; }
|
navigation { return T_NAVIGATION; }
|
||||||
validator { return T_VALIDATOR; }
|
validator { return T_VALIDATOR; }
|
||||||
required { return T_REQUIRED; }
|
required { return T_REQUIRED; }
|
||||||
|
@ -510,6 +510,15 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&)
|
|||||||
m_Impl << "\t\t" << "BOOST_THROW_EXCEPTION(ValidationError(dynamic_cast<ConfigObject *>(this), boost::assign::list_of(\"" << field.Name << "\"), \"Attribute must not be empty.\"));" << std::endl << std::endl;
|
m_Impl << "\t\t" << "BOOST_THROW_EXCEPTION(ValidationError(dynamic_cast<ConfigObject *>(this), boost::assign::list_of(\"" << field.Name << "\"), \"Attribute must not be empty.\"));" << std::endl << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (field.Attributes & FADeprecated) {
|
||||||
|
if (field.Type.GetRealType().find("::Ptr") != std::string::npos)
|
||||||
|
m_Impl << "\t" << "if (" << argName << ")" << std::endl;
|
||||||
|
else
|
||||||
|
m_Impl << "\t" << "if (!" << argName << ".IsEmpty())" << std::endl;
|
||||||
|
|
||||||
|
m_Impl << "\t\t" << "Log(LogWarning, \"" << klass.Name << "\") << \"Attribute '" << field.Name << "' for object '\" << dynamic_cast<ConfigObject *>(this)->GetName() << \"' of type '\" << dynamic_cast<ConfigObject *>(this)->GetReflectionType()->GetName() << \"' is deprecated and should not be used.\";" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
if (field.Type.ArrayRank > 0) {
|
if (field.Type.ArrayRank > 0) {
|
||||||
m_Impl << "\t" << "if (avalue) {" << std::endl
|
m_Impl << "\t" << "if (avalue) {" << std::endl
|
||||||
<< "\t\t" << "ObjectLock olock(avalue);" << std::endl
|
<< "\t\t" << "ObjectLock olock(avalue);" << std::endl
|
||||||
|
@ -72,7 +72,8 @@ enum FieldAttribute
|
|||||||
FARequired = 256,
|
FARequired = 256,
|
||||||
FANavigation = 512,
|
FANavigation = 512,
|
||||||
FANoUserModify = 1024,
|
FANoUserModify = 1024,
|
||||||
FANoUserView = 2048
|
FANoUserView = 2048,
|
||||||
|
FADeprecated = 4096
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FieldType
|
struct FieldType
|
||||||
|
Loading…
x
Reference in New Issue
Block a user