/trusted-certificate-issuer

Trusted Certificate Service (TCS) is a K8s service to protect signing keys using Intel's SGX technology. K8s CSR and cert-manager CR APIs are both supported. TCS also contains integration samples for Istio service mesh and Key Management Reference Application (KMRA).

Primary LanguageGoApache License 2.0Apache-2.0

Trusted Certificate Service for Kubernetes Platform

Overview

Trusted Certificate Service (TCS) is a Kubernetes certificate signing solution that uses the security capabilities provided by Intel® Software Guard Extensions (Intel® SGX). The signing key is stored and used inside the Intel SGX enclave(s) and is never stored in clear anywhere in the system. TCS is implemented as a cert-manager external issuer by providing support for both cert-manager and kubernetes certificate signing APIs.

Getting started

All the examples in this page are using self-signed CA certificates. If you are looking for more advanced use cases (e.g., Istio integration) please check the sample use cases.

Prerequisites

Prerequisites for building and running Trusted Certificate Service:

  • Kubernetes cluster with one or more nodes with Intel® SGX supported hardware
  • Intel® SGX device plugin for Kubernetes
  • Intel® SGX AESM daemon
  • cert-manager. The cmctl is also used later in the examples so you may want to install it also.
  • Linux kernel version 5.11 or later on the host (in tree Intel SGX driver)
  • git, or similar tool, to obtain the source code
  • Docker, or similar tool, to build container images
  • Container registry (local or remote)

Installing with Helm

If you want to use Helm to install TCS see the document here.

Installing with source code

This section covers how to obtain the source code, build and install it.

  1. Getting the source code
git clone https://github.com/intel/trusted-certificate-issuer.git
  1. Build and push the container image

Choose a container registry to push the generated image using REGISTRY make variable. The registry should be reachable from the Kubernetes cluster.

NOTE: By default, the enclave signing is done using a private key auto-generated by the TCS issuer. In case, if you want to integrate your own signing tool, modify/replace the enclave-config/sign-enclave.sh script accordingly before building the docker image. Refer to Intel(R) SGX SDK developer reference for more details about enclave signing.

$ cd trusted-certificate-issuer
$ export REGISTRY="localhost:5000" # docker registry to push the container image
$ make docker-build
$ make docker-push
  1. Deploy custom resource definitions (CRDs)
# set the KUBECONFIG based on your configuration
export KUBECONFIG="$HOME/.kube/config"
make install # Install CRDs
  1. Make the deployment
make deploy

By default, tcs-issuer namespace is used for the deployment.

# Ensure that the pod is running state
$ kubectl get po -n tcs-issuer
NAME                              READY   STATUS    RESTARTS   AGE
tcs-controller-5dd5c46b44-4nz9f   1/1     Running   0          30m

Create an Issuer

Once the deployment is up and running, you are ready to provision TCS issuer(s) using either a namespace-scoped TCIssuer or a cluster-scoped TCSClusterIssuer resource.

The example below creates a TCS issuer named my-ca for sandbox namespace:

kubectl create ns sandbox
cat <<EOF |kubectl create -f -
apiVersion: tcs.intel.com/v1alpha1
kind: TCSIssuer
metadata:
    name: my-ca
    namespace: sandbox
spec:
    secretName: my-ca-cert
EOF

Successful deployment looks like this:

$ kubectl get tcsissuers -n sandbox
NAME    AGE    READY   REASON      MESSAGE
my-ca   2m     True    Reconcile   Success

$ kubectl get secret my-ca-cert -n sandbox
NAME                  TYPE                                  DATA   AGE
my-ca-cert            kubernetes.io/tls                     2      3h14m

The above issuer creates and stores it's private key inside the Intel SGX enclave and the root certificate is saved as a Kubernetes Secret with name specified with spec.secretName, under the issuer's namespace.

Typically the issuer secret (my-ca-cert in our case) contains both the certificate and the private key. But in the Trusted Certificate Service case, the private key is empty since they key is stored and used inside a Intel SGX enclave. You can verify the empty private key in the secret with the following command:

kubectl get secrets -n sandbox my-ca-cert -o jsonpath='{.data.tls\.key}'

drawing

Figure 1: Trusted Certificate Install

  1. The TCSIssuer is created.
  2. This automatically creates the my-ca-cert secret. The tls.key field is blank because the private key is actually created and stored within a Intel SGX enclave.

Below is a demo of the install process.

Create certificates

Creating and signing certificates can be done by using cert-manager Certificate or Kubernetes CertificateSigningRequest APIs.

Using cert-manager Certificate

This example shows how to request X509 certificate signed by the Trusted Certificate Service using cert-manger Certificate API. Create a cert-manager Certificate object and set the spec.issuerRef to TCSIssuer(or TCSClusterIssuer).

cat <<EOF |kubectl create -f -
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: my-certificate
  namespace: sandbox
spec:
  # The secret name to store the signed certificate
  secretName: demo-cert-tls
  # Common Name
  commonName: intel.sgx.demo
  # Ensure the issuerRef is set to the right issuer
  issuerRef:
    group: tcs.intel.com # TCS issuer API group
    kind: TCSIssuer      # Configured issuer type
    name: my-ca          # Configured issuer name
EOF

The cert-manager creates a corresponding CertificateRequest for the Certificate above. One has to approve the CertificateRequest so that the TCS controller can sign the request in the next reconcile loop.

$ kubectl get certificaterequest -n sandbox
NAME                   APPROVED   DENIED   READY   ISSUER   REQUESTOR                                         AGE
my-certificate-nljcz   False               False   my-ca    system:serviceaccount:cert-manager:cert-manager   1m

Privileged user needs to approve the CertificateRequest with the cert-manager's cmctl utility:

$ cmctl approve my-certificate-nljcz -n sandbox

Check if the certificate is exported to the secret referenced in the spec.secretName.

$ kubectl get certificates,secret -n sandbox
NAME                                         READY   SECRET          AGE
certificate.cert-manager.io/my-certificate   True    demo-cert-tls   2m1s

NAME                         TYPE                                  DATA   AGE
secret/default-token-69dv6   kubernetes.io/service-account-token   3      3h15m
secret/demo-cert-tls         kubernetes.io/tls                     2      2m1s
secret/my-ca-cert            kubernetes.io/tls                     2      3h14m

drawing

Figure 2: Trusted Certificate Issuer with cert-manager

  1. The TCSIssuer is created.
  2. This automatically creates the my-ca-cert secret.
  3. A user creates a Certificate object specifying to use the TCS Issuer.
  4. cert-manager automatically creates a CertificateRequests object.
  5. A user approves the CertificateRequests object.
  6. The TCS Controller then takes the request and signs the certificate inside the Intel SGX enclave using the private key stored within that enclave.
  7. The signed certificate is then copied into the demo-cert-tls secret that was specified in the original Certificate object.
  8. Finally, that same signed certificate is copied back into the CertificateRequests object.

Below is a demo of this working with cert-manager.

Using Kubernetes CSR

This example shows how to request an X509 certificate signed by the Trusted Certificate Service using Kubernetes CSR.

First, generate a PEM encoded private key (privkey.pem) and certificate signing request (csr.pem) using openssl tool:

$ openssl req -new -nodes -newkey rsa:3072 -keyout privkey.pem -out ./csr.pem -subj "/O=Foo Company/CN=foo.bar.com"

Create a Kubernetes CertificateSigningRequest using the csr (csr.pem) generated above. The spec.signerName field must refer to the TCS issuer we configured earlier in the form of <issuer-type>.<issuer-group>/<issuer-namespace>.<issuer-name>. In this example the signer name is tcsissuer.tcs.intel.com/sandbox.my-ca.

Note: the issuer namespace in the case of tcsclusterissuer is the namespace of the Trusted Certificate Service.

cat <<EOF |kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: test-csr
spec:
  groups:
  - system:authenticated
  request: $(cat csr.pem | base64 | tr -d '\n')
  signerName: tcsissuer.tcs.intel.com/sandbox.my-ca
  usages:
  - client auth
EOF

Now the test-csr is the in pending state waiting for approval.

$ kubectl get certificatesigningrequests
NAME       AGE   SIGNERNAME                              REQUESTOR          CONDITION
test-csr   46s   tcsissuer.tcs.intel.com/sandbox.my-ca   kubernetes-admin   Pending

Privileged user needs to approve the test-csr with the following command:

# Approve the CSR so the TCS controller generates the certificate
kubectl certificate approve test-csr

Once the request is approved, the Trusted Certificate Service signs it. At this point the CSR contains the requested certificate signed by the CA using the private key stored inside the Intel SGX enclave.

You can examine the CSR with the following command:

$ kubectl describe csr

Name:         test-csr
Labels:       <none>
Annotations:  kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"certificates.k8s.io/v1","kind":"CertificateSigningRequest","metadata":{"annotations":{},"name":"test-csr"},"spec":{"groups":["system:authenticated"],"request":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJRGNUQ0NBZGtDQVFBd0xERVVNQklHQTFVRUNnd0xSbTl2SUVOdmJXRndibmt4RkRBU0JnTlZCQU1NQzJadgpieTVpWVhJdVkyOXRNSUlCb2pBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVk4QU1JSUJpZ0tDQVlFQTZhNzkvTmZLCmdrYzQ5dXd6TVFUajBwZzhuZjZ3VU5tcmNVaG5IUDNhUitDYjZKcE0wOVF3RHBmblI2VU13ejZFVy9RSis3WVQKMndLUFJTRVZqZ3owT29NdXh0c0tScGN2VCtWaDZkb3JjSkU0ZTdjQ2FWK1ZKN0pQRGtwYzdFNSt6VCtncVlRKwptMWhjS0FmTEk0VEpZNzJZR2MzTWt5QkVqRzNsKzl3emxHNVlpZEduYVFjNDhMNUJQSXFxOEdKelpWSTkvQWxLClVDVjcwM2pGQnpKdTBEbFpTQWd2WEo1RUhNbWVhaFBQYTFOV2dkM29mQ2FUcTlnM0xaSTBDejdWbndOK0l1bzEKNGpRcE1zNzVQTFZVUTQ2SEZ0YUxJTWZPNDlkZk94SUwwNlkwZG1XNUc0R05zNUR4SkhtYm11QlQ1NGMrUm5MUQoyVldJL2VRS2xQQW5Sdk00SmpEM3hEcENvOGViSE9nS2RsRU9MTkFPTEk0L2VMUG1GcXlTUGxuY2RTZlFqc2UvCkJQOEpuQk9Xa0xpSUZ4bzBwT1lrTUFDaHhWdDJkdURLcldRZm1JSkhUUSs0Q05OZjhlanZOZkZCY0pmNllldHUKRnlkNnA4WmwrYkV2TldYbDBKeGNQNWlFVGFYWkZqblJqMWxzZWVSbWo3OGFyRDZCUkhTTFlsM0pBZ01CQUFHZwpBREFOQmdrcWhraUc5dzBCQVFzRkFBT0NBWUVBMXYrOURlUE5XOER6Z2twVzBhU1czdW1xR05xc05zaWNhQjc1Cjc3UGsyRnNBMTMya2JWTXBBY2NCRzc1WGh4T0VkNFNYdTJ0eVI1MGxOMUpaNnJldzY5b1dUYWZTTTVXNm00RFAKcE1tVjRJbTJiajlUTUhYeHdXVjdXVk5JL2dQK1BFRDVROVJMNy82Sjh2VnV5aFhZaTAyc2NkampKaStIT0M4Ywo1TFpLem5TQUhtcmZEVGlveG5ydUNqY1ZEZlFlSGlJMkw1SW94aXAwUmt5L0Y1UkhwTjRyMHFQS25Na2F3enRYClV3alB6Nk9uWGVPK1EvVGZyRm5ka2V3OCtsSFc2akxneXNUNlU3SjdmdjVuL1lSUXdYSHJadi9LNFVneW9zU3oKZy9PSkZoOVpyWjl6WFBhT01sN1pLYnlUUXE2NGtMSmFEQys0eWIycXlUT1hMUm1xK0Y1MWc2a0tJdDdMWXdtMQpjR0N3WTc2WmFHMm9hVkQxRVNQSWtpc0I4U01ncVNEajlhQjFxRDJ0Y1E4RGxoV1o3dEdDd3M5VC9RUDlvQnpsCjc5S0g3Qnc1QnVSVFlRT0srMTdJSWUrNUx0YVFzS1dpczBsaGtvQ1R3TjdUS2FnQ1dLWWk0RE16em1wVlNvbTEKaVphb21nUDJIKy8yQ3RoOUNJN1dwVWR5WklkQgotLS0tLUVORCBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0K","signerName":"tcsissuer.tcs.intel.com/sandbox.my-ca","usages":["client auth"]}}

CreationTimestamp:  Mon, 24 Jan 2022 16:11:10 +0200
Requesting User:    kubernetes-admin
Signer:             tcsissuer.tcs.intel.com/sandbox.my-ca
Status:             Approved,Issued
Subject:
         Common Name:    foo.bar.com
         Serial Number:  
         Organization:   Foo Company

drawing

Figure 3: Trusted Certificate Issuer with Kubernetes CSR

  1. The TCSIssuer is created.
  2. This automatically creates the my-ca-cert secret.
  3. A user creates a certificate signing request using openssl and saving the private key. Using that csr.pem file, a CertificateSigningRequest object is created in Kubernetes.
  4. A user approves the CertificateSigningRequest object.
  5. The TCS Controller then takes the request and signs the certificate inside the Intel SGX enclave using the private key stored within that enclave.
  6. The signed certificate is then copied back into the original CertificateSigningRequest object into the certificate field.

Below is a demo of this working with Kubernetes CSR.

Deployment in Azure

You can deploy TCS also in Azure by following the instructions here.

Sample use cases

Refer to more example use cases related to Istio service mesh and Trusted Certificate Service

Limitations

  • This version of the software is pre-production release and is meant for evaluation and trial purposes only.
  • The certificate authority (CA) private key transport method (via QuoteAttestation custom resource) does not guarantee any authenticity, only confidentiality, and therefore cannot protect from attacks like key substitution or key replay.