This is the second article of a series presenting how to enable external binary access to SAS Cloud Analytics Services (CAS) by applying core connectivity principles: a valid network route, proper DNS resolution, and trusted TLS certificates.
In the first article you can find a description of the architecture, requirements and preliminary checks; here we present a practical walkthrough using the automation provided by cloud environments and the CAS Operator to provision a Kubernetes LoadBalancer Service.
The post includes client‑side verification steps, and a connection example using the Python SWAT package, demonstrating end‑to‑end connectivity from an external environment.
The core objective is to show the “happy path” for managed/cloud-like environments where Kubernetes can provision a LoadBalancer and possibly assign a DNS record automatically.
In short: PatchTransformer → kustomization.yaml → build/apply → restart CAS → validate (Service/DNS/SAN) → client test.
You can use a LoadBalancer service as the gateway between external clients and CAS when the Kubernetes environment supports exposing a service through a network load balancer, for example on cloud platforms.
As we have seen in the first article, when you define a Kubernetes service of type LoadBalancer on cloud platforms, the Kubernetes cluster triggers the cloud infrastructure to provision a network load balancer configured to route the incoming connections to the CAS controller pod.
The CAS Operator can automate the creation of the LoadBalancer service and include the service name in the CAS server TLS certificate, all though simple declarative configuration settings.
If the environment has been properly configured, it can also automatically create a DNS record that resolves to the load balancer frontend.
Select any image to see a larger version.
Mobile users: To view the images, select the "Full" version at the bottom of the page.
You can find the steps to perform this configuration in the Configure External Access to CAS section of the Optional Customizations page in the “SAS® Viya® Platform: Deployment Guide”.
Copy the sample file included with the SAS Viya deployment assets to the working directory, and change its permissions so that you can modify it:
cd $deploy;
cp ./sas-bases/examples/cas/configure/cas-enable-external-services.yaml \
./site-config/cas-enable-external-services.yaml
chmod +w ./site-config/cas-enable-external-services.yaml
This file includes a patch to the CASDeployment custom resource and, if you use it "as it is", it enables a binary connection via a new NodePort service. To get a LoadBalancer service, you must edit the file and add a serviceTemplate section. Also, according to the online documentation, you can add an additional key named publishExtHostnameSuffix so that the CAS Operator will automatically add a corresponding subject alternative name (SAN) to the CAS TLS certificate that is created by the SAS certificate framework. For example, if you specify a publishExtHostnameSuffix value of “.myviya.example.com”, then the TLS certificate will include the full name sas-cas-server-default-bin.myviya.example.com. Notice how we placed a trailing dot in the publishExtHostnameSuffix value: the CAS Operator prepends the service name to this value, and the end result is a full DNS name.
Your file should be similar to the following - possibly with a different DNS subdomain value.
---
apiVersion: builtin
kind: PatchTransformer
metadata:
name: cas-enable-external-services
patch: |-
- op: add
path: /spec/publishBinaryService
value: true
- op: add
path: /spec/serviceTemplate
value:
spec:
type: LoadBalancer
- op: add
path: /spec/publishExtHostnameSuffix
value: .myviya.example.com
target:
group: viya.sas.com
kind: CASDeployment
name: .*
version: v1alpha1
Since this is a yaml file, double check that the lines are indented correctly.
As with most CAS configuration files, this patch applies to all CAS servers that you might have created in your SAS Viya namespace. If you have multiple CAS servers and only want to enable external connectivity to select instances, then modify accordingly the name selector in the target section.
Security considerations
You can add additional fields to the serviceTemplate section to further customize the LoadBalancer service that the CAS Operator will create. Typical use cases include security options, such as loadBalancerSourceRanges to restrict traffic through the cloud-provider load balancer to the specified client IP ranges, and custom annotations that instruct the cloud provider to create an internal load balancer (i.e. a load balancer without a public IP address, thus only reachable by clients on an internal network). Here is an example serviceTemplate section that includes additional fields:
- op: add
path: /spec/serviceTemplate
value:
metadata:
annotations:
service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: "300"
service.beta.kubernetes.io/aws-load-balancer-internal: "true"
spec:
type: LoadBalancer
# loadBalancerSourceRanges are optional and depend on your requirements
loadBalancerSourceRanges:
- 192.168.0.0/16
- 10.0.0.0/8
Please be aware that within this serviceTemplate you cannot use most of the keys that would be valid for a Kubernetes Service object. SAS Viya official documentation notes that many keys are not supported, for a simple reason: the serviceTemplate defined in this file is applied to every Kubernetes Service created by the CAS Operator. For example, if you add a ports field, the same load balancer port could be defined in multiple Services, which can prevent connectivity.
After customizing the new patch transformer file, reference it in the transformers block of the kustomization.yaml file, then use the same steps as the initial deployment to create and apply the updated site.yaml manifest to your Kubernetes cluster.
If there are no syntax errors, the CAS Operator will immediately create the new service. No restarts are required. Yet, you still need to restart the CAS server pods so that CAS picks up the updated TLS certificate that includes the external DNS alias for the load balancer.
Since this article focuses on automation, we run our tests in Azure AKS. Why? The publishExtHostnameSuffix key in the serviceTemplate has an additional effect; it instructs the CAS Operator to add the following annotation to the new service: service.beta.kubernetes.io/azure-dns-label-name. This label is used by Azure AKS clusters to automatically create a corresponding DNS entry for the newly-created load balancer.
This label is still present, but ignored, on any other Kubernetes platform. On those platforms, it’s up to your IT team to create a DNS entry that correctly resolves the hostname alias/CNAME record for the load balancer.
Some solutions can automate the creation of this DNS entry. For example, on OpenShift clusters, Red Hat provides the External DNS Operator, that leverages the open source ExternalDNS project. Once installed and integrated with your DNS server, it can monitor the Kubernetes cluster and automatically register DNS entries for Kubernetes services as soon as they are created.
Finally, example manual instructions for AWS clusters are provided at Configure External Access to Amazon Web Services CAS Services.
It’s finally time to validate the new settings. You should verify all 3 high-level requirements discussed in the previous article: a valid network route (i.e. the new load balancer), proper name and address resolution (i.e. the DNS alias), and TLS trust (i.e. the CAS server certificate).
After applying the new configuration, check that the namespace contains the expected external service:
NS=gelcorp
kubectl -n ${NS} get service sas-cas-server-default-bin
Your output should be similar to the following. Verify that the service of type LoadBalancer has been assigned an external IP (or, on AWS, an external DNS name).
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
sas-cas-server-default-bin LoadBalancer 172.30.21.88 20.1.248.130 5570:32209/TCP 80s
Validate that the chosen hostname you intend clients to use resolves to the external load balancer IP address.
# this corresponds to the value set in publishExtHostnameSuffix
MY_SUBDOMAIN=".myviya.example.com"
echo Looking for the IP address of: "sas-cas-server-default-bin""${MY_SUBDOMAIN}"
dig +short "sas-cas-server-default-bin""${MY_SUBDOMAIN}"
You should get the same IP address that was returned in the previous check as the Load Balancer external IP, for example 20.1.248.130.
You can use the following command to list all the aliases that the CAS Operator has automatically defined for the CAS server certificate:
NS=gelcorp
kubectl -n ${NS} get secret sas-cas-server-default-controller -o jsonpath="{.data['tls\.crt']}" | base64 -d | openssl x509 -text -noout | grep -B 1 "sas-cas-server-default-bin"
You should get a result similar to the following. Nested with many other aliases and IP addresses, you should recognize both the full DNS name and the external IP highlighted in the previous steps (in this example, sas-cas-server-default-bin.myviya.example.com and 20.1.248.130) :
X509v3 Subject Alternative Name:
DNS:myviya-worker-1, DNS:controller, DNS:controller.sas-cas-server-default, DNS:controller.sas-cas-server-default.gelcorp, DNS:controller.sas-cas-server-default.gelcorp.svc.cluster.local, DNS:gelcorp.myviya.example.com, DNS:localhost, DNS:sas-cas-server-default, DNS:sas-cas-server-default-bin, DNS:sas-cas-server-default-bin.myviya.example.com, DNS:sas-cas-server-default-client, DNS:sas-cas-server-default-controller, IP Address:10.0.1.7, IP Address:10.128.2.64, IP Address:127.0.0.1, IP Address:172.30.196.203, IP Address:172.30.79.248, IP Address:20.1.248.130
Now that all the configuration and verification steps have been performed, it's time to start a connection from an external client! For example, you can use a python script from a Windows client.
import swat
from pathlib import Path
username = "MyUserName"
password = "MySecretPassword"
### Insert your DNS alias here!
server = "sas-cas-server-default-bin.myviya.example.com"
### Connect to CAS
if server == "sas-cas-server-default-bin.myviya.example.com":
raise ValueError(f"Please enter *your* DNS server alias in the server variable and try again")
else:
conn = swat.CAS(server, 5570, username, password)
print(conn.serverStatus())
If you get a printout similar to the following, you have a successful connection:
NOTE: Grid node action status report: 3 nodes, 8 total actions executed.
[About]
{'CAS': 'Cloud Analytic Services', 'Version': '4.00', 'VersionLong': 'V.04.00M0P09082025', 'Viya Release': '20260214.1771047480056', 'Viya Version': 'Long-Term Support 2025.09', 'Copyright': 'Copyright © 2014-2025 SAS Institute Inc. All Rights Reserved.', 'ServerTime': '2026-02-16T17:22:51Z', 'System': {'Hostname': 'controller.sas-cas-server-default.gelcorp.svc.cluster.local', 'OS Name': 'Linux', 'OS Family': 'LIN X64', 'OS Release': '5.14.0-427.107.1.el9_4.x86_64', 'OS Version': '#1 SMP PREEMPT_DYNAMIC Wed Jan 14 07:05:59 EST 2026', 'Model Number': 'x86_64', 'Linux Distribution': 'Red Hat Enterprise Linux release 8.10 (Ootpa)'}, 'license': {'site': '(SIMPLE) THIS ORDER IS FOR SAS INTERNAL USE ONLY', 'siteNum': 70180938, 'expires': '20Mar2026:00:00:00', 'gracePeriod': 0, 'warningPeriod': 15}, 'CASHostAccountRequired': 'OPTIONAL', 'Transferred': 'NO', 'GlobalReadOnlyMode': 'NO', 'CASCacheLocation': 'CAS Disk Cache'}
[server]
Server Status
nodes actions
0 3 8
[nodestatus]
Node Status
name role uptime running stalled
0 worker-0.sas-cas-server-default.gelcorp.svc.c... worker 34.958 0 0
1 worker-1.sas-cas-server-default.gelcorp.svc.c... worker 34.958 0 0
2 controller.sas-cas-server-default.gelcorp.svc... controller 35.016 0 0
+ Elapsed: 0.00614s, user: 0.00141s, sys: 0.00145s, mem: 1.05mb
Successfully configuring external binary access to your CAS server requires proper network connectivity, DNS resolution and attention to TLS certificate trust. In this article we have seen how you can use the CAS Operator and infrastructure automation to ensure that all prerequisites are met. These tools not only reduce manual effort but also ensure consistency across deployments, enabling faster identification and resolution of issues. On the other hand, they require certain assumptions and limit some choices; for example, you cannot change the service name and port. In the next article, you will see how to leverage manual steps to get custom choices, using a NodePort service with an external load balancer and TLS certificate customization. And, since with great powers come great failures, the series will end with comprehensive troubleshooting.
Find more articles from SAS Global Enablement and Learning here.
Nearly 200 sessions are now available on demand with the SAS Innovate Digital Pass.
Explore Now →The rapid growth of AI technologies is driving an AI skills gap and demand for AI talent. Ready to grow your AI literacy? SAS offers free ways to get started for beginners, business leaders, and analytics professionals of all skill levels. Your future self will thank you.