istio: File path based Gateway TLS setting is not working when using SPIRE as workload identity issuer.

Is this the right place to submit this?

  • This is not a security vulnerability or a crashing bug
  • This is not a question about how to use Istio

Bug Description

Hypothesis

When SPIRE is configured to provide workload identity it replaces the default sds-cluster. However for ingress gateway, the source of the TLS certs is also moved to sds-cluster. The default SDS client, when SPIRE workload api socket is not mount, understand the specific resource name file-cert:<key>~<cert>. However, once it is replaced by SPIRE, the above resource name is passed onto the spire-agent, which is not able to resolve it.

This breaks the file based TLS SIMPLE mode configuration when SPIRE is the workload identity issuer.

Context I set up my mesh to use SPIRE issuing workload identity. Traffic between proxies, including ingress gateway, are mTLS based on SPIRE issued identity. Workload socket are mounted from spire-agent through CSI.

Error case I’m trying to set up SIMPLE mode TLS at the ingress gateway. Following is the Gateway resource:

apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: main-gateway
  namespace: mesh-config
spec:
  selector:
    istio: ingressgateway
  servers:
    - hosts:
        - "*"
      port:
        name: http
        number: 8080
        protocol: HTTP
    - hosts:
        - "romeo.example.net"
      port:
        name: https
        number: 8443
        protocol: HTTPS
      tls:
        mode: SIMPLE
        privateKey: /run/secrets/gateway-tls/tls.key
        serverCertificate: /run/secrets/gateway-tls/tls.cert

Running this configuration, I fail to curl over TLS. (I replaced the host name in logs below to avoid expose internal details)

The gateway open up at 8443, but my NLB maps 443 to 8443.

❯ curl -k https://romeo.example.net/httpbin/hostname
curl: (35) LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to romeo.example.net:443
❯ openssl s_client -connect romeo.example.net:443
CONNECTED(00000006)
00D329DB01000000:error:0A000126:SSL routines:ssl3_read_n:unexpected eof while reading:ssl/record/rec_layer_s3.c:304:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 0 bytes and written 345 bytes
Verification: OK
---
New, (NONE), Cipher is (NONE)
This TLS version forbids renegotiation.
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---
❯ istioctl proxy-config secret istio-ingressgateway-6bd97dcb68-22rc5.istio-system
RESOURCE NAME                                                                    TYPE           STATUS      VALID CERT     SERIAL NUMBER                                NOT AFTER                NOT BEFORE
file-cert:/run/secrets/gateway-tls/tls.cert~/run/secrets/gateway-tls/tls.key                    WARMING     false
...

In ingress gateway log stream, I saw

2023-10-20T02:30:35.254103Z     warning envoy config external/envoy/source/common/config/grpc_stream.h:153      StreamSecrets gRPC config stream to sds-grpc closed: 3, workload is not authorized for the requested identities ["file-cert:/run/secrets/gateway-tls/tls.cert~/run/secrets/gateway-tls/tls.key"]      thread=18

It seems to me that the proxy attempted to fetch identity from spire-agent for unknown reason.

I dump the config on ingress gateway, the TLS config doesn’t seem to be right

            "tls_certificate_sds_secret_configs": [
             {
              "name": "file-cert:/run/secrets/gateway-tls/tls.cert~/run/secrets/gateway-tls/tls.key",
              "sds_config": {
               "api_config_source": {
                "api_type": "GRPC",
                "grpc_services": [
                 {
                  "envoy_grpc": {
                   "cluster_name": "sds-grpc"
                  }
                 }
                ],
                "set_node_on_first_message_only": true,
                "transport_api_version": "V3"
               },
               "resource_api_version": "V3"
              }
             }
            ]

Alternative

Using the same cert and key, I place them in Kubernetes secret, the TLS works correctly.

      tls:
        mode: SIMPLE
        credentialName: romeo

That indicate the keys and cert are correct.

Restriction

I don’t wish to use Kubernetes secret to store the key and cert as it is not safe. My design is to use a sidecar mount in memory medium with the gateway and rotate the cert and key in memory.

Version

❯ istioctl version
client version: 1.19.0
control plane version: 1.18.2
data plane version: 1.18.2 (6 proxies)

Additional Information

No response

About this issue

  • Original URL
  • State: open
  • Created 8 months ago
  • Comments: 19 (9 by maintainers)

Most upvoted comments

There are already 2 SDS paths in Istio. the local UDS (for workload cert and files) and remote Istiod XDS (over ADS) for credentialName.

So really this is probably looking for a 3 paths: local UDS for workload cert (by istio-agent or spire or other), local uds for files (by istio agent), remote ADS (for credential name).