How does consul client agent get service account details of a service

Hi, I am trying to understand the workflow of Consul service mesh on Kubernetes. Consul client agent run on every node of the cluster and when ever a service is created, it registers with the client agent. The agent initiates a side car proxy for the service based on the service definition. The client agent also creates a private key for the service and send a CSR to the Consul server over a gRPC channel. The server validates the CSR and issues a certificate with SAN as service identity based on SPIFFE. I can not understand from the documentation how consul server knows about the SPIFFE identity of a service.

send a CSR to the Consul server over a gRPC channel

I think this is done via consul’s RPC mechanism, not gRPC. But not a big difference.

I can not understand from the documentation how consul server knows about the SPIFFE identity of a service.

When the client agent constructs the CSR it contains the desired SPIFFE ID.

But maybe I’m missing your exact question?

Hi @zara.butt,

If I’m understanding correctly, you’re saying that you currently don’t understand how Consul associates a pod with a particular service.

The tl;dr is that this association happens by the pod authenticating to Consul using a Kubernetes service account token via Consul’s Kubernetes auth method.

See below for a longer explanation…

Consul requires pods in the mesh to have a Kubernetes Service Account mounted in the pod. The service account name must match the name of the Kubernetes Service object that is associated with the Pod.

When connect-inject is enabled for the Pod, Consul injects an init container into the pod via Kubernetes. This container runs a command that uses the service account token to login to Consul via the Kubernetes auth method. This login flow is described in the Auth Methods: Overall Login Process.

If the authentication is successful, Consul will then evaluate the configured ACL Binding Rules associated with the auth method, find a matching rule, and then return a Consul ACL token with the appropriate service identity per that rule’s specification.

The binding rule looks something like this:

$ consul acl binding-rule list \
  -method=hashicorp-consul-k8s-auth-method \
  -format=json
[
    {
        "ID": "cf6387c1-c99e-c326-7280-67906dd8b8fe",
        "Description": "Kubernetes binding rule",
        "AuthMethod": "hashicorp-consul-k8s-auth-method",
        "Selector": "serviceaccount.name!=default",
        "BindType": "service",
        "BindName": "${serviceaccount.name}",
        "CreateIndex": 2672982,
        "ModifyIndex": 22739230
    }
]

This particular rule instructs Consul to issue a token with a service identity for the name that matches the serviceaccount.name value in the K8s Service Account token, as long as that name does not equal default.

For example, if your pod’s name is web, and its service account name is also web, Consul will issue a token that grants permission to register a service and sidecar proxy for the service web.

This token is subsequently used by the Envoy proxy to authenticate to Consul when it starts. Consul will follow the CSR process you described, and return a certificate to the sidecar proxy with the appropriate SPIFFE ID for the service which it authenticated as.

Sorry for the long winded answer. I hope this is the level of detail you were looking for. If not, please let us know, and @lkysow or I will try to better answer your question.

Thank you for the detailed response. It answers my question. Basically when the proxy authenticates to Consul Client agent using the Consul ACL token, It will validate that and generate a CSR and send it to the Consul Server along with the token. The server will again validate the token and then issue a X.509 Certificate with the SPIFFE ID as the SAN.

Yes, that is correct. :slight_smile: