This tutorial was contributed by Ambassador.
Ambassador Edge Stack (AES) is an API gateway that serves as an ingress controller into your Kubernetes cluster. AES offers a comprehensive set of security functionality, supports a broad range of protocols, and supports progressive releases with modern traffic management.
You can use Consul with AES for service discovery and end-to-end TLS, including mTLS between services. This capability is particularly useful when deploying AES in hybrid clouds, where applications are deployed on VMs and Kubernetes. In this environment, AES can securely route over TLS to any application regardless of where it is deployed.
In this tutorial, you will register a service with Consul and use AES to dynamically route requests to that service based on Consul’s service discovery catalog.
Prerequisites
Before you start, you will need the following.
- kubectl v1.21+
- Helm v3.5.4+
- An active Kubernetes Cluster
- Properly configured permissions depending on your platform
NOTE: You may use Minikube with the VirtualBox driver in this tutorial. However, be aware that this deployment is intended for a public cloud environment. If you decide to use Minikube then ensure you are starting Minikube with sufficient resources minikube start --driver=virtualbox --cpus 4 --memory 6000MB
Install Ambassador
Install AES with the Ambassador Helm chart. You can reference the Ambassador quickstart for detailed installation instructions and options.
Add the Ambassador repository with Helm.
$ helm repo add datawire https://www.getambassador.io
Next, create a namespace for Ambassador and install the Helm chart.
$ kubectl create namespace ambassador && \
helm install ambassador --namespace ambassador datawire/ambassador && \
kubectl -n ambassador wait --for condition=available --timeout=90s deploy -lproduct=aes
Verify the deployment is successful by retrieving the Ambassador services information.
$ kubectl -n ambassador get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ambassador LoadBalancer 10.104.22.0 10.104.22.0 80:30249/TCP,443:32184/TCP 4m2s
ambassador-admin ClusterIP 10.105.158.155 <none> 8877/TCP,8005/TCP 4m2s
ambassador-redis ClusterIP 10.102.28.18 <none> 6379/TCP 4m2s
Install Consul
You can install Consul on a variety of platforms. A few common platforms include GKE, AKS, and EKS. For more information on installing Consul with these popular platforms, check out the following links.
Add the HashiCorp repository to install Consul with Helm.
$ helm repo add hashicorp https://helm.releases.hashicorp.com
Copy the below Consul installation values into a new YAML file.
global:
datacenter: dc1
ui:
service:
type: 'LoadBalancer'
syncCatalog:
enabled: true
server:
replicas: 1
bootstrapExpect: 1
connectInject:
enabled: true
consul-values.yaml
Install Consul with Helm and the consul-values.yaml file.
$ helm install -f consul-values.yaml hashicorp hashicorp/consul --version "0.34.1"
To verify your deployment, ensure that all Consul pods are running.
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
hashicorp-consul-96fgh 1/1 Running 0 51s
hashicorp-consul-connect-injector-webhook-deployment-cfd756cqrb 1/1 Running 0 51s
hashicorp-consul-connect-injector-webhook-deployment-cfd75dkghr 1/1 Running 0 51s
hashicorp-consul-server-0 1/1 Running 0 51s
hashicorp-consul-sync-catalog-cfdc976cf-mb5ss 1/1 Running 0 51s
hashicorp-consul-webhook-cert-manager-549b7d6798-kqvlq 1/1 Running 0 51s
Configure Ambassador Edge Stack
You must have the AES quickstart completed or properly installed AES for this section to work.
The ConsulResolver allows services to register with Consul, it is opt-in and must be configured. For each Mapping you want to use with the ConsulResolver, you will apply the resolver: consul-dc1
value. If the ConsulResolver is not specified, the default resolver will be used.
Enable AES to discover services registered to Consul by creating the ConsulResolver. Copy the configuration values into a new YAML file and apply them with kubectl
.
---
apiVersion: getambassador.io/v2
kind: ConsulResolver
metadata:
name: consul-dc1
spec:
address: http://hashicorp-consul-server-0.hashicorp-consul-server.default.svc.cluster.local:8500
datacenter: dc1
consul-resolver.yaml
$ kubectl apply -f consul-resolver.yaml
Register an application with Consul
To test AES’s routing functionality, resister a demo application with Consul. AES will use the endpoint data from Consul once the service is registered.
Define and deploy the demo application
Create a specification that will register the quote pod as a Consul service with the name quote-consul
.
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: quote-consul
spec:
replicas: 1
strategy:
type: RollingUpdate
selector:
matchLabels:
app: quote-consul
template:
metadata:
labels:
app: quote-consul
annotations:
'consul.hashicorp.com/connect-inject': 'false'
spec:
containers:
- name: backend
image: docker.io/datawire/quote:0.5.0
ports:
- name: http
containerPort: 8080
env:
- name: CONSUL_IP
valueFrom:
fieldRef:
fieldPath: status.hostIP
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: SERVICE_NAME
value: 'quote-consul'
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 3
resources:
limits:
cpu: '0.1'
memory: 100Mi
quote.yaml
The quote application contains code to automatically register itself with Consul, with the CONSUL_IP
and POD_IP
environment variables specified within the quote container spec.
Note, the SERVICE_NAME
environment variable in the quote deployment specifies the service name for Consul. The default value is set to quote-consul
, so you only need to include it if you want to change the service name.
Deploy the demo application in Kubernetes. Note that in practice this application can be deployed anywhere in your data center (e.g., on VMs).
$ kubectl apply -f quote.yaml
Verify success
Verify the quote pod is registered with Consul. You can verify the quote pod is registered correctly by accessing the Consul UI.
$ kubectl port-forward service/hashicorp-consul-ui 8500:80
Navigate to http://localhost:8500/
from a web browser, the service named quote-consul
should be displayed.
Route to Consul services
Now that you have a demo application registered with Consul, you can configure AES to route traffic to it.
Create the Mapping for Quote-Consul
Copy the following configuration values into a new YAML file.
---
apiVersion: getambassador.io/v2
kind: Mapping
metadata:
name: consul-quote-mapping
spec:
prefix: /quote-consul/
service: quote-consul
resolver: consul-dc1
load_balancer:
policy: round_robin
quote-mapping.yaml
Install the Mapping to your cluster with kubectl
.
$ kubectl apply -f quote-mapping.yaml
Verify success
Add the Ambassador IP as an environment variable.
export AMBASSADOR_LB_ENDPOINT=$(kubectl -n ambassador get svc ambassador \
-o "go-template={{range .status.loadBalancer.ingress}}{{or .ip .hostname}}{{end}}")
NOTE: If using Minikube, be aware that this deployment uses the Kubernetes resource type LoadBalancer. To circumvent this limitation and expose an external IP address in Minikube, you may follow the steps suggested in this StackOverflow post. You may also use the command minikube tunnel
as an alternative. If you choose to use minikube tunnel
then issue the command in a different shell session.
Send a request to the quote-consul
API with curl. Replace $AMBASSADOR_LB_ENDPOINT
with your Ambassador IP.
$ curl --location --insecure http://$AMBASSADOR_LB_ENDPOINT/quote-consul/
{
"server": "janky-elderberry-vtqtolsz",
"quote": "The last sentence you read is often sensible nonsense.",
"time": "2021-03-24T23:33:08.515530972Z"
}
The response demonstrates that you are successfully routing traffic to the quote application, the location of which is registered in Consul.
Encrypt traffic with the Consul connector
AES can use certificates stored in Consul to originate encrypted TLS connections from AES to services in the Consul service mesh. This requires the use of the AES Consul connector.
The AES Consul connector retrieves the TLS certificate issued by the Consul CA and stores it in a Kubernetes secret for AES to use. The AES Consul Connector will install the following into your cluster:
- RBAC resources
- the Consul connector service
- a TLSContext named
ambassador-consul
to load theambassador-consul-connect
secret into Ambassador Edge Stack
Deploy the Ambassador Edge Stack Consul connector
Deploy Ambassador Edge Stack Consul connector with the following command.
$ kubectl apply -f https://www.getambassador.io/yaml/consul/ambassador-consul-connector.yaml
Deploy another demo application
Deploy a new version of the demo application and configure it to inject the Consul sidecar proxy by setting consul.hashicorp.com/connect-inject
to true
.
Copy the following configuration values into a new YAML file.
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: quote-connect
spec:
replicas: 1
strategy:
type: RollingUpdate
selector:
matchLabels:
app: quote-connect
template:
metadata:
labels:
app: quote-connect
annotations:
'consul.hashicorp.com/connect-inject': 'true'
spec:
containers:
- name: quote
image: docker.io/datawire/quote:0.5.0
ports:
- name: http
containerPort: 8080
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 3
resources:
limits:
cpu: '0.1'
memory: 100Mi
---
apiVersion: v1
kind: Service
metadata:
name: quote-connect
annotations:
a8r.io/description: 'Quote of the moment service'
a8r.io/owner: 'No owner'
a8r.io/chat: '#ambassador'
a8r.io/bugs: 'https://github.com/datawire/qotm/issues'
a8r.io/documentation: 'https://github.com/datawire/qotm/blob/master/README.md'
a8r.io/repository: 'https://github.com/datawire/qotm'
a8r.io/support: 'http://a8r.io/Slack'
a8r.io/runbook: 'https://github.com/datawire/qotm/blob/master/README.md'
a8r.io/incidents: 'https://github.com/datawire/qotm/issues'
a8r.io/dependencies: 'None'
spec:
ports:
- name: http
port: 80
targetPort: 8080
selector:
app: quote-connect
quote-connect.yaml
Annotations attach metadata to Kubernetes objects. You can use annotations to link external information to objects, working in a similar, yet different, fashion to labels. For more information on annotations, you can check out this article, or get started with annotations in your own cluster here.
Apply the demo application to your cluster with kubectl
$ kubectl apply -f quote-connect.yaml
This will deploy a demo application called quote-connect
with the Consul Connect sidecar proxy. The sidecar proxy will register the application with Consul, require TLS to access the application, and expose other Consul service segmentation features.
Verify success
Verify the quote-connect
application is registered in Consul by accessing the Consul UI on http://localhost:8500/
after configuring port forwarding.
$ kubectl port-forward service/hashicorp-consul-ui 8500:80
The quote
service should be displayed in the Consul UI. It gets its name from the container’s name property we defined in the YAML above.
Create the Mapping for Consul service mesh
Create a Mapping to route to the quote
service in Consul.
---
apiVersion: getambassador.io/v2
kind: Mapping
metadata:
name: quote-connect-mapping
spec:
prefix: /quote-connect/
service: quote-connect-sidecar-proxy
resolver: consul-dc1
tls: ambassador-consul
load_balancer:
policy: round_robin
quote-connect-mapping.yaml
Apply the mapping to your cluster.
$ kubectl apply -f quote-connect-mapping.yaml
Verify success
Send a request to the /quote-connect/
API. Replace $AMBASSADOR_LB_ENDPOINT
with your Ambassador IP, if you didn’t set the environment variable through the AES quickstart.
$ curl --location --insecure http://$AMBASSADOR_LB_ENDPOINT/quote-connect/
{
"server": "tasty-banana-2h6qpwme",
"quote": "Nihilism gambles with lives, happiness, and even destiny itself!",
"time": "2021-03-24T23:31:58.47597266Z"
}
The response demonstrates that you are securely routing traffic to the quote application through the Consul Connect service mesh sidecar proxy.
Clean-up
You can remove all deployed resources by issuing the command below.
$ kubectl delete -f quote-connect-mapping.yaml && \
kubectl delete -f quote-connect.yaml && \
kube delete -f https://www.getambassador.io/yaml/consul/ambassador-consul-connector.yaml && \
kubectl delete -f quote-mapping.yaml && \
kubectl delete -f quote.yaml && \
kubectl delete -f consul-resolver.yaml && \
helm uninstall hashicorp && \
helm uninstall ambassador -n ambassador && \
kubectl delete ns ambassador
Next steps
In this tutorial you configured AES to route traffic to a service registered with Consul.
To learn more about Ambassador Edge Stack’s use cases and features, review the Ambassador site. You can learn more about other load balancer integrations with Consul by visiting the LoadBalancer collection