Setting up Upstream TLS

Configuring Upstream TLS for Gloo

We can configure Gloo to use client-side TLS when connecting to upstream services.

Client TLS

Gloo supports client-side TLS where the proxy (Envoy) presents a certificate to upstream servers when initiating a connection on behalf of a downstream client, encrypting all traffic between the proxy and the upstream.

Prepare sample environment

Let’s deploy a sample application and configure a route to it. We will expect the route to return errors because the sample application is serving HTTPS, not HTTP.

kubectl apply -n default -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: example-tls-server
  name: example-tls-server
spec:
  selector:
    matchLabels:
      app: example-tls-server
  replicas: 1
  template:
    metadata:
      labels:
        app: example-tls-server
    spec:
      containers:
      - image: docker.io/soloio/example-tls-server:latest
        imagePullPolicy: Always
        name: example-tls-server
        ports:
        - containerPort: 8080
          name: http
---
apiVersion: v1
kind: Service
metadata:
  name: example-tls-server
  labels:
    service: example-tls-server
spec:
  ports:
  - port: 8080
    protocol: TCP
  selector:
    app: example-tls-server
EOF

If we query the Gloo upstream generated by Discovery, we should see it:

glooctl get upstream default-example-tls-server-8080
+---------------------------------|------------|----------|--------------------------------+
|            UPSTREAM             |    TYPE    |  STATUS  |            DETAILS             |
+---------------------------------|------------|----------|--------------------------------+
| default-example-tls-server-8080 | Kubernetes | Accepted | svc name:                      |
|                                 |            |          | example-tls-server             |
|                                 |            |          | svc namespace: default         |
|                                 |            |          | port:          8080            |
|                                 |            |          |                                |
+---------------------------------|------------|----------|--------------------------------+

Now let’s create a route to the example tls server like we did in the hello world tutorial

glooctl add route \
    --path-exact /hello \
    --dest-name default-example-tls-server-8080

Adding Client SSL to Gloo

Let’s see what happens when we try to hit our route without adding client tls config to Gloo:

curl $(glooctl proxy url)/hello

The response should be an error:

Client sent an HTTP request to an HTTPS server.

This response indicates Envoy attempted to use HTTP to communicate to our HTTPS service. Let’s fix this by adding the required certificates to the Upstream.

The certificates added to the Upstream should match those required by the server.

The certificates used for this service are hard-coded for testing purposes. Let’s create local copies of them:

# create the certificate
cat > cert.pem <<EOF
-----BEGIN CERTIFICATE-----
MIIDeDCCAmACCQDigH3yyOvEADANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJV
UzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEa
MBgGA1UECgwRWW91ciBPcmdhbml6YXRpb24xEjAQBgNVBAsMCVlvdXIgVW5pdDES
MBAGA1UEAwwJbG9jYWxob3N0MB4XDTE5MTAwOTEzMjkwOVoXDTI5MTAwNjEzMjkw
OVowfjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM
DU1vdW50YWluIFZpZXcxGjAYBgNVBAoMEVlvdXIgT3JnYW5pemF0aW9uMRIwEAYD
VQQLDAlZb3VyIFVuaXQxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBAOFNQLb4iFwM8z1llBmgBtgYdXcJyatgKcNr2OdU
P5q1GijCblcc20+6RaOY0i1ibkFwlxDNn22TxvANSQlm4eMZpE/N9/isVuIA9s6A
7DlQxjcxOOWj0308ukmSzSNv+SGGxDh9yeOxh3O7tQRb6y9FTEpe32qTMRkDMXNs
1pSP+JKRF3huTgt+kdxSXm2I9+ZMQURxky3cFO4eQ/cI05q1gcJViqa0rT8saDNz
kqPOm9OCWWVP9rBE04Ilyj4CKFvzlToKJOopRd6owGL8tSv+bdy+D8EFiqvwSXE6
EpaduMp/HfWVaOfrJDsfNn/3imu4fWtlCN6jndQHcG77y60CAwEAATANBgkqhkiG
9w0BAQsFAAOCAQEAWRn+YUOhltQAtnMZeDMfjMw0UJRjCrczfOmwAFnVqbhhtaev
F5XMbTYInPE0xIHlRVN8RxAvdLxMrRFhOBdKBM7efMD0XVMo5TeQzL90M0Nozgly
IOSuMlBCL8tyoSLPpMy+jmY2ALYooxoXOqC6fdLbvPAIDoTuRlRB3zq8OX58yt+J
lYvOIZmr5ImoKQvLn8fsUZtY93e6bo+l+iFBgbxo5UovZp1IjehWGprViC1+INZr
PRzwa8qrDxnNsVdUFQhgKb6s+uFmjtN8fqF00t2xvdKblJr5WN3TnFiQgLX+DFyB
p80GBupbMkI8FUpM3QwCPRxkIE74WY4dCgbkng==
-----END CERTIFICATE-----
EOF
# create the key
cat > key.pem <<EOF
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDhTUC2+IhcDPM9
ZZQZoAbYGHV3CcmrYCnDa9jnVD+atRoowm5XHNtPukWjmNItYm5BcJcQzZ9tk8bw
DUkJZuHjGaRPzff4rFbiAPbOgOw5UMY3MTjlo9N9PLpJks0jb/khhsQ4fcnjsYdz
u7UEW+svRUxKXt9qkzEZAzFzbNaUj/iSkRd4bk4LfpHcUl5tiPfmTEFEcZMt3BTu
HkP3CNOatYHCVYqmtK0/LGgzc5KjzpvTglllT/awRNOCJco+Aihb85U6CiTqKUXe
qMBi/LUr/m3cvg/BBYqr8ElxOhKWnbjKfx31lWjn6yQ7HzZ/94pruH1rZQjeo53U
B3Bu+8utAgMBAAECggEAPH6eusJe8sBza2/j5UGHtOxUVgMlyENI03UYx3xim6q2
/GzAbdmMtYqhejzlalQ8oIuXtGZRwX1ldD1M+B5M1sqiyN7YD0hPB94UZvxM8VLT
9ivcSCTF+6Gbr3egZzyAm1TxSO3VkLKxWQz0nNgFfSrRQkLZIGenTj0CQSjfMQI6
NPbJbp3mD9AQsKjDSvwo4rwwSe8vedXyYikuwMABHZ0bydIeuB+So8LvUZipToM5
jf08GejdeL+vuNoCueRsJ2hvMrGrqdfKx3+FcyB26SKv9nuQmv7verxlAn+t+Afi
pH/1BOHrCoJQgP5lGH0H+UmGwf9HO8ciJqu3dWd7rQKBgQD7RTdLGBWQS451ULxI
Utj62iHv/TzB3vge2ZGbTb56SefhPkcj1o1NXDqBIYOpusYddcr38LeBHs3QBSF9
WMvRa2NojV7R5CUXvEzioH7GlMOaL7sIjmoBYjE1QRsfuKUAcKDXw3VJVYuoHRgK
HswFSvhtELEihID6UZcAvWpvDwKBgQDliuc2ipMRjNCMune5uoElYDyamRM/4v8x
GYRAWoRTCVcsAKGtUso9/CXsw9+Ld2Q7XqaEsD4YsyfWQEED2gIY6OcEURAT/o+o
IQQdJnO4A0EJks2mhLzBwN3has/Q0IgJXOZp2ulZ+bsbh3GeifXnd6NF2p9IM1/Q
VaXl6IuZgwKBgQDbxxftE/zQgHXzgRGexPBKwf8LNdotzQQDn9PvHlosBnbOmjWJ
UEG516DIj/Lkw5xD6mME6UToqHPmroYzaDamTyLdMUItnjsffrFVTIJ22WoZdARJ
IJ/x49wcs3yxC0UvlFPrRWhSI4QLIJ+FQpi7TG7snrwA8BsMV88Xc5Yj2wKBgQDK
MRB5epcRXnhVfer4LtCTm7HGfA/4tnsTROa5yQHGIvQmTmgbxFFhSDof1GmU8BXa
NgV328bW+vicQP0D54TxbDYSF1WSRylDb9Gv268S58riI+4CP+oEwV6wsOVdilJJ
7QsJM0tZdiDanvP2Mo/o0/l+DpU/hAFiAg+f9LcDAQKBgQCTPi8SrDqwQGXI+S+P
6j8thYveTF5qRSpbIxA0sXXXFF6Ufa3F+uhbiEAEohgtMkyw1pjjixtqIAwspI0R
UkZt4Iyw6JHANf03UDGCDunBaDoHxef0e3k9/kC38dbbq2vaKUvN5kLqhDa0t798
kXRTzTu3F02+HoyBwn0QC0tWWg==
-----END PRIVATE KEY-----
EOF

Now we should create the Kubernetes secret to hold these certs:

kubectl create secret tls upstream-tls --key key.pem \
   --cert cert.pem --namespace default
secret/upstream-tls created

Now we’ve got to configure the default-example-tls-server-8080 upstream to reference this secret in its sslConfig.

This can be done using either glooctl to modify the Upstream directly, or adding an annotation to the the service:


glooctl edit upstream \
    --name default-example-tls-server-8080 \
    --namespace gloo-system \
    --ssl-secret-name upstream-tls \
    --ssl-secret-namespace default

kubectl annotate service -n default example-tls-server gloo.solo.io/sslService.secret=upstream-tls

See the guide on using Service annotations to configure SSL for the full set of options when using Service annotations to configure upstream SSL.

Now if we get the default-example-tls-server-8080 Upstream, we should see the new SSL configuration:

kubectl get upstream -n gloo-system \
    default-example-tls-server-8080 -o yaml
apiVersion: gloo.solo.io/v1
kind: Upstream
metadata:
  labels:
    discovered_by: kubernetesplugin
    service: example-tls-server
  name: default-example-tls-server-8080
  namespace: gloo-system
spec:
  discoveryMetadata: {}
  kube:
    selector:
      app: example-tls-server
    serviceName: example-tls-server
    serviceNamespace: default
    servicePort: 8080
  sslConfig:
    secretRef:
      name: upstream-tls
      namespace: default
status:
  reported_by: gloo
  state: 1

Try the request again

curl $(glooctl proxy url)/hello

The response should be an error:

Hello, world!

Great! Now we’ve seen how Gloo can be configured to encrypt traffic sent to a backend service which is configured to serve TLS.