Welcome to the first installment of our blog series focusing on several use-cases how Google Workload Identity Federation, or “WIF”, can be leveraged by SAS Viya. We’ve split the blog into 2 parts. While this part covers the theory and configuration of WIF and describes the simple use-case, the second part contains a deep-dive into more sophisticated topics such as leveraging WIF for user-based authentication against Big Query and Google Cloud Storage.
Google Workload Identity Federation is a mechanism that allows applications running outside Google Cloud to authenticate and access Google Cloud resources without relying on long-lived service account keys. This is achieved by leveraging federated identities from external identity providers (IdPs) such as AWS, GitHub, Azure Entra ID and on-premises MS Active Directory.
WIF reduces the risk of credential theft by managing service account keys by using short-lived tokens. It also simplifies the process of managing federated identities compared to handling service account keys. Access policies can be configured directly within Google Cloud IAM.
Workloads running on a Kubernetes cluster, such as the SAS Viya platform, benefit from using Google Workload Identity Federation as well. By using WIF, these workloads can authenticate securely without embedding service account keys within Kubernetes secrets.
As it is part of Google’s access management, WIF becomes relevant for various use-cases with SAS Viya. In the 2 installments of this blog, we’ll describe the most common ones, starting from using WIF for an external Infrastructure Data Server (PostgreSQL database), moving on to Google Object Storage (GCS) and Google Big Query.
Let’s start with an overview of how Google Workload Identity Federation works.
First, we should clarify some terms which can easily be confused. Unfortunately, you can find 2 services in Google’s IAM portfolio which are named nearly identical: Google Workload Identity Federation and Google Workforce Identity Federation. While Workload Identity Federation is primarily used to authenticate applications and services, Workforce Identity Federation is designed to authenticate and authorize a workforce – e.g. a group of users. But nonetheless, Workload Identity Federation can be used for authentication users as well. In this blog, we’ll only talk about Workload Identity Federation.
Google WIF comes in different “flavors”. Typically, it will be used for authenticating service accounts, but as said above, it can be used to authenticate users as well. With SAS Viya on Kubernetes in mind, this means that you can configure WIF to authenticate a service account which is assigned to a Kubernetes pod for using a Google service. For example, the service account sas-data-server-operator is assigned to the SAS Data Server Operator pod, which handles the connections to external PostgreSQL databases for the SAS Infrastructure Data Server. By using WIF, you can allow this service account to access a Google Cloud SQL PostgreSQL database instance.
In other situations, authenticating the service account assigned to a pod is not sufficient as more fine-grained access controls are required. Imagine using the SAS/Access to Google BigQuery engine. When you submit a Libname statement in a SAS Studio session you most likely do want to implement user- or group-based access controls based on the current user.
Workload Identity Federation is based on token-based authentication. Instead of credentials such as passwords, the client (i.e. a SAS microservice or a SAS Compute session) sends a token which then needs to be validated by Google before access is granted. This adds a third player to the game: the authentication provider. For authenticating service accounts, this 3rd party is simply your Kubernetes API server, for user authentication it needs to be something else, as Kubernetes has no concept of what a “user” is. As we’ll see later, when discussing the more advanced use-cases, Microsoft’s Entra ID can be used for this purpose.
How does WIF work in detail? For simplicity reasons, we’ll focus on the “service account authentication” scenario here (as the “user authentication” scenario adds complexity due to the integration of the external authentication provider). Read more about WIF in the official Google documentation.
Let’s start with the Kubernetes side and especially with the role of the Kubernetes API server: as mentioned above, it can act as an authentication provider for the service accounts it manages. To accomplish this, it creates ID tokens for all service accounts and provides ways to validate these tokens on request. Because these ID tokens are OIDC tokens, the Kubernetes API server functions as an OIDC provider.
If an application (i.e. pod) needs to know the ID token of its’ service account, it can “project” the token as a file to its’ filesystem. Here’s a YAML fragment that shows how this works:
kind: Pod
spec:
volumes:
- name: token-volume
projected:
sources:
- serviceAccountToken:
expirationSeconds: 3600
path: token
containers:
- volumeMounts:
- name: token-volume
mountPath: /var/run/service-account/token
readOnly: true
serviceAccountName: my-service-account
Based on this definition, the ID token for my-service-account will be available in the container as a file at /var/run/service-account/token. Note that token projection is not needed if your SAS Viya environment runs in Google Kubernetes (GKE).
Unfortunately, the application cannot send the ID token directly to the Google service for requesting access for two reasons:
The first problem is solved by mapping the Kubernetes service account to a Google service account and allowing the Kubernetes account to impersonate the Google account so that it inherits all IAM permissions assigned to the Google account.
The following screenshot shows an example for this:
WIF requires a Workload Identity pool with a configured OIDC provider (which is the Kubernetes API server in this case) and a GCP service account. Here’s a basic example how to create the WIF configuration:
# create the WIF pool
gcloud iam workload-identity-pools create my-pool --location="global" \
--display-name="my-wif-pool"
# get the token signing keys of the Kubernetes cluster
kubectl get --raw /openid/v1/jwks > ~/tmp/cluster-jwks.json
# add an OIDC provider to the WIF pool
gcloud iam workload-identity-pools providers create-oidc my-oidc-prv \
--location="global" \
--jwk-json-path="/tmp/cluster-jwks.json" \
--workload-identity-pool="my-pool" \
--issuer-uri="https://kubernetes.default.svc" \
--attribute-mapping="google.subject=assertion.sub"
For the more advanced use-case of authenticating users instead of service accounts, you should add a mapping for groups (assertion.groups) as well. The above code snippet also shows how the token signing keys (in a JSON Web Key Set – JWKS) are passed to the pool after retrieving them from the Kubernetes cluster.
Moving on to the GCP service account next. It must be assigned with all required IAM roles (for example with the "Cloud SQL Admin" role for accessing a Cloud SQL database). Using the gcloud CLI, this could be configured like shown here:
# create a Google service account
gcloud iam service-accounts create <gcp-service-account> \
--project=<gcp-project>
# assign IAM permissions to the Google service account, e.g. for Cloud SQL
gcloud projects add-iam-policy-binding <gcp-project> \
--member="serviceAccount:<gcp-service-account>@<gcp-
project>.iam.gserviceaccount.com" \
--role="roles/cloudsql.admin"
# map a Kubernetes service account to this Google account
K8S_SA=system:serviceaccount:<namespace>:<service-account>
gcloud iam service-accounts add-iam-policy-binding \
<gcp-service-account>@<gcp-project>.iam.gserviceaccount.com \
--member="principal://iam.googleapis.com/projects/<gcp-
project>/locations/global/workloadIdentityPools/<gcp-
wif.pool>/subject/${K8S_SA}" \
--role=roles/iam.workloadIdentityUser
The second problem mentioned above is solved by using the Google Security Token Service (STS). STS can swap the OIDC ID token for an authentication token which other Google services understand. The WIF configuration provides the information needed by STS to validate the ID token stores because it stores a copy of the token signing keys. The following picture shows this process:
Ok, with all of this in place, let’s move on to the first use-case: how to use a Google Cloud SQL PostgreSQL database for the SAS Infrastructure Data Server.
We’ll start by looking at how WIF can be used when SAS Viya is configured to use an external PostgreSQL database as the Infrastructure Data Server. Like the other public cloud vendors, Google offers managed PostgreSQL database servers as part of their Google Cloud SQL service offering which is a good fit for this option.
For this use-case we can leverage the WIF “service account authentication” configuration, as it will be the SAS Viya services connecting to the PostgreSQL databases (often called “SharedServices” and “CDS” when SAS solutions are involved), not the end users. Since we’ve covered most of the configuration details, we can just summarize what you need to put in place for the basic setup:
While this completes the configuration on the Google side, there are some additional steps on the SAS side which we haven’t talked about yet. As it is an IAM framework which only exists in Google cloud, client applications must be specifically designed to recognize and integrate WIF, typically by using libraries from Google's SDK, such as the google-auth-library. To overcome this limitation, Google recommends that clients use Google Cloud SQL Auth Proxy which leverages WIF to provide secure access to Cloud SQL instances.
Technically, in our use-case, the Google SQL Auth Proxy runs as pod in the SAS namespace on Kubernetes. Instead of directly connecting to the Google Cloud SQL databases, SAS services will connect to this proxy pod:
To support you with the configuration, SAS ships a YAML template for deploying the Google SQL Auth Proxy at sas-bases/examples/postgres/cloud-sql-proxy.yaml (also note the Readme.md in the same folder). This template needs some modifications however:
The WIF configuration can easily be generated by running the following gcloud CLI command. It will create a JSON file with all relevant URLs (but does not contain any sensitive credentials):
gcloud iam workload-identity-pools create-cred-config \
projects/<gcp-project>/locations/global/workloadIdentityPools/
<gcp-wif.pool>/providers/<gcp-wif-oidc-provider> \
--service-account=<gcp-service-account>@<gcp-
project>.iam.gserviceaccount.com \
--credential-source-file=/var/run/service-account/token \
--credential-source-type=text \
--output-file=/tmp/credentials-configuration.json
Next, make the generated file available to the SQL Auth Proxy pod by uploading the JSON file to a ConfigMap and mounting that map to the pod. Here’s a YAML fragment to show how this fits together:
containers:
- env:
- name: POSTGRES_CONNECTION_NAME
value: " <gcp-project>:<gcp-region>:<gcp-sql-instance>"
- name: GOOGLE_APPLICATION_CREDENTIALS
value: "/etc/wif/credentials-configuration.json"
volumeMounts:
- name: wif-configuration
mountPath: "/etc/wif"
readOnly: true
- name: token
mountPath: /var/run/service-account/token
readOnly: true
command:
- "/cloud_sql_proxy"
args:
- "-credential_file=/etc/wif/credentials-configuration.json"
- "-instances=$(POSTGRES_CONNECTION_NAME)=tcp:0.0.0.0:5432"
volumes:
- name: token
projected:
sources:
- serviceAccountToken: ...
- name: wif-configuration
configMap:
name: <name-of-configmap>
Note that the SQL Auth Proxy pod does not need to be exposed for external access, so you only need to create a Service definition but no Ingress or Route:
kind: Service
apiVersion: v1
metadata:
name: google-sql-proxy
spec:
ports:
- name: sql
protocol: TCP
port: 5432
targetPort: 5432
selector:
app: google-sql-proxy
type: ClusterIP
This completes the configuration of the Google SQL Auth Proxy. Once the pod is deployed, you can point SAS to it by modifying the transformer patch used for configuring the external PostgreSQL which can be found at site-config/postgres/platform-dataserver-transformer.yaml. In this file, change the value of /spec/registrations/0/host to the name you used when defining the Service (gcp-sql-proxy in the example given above).
And that’s it? Well, almost. You will notice soon that you still need to provide a local database user (often named "postgres" or "dbmsowner") and password in the file site-config/postgres/postgres-user.env to avoid errors. But why’s that? Didn’t we intend to get rid of passwords by using WIF?
While that’s true, our current configuration only helped us to access our PostgreSQL database instance, but the Google service account we’re impersonating is not known inside the PostgreSQL database and hence has no permissions on any schema, database or table. For that reason, we’re falling back to use a local user account defined in PostgreSQL.
Luckily, we can improve this situation by enabling a feature called “IAM database authentication” as this feature allows the Google service account to authenticate to Cloud SQL databases:
gcloud sql instances patch <gcp-sql-instance>
--database-flags cloudsql.iam_authentication=on
You will also need to create a database user for the Google Service account:
gcloud sql users create <gcp-service-account>@<gcp-project>.iam \
--instance=<cloud-sql-instance-name> \
--type=cloud_iam_service_account
With this feature enabled and the user created on the Postgres side, there is no need for a password in the site-config/postgres/postgres-user.env file anymore, so it would basically look like this:
username=<gcp-service-account>@<gcp-project>.iam
password=
Make sure to review all the requirements for using an External Postgres database for the SAS Viya platform as described here.
As a final note: if you decide to switch to IAM database authentication, do not forget to assign the right permissions to your Google service account
GRANT ALL PRIVILEGES ON DATABASE "SharedServices" TO "<gcp-service-account>@<gcp-project>.iam";
With this, we’d like to end our first installment of our blog series about using Google Workload Identity Federation with SAS Viya on Kubernetes. In this part we have covered some groundwork to explain how WIF works and how it is configured. In our first use-case we showed how to use it for connecting to a Google SQL PostgreSQL instance as the external Infrastructure Data Server required by SAS.
We hope that you found it interesting and invite you to read on to learn about more sophisticated topics such as leveraging WIF for user-based authentication against Big Query and Google Cloud Storage in the blog’s second part.
Stay tuned.
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.