This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Resources

Managing secret resources with Trustee

Trustee, and the KBS in particular, are built around providing secrets to workloads. These secrets are fulfilled by secret backend plugins, the most common of which is the resource plugin. In practice the terms secret and resource are used interchangeably.

There are several ways to configure secret resources.

Identifying Resources

Confidential Containers and Trustee use the Resource URI scheme to identify resources. A full Resource URI has the form kbs://<kbs_host>:<kbs_port>/<repository>/<type>/<tag>, but in practice the KBS Host and KBS Port are ignored to avoid coupling a resource to a particular IP and port.

Instead, resources are typically expressed as

kbs:///<repository>/<type>/<tag>`

Often resources are referred to just as <repository>/<type>/<tag>. This is what the KBS Client refers to as the resource path.

Providing Resources to Trustee

By default, Trustee supports a few different ways of provisioning resources.

KBS Client

You can use the KBS Client to provision resources.

kbs-client --url <kbs-url> config \
    --auth-private-key <admin-private-key> set-resource \
    --path <resource-path> --resource-file <path-to-resource-file>

For more details about using the KBS Client, refer to the KBS Client page

Filesystem Backend

By default Trustee will store resources on the filesystem. You can provision resources by placing them into the appropriate directory. When using Kubernetes, you can inject a secret like this.

cat "$KEY_FILE" | kubectl exec -i deploy/trustee-deployment -n trustee-operator-system -- tee "/opt/confidential-containers/kbs/repository/${KEY_PATH}" > /dev/null

This approach can be extended to integrate the resource backend with other Kubernetes components.

Operator

If you are using the Trustee operator, you can specify Kubernetes secrets that will be propagated to the resource backend.

A secret can be added like this

kubectl create secret generic kbsres1 --from-literal key1=res1val1 --from-literal key2=res1val2 -n kbs-operator-system

Advanced configurations

There are additional plugins and additional backends for the resource plugin. For example, Trustee can integrate with Azure Key Vault or PKCS11 HSMs.

1 - Resource Backends

Backends for resource storage

Resource Storage Backend

KBS stores confidential resources through a StorageBackend abstraction specified by a Rust trait. The StorageBackend interface can be implemented for different storage backends like e.g. databases or local file systems.

The KBS config file defines which resource backend KBS will use. The default is the local file system (LocalFs).

Local File System Backend

With the local file system backend default implementation, each resource file maps to a KBS resource URL. The file path to URL conversion scheme is defined below:

Resource File Path Resource URL
file://<$(KBS_REPOSITORY_DIR)>/<repository_name>/<type>/<tag> https://<kbs_address>/kbs/v0/resource/<repository_name>/<type>/<tag>

The KBS root file system resource path is specified in the KBS config file as well, and the default value is /opt/confidential-containers/kbs/repository.

Aliyun KMS

Alibaba Cloud KMS(a.k.a Aliyun KMS) can also work as the KBS resource storage backend. In this mode, resources will be stored with generic secrets in a KMS instance. One KBS can be configured with a specified KMS instance in repository_config field of KBS launch config. These materials can be found in KMS instance’s AAP. When being accessed, a resource URI of kbs:///repo/type/tag will be translated into the generic secret with name tag. Hinting that repo/type field will be ignored.

Pkcs11

The Pkcs11 backend uses Pkcs11 to store plaintext resources in an HSM. Pkcs11 is a broad specification supporting many cryptographic operations. Here we make use only of a small subset of these features. Often with Pkcs11 an HSM is used to wrap and unwrap keys or store wrapped keys. Here we do something simpler. Since the KBS expects resources to be in plaintext, we store these resources in the HSM as secret keys of the generic secret type. This storage backend will provision resource to the HSM in the expected way when a user uploads a resource to the KBS. The user must simply specify the location of an initialized HSM slot. Keys can also be provisioned to the HSM separately but they must have the expected attributes.

The Pkcs11 backend is configured with the following values.

  • module The module path should point to a binary implementing Pkcs11 for the HSM that you want to use. For example, if you are using SoftHSM, you might set the module path to /usr/local/lib/softhsm/libsofthsm2.so.
  • slot_index The slot index points to the slot in your HSM where the secrets will be stored. The slot must be initialized before starting the KBS. No slot_index is set, the first slot will be used.
  • pin The user password for authenticating a session with the above slot.

2 - Azure Key Vault Integration

This documentation describes how to mount secrets stored in Azure Key Vault into a KBS deployment

Premise

AKS

We assume an AKS cluster configured with Workload Identity and Key Vault Secrets Provider. The former provides a KBS pod with the privileges to access an Azure Key Vault (AKV) instance. The latter is an implementation of Kubernetes’ Secret Store CSI Driver, mapping secrets from external key vaults into pods. The guides below provide instructions on how to configure a cluster accordingly:

AKV

There should be an AKV instance that has been configured with role based access control (RBAC), containing two secrets named coco_one coco_two for the purpose of the example. Find out how to configure your instance for RBAC in the guide below.

Provide access to Key Vault keys, certificates, and secrets with an Azure role-based access control

Note: You might have to toggle between Access Policy and RBAC modes to create your secrets on the CLI or via the Portal if your user doesn’t have the necessary role assignments.

CoCo

While the steps describe a deployment of KBS, the configuration of a Confidential Containers environment is out of scope for this document. CoCo should be configured with KBS as a Key Broker Client (KBC) and the resulting KBS deployment should be available and configured for confidential pods.

Azure environment

Configure your Resource group, Subscription and AKS cluster name. Adjust accordingly:

export SUBSCRIPTION_ID="$(az account show --query id -o tsv)"
export RESOURCE_GROUP=my-group
export KEYVAULT_NAME=kbs-secrets
export CLUSTER_NAME=coco

Instructions

Create Identity

Create a User managed identity for KBS:

az identity create --name kbs -g "$RESOURCE_GROUP"
export KBS_CLIENT_ID="$(az identity show -g "$RESOURCE_GROUP" --name kbs --query clientId -o tsv)"
export KBS_TENANT_ID=$(az aks show --name "$CLUSTER_NAME" --resource-group "$RESOURCE_GROUP" --query identity.tenantId -o tsv)

Assign a role to access secrets:

export KEYVAULT_SCOPE=$(az keyvault show --name "$KEYVAULT_NAME" --query id -o tsv)
az role assignment create --role "Key Vault Administrator" --assignee "$KBS_CLIENT_ID" --scope "$KEYVAULT_SCOPE"

Namespace

By default KBS is deployed into a coco-tenant Namespace:

export NAMESPACE=coco-tenant
kubectl create namespace $NAMESPACE

KBS identity and Service Account

Workload Identity provides individual pods with IAM privileges to access Azure infrastructure resources. An azure identity is bridged to a Service Account using OIDC and Federated Credentials. Those are scoped to a Namespace, we assume we deploy the Service Account and KBS into the default Namespace, adjust accordingly if necessary.

export AKS_OIDC_ISSUER="$(az aks show --resource-group "$RESOURCE_GROUP" --name "$CLUSTER_NAME" --query "oidcIssuerProfile.issuerUrl" -o tsv)"
az identity federated-credential create \
 --name kbsfederatedidentity \
 --identity-name kbs \
 --resource-group "$RESOURCE_GROUP" \
 --issuer "$AKS_OIDC_ISSUER" \
 --subject "system:serviceaccount:${NAMESPACE}:kbs"

Create a Service Account object and annotate it with the identity’s client id.

cat <<EOF> service-account.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  annotations:
    azure.workload.identity/client-id: ${KBS_CLIENT_ID}
  name: kbs
  namespace: ${NAMESPACE}
EOF
kubectl apply -f service-account.yaml

Secret Provider Class

A Secret Provider Class specifies a set of secrets that should be made available to k8s workloads.

cat <<EOF> secret-provider-class.yaml
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: ${KEYVAULT_NAME}
  namespace: ${NAMESPACE}
spec:
  provider: azure
  parameters:
    usePodIdentity: "false"
    clientID: ${KBS_CLIENT_ID}
    keyvaultName: ${KEYVAULT_NAME}
    objects: |
      array:
      - |
        objectName: coco_one
        objectType: secret
      - |
        objectName: coco_two
        objectType: secret
    tenantId: ${KBS_TENANT_ID}
EOF
kubectl create -f secret-provider-class.yaml

Deploy KBS

The default KBS deployment needs to be extended with label annotations and CSI volume. The secrets are mounted into the storage hierarchy default/akv.

git clone https://github.com/confidential-containers/kbs.git
cd kbs
git checkout v0.8.2
cd kbs/config/kubernetes
mkdir akv
cat <<EOF> akv/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: coco-tenant

resources:
- ../base

patches:
- path: patch.yaml
  target:
    group: apps
    kind: Deployment
    name: kbs
    version: v1
EOF
cat <<EOF> akv/patch.yaml
- op: add
  path: /spec/template/metadata/labels/azure.workload.identity~1use
  value: "true"
- op: add
  path: /spec/template/spec/serviceAccountName
  value: kbs
- op: add
  path: /spec/template/spec/containers/0/volumeMounts/-
  value:
    name: secrets
    mountPath: /opt/confidential-containers/kbs/repository/default/akv
    readOnly: true
- op: add
  path: /spec/template/spec/volumes/-
  value:
    name: secrets
    csi:
      driver: secrets-store.csi.k8s.io
      readOnly: true
      volumeAttributes:
        secretProviderClass: ${KEYVAULT_NAME}
EOF
kubectl apply -k akv/

Test

The KBS pod should be running, the pod events should give indication of possible errors. From a confidential pod the AKV secrets should be retrievable via Confidential Data Hub:

$ kubectl exec -it deploy/nginx-coco -- curl http://127.0.0.1:8006/cdh/resource/default/akv/coco_one
a secret