Seamlessly encrypt traffic from any apps in your Service Mesh to Memorystore (Redis)
Updated on December 16th, 2022 with the deployment of Online Boutique via its Helm chart.
Anthos Service Mesh (ASM), a managed Istio implementation, can improve your security posture for your Kubernetes clusters and your apps. Istio aims to bring as much value to users out of the box without any configuration at all. ASM, on top of that, simplifies all the management of both the control plane and the data plane and the integration with monitoring and logging. Without any compromise, your apps in your Mesh will benefit from advanced features like traffic encryption, logging, tracing, etc. without updating the code of your apps.
In this tutorial, we will see how easy and seamless it is to encrypt traffic from the Online Boutique sample apps to Memorystore (Redis) by leveraging Istio/ASM. For this, we will set up a TLS origination on the cartservice
app, thanks to Istio configuration.
TLS origination occurs when an Istio proxy (sidecar or egress gateway) is configured to accept unencrypted internal HTTP connections, encrypt the requests, and then forward them to HTTPS servers that are secured using simple or mutual TLS. This is the opposite of TLS termination where an ingress proxy accepts incoming TLS connections, decrypts the TLS, and passes unencrypted requests on to internal mesh services.
Objectives
- Create a Google Kubernetes Engine (GKE) cluster
- Deploy the Online Boutique sample apps with an in-cluster redis database
- Provision a Memorystore (Redis) instance allowing only in-transit encryption
- Connect the
cartservice
app to the Memorystore (Redis) instance - Enable the managed Anthos Service Mesh (ASM) on this cluster
- Configure the TLS origination from the
cartservice
app to the Memorystore (Redis) instance - Verify that the
cartservice
app is successfully communicating over TLS with the Memorystore (Redis) instance
Set up your environment
This assumes that you have a Google Cloud Project already created, that’s where we will provision all the resources needed for this tutorial.
Initialize the common variables used throughout this tutorial:
PROJECT_ID=FIXME-WITH-YOUR-EXISTING_PROJECT-ID
REGION=us-east4
ZONE=us-east4-a
PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format='get(projectNumber)')
To avoid repeating the --project
in the commands throughout this tutorial, let's set the current project:
gcloud config set project ${PROJECT_ID}
Enable the required APIs
gcloud services enable \
redis.googleapis.com \
mesh.googleapis.com
Create a GKE cluster
CLUSTER=redis-tls-tutorial
gcloud container clusters create ${CLUSTER} \
--zone ${ZONE} \
--machine-type=e2-standard-4 \
--num-nodes 4 \
--workload-pool ${PROJECT_ID}.svc.id.goog \
--labels mesh_id=proj-${PROJECT_NUMBER} \
--network default
Deploy the Online Boutique sample apps
Deploy the Online Boutique sample apps using by default an in-cluster Redis database:
NAMESPACE=onlineboutique
helm upgrade onlineboutique oci://us-docker.pkg.dev/online-boutique-ci/charts/onlineboutique \
--install \
--create-namespace \
-n ${NAMESPACE}
After all the apps are successfully deployed, you could navigate to the Online Boutique website by clicking on the link below:
echo -n "http://" && kubectl get svc frontend-external -n ${NAMESPACE} -o json | jq -r '.status.loadBalancer.ingress[0].ip'
Provision a Memorystore (Redis) instance allowing only in-transit encryption
REDIS_NAME=redis-tls-tutorial
gcloud redis instances create ${REDIS_NAME} \
--size 1 \
--region ${REGION} \
--zone ${ZONE} \
--redis-version redis_6_x \
--network default \
--transit-encryption-mode SERVER_AUTHENTICATION
Notes:
- You can connect to a Memorystore (Redis) instance from GKE clusters that are in the same region and use the same network as your instance.
- You cannot connect to a Memorystore (Redis) instance from a GKE cluster without VPC-native/IP aliasing enabled.
- In-transit encryption is only available at creation time of your Memorystore (Redis) instance. The Certificate Authority is valid for 10 years, rotation every 5 years.
Wait for the Memorystore (Redis) instance to be succesfully provisioned and get the connection information of the Memorystore (Redis) instance just provisioned, we will need these information in a following section:
REDIS_IP=$(gcloud redis instances describe ${REDIS_NAME} \
--region ${REGION} \
--format 'get(host)')
REDIS_PORT=$(gcloud redis instances describe ${REDIS_NAME} \
--region ${REGION} \
--format 'get(port)')
Connect the Online Boutique sample apps to the Memorystore (Redis) instance
Update the Online Boutique deployment via its Helm chart:
helm upgrade onlineboutique oci://us-docker.pkg.dev/online-boutique-ci/charts/onlineboutique \
--install \
--create-namespace \
-n ${NAMESPACE} \
--set cartDatabase.inClusterRedis.create=false \
--set cartDatabase.connectionString=${REDIS_IP}:${REDIS_PORT}
This deployment will:
- Update the
cartservice
's environment variables to point to the Memorystore (Redis) instance; - Remove the default in-cluster
redis
database, not needed anymore.
Navigate to the Online Boutique website by clicking on the link below:
echo -n "http://" && kubectl get svc frontend-external -n ${NAMESPACE} -o json | jq -r '.status.loadBalancer.ingress[0].ip'
You should have a HTTP Status: 500 Internal Server Error
page at this point. This is expected since we haven't yet set up the TLS communication between cartservice
and the Memorystore (Redis) instance. With the next sections, we will leverage ASM and Istio in order to accomplish this part and fix the issue!
Install the managed ASM on this cluster
Register your cluster to a Fleet:
gcloud container fleet memberships register ${CLUSTER} \
--gke-cluster ${ZONE}/${CLUSTER} \
--enable-workload-identity
Enable ASM in your Fleet:
gcloud container fleet mesh enable
Enable the ASM automatic control plane management to let Google apply the recommended configuration of ASM:
gcloud container fleet mesh update \
--management automatic \
--memberships ${CLUSTER}
Wait for the managed ASM to be successfully enabled for your GKE cluster (controlePlaneManagement
and dataPlaneManagement
with state: ACTIVE
):
gcloud container fleet mesh describe
Configure the TLS origination from the Mesh to the Memorystore (Redis) instance
Get the Certificate Authority of the Memorystore (Redis) instance:
REDIS_CERT=$(gcloud redis instances describe ${REDIS_NAME} \
--region ${REGION} \
--format 'get(serverCaCerts[0].cert)')
Update the Online Boutique deployment via its Helm chart:
helm upgrade onlineboutique oci://us-docker.pkg.dev/online-boutique-ci/charts/onlineboutique \
--install \
--create-namespace \
-n ${NAMESPACE} \
--set cartDatabase.inClusterRedis.create=false \
--set cartDatabase.connectionString=${REDIS_IP}:${REDIS_PORT} \
--set cartDatabase.externalRedisTlsOrigination.enable=true \
--set cartDatabase.externalRedisTlsOrigination.certificate="${REDIS_CERT}" \
--set cartDatabase.externalRedisTlsOrigination.endpointAddress=${REDIS_IP} \
--set cartDatabase.externalRedisTlsOrigination.endpointPort=${REDIS_PORT}
This deployment will:
- Annotate the
cartservice
deployment to mount theredis-cert
secret via itsistio-proxy
sidecar; - Deploy a
ServiceEntry
to register the Memorystore (Redis) instance in the Mesh as an external endpoint with its private IP address and port; - Deploy a
DestinationRule
to configure the outgoing connections to this Memorystore (Redis) instance with TLS inSIMPLE
mode (notMUTUAL
) with its associated Certificate Authority.
Label the the Online Boutique Namespace
to inject the Istio/ASM sidecar proxies in its apps:
kubectl label namespace ${NAMESPACE} istio-injection=enabled
Restart the cartservice
app in order to inject the Istio/ASM sidecar proxies and configs we just deployed previously:
kubectl rollout restart deployment cartservice \
-n ${NAMESPACE}
As a side note, since Online Boutique v0.38.0, the cartservice
app got a fix allowing to make this TLS origination working properly.
Navigate to the Online Boutique website by clicking on the link below:
echo -n "http://" && kubectl get svc frontend-external -n ${NAMESPACE} -o json | jq -r '.status.loadBalancer.ingress[0].ip'
That’s it! You should now see the Online Boutique website working successfully again, now connected to the Memorystore (Redis) instance over TLS only. Congrats!
Cleaning up
To avoid incurring charges to your Google Cloud account, you can delete the resources used in this tutorial.
Unregister the GKE cluster from the Fleet:
gcloud container fleet memberships unregister ${CLUSTER} \
--project=${PROJECT_ID} \
--gke-cluster=${ZONE}/${CLUSTER}
Delete the GKE cluster:
gcloud container clusters delete ${CLUSTER} \
--zone ${ZONE}
Delete the Memorystore (Redis) instance:
gcloud redis instances delete ${REDIS_NAME}
What’s next
- Watch this ASM value over Istio OSS episode on YouTube.
- Learn more about ASM security best practices.
- Watch this Architecting zero trust networks with GKE and ASM episode on YouTube
- Learn more about how to Strengthen your app’s security with ASM and Anthos Config Management.
Originally posted at mathieu-benoit.github.io.