Deploy XtremeCloud SSO to an Istio Service Mesh
Introduction
Istio is an open platform for providing a uniform way to integrate microservices, manage traffic flow across microservices, enforce policies and aggregate telemetry data. Istio’s control plane provides an abstraction layer over the underlying cluster management platform, such as Kubernetes.
Istio is composed of these components:
-
Envoy - Sidecar proxies per microservice to handle ingress/egress traffic between services in the cluster and from a service to external services. The proxies form a secure microservice mesh providing a rich set of functions like discovery, rich layer-7 routing, circuit breakers, policy enforcement and telemetry recording/reporting functions.
Note: The service mesh is not an overlay network. It simplifies and enhances how microservices in an application talk to each other over the network provided by the underlying platform.
-
Istiod - The Istio control plane. It provides service discovery, configuration and certificate management. It consists of the following sub-components:
-
Pilot - Responsible for configuring the proxies at runtime.
-
Citadel - Responsible for certificate issuance and rotation.
-
Galley - Responsible for validating, ingesting, aggregating, transforming and distributing config within Istio.
-
-
Operator - The component provides user-friendly options to operate the Istio service mesh.
Implementation Considerations
Using NGINX as an Ingress Proxy in the Istio Service Mesh
Outside of a service mesh, XtremeCloud SSO containers are typically front-ended by an NGINX Kubernetes Ingress Controller (KIC). Although the desired functionality is in place, end-to-end encryption to the Single Sign-On (SSO) services is not available since SSL/TLS is terminated at the NGINX-based KIC. Some organizations find this acceptable, depending on the network isolation of their Kubernertes clusters.
For those organizations that need end-to-end encryption all the way to the application services, an alternative approach is needed. Without Istio deployed, it is necessary to enable SSL/TLS in the XtremeCloud SSO Wildfly-based application server. Although this is a supported configuration by Eupraxia Labs, this is generally not advised. This configuration adds complexity to the container’s configuration and requires the XtremeCloud SSO container to perform cryptographic operations that typically consumes 20% of the container’s compute power.
Using Istio, not only is the payload encrypted in flight, the endpoint itself is protected since only pre-authorized clients via mutual TLS (mTLS) can connect to the SSO service. This is consistent with an Istio-based Zero Trust Architecture (ZTA) that we feel is essential in a CyberSAAFE configuration.
This brings us to the idea of using NGINX as an ingress proxy with the Istio Service Mesh. There are three (3) approaches to deploy an ingress proxy, such as NGINX, within an Istio Service Mesh:
- Run dedicated ingress proxies within each team or microservice (Dedicated Model)
- A set of ingress proxies shared amongst many teams or microservices (Shared Model)
- A combination, where a team has a dedicated ingress that spans multiple namespaces they own, or the organization has a combination of teams with dedicated ingresses and teams that may use a shared ingress, or a combination of all the above (Hybrid Model). There is a lot of flexibility here.
In the diagram below, the Dedicated Model (on the left) and the Shared Model are illustrated.
We’re going to focus on the Dedicated Model since a lot of microservices in a namespace are likely to be handled by NGINX within that same namespace. The complexity of that alone is a lot for teams to manage and centralization of a single large (or even multiple) NGINX proxy moves us away from some of the benefits of microservices.
Let’s install an NGINX ingress proxy into an Istio Service Mesh. This will be a manual installation to illustrate and explain the steps. However, any organization with an XtremeCloud SSO subscription will be provided with Helm charts and a Codefresh CI/CD pipeline for an automated installation experience. This installation will be on Minikube to show the flexibility of the implementation to run even on the desktop.
First of all, download an Istio version of choice. Please refer to our Certification Matrix during your installation of XtremeCloud SSO. This will be version 1.6.5 of Istio on a Kubernetes 1.18 version.
curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.6.5 sh -
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 107 100 107 0 0 100 0 0:00:01 0:00:01 --:--:-- 100
100 3896 100 3896 0 0 2014 0 0:00:01 0:00:01 --:--:-- 0
Downloading istio-1.6.5 from https://github.com/istio/istio/releases/download/1.6.5/istio-1.6.5-osx.tar.gz ...
Istio 1.6.5 Download Complete!
Istio has been successfully downloaded into the istio-1.6.5 folder on your system.
Next Steps:
See https://istio.io/docs/setup/kubernetes/install/ to add Istio to your Kubernetes cluster.
To configure the istioctl client tool for your workstation,
add the /Users/davidjbrewer/apps/test-stuff/istio-1.6.5/bin directory to your environment path variable with:
export PATH="$PATH:/Users/davidjbrewer/apps/istio-1.6.5/bin"
Begin the Istio pre-installation verification check by running:
istioctl verify-install
Need more information? Visit https://istio.io/docs/setup/kubernetes/install/
Move to the Istio package directory.
$ cd istio-1.6.5
Add the istioctl client to your path.
$ export PATH=$PWD/bin:$PATH
Deploy Istio (with global mTLS):
$ istioctl manifest apply \
--set values.global.mtls.enabled=true \
--set values.global.controlPlaneSecurityEnabled=true
We’re going to create a new namespace and label it for sidecar proxies:
$ kubectl create ns iam
$ kubectl label namespace iam istio-injection=enabled
We can confirm that namespace ‘iam’ is injection-enabled:
Davids-MacBook-Pro:xtremecloud-sso-minikube davidjbrewer$ kubectl get namespace -L istio-injection
NAME STATUS AGE ISTIO-INJECTION
default Active 4d21h enabled
iam Active 3d2h enabled
ingress Active 4d21h enabled
istio-system Active 4d21h disabled
kube-node-lease Active 4d21h
kube-public Active 4d21h
kube-system Active 4d21h
kubernetes-dashboard Active 4d21h
Another quick check is to describe the namespace:
Davids-MacBook-Pro:xtremecloud-sso-minikube davidjbrewer$ kubectl describe namespace iam
Name: iam
Labels: istio-injection=enabled
Annotations: <none>
Status: Active
No resource quota.
No LimitRange resource.
Deploy the NGINX Ingress Controller and configurations:
export KUBE_API_SERVER_IP=$(kubectl get svc kubernetes -n default -o jsonpath='{.spec.clusterIP}')/32
sed "s#__KUBE_API_SERVER_IP__#${KUBE_API_SERVER_IP}#" nginx-in-istio-iam-ns.yaml | kubectl apply -f -
This is the NGINX Controller configuration for deployment into the ‘iam’ namespace:
# nginx-in-istio-iam-ns.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
namespace: iam
annotations:
certmanager.k8s.io/cluster-issuer: letsencrypt-prod
ingress.kubernetes.io/ssl-passthrough: "false"
kubernetes.io/ingress.class: nginx
kubernetes.io/load-balance: ip_hash # ip_hash provides stickiness to the same XtremeCloud SSO pod
kubernetes.io/tls-acme: "true"
nginx.ingress.kubernetes.io/affinity: cookie
nginx.ingress.kubernetes.io/session-cookie-expires: "172800"
nginx.ingress.kubernetes.io/session-cookie-max-age: "172800"
nginx.ingress.kubernetes.io/session-cookie-name: nginx-route
nginx.ingress.kubernetes.io/service-upstream: "true"
nginx.ingress.kubernetes.io/upstream-vhost: sso.iam.svc.cluster.local
nginx.ingress.kubernetes.io/server-snippet: |
proxy_ssl_name sso-dev.eupraxialabs.com;
proxy_ssl_server_name on;
name: nginx-ingress
spec:
rules:
- host: sso-dev.eupraxialabs.com
http:
paths:
- backend:
serviceName: sso
servicePort: 8080
path: /
tls:
- hosts:
- sso-dev.eupraxialabs.com
secretName: sso-dev-eupraxialabs-com
---
# Deployment: nginx-ingress-controller
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-ingress-controller
namespace: iam
spec:
replicas: 1
selector:
matchLabels:
app: ingress-nginx
template:
metadata:
labels:
app: ingress-nginx
annotations:
prometheus.io/port: '10254'
prometheus.io/scrape: 'true'
# Do not redirect inbound traffic to Envoy.
traffic.sidecar.istio.io/includeInboundPorts: ""
traffic.sidecar.istio.io/excludeInboundPorts: "80,443"
# Exclude outbound traffic to kubernetes master from redirection.
traffic.sidecar.istio.io/excludeOutboundIPRanges: __KUBE_API_SERVER_IP__
sidecar.istio.io/inject: 'true'
spec:
serviceAccountName: nginx-ingress-serviceaccount
containers:
- name: nginx
image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.12.0
securityContext:
runAsUser: 0
args:
- /nginx-ingress-controller
- --default-backend-service=$(POD_NAMESPACE)/nginx-default-http-backend
- --configmap=$(POD_NAMESPACE)/nginx-configuration
- --tcp-services-configmap=$(POD_NAMESPACE)/nginx-tcp-services
- --udp-services-configmap=$(POD_NAMESPACE)/nginx-udp-services
- --annotations-prefix=nginx.ingress.kubernetes.io
- --v=10
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
livenessProbe:
failureThreshold: 8
initialDelaySeconds: 15
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
httpGet:
path: /healthz
port: 10254
scheme: HTTP
readinessProbe:
failureThreshold: 8
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
httpGet:
path: /healthz
port: 10254
scheme: HTTP
---
# Service: ingress-nginx
apiVersion: v1
kind: Service
metadata:
name: ingress-nginx
namespace: iam
labels:
app: ingress-nginx
spec:
type: LoadBalancer
selector:
app: ingress-nginx
ports:
- name: http
port: 80
targetPort: http
- name: https
port: 443
targetPort: https
---
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-configuration
namespace: iam
labels:
app: ingress-nginx
data:
ssl-redirect: "true"
use-forwarded-headers: "true"
---
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-tcp-services
namespace: iam
labels:
app: ingress-nginx
---
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-udp-services
namespace: iam
labels:
app: ingress-nginx
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: nginx-ingress-serviceaccount
namespace: iam
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: nginx-ingress-clusterrole
namespace: iam
rules:
- apiGroups:
- ""
resources:
- configmaps
- endpoints
- nodes
- pods
- secrets
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- "extensions"
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- "extensions"
resources:
- ingresses/status
verbs:
- update
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
name: nginx-ingress-role
namespace: iam
rules:
- apiGroups:
- ""
resources:
- configmaps
- pods
- secrets
- namespaces
verbs:
- get
- apiGroups:
- ""
resources:
- configmaps
resourceNames:
# Defaults to "<election-id>-<ingress-class>"
# Here: "<ingress-controller-leader>-<nginx>"
# This has to be adapted if you change either parameter
# when launching the nginx-ingress-controller.
- "ingress-controller-leader-nginx"
verbs:
- get
- update
- apiGroups:
- ""
resources:
- configmaps
verbs:
- create
- apiGroups:
- ""
resources:
- endpoints
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
name: nginx-ingress-role-nisa-binding
namespace: iam
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: nginx-ingress-role
subjects:
- kind: ServiceAccount
name: nginx-ingress-serviceaccount
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: nginx-ingress-clusterrole-nisa-binding
namespace: iam
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: nginx-ingress-clusterrole
subjects:
- kind: ServiceAccount
name: nginx-ingress-serviceaccount
namespace: iam
---
# Deployment: nginx-default-http-backend
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-default-http-backend
namespace: iam
labels:
app: nginx-default-http-backend
spec:
replicas: 1
selector:
matchLabels:
app: nginx-default-http-backend
template:
metadata:
labels:
app: nginx-default-http-backend
# rewrite kubelet's probe request to pilot agent to prevent health check failure under mtls
annotations:
sidecar.istio.io/rewriteAppHTTPProbers: "true"
spec:
terminationGracePeriodSeconds: 60
containers:
- name: backend
# Any image is permissible as long as:
# 1. It serves a 404 page at /
# 2. It serves 200 on a /healthz endpoint
image: gcr.io/google_containers/defaultbackend:1.4
securityContext:
runAsUser: 0
ports:
- name: http
containerPort: 8080
livenessProbe:
httpGet:
path: /healthz
port: 8080
scheme: HTTP
initialDelaySeconds: 30
timeoutSeconds: 5
resources:
limits:
cpu: 10m
memory: 20Mi
requests:
cpu: 10m
memory: 20Mi
---
# Service: nginx-default-http-backend
apiVersion: v1
kind: Service
metadata:
name: nginx-default-http-backend
namespace: iam
labels:
app: nginx-default-http-backend
spec:
ports:
- name: http
port: 80
targetPort: http
selector:
app: nginx-default-http-backend
---
We’re not going to cover the details of the Cert Manager (ACME) installation, but we’ll show you some deployment details:
Davids-MacBook-Pro:xtremecloud-sso-minikube davidjbrewer$ helm ls
NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE
cert-manager 1 Mon Aug 10 10:19:40 2020 DEPLOYED cert-manager-v0.16.0 v0.16.0 cert-manager
Davids-MacBook-Pro:xtremecloud-sso-minikube davidjbrewer$ kubectl get certs
NAME READY SECRET AGE
sso-dev.eupraxialabs-com True sso-dev-eupraxialabs-com 30h
Davids-MacBook-Pro:xtremecloud-sso-minikube davidjbrewer$ kubectl get clusterissuer
NAME READY AGE
letsencrypt-prod True 30h
Davids-MacBook-Pro:xtremecloud-sso-minikube davidjbrewer$ kubectl get pods -n cert-manager
NAME READY STATUS RESTARTS AGE
cert-manager-c456f8b56-pf7f6 1/1 Running 5 30h
cert-manager-cainjector-6b4f5b9c99-jlrps 1/1 Running 10 30h
cert-manager-webhook-5cfd5478b-srt2v 1/1 Running 7 30h
With Let’s Encrypt (details not covered here) installed, let’s ‘exec’ into the sidecar of the NGINX Controller and connect to NGINX and verify the certificate:
Davids-MacBook-Pro:xtremecloud-sso-minikube davidjbrewer$ kubectl exec -it $(kubectl get pod -l app=ingress-nginx -o jsonpath={.items..metadata.name}) -c istio-proxy -- curl -v --resolve sso-dev.eupraxialabs.com:443:127.0.0.1 https://sso-dev.eupraxialabs.com
* Added sso-dev.eupraxialabs.com:443:127.0.0.1 to DNS cache
* Rebuilt URL to: https://sso-dev.eupraxialabs.com/
* Hostname sso-dev.eupraxialabs.com was found in DNS cache
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to sso-dev.eupraxialabs.com (127.0.0.1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server accepted to use h2
* Server certificate:
* subject: CN=sso-dev.eupraxialabs.com
* start date: Aug 10 14:25:20 2020 GMT
* expire date: Nov 8 14:25:20 2020 GMT
* subjectAltName: host "sso-dev.eupraxialabs.com" matched cert's "sso-dev.eupraxialabs.com"
* issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
* SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x5555e9bce580)
> GET / HTTP/2
> Host: sso-dev.eupraxialabs.com
> User-Agent: curl/7.58.0
> Accept: */*
>
* Connection state changed (MAX_CONCURRENT_STREAMS updated)!
< HTTP/2 200
< server: nginx/1.13.9
< date: Tue, 11 Aug 2020 20:54:49 GMT
< content-type: text/html
< content-length: 1087
< vary: Accept-Encoding
< last-modified: Fri, 01 May 2020 15:08:38 GMT
< accept-ranges: bytes
< x-envoy-upstream-service-time: 2
< strict-transport-security: max-age=15724800; includeSubDomains;
<
<!--
~ Copyright 2016 Red Hat, Inc. and/or its affiliates
~ and other contributors as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="refresh" content="0; url=/auth/" />
<meta name="robots" content="noindex, nofollow">
<script type="text/javascript">
window.location.href = "/auth/"
</script>
</head>
<body>
If you are not redirected automatically, follow this <a href='/auth'>link</a>.
</body>
</html>
* Connection #0 to host sso-dev.eupraxialabs.com left intact
As expected, we have a valid LetsEncrypt certificate applied to the NGINX Kubernetes Ingress Controller (KIC) and we connected to the SSO pod.
A quick check inside the NGINX Controller container shows the valid certificates:
Davids-MacBook-Pro:xtremecloud-sso-minikube davidjbrewer$ k exec -it nginx-ingress-controller-6c6fdf5598-jz89l -c nginx -- bash
root@nginx-ingress-controller-6c6fdf5598-jz89l:/# ls -lsa
.dockerenv boot/ etc/ lib/ mnt/ proc/ sbin/ tmp/
Dockerfile build.sh home/ lib64/ nginx-ingress-controller root/ srv/ usr/
bin/ dev/ ingress-controller/ media/ opt/ run/ sys/ var/
root@nginx-ingress-controller-6c6fdf5598-jz89l:/# ls -lsa ingress-controller/
clean-nginx-conf.sh ssl/
root@nginx-ingress-controller-6c6fdf5598-jz89l:/# ls -lsa ingress-controller/ssl/
default-fake-certificate.pem iam-sso-dev-eupraxialabs-com-full-chain.pem iam-sso-dev-eupraxialabs-com.pem
root@nginx-ingress-controller-6c6fdf5598-jz89l:/# ls -lsa ingress-controller/ssl/
total 28
4 drw-r-xr-x 2 root root 4096 Aug 5 16:54 .
4 drwxrwxr-x 1 root root 4096 Aug 5 16:53 ..
4 -rw------- 1 root root 2933 Aug 5 16:53 default-fake-certificate.pem
8 -rw-r--r-- 1 root root 4782 Aug 5 16:54 iam-sso-dev-eupraxialabs-com-full-chain.pem
8 -rw------- 1 root root 5258 Aug 5 16:53 iam-sso-dev-eupraxialabs-com.pem
Note the presence of the default-fake certificate. That fake certificate is defined by the NGINX Ingress Controller for all Ingress resources that do not define their own. If a certificate is not provided, the fake is used. An Istio Ingress Gateway does not have a fake certificate for use. The certificate must be defined in every Gateway resource.
Let’s look at the pods running in the istio-system namespace:
Davids-MacBook-Pro:xtremecloud-sso-minikube davidjbrewer$ kubectl get po -n istio-system
NAME READY STATUS RESTARTS AGE
grafana-b54bb57b9-z7dpt 1/1 Running 3 2d4h
istio-egressgateway-7486cf8c97-pnb54 1/1 Running 3 2d4h
istio-ingressgateway-6bcb9d7bbf-qkkgt 0/1 Running 4 2d4h
istio-tracing-9dd6c4f7c-bbjs2 1/1 Running 6 2d4h
istiod-788f76c8fc-hhk4b 1/1 Running 4 2d4h
kiali-d45468dc4-2s2tr 1/1 Running 3 2d4h
prometheus-6477cfb669-jqjvp 2/2 Running 11 2d4h
Although the *istio-ingressgateway is not running, it does not affect the NGINX Ingress Contoller’s functions. Remember, we have annotations in our NGINX KIC deployment to not use the Istio Envoy Proxy for ingress into the service mesh:
traffic.sidecar.istio.io/includeInboundPorts: ""
traffic.sidecar.istio.io/excludeInboundPorts: "80,443"
Davids-MacBook-Pro:xtremecloud-sso-minikube davidjbrewer$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx LoadBalancer 10.97.201.174 10.97.201.174 80:31767/TCP,443:32396/TCP 30h
nginx-default-http-backend ClusterIP 10.96.122.98 <none> 80/TCP 30h
postgres ClusterIP 10.110.39.39 <none> 5432/TCP 2d4h
sso ClusterIP 10.109.50.231 <none> 8080/TCP 30h
Installation Summary
Let’s bring up K9s and look at the installation results.
Additional Information
Let’s get a status on the Istio Service Mesh:
Davids-MacBook-Pro:xtremecloud-sso-minikube davidjbrewer$ istioctl proxy-status
NAME CDS LDS EDS RDS PILOT VERSION
httpbin-66cdbdb6c5-s6zl7.default SYNCED SYNCED SYNCED SYNCED istiod-59b9dd8b9c-7tb97 1.6.5
istio-ingressgateway-6f9df9b8-rc46f.istio-system SYNCED SYNCED SYNCED SYNCED istiod-59b9dd8b9c-7tb97 1.6.5
nginx-default-http-backend-7bc59fd8f-qwqvd.ingress SYNCED SYNCED SYNCED SYNCED istiod-59b9dd8b9c-7tb97 1.6.5
nginx-default-http-backend-7bc59fd8f-skln7.iam SYNCED SYNCED SYNCED SYNCED istiod-59b9dd8b9c-7tb97 1.6.5
nginx-ingress-controller-6c6fdf5598-d72hw.ingress SYNCED SYNCED SYNCED SYNCED istiod-59b9dd8b9c-7tb97 1.6.5
nginx-ingress-controller-6c6fdf5598-gh4wc.default SYNCED SYNCED SYNCED SYNCED istiod-59b9dd8b9c-7tb97 1.6.5
nginx-ingress-controller-6c6fdf5598-jz89l.iam SYNCED SYNCED SYNCED SYNCED istiod-59b9dd8b9c-7tb97 1.6.5
postgres-6cbbc9d488-7wssm.iam SYNCED SYNCED SYNCED SYNCED istiod-59b9dd8b9c-7tb97 1.6.5
prometheus-6477cfb669-6h2xb.istio-system SYNCED SYNCED SYNCED SYNCED istiod-59b9dd8b9c-7tb97 1.6.5
xtremecloud-sso-minikube-0.iam SYNCED SYNCED SYNCED SYNCED istiod-59b9dd8b9c-7tb97 1.6.5
If a proxy is missing from this list it means that it is not currently connected to a Istiod instance so will not be receiving any configuration.
- SYNCED means that Envoy has acknowledged the last configuration Istiod has sent to it.
- NOT SENT means that Istiod hasn’t sent anything to Envoy. This usually is because Istiod has nothing to send.
- STALE means that Istiod has sent an update to Envoy but has not received an acknowledgement. This usually indicates a networking issue between Envoy and Istiod or a bug with Istio itself.
So, we’re healthy.
Advanced Debugging Techniques
If you are experiencing issues with getting Cert-Manager (ACME) issuing a certificate due to a DNS-01 challenge, check the following.
From a dnsutils pod, let’s look up a domain’s Start of Authority (SOA) record:
Davids-MacBook-Pro:xtremecloud-sso-minikube davidjbrewer$ kubectl exec -i -t -n default dnsutils -- nslookup -type=soa eupraxialabs.com
Server: 10.96.0.10
Address: 10.96.0.10#53
cluster.local
origin = ns.dns.cluster.local
mail addr = hostmaster.cluster.local
serial = 1597589609
refresh = 7200
retry = 1800
expire = 86400
minimum = 30
That is not the expected result. Cert-Manager expects to see the following, since Cloudflare is providing the DNS services:
Let’s see if cert-manager added the TXT record to the DNS provider:
Davids-MacBook-Pro:xtremecloud-sso-minikube davidjbrewer$ dig _acme-challenge.eupraxialabs.com TXT
; <<>> DiG 9.10.6 <<>> _acme-challenge.eupraxialabs.com TXT
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 34862
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;_acme-challenge.eupraxialabs.com. IN TXT
;; AUTHORITY SECTION:
eupraxialabs.com. 900 IN SOA gabe.ns.cloudflare.com. dns.cloudflare.com. 2034925929 10000 2400 604800 3600
;; Query time: 44 msec
;; SERVER: 192.168.1.1#53(192.168.1.1)
;; WHEN: Sun Aug 16 13:09:54 CDT 2020
;; MSG SIZE rcvd: 120
That is the expected result. Another easy way to check, outside of Kubernetes, is to do a nslookup type query of SOA on the domain of interest.
Davids-MacBook-Pro:xtremecloud-sso-minikube davidjbrewer$ nslookup -type=soa eupraxialabs.com
Server: 192.168.1.1
Address: 192.168.1.1#53
Non-authoritative answer:
eupraxialabs.com
origin = gabe.ns.cloudflare.com
mail addr = dns.cloudflare.com
serial = 2034925929
refresh = 10000
retry = 2400
expire = 604800
minimum = 3600
Authoritative answers can be found from:
We’re going to edit the configMap for CoreDNS and set up an external resolver to a Google DNS server:
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: v1
data:
Corefile: |
.:53 {
errors
health {
lameduck 5s
}
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . 8.8.8.8 <<<<<<<<<<<<<<<<<<<<<<<<************* changed from /etc/resolv.conf
cache 30
loop
reload
loadbalance
}
kind: ConfigMap
metadata:
creationTimestamp: "2020-08-14T19:46:54Z"
managedFields:
- apiVersion: v1
fieldsType: FieldsV1
fieldsV1:
f:data: {}
manager: kubeadm
operation: Update
time: "2020-08-14T20:34:23Z"
- apiVersion: v1
fieldsType: FieldsV1
fieldsV1:
f:data:
f:Corefile: {}
manager: kubectl
operation: Update
time: "2020-08-16T18:44:33Z"
name: coredns
namespace: kube-system
resourceVersion: "49014"
selfLink: /api/v1/namespaces/kube-system/configmaps/coredns
uid: e4fae5b4-baa6-47a0-aa71-68cdb7dd5e33
Delete the CoreDNS pod and try it again:
Davids-MacBook-Pro:xtremecloud-sso-minikube davidjbrewer$ kubectl exec -i -t -n default dnsutils -- nslookup -type=soa eupraxialabs.com
Server: 10.96.0.10
Address: 10.96.0.10#53
cluster.local
origin = ns.dns.cluster.local
mail addr = hostmaster.cluster.local
serial = 1597611039
refresh = 7200
retry = 1800
expire = 86400
minimum = 30
It provides the same answer, so it looks inconclusive. However, cert-manager was able to get the SOA and the certificate was issued as expected. Again, this is being done in MiniKube and needs further investigation.
Logging Levels for an Istio Proxy
Let’s take a look at logging levels within an istio-proxy.
As we will see, it is very easy to change the logging level of an istio-proxy:
$ kubectl exec -it xtremecloud-sso-minikube-0 -c istio-proxy -- sh -c 'curl -k -X POST localhost:15000/logging?level=info'
active loggers:
admin: info
aws: info
assert: info
backtrace: info
cache_filter: info
client: info
config: info
connection: info
conn_handler: info
decompression: info
dubbo: info
file: info
filter: info
forward_proxy: info
grpc: info
hc: info
health_checker: info
http: info
http2: info
hystrix: info
init: info
io: info
jwt: info
kafka: info
lua: info
main: info
misc: info
mongo: info
quic: info
quic_stream: info
pool: info
rbac: info
redis: info
router: info
runtime: info
stats: info
secret: info
tap: info
testing: info
thrift: info
tracing: info
upstream: info
udp: info
wasm: info
We’re going to put our sidecar that is in the pod with XtremeCloud SSO into ‘debug’ mode:
$ kubectl exec -it xtremecloud-sso-minikube-0 -c istio-proxy -- sh -c 'curl -k -X POST localhost:15000/logging?level=debug'
active loggers:
admin: debug
aws: debug
assert: debug
backtrace: debug
cache_filter: debug
client: debug
config: debug
connection: debug
conn_handler: debug
decompression: debug
dubbo: debug
file: debug
filter: debug
forward_proxy: debug
grpc: debug
hc: debug
health_checker: debug
http: debug
http2: debug
hystrix: debug
init: debug
io: debug
jwt: debug
kafka: debug
lua: debug
main: debug
misc: debug
mongo: debug
quic: debug
quic_stream: debug
pool: debug
rbac: debug
redis: debug
router: debug
runtime: debug
stats: debug
secret: debug
tap: debug
testing: debug
thrift: debug
tracing: debug
upstream: debug
udp: debug
wasm: debug
As we can see, ‘debug’ entries are now appearing in the XtremeCloud SSO sidecar logs:
$ kubectl logs -f xtremecloud-sso-minikube-0 -c istio-proxy
2020-08-02T15:16:55.629304Z debug envoy http [external/envoy/source/common/http/conn_manager_impl.cc:1337] [C14064][S17228183679396321216] request end stream
2020-08-02T15:16:55.629333Z debug envoy router [external/envoy/source/common/router/router.cc:477] [C14064][S17228183679396321216] cluster 'agent' match for URL '/healthz/ready'
2020-08-02T15:16:55.629362Z debug envoy router [external/envoy/source/common/router/router.cc:634] [C14064][S17228183679396321216] router decoding headers:
':authority', '172.17.0.12:15021'
':path', '/healthz/ready'
':method', 'GET'
':scheme', 'http'
'user-agent', 'kube-probe/1.18'
'accept-encoding', 'gzip'
'x-forwarded-proto', 'http'
'x-request-id', '5c46e1fd-19fd-48f0-9814-64576b5f1467'
'x-envoy-expected-rq-timeout-ms', '15000'
2020-08-02T15:16:55.629399Z debug envoy pool [external/envoy/source/common/http/conn_pool_base.cc:118] [C7] using existing connection
2020-08-02T15:16:55.629409Z debug envoy pool [external/envoy/source/common/http/conn_pool_base.cc:68] [C7] creating stream
2020-08-02T15:16:55.629422Z debug envoy router [external/envoy/source/common/router/upstream_request.cc:317] [C14064][S17228183679396321216] pool ready
2020-08-02T15:16:55.630491Z debug envoy http [external/envoy/source/common/http/conn_manager_impl.cc:268] [C10704] new stream
2020-08-02T15:16:55.630976Z debug envoy http [external/envoy/source/common/http/conn_manager_impl.cc:782] [C10704][S1098415029100968055] request headers complete (end_stream=true):
':authority', '127.0.0.1:15000'
':path', '/stats?usedonly&filter=^(server.state|listener_manager.workers_started)'
':method', 'GET'
'user-agent', 'Go-http-client/1.1'
'accept-encoding', 'gzip'
2020-08-02T15:16:55.630992Z debug envoy http [external/envoy/source/common/http/conn_manager_impl.cc:1337] [C10704][S1098415029100968055] request end stream
2020-08-02T15:16:55.631007Z debug envoy admin [external/envoy/source/server/http/admin_filter.cc:66] [C10704][S1098415029100968055] request complete: path: /stats?usedonly&filter=^(server.state|listener_manager.workers_started)
2020-08-02T15:16:55.637364Z debug envoy http [external/envoy/source/common/http/conn_manager_impl.cc:1710] [C10704][S1098415029100968055] encoding headers via codec (end_stream=false):
':status', '200'
'content-type', 'text/plain; charset=UTF-8'
'cache-control', 'no-cache, max-age=0'
'x-content-type-options', 'nosniff'
'date', 'Sun, 02 Aug 2020 15:16:55 GMT'
'server', 'envoy'
2020-08-02T15:16:55.637738Z debug envoy client [external/envoy/source/common/http/codec_client.cc:104] [C7] response complete
2020-08-02T15:16:55.637774Z debug envoy router [external/envoy/source/common/router/router.cc:1149] [C14064][S17228183679396321216] upstream headers complete: end_stream=true
2020-08-02T15:16:55.637830Z debug envoy http [external/envoy/source/common/http/conn_manager_impl.cc:1649] [C14064][S17228183679396321216] closing connection due to connection close header
2020-08-02T15:16:55.637847Z debug envoy http [external/envoy/source/common/http/conn_manager_impl.cc:1710] [C14064][S17228183679396321216] encoding headers via codec (end_stream=true):
':status', '200'
'date', 'Sun, 02 Aug 2020 15:16:55 GMT'
'content-length', '0'
'x-envoy-upstream-service-time', '8'
'server', 'envoy'
'connection', 'close'
2020-08-02T15:16:55.637872Z debug envoy connection [external/envoy/source/common/network/connection_impl.cc:109] [C14064] closing data_to_write=143 type=2
2020-08-02T15:16:55.637882Z debug envoy connection [external/envoy/source/common/network/connection_impl_base.cc:30] [C14064] setting delayed close timer with timeout 1000 ms
2020-08-02T15:16:55.637899Z debug envoy pool [external/envoy/source/common/http/http1/conn_pool.cc:48] [C7] response complete
2020-08-02T15:16:55.637910Z debug envoy pool [external/envoy/source/common/http/conn_pool_base.cc:93] [C7] destroying stream: 0 remaining
2020-08-02T15:16:55.637995Z debug envoy connection [external/envoy/source/common/network/connection_impl.cc:622] [C14064] write flush complete
2020-08-02T15:16:55.638888Z debug envoy connection [external/envoy/source/common/network/connection_impl.cc:514] [C14064] remote early close
2020-08-02T15:16:55.638901Z debug envoy connection [external/envoy/source/common/network/connection_impl.cc:200] [C14064] closing socket: 0
2020-08-02T15:16:55.638954Z debug envoy conn_handler [external/envoy/source/server/connection_handler_impl.cc:111] [C14064] adding to cleanup list
Two (2) Entry Points into the Istio Service Mesh
Ingress-nginx is our ingress into the Service Mesh with XtremeCloud SSO behind the proxy. Istio-ingressgateway is our Envoy ingress into the Service Mesh.
Davids-MacBook-Pro:xtremecloud-sso-minikube davidjbrewer$ minikube -p xtremecloud-istio tunnel
Status:
machine: xtremecloud-istio
pid: 18649
route: 10.96.0.0/12 -> 192.168.99.100
minikube: Running
services: [ingress-nginx, istio-ingressgateway]
errors:
minikube: no errors
router: no errors
loadbalancer emulator: no errors
Status:
machine: xtremecloud-istio
pid: 18649
route: 10.96.0.0/12 -> 192.168.99.100
minikube: Running
services: [ingress-nginx, istio-ingressgateway]
errors:
minikube: no errors
router: no errors
loadbalancer emulator: no errors