Skip to content

Commit 64aa42e

Browse files
committed
doc: Add a readme to the cln-grpc proxy
These are some common questions that come up from time to time, so let's make sure we address them.
1 parent 02f9c2d commit 64aa42e

File tree

1 file changed

+144
-0
lines changed

1 file changed

+144
-0
lines changed

plugins/grpc-plugin/README.md

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# GRPC plugin for Core Lightning
2+
3+
This plugin exposes the JSON-RPC interface through grpc over the
4+
network. It listens on a configurable port, authenticates clients
5+
using mTLS certificates, and will forward any request to the JSON-RPC
6+
interface, performing translations from protobuf to JSON and back.
7+
8+
9+
## Getting started
10+
11+
The plugin only runs when `lightningd` is configured with the option
12+
`--grpc-port`. Upon starting the plugin generates a number of files,
13+
if they don't already exist:
14+
15+
- `ca.pem` and `ca-key.pem`: These are the certificate and private
16+
key for your own certificate authority. The plugin will only accept
17+
incoming connections using certificates that are signed by theis
18+
CA.
19+
- `server.pem` and `server-key.pem`: this is the identity
20+
(certificate and private key) used by the plugin to authenticate
21+
itself. It is signed by the CA, and the client will verify its
22+
identity.
23+
- `client.pem` and `client-key.pem`: this is an example identity that
24+
can be used by a client to connect to the plugin, and issue
25+
requests. It is also signed by the CA.
26+
27+
These files are generated with sane defaults, however you can generate
28+
custom certificates should you require some changes (see below for
29+
details).
30+
31+
## Connecting
32+
33+
The client needs a valid mTLS identity in order to connect to the
34+
plugin, so copy over the `ca.pem`, `client.pem` and `client-key.pem`
35+
files from the node. The RPC interface is described in the [protobuf
36+
file][proto], and we'll first need to generate language specific
37+
bindings.
38+
39+
In this example we walk through the steps for python, however they are
40+
mostly the same for other languages.
41+
42+
We start by downloading the dependencies and `protoc` compiler:
43+
44+
```bash
45+
pip install grpcio-tools
46+
```
47+
48+
Next we generate the bindings in the current directory:
49+
50+
```bash
51+
python -m grpc_tools.protoc \
52+
-I path/to/cln-grpc/proto \
53+
path/to/cln-grpc/proto/node.proto \
54+
--python_out=. \
55+
--grpc_python_out=. \
56+
--experimental_allow_proto3_optional
57+
```
58+
59+
This will generate two files in the current directory:
60+
61+
- `node_pb2.py`: the description of the protobuf messages we'll be
62+
exchanging with the server.
63+
- `node_pb2_grpc.py`: the service and method stubs representing the
64+
server-side methods as local objects and associated methods.
65+
66+
And finally we can use the generated stubs and mTLS identity to
67+
connect to the node:
68+
69+
```python
70+
from pathlib import Path
71+
from node_pb2_grpc import NodeStub
72+
import node_pb2
73+
74+
p = Path(".")
75+
cert_path = p / "client.pem"
76+
key_path = p / "client-key.pem"
77+
ca_cert_path = p / "ca.pem"
78+
79+
creds = grpc.ssl_channel_credentials(
80+
root_certificates=ca_cert_path.open('rb').read(),
81+
private_key=key_path.open('rb').read(),
82+
certificate_chain=cert_path.open('rb').read()
83+
)
84+
85+
channel = grpc.secure_channel(
86+
f"localhost:{grpc_port}",
87+
creds,
88+
options=(('grpc.ssl_target_name_override', 'cln'),)
89+
)
90+
stub = NodeStub(channel)
91+
92+
print(stub.Getinfo(node_pb2.GetinfoRequest()))
93+
```
94+
95+
In this example we first local the client identity, as well as the CA
96+
certificate so we can verify the server's identity against it. We then
97+
create a `creds` instance using those details. Next we open a secure
98+
channel, i.e., a channel over TLS with verification of identities.
99+
100+
Notice that we override the expected SSL name with `cln`. This is
101+
required because the plugin does not know the domain under which it
102+
will be reachable, and will therefore use `cln` as a standin. See
103+
custom certificate generation for how this could be changed.
104+
105+
We then use the channel to instantiate the `NodeStub` representing the
106+
service and its methods, so we can finally call the `Getinfo` method
107+
with default arguments.
108+
109+
## Generating custom certificates
110+
111+
The automatically generated mTLS certificate will not know about
112+
potential domains that it'll be served under, and will chose a number
113+
of other parameters by default. If you'd like to generate a server
114+
certificate with a custom domain you can use the following:
115+
116+
117+
```bash
118+
openssl genrsa -out server-key.pem 2048
119+
```
120+
121+
This generates the private key. Next we create a Certificate Signature Request (CSR) that we can then process using our CA identity:
122+
123+
```bash
124+
openssl req -key server-key.pem -new -out server.csr
125+
```
126+
127+
You will be asked a number of questions, the most important of which
128+
is the _Common Name_, which you should set to the domain name you'll
129+
be serving the interface under. Next we can generate the actual
130+
certificate by processing the request with the CA identity:
131+
132+
```bash
133+
openssl x509 -req -CA ca.pem -CAkey ca-key.pem \
134+
-in server.csr \
135+
-out server.pem \
136+
-days 365 -CAcreateserial
137+
```
138+
139+
This will finally create the `server.pem` file, signed by the CA,
140+
allowing you to access the node through its real domain name. You can
141+
now move `server.pem` and `server-key.pem` into the lightning
142+
directory, and they should be picked up during the start.
143+
144+
[proto]: https://github.com/ElementsProject/lightning/blob/master/cln-grpc/proto/node.proto

0 commit comments

Comments
 (0)