Skip to content
Merged
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 @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
### Removed

- Removed the unused experimental `ccf.host.triggerSubprocess()` JS API
- Removed ACME client and support for ACME-endorsed interfaces (#7414).

### Fixed

Expand Down
8 changes: 0 additions & 8 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1146,14 +1146,6 @@ if(BUILD_TESTS)
NAME election_test PYTHON_SCRIPT ${CMAKE_SOURCE_DIR}/tests/election.py
)

if(LONG_TESTS)
add_e2e_test(
NAME acme_endorsement_test
PYTHON_SCRIPT ${CMAKE_SOURCE_DIR}/tests/acme_endorsement.py
LABEL ACME
)
endif()

add_piccolo_test(
NAME pi_ls
PYTHON_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/tests/infra/piccolo_driver.py
Expand Down
7 changes: 0 additions & 7 deletions doc/audit/builtin_maps.rst
Original file line number Diff line number Diff line change
Expand Up @@ -264,13 +264,6 @@ PEM identity of previous service, which this service recovered from.

**Value** Previous :term:`Service Identity`, represented as a PEM-encoded JSON string.

``service.acme_certificates``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

**Key** Name of a network interface (string).

**Value** Endorsed TLS certificate for the interface, represented as a PEM-encoded string.

``proposals``
~~~~~~~~~~~~~

Expand Down
83 changes: 1 addition & 82 deletions doc/host_config_schema/cchost_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,27 +102,9 @@
"type": "string",
"enum": ["Node", "Service", "ACME", "Unsecured"],
"default": "Service",
"description": "The type of endorsement for the TLS certificate used in client sessions. If the endorsement is not available, client sessions will be terminated, before the TLS handshake is complete. 'Node' means self-signed, 'Service' means service-endorsed, 'ACME' means an ACME-capable CA, 'Unsecured' means unencrypted traffic and no endorsement authority"
},
"acme_configuration": {
"type": "string",
"description": "Name of the ACME configuration defined in the network.acme.configurations section"
"description": "The type of endorsement for the TLS certificate used in client sessions. If the endorsement is not available, client sessions will be terminated, before the TLS handshake is complete. 'Node' means self-signed, 'Service' means service-endorsed, 'ACME' is deprecated, 'Unsecured' means unencrypted traffic and no endorsement authority"
}
},
"oneOf": [
{
"required": ["acme_configuration"]
},
{
"not": {
"properties": {
"authority": {
"const": "ACME"
}
}
}
}
],
"required": ["authority"],
"additionalProperties": false
},
Expand Down Expand Up @@ -157,69 +139,6 @@
"required": ["bind_address"]
},
"description": "Interfaces to listen on for incoming client TLS connections, as a dictionary from unique interface name to RPC interface information"
},
"acme": {
"type": "object",
"properties": {
"configurations": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"ca_certs": {
"type": "array",
"items": {
"type": "string"
},
"default": [],
"description": "Root certificate(s) of the CA to connect to in PEM format (for TLS connections to the CA, e.g. Let's Encrypt's ISRG Root X1)"
},
"directory_url": {
"type": "string",
"description": "URL of the ACME server's directory"
},
"service_dns_name": {
"type": "string",
"description": "DNS name of the service we represent"
},
"alternative_names": {
"type": "array",
"items": {
"type": "string"
},
"default": [],
"description": "Alternative names for the service we represent (X509 SANs)"
},
"contact": {
"type": "array",
"items": {
"type": "string"
},
"default": [],
"description": "Contact addresses (see RFC8555 7.3, e.g. mailto:john@example.com)"
},
"terms_of_service_agreed": {
"type": "boolean",
"default": false,
"description": "Indication that the user/operator is aware of the latest terms and conditions for the CA"
},
"challenge_type": {
"type": "string",
"default": "http-01",
"description": "Type of the ACME challenge (usually http-01; others are supported but require a custom challenge handler)"
},
"challenge_server_interface": {
"type": "string",
"description": "Name of the interface for the http-01 challenge frontend to listen on"
}
},
"description": "ACME Configurations",
"additionalProperties": false
}
}
},
"description": "Configuration for the ACME client(s) to obtain globally valid TLS certificates, e.g. from Let's Encrypt",
"additionalProperties": false
}
},
"description": "This section includes configuration for the interfaces a node listens on (for both client and node-to-node communications)",
Expand Down
65 changes: 0 additions & 65 deletions doc/operations/certificates.rst
Original file line number Diff line number Diff line change
Expand Up @@ -78,68 +78,3 @@ The procedure that operators and members should follow is summarised in the foll
section Service <br> Certificate
Initial Validity Period (24h default): done, 01-01/00:00, 1d
Post Service Open Validity Period : 01-01/15:00, 5d


ACME-endorsed TLS certificates
------------------------------

Unendorsed, self-signed (CA) service certificates are a complication for clients as they need to be given a copy of the certificate before they can establish TLS connections to the service, or the service certificate is permanently installed in their trust store. To alleviate this, CCF provides an `ACME <https://en.wikipedia.org/wiki/Automatic_Certificate_Management_Environment>`_ client, which is used to obtain TLS certificates that are endorsed by external certificate authorities. For instance, the `Let's Encrypt <https://letsencrypt.org/>`_ CA is endorsed by a root certificate that is pre-installed on most current operating systems, which means that clients usually have all required certificates to establish TLS connections without further configuration, if the service certificate is endorsed by Let's Encrypt. CCF handles the creation and renewal of ACME certificates, but it requires some configuration:

1. Get a globally reachable DNS name for your CCF network, e.g. ``my-ccf.example.com``, which resolves to the address of at least one node in the network. Multiple nodes or a load balancer address are fine too.

2. ACME `http-01 <https://letsencrypt.org/docs/challenge-types/>`_ challenges require a challenge server to be reachable on port 80 (non-negotiable). To be able to bind to that port, the executable may need to be given special permission, e.g. by running ``sudo setcap CAP_NET_BIND_SERVICE=+eip <start node command>``. Alternatively, port 80 can be redirected to a non-privileged port that the executable may bind to without special permission.

3. Each interface defined in the configuration file can be given the name of an ACME configuration to use. The settings of each ACME configuration are defined in ``network.acme`` :doc:`configuration entry </operations/configuration>`. Note that this information is required by *all* nodes as they might have to renew the certificate(s) later. Further, an additional interface for the challenge server is required.

.. note:: ACME-endorsed interfaces *cannot* be used by new nodes to join a service, since they are not endorsed by the service certificate. Therefore, at least one interface must be configured to use "Service" as an endorsement authority.

The various options are as follows:

.. code-block:: python

"network": {
"rpc_interfaces": {
# ... ,
"acme_endorsed_interface": {
# ... ,
"endorsement": {
# ... ,
"acme_configuration": "my-acme-cfg"
}
},
"acme_challenge_server_interface": {
"bind_address": "...:80",
"endorsement": {
"authority": "Unsecured"
},
"accepted_endpoints": [ "/.well-known/acme-challenge/.*" ]
# ...
}
},
"acme": {
"configurations": {
"my-acme-cfg": {
"ca_certs": [ "-----BEGIN CERTIFICATE-----\nMIIBg ..." ],
"directory_url": "https://...",
"service_dns_name": "my-ccf.example.com",
"alternative_names": [ "www.my-ccf.example.com", ... ],
"contact": ["mailto:john@example.com"],
"terms_of_service_agreed": true,
"challenge_type": "http-01",
"challenge_server_interface": "acme_challenge_server_interface"
}
}
}
}


- ``ca_certs``: CCF will need to establish HTTPS connections with the CA, but does not come with root certificates by default and therefore will fail to establish connections. This setting is populated with one or more such certificates; e.g. for Let's Encrypt this would be their ISRG Root X1 certificate (see `here <https://letsencrypt.org/certificates/>`_) in PEM format.
- ``directory_url``: This is the main entry point for the ACME protocol. For Let's Encrypt's `staging environment <https://letsencrypt.org/docs/staging-environment/>`_, this is ``https://acme-staging-v02.api.letsencrypt.org/directory``; minus the ``-staging`` for their production environment).
- ``service_dns_name``: The DNS name for the network from step 1.
- ``alternative_names``: Alternative names for the service we represent (X509 SANs).
- ``contact``: A list of contact addresses, usually e-mail addresses, which must be prefixed with ``mailto:``. These contacts may receive notifications about service changes, e.g. certificate revocation or expiry.
- ``terms_of_service_agreed``: A Boolean confirming that the operator accepts the terms of service for the CA. RFC8555 requires this to be set explicitly by the operator.
- ``challenge_type``: Currently only `http-01 <https://letsencrypt.org/docs/challenge-types/>`_ is supported.
- ``challenge_server_interface``: Name of the interface that the ACME challenge server listens on. For http-01 challenges in production, this interface must be exposed publicly on port 80.

4. CCF nodes periodically check for certificate expiry and trigger renewal when 66% of the validity period has elapsed. The resulting certificates are stored in the ``ccf.gov.service.acme_certificates`` table and upon an update to this table, nodes will automatically install the corresponding certificate on their interfaces. If necessary, renewal can also be triggered manually by submitting a ``trigger_acme_refresh`` governance proposal.
3 changes: 0 additions & 3 deletions doc/schemas/node_openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -200,9 +200,6 @@
},
"Endorsement": {
"properties": {
"acme_configuration": {
"$ref": "#/components/schemas/string"
},
"authority": {
"$ref": "#/components/schemas/Authority"
}
Expand Down
50 changes: 0 additions & 50 deletions include/ccf/node/acme_subsystem_interface.h

This file was deleted.

72 changes: 0 additions & 72 deletions include/ccf/service/acme_client_config.h

This file was deleted.

Loading