opentelemetry-cpp/docs/testing-with-ssl.md

352 lines
10 KiB
Markdown

# 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 :
```