diff --git a/doc/09-object-types.md b/doc/09-object-types.md
index 4945b18ec..4c73a9057 100644
--- a/doc/09-object-types.md
+++ b/doc/09-object-types.md
@@ -61,6 +61,7 @@ Configuration Attributes:
bind\_port | Number | **Optional.** The port the api listener should be bound to. Defaults to `5665`.
accept\_config | Boolean | **Optional.** Accept zone configuration. Defaults to `false`.
accept\_commands | Boolean | **Optional.** Accept remote commands. Defaults to `false`.
+ max\_anonymous\_clients | Number | **Optional.** Limit the number of anonymous client connections (not configured endpoints and signing requests).
cipher\_list | String | **Optional.** Cipher list that is allowed. For a list of available ciphers run `openssl ciphers`. Defaults to `ALL:!LOW:!WEAK:!MEDIUM:!EXP:!NULL`.
tls\_protocolmin | String | **Optional.** Minimum TLS protocol version. Must be one of `TLSv1`, `TLSv1.1` or `TLSv1.2`. Defaults to `TLSv1`.
access\_control\_allow\_origin | Array | **Optional.** Specifies an array of origin URLs that may access the API. [(MDN docs)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Access-Control-Allow-Origin)
diff --git a/doc/16-upgrading-icinga-2.md b/doc/16-upgrading-icinga-2.md
index 266e073f5..9c8d79a23 100644
--- a/doc/16-upgrading-icinga-2.md
+++ b/doc/16-upgrading-icinga-2.md
@@ -49,6 +49,14 @@ New [Icinga constants](17-language-reference.md#icinga-constants) have been adde
The keywords `namespace` and `using` are now [reserved](17-language-reference.md#reserved-keywords) for the namespace functionality provided
with v2.10. Read more about how it works [here](17-language-reference.md#namespaces).
+### Configuration: ApiListener
+
+Anonymous JSON-RPC connections in the cluster can now be configured with `max_anonymous_clients`
+attribute.
+The corresponding REST API results from `/v1/status/ApiListener` in `json_rpc` have been renamed
+from `clients` to `anonymous_clients` to better reflect their purpose. Authenticated clients
+are counted as connected endpoints. A similar change is there for the performance data metrics.
+
### API: schedule-downtime Action
The attribute `child_options` was previously accepting 0,1,2 for specific child downtime settings.
diff --git a/lib/remote/apilistener.cpp b/lib/remote/apilistener.cpp
index 0750f7892..425ca6cc8 100644
--- a/lib/remote/apilistener.cpp
+++ b/lib/remote/apilistener.cpp
@@ -566,7 +566,9 @@ void ApiListener::NewClientHandlerInternal(const Socket::Ptr& client, const Stri
m_SyncQueue.Enqueue(std::bind(&ApiListener::SyncClient, this, aclient, endpoint, needSync));
} else {
if (!AddAnonymousClient(aclient)) {
- Log(LogNotice, "ApiListener", "Ignoring anonymous JSON-RPC connection. Max connections exceeded.");
+ Log(LogNotice, "ApiListener")
+ << "Ignoring anonymous JSON-RPC connection " << conninfo
+ << ". Max connections (" << GetMaxAnonymousClients() << ") exceeded.";
aclient->Disconnect();
}
}
@@ -1315,7 +1317,7 @@ std::pair ApiListener::GetStatus()
}
/* connection stats */
- size_t jsonRpcClients = GetAnonymousClients().size();
+ size_t jsonRpcAnonymousClients = GetAnonymousClients().size();
size_t httpClients = GetHttpClients().size();
size_t workQueueItems = JsonRpcConnection::GetWorkQueueLength();
size_t workQueueCount = JsonRpcConnection::GetWorkQueueCount();
@@ -1336,7 +1338,7 @@ std::pair ApiListener::GetStatus()
{ "zones", connectedZones },
{ "json_rpc", new Dictionary({
- { "clients", jsonRpcClients },
+ { "anonymous_clients", jsonRpcAnonymousClients },
{ "work_queue_items", workQueueItems },
{ "work_queue_count", workQueueCount },
{ "sync_queue_items", syncQueueItems },
@@ -1356,7 +1358,7 @@ std::pair ApiListener::GetStatus()
perfdata->Set("num_conn_endpoints", Convert::ToDouble(allConnectedEndpoints->GetLength()));
perfdata->Set("num_not_conn_endpoints", Convert::ToDouble(allNotConnectedEndpoints->GetLength()));
- perfdata->Set("num_json_rpc_clients", jsonRpcClients);
+ perfdata->Set("num_json_rpc_anonymous_clients", jsonRpcAnonymousClients);
perfdata->Set("num_http_clients", httpClients);
perfdata->Set("num_json_rpc_work_queue_items", workQueueItems);
perfdata->Set("num_json_rpc_work_queue_count", workQueueCount);
@@ -1384,7 +1386,8 @@ double ApiListener::CalculateZoneLag(const Endpoint::Ptr& endpoint)
bool ApiListener::AddAnonymousClient(const JsonRpcConnection::Ptr& aclient)
{
boost::mutex::scoped_lock lock(m_AnonymousClientsLock);
- if (m_AnonymousClients.size() > 100)
+
+ if (GetMaxAnonymousClients() >= 0 && m_AnonymousClients.size() + 1 > GetMaxAnonymousClients())
return false;
m_AnonymousClients.insert(aclient);
diff --git a/lib/remote/apilistener.ti b/lib/remote/apilistener.ti
index e4227a6d1..b98dae1cb 100644
--- a/lib/remote/apilistener.ti
+++ b/lib/remote/apilistener.ti
@@ -50,6 +50,9 @@ class ApiListener : ConfigObject
[config] bool accept_config;
[config] bool accept_commands;
+ [config] int max_anonymous_clients {
+ default {{{ return -1; }}}
+ };
[config] String ticket_salt;