Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
### Changed

- When the `fetch_recent_snapshot` behaviour is enabled by the node config, the Joiner will now prefer the peer's snapshot over _any_ local snapshot, regardless of version (#7314).
- The snapshot-serving endpoints required for `fetch_recent_snapshot` behaviour are now disabled-by-default to avoid public DoS requests. They should be enabled on a per-interface basis by adding `"enabled_operator_features": ["SnapshotRead"]` to the interface's configuration, on an interface with local visibility used for node-to-node join requests (#7440).

## [6.0.16]

Expand Down
8 changes: 8 additions & 0 deletions doc/host_config_schema/cchost_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,14 @@
}
},
"additionalProperties": false
},
"enabled_operator_features": {
"type": "array",
"items": {
"enum": ["SnapshotRead"],
"type": "string"
},
"description": "An array of features which should be enabled on this interface, providing access to endpoints with specific security or performance constraints. The only feature currently supported is 'SnapshotRead', which gates access to the /snapshot/* endpoints used to fetch snapshots directly from nodes. Since these require disk IO and produce large responses, this feature should not be enabled on interfaces with public access, and instead restricted to interfaces with local connectivity for node-to-node and operator access."
}
},
"required": ["bind_address"]
Expand Down
20 changes: 19 additions & 1 deletion doc/schemas/gov_openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,15 @@
"bind_address": {
"type": "string"
},
"enabled_operator_features": {
"items": {
"enum": [
"SnapshotRead"
],
"type": "string"
},
"type": "array"
},
"endorsement": {
"properties": {
"acme_configuration": {
Expand Down Expand Up @@ -662,6 +671,15 @@
"bind_address": {
"type": "string"
},
"enabled_operator_features": {
"items": {
"enum": [
"SnapshotRead"
],
"type": "string"
},
"type": "array"
},
"endorsement": {
"properties": {
"acme_configuration": {
Expand Down Expand Up @@ -1376,7 +1394,7 @@
"info": {
"description": "This API is used to submit and query proposals which affect CCF's public governance tables.",
"title": "CCF Governance API",
"version": "4.7.4"
"version": "4.7.5"
},
"openapi": "3.0.0",
"paths": {
Expand Down
15 changes: 15 additions & 0 deletions doc/schemas/node_openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,9 @@
"bind_address": {
"$ref": "#/components/schemas/string"
},
"enabled_operator_features": {
"$ref": "#/components/schemas/OperatorFeature_set"
},
"endorsement": {
"$ref": "#/components/schemas/Endorsement"
},
Expand Down Expand Up @@ -589,6 +592,18 @@
],
"type": "string"
},
"OperatorFeature": {
"enum": [
"SnapshotRead"
],
"type": "string"
},
"OperatorFeature_set": {
"items": {
"$ref": "#/components/schemas/OperatorFeature"
},
"type": "array"
},
"ParserConfiguration": {
"properties": {
"initial_window_size": {
Expand Down
11 changes: 11 additions & 0 deletions include/ccf/endpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "ccf/http_consts.h"
#include "ccf/rest_verb.h"
#include "ccf/service/map.h"
#include "ccf/service/operator_feature.h"

#include <string>
#include <utility>
Expand Down Expand Up @@ -229,6 +230,8 @@ namespace ccf::endpoints
* @see ccf::any_cert_auth_policy
*/
AuthnPolicies authn_policies;

std::set<OperatorFeature> required_operator_features;
};

using EndpointDefinitionPtr = std::shared_ptr<const EndpointDefinition>;
Expand Down Expand Up @@ -308,6 +311,14 @@ namespace ccf::endpoints
*/
Endpoint& set_openapi_hidden(bool hidden);

/** Add an opt-in feature which this endpoint uses. The endpoint will only
* be available on interfaces which have opted in to enabling all required
* features.
*
* @return This Endpoint for further modification
*/
Endpoint& require_operator_feature(OperatorFeature feature);

/** Sets the JSON schema that the request parameters must comply with.
*
* @param j Request parameters JSON schema
Expand Down
8 changes: 8 additions & 0 deletions include/ccf/service/node_info_network.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "ccf/ds/nonstd.h"
#include "ccf/http_configuration.h"
#include "ccf/service/acme_client_config.h"
#include "ccf/service/operator_feature.h"

#include <string>

Expand Down Expand Up @@ -115,6 +116,11 @@ namespace ccf
/// Timeout for forwarded RPC calls (in milliseconds)
std::optional<size_t> forwarding_timeout_ms = std::nullopt;

/// Features enabled for this interface. Any endpoint with required
/// features will be inaccessible (on this interface) if this does not
/// contain those features.
std::set<ccf::endpoints::OperatorFeature> enabled_operator_features;

struct Redirections
{
RedirectionResolverConfig to_primary;
Expand All @@ -136,6 +142,7 @@ namespace ccf
http_configuration == other.http_configuration &&
accepted_endpoints == other.accepted_endpoints &&
forwarding_timeout_ms == other.forwarding_timeout_ms &&
enabled_operator_features == other.enabled_operator_features &&
redirections == other.redirections;
}
};
Expand Down Expand Up @@ -183,6 +190,7 @@ namespace ccf
http_configuration,
accepted_endpoints,
forwarding_timeout_ms,
enabled_operator_features,
redirections);
DECLARE_JSON_TYPE(NodeInfoNetwork_v2::ACME);
DECLARE_JSON_REQUIRED_FIELDS(NodeInfoNetwork_v2::ACME, configurations);
Expand Down
19 changes: 19 additions & 0 deletions include/ccf/service/operator_feature.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the Apache 2.0 License.
#pragma once

#include "ccf/ds/json.h"

namespace ccf::endpoints
{
enum class OperatorFeature : uint8_t
{
SnapshotRead,
};

DECLARE_JSON_ENUM(
OperatorFeature,
{
{OperatorFeature::SnapshotRead, "SnapshotRead"},
});
}
6 changes: 4 additions & 2 deletions src/ds/pending_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@ struct PendingIO
*/
static void clear_empty(std::vector<PendingIO<T>>& list)
{
std::remove_if(
list.begin(), list.end(), [](PendingIO<T>& p) { return p.clear; });
list.erase(
std::remove_if(
list.begin(), list.end(), [](PendingIO<T>& p) { return p.clear; }),
list.end());
}
};
6 changes: 6 additions & 0 deletions src/endpoints/endpoint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ namespace ccf::endpoints
return *this;
}

Endpoint& Endpoint::require_operator_feature(OperatorFeature feature)
{
required_operator_features.insert(feature);
return *this;
}

Endpoint& Endpoint::set_params_schema(const nlohmann::json& j)
{
params_schema = j;
Expand Down
5 changes: 5 additions & 0 deletions src/node/node_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -1872,6 +1872,11 @@ namespace ccf
consensus->can_replicate());
}

std::optional<ccf::NodeId> get_primary() override
{
return consensus->primary();
}

bool is_in_initialised_state() const override
{
return sm.check(NodeStartupState::initialized);
Expand Down
Loading