From 2b55c5995d616045f70e50bd572968715b1e460f Mon Sep 17 00:00:00 2001 From: Jilks Smith Date: Thu, 28 Nov 2024 03:19:35 +0300 Subject: [PATCH] Add mts/tls docs Signed-off-by: Jilks Smith --- docs/computations.md | 100 ++++++++++++++++++++++++++++++++++++++++++- docs/img/ui/tls.png | Bin 0 -> 27907 bytes 2 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 docs/img/ui/tls.png diff --git a/docs/computations.md b/docs/computations.md index 124a517..20f65f4 100644 --- a/docs/computations.md +++ b/docs/computations.md @@ -212,7 +212,7 @@ LINE='"quiet console=null rootfstype=ramfs"' ./build/cocos-cli sevsnpmeasure --mode snp --vcpus 4 --vcpu-type EPYC-v4 --ovmf $OVMF_CODE --kernel $KERNEL --initrd $INITRD --append "$LINE" ``` -Once caluated this can be replaced on the attestation policy file using: +Once calculated this can be replaced on the attestation policy file using: ```shell ./build/cocos-cli backend measurement @@ -236,6 +236,104 @@ This can also be edited into the downloaded attestation policy as below: ./build/cocos-cli backend hostdata ``` +#### mTLS/TLS configuration + +To ensure secure communications, prevent unauthorized access, data interception, and man-in-the-middle (MITM) attacks in Prism and COCOS Transport Layer Security (TLS) and Mutual TLS (mTLS) features can be enabled as described above. +TLS/ mTLS configurations ensures that: + +- Algorithms and Datasets uploaded to Agent and Results downloaded from agent through the CLI remains private. +- The integrity of data is preserved (i.e., no tampering). +- The Agent's identity is verified through a server certificate either issued by a trusted Certificate Authority (CA) or self-signed + +For TLS connection: + +1. The CLI connects to the Agent. +2. Agent shows its certificate to the CLI. +3. CLI verifies that certificate. +4. CLI sends data to the Agent in an encrypted communication channel. + +![tls_illustration](./img/ui/tls.png) + +For MTLS connection: + +1. CLI connects to the Agent. +2. Agent shows its certificate to the CLI. +3. CLI verifies that certificate. +4. CLI shows its certificate to the Agent. +5. Agent verifies that certificate and allows the CLI to send requests. +6. CLI sends data to the Agent in an encrypted communication channel. + +![mtls_illustration info](./img/ui/mtls.png) + +To generate your own certificates for configuring either of the modes: + +```bash +CLIENT_ORG_UNIT="example_prism_cli" +SERVER_ORG_UNIT="example_prism_agent" +WORK_DIR="" + +# 1. Generate CA's private key and self-signed certificate +openssl req -x509 -sha256 -newkey rsa:4096 -days 365 -nodes -keyout "$WORK_DIR/ca-key.pem" -out "$WORK_DIR/ca-cert.pem" -subj "/CN=Example_Selfsigned_ca/O=ExampleOrg/OU=example_ca/emailAddress=info@example.com" + +echo "CA's self-signed certificate" +openssl x509 -in "$WORK_DIR/ca-cert.pem" -noout -text + +# 2. Generate server's private key and certificate signing request (CSR) +openssl req -newkey rsa:4096 -sha256 -nodes -keyout "$WORK_DIR/server-key.pem" -out "$WORK_DIR/server-req.pem" -subj "/CN=Example_Selfsigned/O=ExampleOrg/OU=$SERVER_ORG_UNIT/emailAddress=info@example.com" + +# 3. Use CA's private key to sign web server's CSR and get back the signed certificate +openssl x509 -req -in "$WORK_DIR/server-req.pem" -days 365 -CA "$WORK_DIR/ca-cert.pem" -CAkey "$WORK_DIR/ca-key.pem" -CAcreateserial -out "$WORK_DIR/server-cert.pem" -extfile "$WORK_DIR/ext/server-ext.cnf" -extensions v3_req + +echo "Server's signed certificate" +openssl x509 -in "$WORK_DIR/server-cert.pem" -noout -text + +# For mTLS +# 4. Generate client's private key and certificate signing request (CSR) +openssl req -newkey rsa:4096 -sha256 -nodes -keyout "$WORK_DIR/client-key.pem" -out "$WORK_DIR/client-req.pem" -subj "/CN=Example_Selfsigned/O=ExampleOrg/OU=$CLIENT_ORG_UNIT/emailAddress=info@example.com" + +# 5. Use CA's private key to sign client's CSR and get back the signed certificate +openssl x509 -req -in "$WORK_DIR/client-req.pem" -days 365 -CA "$WORK_DIR/ca-cert.pem" -CAkey "$WORK_DIR/ca-key.pem" -CAcreateserial -out "$WORK_DIR/client-cert.pem" -extfile "$WORK_DIR/ext/client-ext.cnf" -extensions v3_req + +echo "Client's signed certificate" +openssl x509 -in "$WORK_DIR/client-cert.pem" -noout -text +``` + +Example extension file: + +```text +[req] +req_extensions = v3_req +distinguished_name = req_distinguished_name + +[req_distinguished_name] + +[v3_req] +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +subjectAltName = @alt_names + +[alt_names] +DNS.1 = localhost +DNS.2 = + +# IP addresses +IP.1 = +``` + +To connect cli to agent, we need to configure the env variables on cli. + +```bash + +export AGENT_GRPC_URL=: +export AGENT_GRPC_CLIENT_CERT= +export AGENT_GRPC_CLIENT_KEY= +export AGENT_GRPC_SERVER_CA_CERTS= +``` + +After this configuration you can connect to agent normally using cli and perform [operations](https://docs.cocos.ultraviolet.rs/cli/) on cli such as algo/data upload etc. + +It is important to note that the Agent is the server and cli the client. Therefore, upload server generated cert, key on the UI as shown above and configure certificates generated for client on CLI. + ## Retrieve Computations In order to get all computations: diff --git a/docs/img/ui/tls.png b/docs/img/ui/tls.png new file mode 100644 index 0000000000000000000000000000000000000000..a2e4c7fbb4c9f8cbe998dc41a5e7b81186f833b3 GIT binary patch literal 27907 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

sYes?X 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 literal 0 HcmV?d00001