File: testing-with-ssl.md

package info (click to toggle)
opentelemetry-cpp 1.19.0-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 8,744 kB
  • sloc: cpp: 79,029; sh: 1,640; makefile: 43; python: 31
file content (351 lines) | stat: -rw-r--r-- 10,509 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
# Testing with SSL/TLS

## Required software

The opentelemetry-collector
[documentation](https://opentelemetry.io/docs/collector/configuration/#setting-up-certificates)
uses [cfssl](https://github.com/cloudflare/cfssl),
so we are using cfssl as well here.

In addition, install `openssl`, which provides tooling for testing.

## Generating CERT

### Generating CA CERT

First, write a CA request file in json, named `ca_csr.json`

It should contains the following data:

```console
shell> cat ca_csr.json
{
  "hosts": ["localhost", "127.0.0.1"],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "O": "OpenTelemetry CA Example"
    }
  ]
}
```

Then, generate a CA certificate:

```console
shell> cfssl genkey -initca ca_csr.json | cfssljson -bare ca
2022/12/13 16:42:57 [INFO] generate received request
2022/12/13 16:42:57 [INFO] received CSR
2022/12/13 16:42:57 [INFO] generating key: rsa-2048
2022/12/13 16:42:57 [INFO] encoded CSR
2022/12/13 16:42:57 [INFO] signed certificate with serial number 78705522450145914781445058194934247010984259280
```

This will create three files, `ca.csr`, `ca.pem` and `ca-key.pem`

Congratulation, "OpenTelemetry CA Example" is now a CA certification
authority, with signing keys.

### Generating Client CERT

Second, write a certificate request file in json, named `client_csr.json`,
for the opentelemetry-cpp client.

It should contains the following data:

```console
shell> cat client_csr.json
{
  "hosts": ["localhost", "127.0.0.1"],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "O": "OpenTelemetry Client Example"
    }
  ]
}
```

Note that the name ("OpenTelemetry Client Example") should be different
from the CA authority name ("OpenTelemetry CA Example"),
otherwise the client certificate will be self-signed, and rejected later in SSL/TLS.

Now, use the CA certificate generated in the previous step
to create and sign a new client certificate.

```console
shell> cfssl gencert -ca ca.pem -ca-key ca-key.pem client_csr.json | cfssljson -bare client_cert
2022/12/13 16:50:18 [INFO] generate received request
2022/12/13 16:50:18 [INFO] received CSR
2022/12/13 16:50:18 [INFO] generating key: rsa-2048
2022/12/13 16:50:18 [INFO] encoded CSR
2022/12/13 16:50:18 [INFO] signed certificate with serial number 579932794730090029542135367576037344135399122179
```

This will create three files, `client_cert.csr`, `client_cert.pem` and `client_cert-key.pem`

### Generating Server CERT

Third and likewise, write a certificate request file in json, named `server_csr.json`,
for the opentelemetry server (the opentelemetry-collector)

It should contains the following data:

```console
shell> cat server_csr.json
{
  "hosts": ["localhost", "127.0.0.1"],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "O": "OpenTelemetry Server Example"
    }
  ]
}
```

Likewise, use a different name from the CA authority name.

Use the CA certificate to create and sign a new server certificate.

```console
shell> cfssl gencert -ca ca.pem -ca-key ca-key.pem server_csr.json | cfssljson -bare server_cert
2022/12/13 17:04:40 [INFO] generate received request
2022/12/13 17:04:40 [INFO] received CSR
2022/12/13 17:04:40 [INFO] generating key: rsa-2048
2022/12/13 17:04:40 [INFO] encoded CSR
2022/12/13 17:04:40 [INFO] signed certificate with serial number 332420451189450993545238745169293824985460186638
```

This will create three files, `server_cert.csr`, `server_cert.pem` and `server_cert-key.pem`

### Verify certificates

Verify the certificates generated, using `openssl`:

```console
shell> openssl verify -CAfile ca.pem server_cert.pem client_cert.pem
server_cert.pem: OK
client_cert.pem: OK
```

Useful commands, to inspect certificates if needed (output not shown here)

```console
shell> openssl x509 -in ca.pem -text
```

```console
shell> openssl x509 -in client_cert.pem -text
```

```console
shell> openssl x509 -in server_cert.pem -text
```

## OpenTelemetry SSL clients

### Simulated client, for testing

Use `openssl` to simulate an opentelemetry-cpp client connecting to port 4318:

```console
shell> openssl s_client -connect localhost:4318 -CAfile ca.pem -cert client_cert.pem -key client_cert-key.pem
```

### OTLP HTTP Client

Use the example `example_otlp_http` client to connect to an OTLP HTTP server:

```console
shell> export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://localhost:4318/v1/traces
shell> export OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE=ca.pem
shell> export OTEL_EXPORTER_OTLP_TRACES_CLIENT_CERTIFICATE=client_cert.pem
shell> export OTEL_EXPORTER_OTLP_TRACES_CLIENT_KEY=client_cert-key.pem
shell> example_otlp_http
```

## OpenTelemetry SSL servers

### Simulated server, for testing

Use `openssl` to simulate an opentelemetry-collector process serving port 4318:

```console
shell> openssl s_server -accept 4318 -CAfile ca.pem -cert server_cert.pem -key server_cert-key.pem
Using default temp DH parameters
ACCEPT
```

This command does not return,
the server waits for SSL connections (Use CTRL-C to quit).

### OTLP HTTP Server

To use a server that:

- implements OTLP HTTP
- supports SSL

use the opentelemetry-collector,
configured to use SSL/TLS for receivers:

```console
shell> cat otel-collector-config-ssl.yaml
receivers:
  otlp:
    protocols:
      http:
        tls:
          ca_file: ca.pem
          cert_file: server_cert.pem
          key_file: server_cert-key.pem
...
```

For example:

```console
shell> /path/to/bin/otelcorecol_linux_amd64 --config /path/to/otel-config-ssl.yaml
```

Note, the `example/http/http_example` can not be used (it understands neither SSL
nor OTLP HTTP).

## Testing SSL on the wire

### Fake client with fake server

This configuration tests nothing in opentelemetry,
but is useful to understand what a nominal SSL communication between a
client and a server should look like.

### Real client with fake server

In this configuration, we can test that the opentelemetry-cpp
client actually sends SSL traffic on the wire.

### Fake client with real server

In this configuration, we can test that the opentelemetry-collector
server actually accepts SSL traffic on the wire.
This can be used to verify the client keys are working properly.

## Full integration test with SSL

Start an opentelemetry-collector, configured to use SSL/TLS.

```console
shell> /path/to/bin/otelcorecol_linux_amd64 --config /path/to/otel-config-ssl.yaml
...
2022-12-13T18:03:21.140+0100    info    otlpreceiver@v0.66.0/otlp.go:89 Starting HTTP server    {"kind": "receiver", "name": "otlp", "pipeline": "metrics", "endpoint": "0.0.0.0:4318"}
2022-12-13T18:03:21.141+0100    info    service/pipelines.go:106        Receiver started.       {"kind": "receiver", "name": "otlp", "pipeline": "metrics"}
2022-12-13T18:03:21.141+0100    info    service/pipelines.go:102        Receiver is starting... {"kind": "receiver", "name": "otlp", "pipeline": "traces"}
2022-12-13T18:03:21.141+0100    info    service/pipelines.go:106        Receiver started.       {"kind": "receiver", "name": "otlp", "pipeline": "traces"}
2022-12-13T18:03:21.141+0100    info    service/service.go:105  Everything is ready. Begin running and processing data.
```

Start the example_otlp_http client, configured to use SSL/TLS.

```console
shell> export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://localhost:4318/v1/traces
shell> export OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE=ca.pem
shell> export OTEL_EXPORTER_OTLP_TRACES_CLIENT_CERTIFICATE=client_cert.pem
shell> export OTEL_EXPORTER_OTLP_TRACES_CLIENT_KEY=client_cert-key.pem
shell> example_otlp_http
```

The opentelemetry-collector process receives data, as seen in logs:

```console
2022-12-13T18:05:36.611+0100 info TracesExporter {"kind": "exporter", "data_type": "traces", "name": "logging", "#spans": 4}
2022-12-13T18:05:36.611+0100 info ResourceSpans #0
Resource SchemaURL:
Resource attributes:
     -> service.name: Str(unknown_service)
     -> telemetry.sdk.version: Str(1.8.1)
     -> telemetry.sdk.name: Str(opentelemetry)
     -> telemetry.sdk.language: Str(cpp)
ScopeSpans #0
ScopeSpans SchemaURL:
InstrumentationScope foo_library 1.8.1
Span #0
    Trace ID       : ebbd7e13e9cdfb05f0ca9ed4b0cdf6c0
    Parent ID      : 042ae76539c294c6
    ID             : c87b21d63c505bae
    Name           : f1
    Kind           : Internal
    Start time     : 2022-12-13 17:05:36.482165738 +0000 UTC
    End time       : 2022-12-13 17:05:36.482170938 +0000 UTC
    Status code    : Unset
    Status message :
ResourceSpans #1
Resource SchemaURL:
Resource attributes:
     -> service.name: Str(unknown_service)
     -> telemetry.sdk.version: Str(1.8.1)
     -> telemetry.sdk.name: Str(opentelemetry)
     -> telemetry.sdk.language: Str(cpp)
ScopeSpans #0
ScopeSpans SchemaURL:
InstrumentationScope foo_library 1.8.1
Span #0
    Trace ID       : ebbd7e13e9cdfb05f0ca9ed4b0cdf6c0
    Parent ID      : 042ae76539c294c6
    ID             : 801227b9ee6d3b03
    Name           : f1
    Kind           : Internal
    Start time     : 2022-12-13 17:05:36.487636362 +0000 UTC
    End time       : 2022-12-13 17:05:36.487641983 +0000 UTC
    Status code    : Unset
    Status message :
ResourceSpans #2
Resource SchemaURL:
Resource attributes:
     -> service.name: Str(unknown_service)
     -> telemetry.sdk.version: Str(1.8.1)
     -> telemetry.sdk.name: Str(opentelemetry)
     -> telemetry.sdk.language: Str(cpp)
ScopeSpans #0
ScopeSpans SchemaURL:
InstrumentationScope foo_library 1.8.1
Span #0
    Trace ID       : ebbd7e13e9cdfb05f0ca9ed4b0cdf6c0
    Parent ID      : 6489f2ada8d95da0
    ID             : 042ae76539c294c6
    Name           : f2
    Kind           : Internal
    Start time     : 2022-12-13 17:05:36.482154908 +0000 UTC
    End time       : 2022-12-13 17:05:36.488641122 +0000 UTC
    Status code    : Unset
    Status message :
ResourceSpans #3
Resource SchemaURL:
Resource attributes:
     -> service.name: Str(unknown_service)
     -> telemetry.sdk.version: Str(1.8.1)
     -> telemetry.sdk.name: Str(opentelemetry)
     -> telemetry.sdk.language: Str(cpp)
ScopeSpans #0
ScopeSpans SchemaURL:
InstrumentationScope foo_library 1.8.1
Span #0
    Trace ID       : ebbd7e13e9cdfb05f0ca9ed4b0cdf6c0
    Parent ID      :
    ID             : 6489f2ada8d95da0
    Name           : library
    Kind           : Internal
    Start time     : 2022-12-13 17:05:36.482136052 +0000 UTC
    End time       : 2022-12-13 17:05:36.489263125 +0000 UTC
    Status code    : Unset
    Status message :
```