Issue identity with the MeshIdentity bundled provider

Uses: Kong Mesh
Incompatible with
konnect
Related Documentation
Tags
Minimum Version
Kong Mesh - 2.12
TL;DR

Apply a MeshIdentity with the bundled provider to issue workload identities, inspect the auto-generated MeshTrust, then apply a MeshTrafficPermission with SPIFFE ID prefix matching to allow traffic between workloads.

Prerequisites

You will need Helm, a package manager for Kubernetes.

This guide requires a running Kubernetes cluster. If you already have a Kubernetes cluster running, you can skip this step. It can be a cluster running locally, like Docker, or in a public cloud like AWS EKS, GCP GKE, etc.

For example, if you are using minikube:

minikube start -p mesh-zone
  1. Install Kong Mesh:

    helm repo add kong-mesh https://kong.github.io/kong-mesh-charts
    helm repo update
    helm upgrade \
      --install \
      --create-namespace \
      --namespace kong-mesh-system \
      kong-mesh kong-mesh/kong-mesh
    kubectl wait -n kong-mesh-system --for=condition=ready pod --selector=app=kong-mesh-control-plane --timeout=90s
    
  2. Apply the demo configuration:

    echo "
    apiVersion: v1
    kind: Namespace
    metadata:
      labels:
        kuma.io/sidecar-injection: enabled
      name: kong-mesh-demo
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: demo-app
      namespace: kong-mesh-demo
    spec:
      ports:
      - appProtocol: http
        port: 5050
        protocol: TCP
        targetPort: 5050
      selector:
        app: demo-app
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: demo-app-v1
      namespace: kong-mesh-demo
    spec:
      ports:
      - appProtocol: http
        port: 5050
        protocol: TCP
        targetPort: 5050
      selector:
        app: demo-app
        version: v1
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: demo-app-v2
      namespace: kong-mesh-demo
    spec:
      ports:
      - appProtocol: http
        port: 5050
        protocol: TCP
        targetPort: 5050
      selector:
        app: demo-app
        version: v2
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: kv
      namespace: kong-mesh-demo
    spec:
      ports:
      - appProtocol: http
        port: 5050
        protocol: TCP
        targetPort: 5050
      selector:
        app: kv
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: demo-app
        version: v1
      name: demo-app
      namespace: kong-mesh-demo
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: demo-app
          version: v1
      template:
        metadata:
          labels:
            app: demo-app
            version: v1
        spec:
          containers:
          - env:
            - name: OTEL_SERVICE_NAME
              value: demo-app
            - name: OTEL_EXPORTER_OTLP_ENDPOINT
              value: http://opentelemetry-collector.mesh-observability:4317
            - name: KV_URL
              value: http://kv.kong-mesh-demo.svc.cluster.local:5050
            - name: APP_VERSION
              valueFrom:
                fieldRef:
                  fieldPath: metadata.labels['version']
            image: ghcr.io/kumahq/kuma-counter-demo:latest@sha256:daf8f5cffa10b576ff845be84e4e3bd5a8a6470c7e66293c5e03a148f08ac148
            name: app
            ports:
            - containerPort: 5050
              name: http
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: demo-app
        version: v2
      name: demo-app-v2
      namespace: kong-mesh-demo
    spec:
      replicas: 0
      selector:
        matchLabels:
          app: demo-app
          version: v2
      template:
        metadata:
          labels:
            app: demo-app
            version: v2
        spec:
          containers:
          - env:
            - name: OTEL_SERVICE_NAME
              value: demo-app
            - name: OTEL_EXPORTER_OTLP_ENDPOINT
              value: http://opentelemetry-collector.mesh-observability:4317
            - name: KV_URL
              value: http://kv.kong-mesh-demo.svc.cluster.local:5050
            - name: APP_VERSION
              valueFrom:
                fieldRef:
                  fieldPath: metadata.labels['version']
            image: ghcr.io/kumahq/kuma-counter-demo:latest@sha256:daf8f5cffa10b576ff845be84e4e3bd5a8a6470c7e66293c5e03a148f08ac148
            name: demo-app
            ports:
            - containerPort: 5050
              name: http
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: kv
      namespace: kong-mesh-demo
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: kv
      template:
        metadata:
          labels:
            app: kv
        spec:
          containers:
          - env:
            - name: OTEL_SERVICE_NAME
              value: kv
            - name: OTEL_EXPORTER_OTLP_ENDPOINT
              value: http://opentelemetry-collector.mesh-observability:4317
            - name: APP_VERSION
              valueFrom:
                fieldRef:
                  fieldPath: metadata.labels['version']
            image: ghcr.io/kumahq/kuma-counter-demo:latest@sha256:daf8f5cffa10b576ff845be84e4e3bd5a8a6470c7e66293c5e03a148f08ac148
            name: app
            ports:
            - containerPort: 5050
              name: http
    ---
    apiVersion: kuma.io/v1alpha1
    kind: Mesh
    metadata:
      name: default
    spec:
      meshServices:
        mode: Exclusive
      mtls:
        backends:
        - name: ca-1
          type: builtin
        enabledBackend: ca-1
    ---
    apiVersion: kuma.io/v1alpha1
    kind: MeshTrafficPermission
    metadata:
      name: kv
      namespace: kong-mesh-demo
    spec:
      from:
      - default:
          action: Allow
        targetRef:
          kind: MeshSubset
          tags:
            app: demo-app
            k8s.kuma.io/namespace: kong-mesh-demo
      targetRef:
        kind: Dataplane
        labels:
          app: kv" | kubectl apply -f -
    kubectl wait -n kong-mesh-demo --for=condition=available --timeout=120s deployment --all
    

This guide covers an experimental feature.

The MeshIdentity policy issues identities for selected data planes. This approach is SPIFFE-compliant and works with Spire. In this guide, you’ll issue identities using the bundled provider.

In Kong Mesh, there are two identity concepts:

  • Identity: A workload identity is the name encoded in its certificate, and this identity is valid only if the certificate is signed by a trust.
  • Trust: Trust defines which identities you accept as valid through trusted certificate authorities (CA) that issue those identities. Each trust belongs to a trust domain, and a mesh can contain multiple trusts.

Issue identities

For MeshIdentity to work, meshServices.mode: Exclusive must be set on the Mesh resource. This value is already configured in the demo Mesh.

MeshIdentity manages identity issuance. To issue a new identity in a mesh, create this resource:

echo "apiVersion: kuma.io/v1alpha1
kind: MeshIdentity
metadata:
  name: identity
  namespace: kong-mesh-system
  labels:
    kuma.io/mesh: default
spec:
  selector:
    dataplane:
      matchLabels: {}
  spiffeID:
    trustDomain: '{{ .Mesh }}.{{ .Zone }}.mesh.local'
    path: '/ns/{{ .Namespace }}/sa/{{ .ServiceAccount }}'
  provider:
    type: Bundled
    bundled:
      meshTrustCreation: Enabled
      insecureAllowSelfSigned: true
      certificateParameters:
        expiry: 24h
      autogenerate:
        enabled: true" | kubectl apply -f -

MeshIdentity uses selector to choose the data planes that receive identities. In this example, the selector issues identity to all data planes in the mesh.

spiffeID defines templates for workload SPIFFE IDs. In this example, the trust domain template combines the mesh name, zone name, and .mesh.local. The path template combines the namespace and service account.

The provider field contains identity provider-specific configuration. This guide uses the Bundled provider. This configuration enables MeshTrust generation, allows self-signed certificates, and sets the certificate expiry time to 24h.

Inspect trust configuration

The MeshIdentity creates a MeshTrust resource.

  1. Verify that the MeshTrust exists:

    kubectl get meshtrusts -n kong-mesh-system
    

    You should see the following output:

    NAME       AGE
    identity   45s
    
  2. Inspect the full generated MeshTrust resource:

    kubectl get meshtrust identity -n kong-mesh-system -oyaml
    

    The generated MeshTrust should look like this:

    apiVersion: kuma.io/v1alpha1
    kind: MeshTrust
    metadata:
      labels:
        kuma.io/env: kubernetes
        kuma.io/mesh: default
        kuma.io/origin: zone
        kuma.io/zone: default
      name: identity
      namespace: kong-mesh-system
    spec:
      caBundles:
      - pem:
          value: |
            -----BEGIN CERTIFICATE-----
            ...
            -----END CERTIFICATE-----
        type: Pem
      origin:
        kri: kri_mid_default_default_kong-mesh-system_identity_
      trustDomain: default.default.mesh.local
    

In the displayed MeshTrust:

  • The control plane generates the caBundle (Certificate Authority bundle): the root certificate that the identity uses to sign workload certs in the Mesh zone.
  • The MeshIdentity template provides the trustDomain: default.default.mesh.local in our example.
  • The origin value gives the KRI (Kuma Resource Identifier) of the MeshIdentity that generated this trust.

Test connectivity

  1. Port-forward the demo-app service on port 5050:

    kubectl port-forward svc/demo-app -n kong-mesh-demo 5050:5050
    
  2. In a new terminal, send a request to demo-app:

    curl -XPOST localhost:5050/api/counter
    

    You should see an error like this:

    {
      "instance": "d11ee97a4b45ff3a7b59091d1612b7f7",
      "status": 500,
      "title": "failed to retrieve zone",
      "type": "https://github.com/kumahq/kuma-counter-demo/blob/main/ERRORS.md#INTERNAL-ERROR"
    }
    

Issuing identity to workloads enables mTLS. Zero trust is the default behavior, so without a MeshTrafficPermission to allow traffic, these errors are expected.

Allow traffic

Create a MeshTrafficPermission:

echo "apiVersion: kuma.io/v1alpha1
kind: MeshTrafficPermission
metadata:
  name: mtp
  namespace: kong-mesh-demo
  labels:
    kuma.io/mesh: default
spec:
  rules:
    - default:
        allow:
          - spiffeID:
              type: Prefix
              value: spiffe://default.default.mesh.local/ns/kong-mesh-demo" | kubectl apply -f -

This MeshTrafficPermission uses SPIFFE ID matching to allow traffic from workloads whose SPIFFE ID starts with spiffe://default.default.mesh.local/ns/kong-mesh-demo.

Based on the template in the MeshIdentity, every workload has a SPIFFE ID with this prefix in:

  • The default mesh
  • The kong-mesh-demo namespace.

You can also allow only workloads matching their exact SPIFFE ID for more fine-grained control.

Validate

Send another request:

curl -XPOST localhost:5050/api/counter

You should see the following output:

{"counter":1,"zone":""}

If you still get the error, wait a few seconds and try again.

Cleanup

To clean up your environment, remove the Docker containers, network, temporary directory, and the control plane configuration. Run the following command:

kubectl config delete-context mesh-zone

Help us make these docs great!

Kong Developer docs are open source. If you find these useful and want to make them better, contribute today!