Skip to main content
The Signicat Blog
Dag Sneeggen

Technical Product Owner @ Signicat

Introducing SWIM: Signicat Workload Identity (in-)Mesh

Securing service-to-service communication in modern cloud environments presents a significant challenge, one that becomes more critical as enterprise clouds grow in size and complexity. This challenge is further compounded by AI agents and AI-driven services. The need for robust workload identity management has never been more pressing.


This article presents Signicat’s solution for managing workload identity: Signicat Workload Identity (in-)Mesh (SWIM). We detail how we leverage a service mesh, mTLS, and open standards to eliminate secrets, create verifiable workload-bound tokens, and fully automate the developer experience. 

Growing pains: Secret Sprawl!

Some years ago Signicat made a strategic bet to go all-in on a cloud-native, modernized platform. As a cornerstone of this platform, we engineered a robust authentication and authorization system, designed from the ground up to be secure by default and highly performant for our internal and external uses. We implemented a Zero-Trust Architecture (ZTA) with our own IAM system which is composed of several solutions. This system enforces authorization by evaluating a combination of internal users, principals, roles, permissions and product eligibility. When an “API Client” is created in our OAuth/OIDC solution it's automatically linked to a non-human principal.

When one internal service wanted to communicate with another service they would acquire an access token using their own managed API client(s).  This would be a standard client credentials flow with a client ID and client secret. The access token is used as a bearer token, and the receiving API would query our IAM system to verify access rights for the specific client/principal for the specific action.

The platform in general and the service-to-service security has been very successful but there was a growing monster hiding: Secret Sprawl! This can grow quite explosively: more teams, many more clients, many more client secrets.

Over the past few years we’ve discovered several fundamental flaws with our initial implementation:

  • Operational Strain of Clients: Internal teams had to manage clients, and decide how many clients they wanted to use. Should each service/solution have one client to communicate with all other services? One client per called service? How do you facilitate disaster recovery scenarios? Of course we tried to provide guidance but we also strongly believe in team autonomy.
  • Operational Strain of Client Secrets: The life cycle management of secrets; secure distribution, storage, and rotation is a significant, error-prone burden on development teams. Secret rotation might sound trivial but in an enterprise with 500+ staff this can be a high-risk process.
  • Security Risks: A single leaked secret is a durable credential that can be used from anywhere, by anyone, making compromise difficult to detect and trace.
  • “Mis-Authenticating“ Services: It’s not perhaps obvious but we were not authenticating the right thing because we were not authenticating the services or solutions running in our cloud. We weren't directly authenticating the service itself, but rather “something” which had access to a specific client ID and secret. While one could argue this effectively authenticates the service, it's an indirect and weaker form of assurance.

The solution: Leveraging in-mesh mTLS

The SWIM architecture treats the service mesh not as a passive network layer, but as an active participant in the security protocol. Signicat Digital Trust Platform uses Istio, however all major service meshes use the same technique: inter-service communication is automatically secured with mTLS, and crucially the mTLS certificates contain SPIFFE IDs linked to Kubernetes service accounts. This is then a platform-managed short-lived unforgeable proof of workload identity. 

To leverage all this we implemented RFC 8705: OAuth 2.0 Mutual-TLS Client Authentication and Certificate-Bound Access Tokens which provided two major advantages:

Eliminating secrets (mTLS client authentication)

The mTLS handshake, enforced by the mesh for every connection, is the client authentication. During this process, the Istio sidecar proxy proves the workload's identity, using the private key it securely manages. The application code itself never sees or handles any cryptographic keys. The mesh then forwards the client’s certificate chain (in an x-forwarded-client-cert (XFCC) header) to our authorization server. The authorization server then validates this chain against the known public root CA of the service mesh before trusting the client/workload.

In other words, we consolidate our trust in the service mesh—in Istio and Kubernetes. We’re comfortable with this because these components are already fundamental to our platform's trust model. Consolidating trust can be very effective as opposed to scattering trust. There’s also tried and tested techniques in Istio to ensure that the XFCC headers your application receives are tamper-proof and trustworthy, and that external requests will never arrive to your application with internal XFCC headers.

Workload-bound tokens

Authentication is only the first step. This architecture also ensures that tokens are bound to the workload, which is a massive security upgrade.

When our OAuth/OIDC solution issues access tokens for a “workload client” it will contain a cnf (confirmation) claim, as specified in RFC 8705. To enhance this, we introduced a new parameter within the cnf claim, x5s#SPIFFE, which contains the workload's full SPIFFE ID. 

      "cnf": {
  "x5t#S256": "87abe78e185a0c5...1b30225e23542b7d503",
  "x5s#SPIFFE": "spiffe://trust-domain/ns/namespace/sa/default"
}

    

When these tokens are presented to internal services they utilize our IAM system for policy enforcement, as mentioned earlier. This will verify the workload-binding by comparing the token's cnf claim against the identity of the calling workload provided by the mesh.

For workload-binding verification, we concluded that our IAM system can simply validate that the SPIFFE ID in the presented certificate matches the x5s#SPIFFE claim in the token. While arguably less stringent than a direct thumbprint match, this validation is robust enough for our trust model and elegantly avoids a race condition where a strict check would fail simply because a short-lived certificate was rotated while the access token itself would be valid.

Automating the developer experience: The SWIM controller 🤖

A secure architecture is only effective if it's easy to use. To eliminate friction for our development teams, we built a custom Kubernetes controller that fully automates the client provisioning process.

This controller watches service accounts across all namespaces. When a team creates a new service account (more commonly a new namespace - which gets a default service account), the controller instantly detects it. It then automatically provisions a corresponding “workload client” in our OAuth/OIDC solution, mapping the Kubernetes identity to an OAuth 2.0 client and associating this client with the team that owns the namespace. This “workload client” gets a client ID (e.g., urn:swim:wl_client:gcp_eu:namespace:serviceaccount) which can be easily mapped to the SPIFFE ID provided in the certificate (e.g., spiffe://gcp_eu.signicat.cloud/ns/namespace/sa/serviceaccount).

To complete the seamless experience, a bot sends a notification directly to the team's Slack channel. This message informs them that their new workload client has been created and provides its ID, ready for immediate use. This level of automation makes securing a new service the path of least resistance—it happens by default, with no tickets and no manual configuration required. The only thing the team has to do is set up permissions for their new workload client in our IAM system.

Example Slack message with following text: Hi Team, A new client ID has been automatically provisioned for your service account XXXX in the XXXX namespace.

Alignment with standards

This architecture isn't created in a vacuum. It's a practical application and extension of existing and emergent standards. The IETF's Workload Identity in Multi System Environments (wimse) working group is focused on defining the future of workload identity. This SWIM architecture shows a concrete implementation — a pattern for applying WIMSE principles within a modern cloud-native platform.

Signicat is also actively contributing to this working group, helping shape the future of standards. We remain deeply committed to standardization, as can be seen by our involvement in several EU Wallet Large Scale Pilots, eIDAS 2.0 and even going as far as hosting the OAuth Security Workshop - OSW 2025 in Reykjavik, Iceland.

The Impact of SWIM at Signicat

The key benefits of the SWIM architecture are clear: it makes developers' lives easier while improving our security posture.

  • No more secret sprawl or even having to manage clients.
  • It’s practically impossible to request a token fraudulently. Your entire kubernetes cluster would need to be compromised because it would require access to your root CA private key, or the ability to make legitimate-looking deployments.
  • A stolen or leaked token would be completely useless because it’s workload-bound.
  • The platform wholly manages all aspects of workload identity (authentication & authorization).

We’re rolling out SWIM as this blog post goes live, and early signs are promising. Internal teams in Signicat are excited about diving in, because SWIM makes everything more secure while reducing operational strain.

The Future of SWIM

The SWIM architecture provides a robust foundation that can be extended with even more sophisticated security patterns to achieve greater traceability and more dynamic authorization. We’re also excited to keep an eye on, and continue to contribute to, the rapidly-moving field of workload identity.

Transaction Tokens

One might question the need for tokens at all if mTLS provides authentication. The answer is that tokens provide essential authorization context. They give information about the specific request - what is intended to be done and why. To ease migration to the new SWIM pattern we used OAuth access tokens, but a logical next step might be the implementation of Transaction Tokens, as detailed in the IETF draft Transaction Tokens. Unlike general-purpose access tokens, a transaction token is a short-lived, single-purpose credential that is bound to a specific request or call chain. Adopting this pattern would provide unparalleled traceability for every action within our platform, further reducing the risk of token misuse and enhancing our audit capabilities. If we implemented transaction tokens we’d of course extend them to include the cnf claims to facilitate workload-bound transaction tokens.

Token-Based Access Control (TBAC)

Another interesting idea gaining traction in the standards community is Token Based Access Control. In this model, the call chain would propagate all relevant security tokens—such as the initial OIDC token from an external end-user, along with internal workload credentials and transaction tokens.

This collection of verifiable credentials would provide our internal IAM system with an incredibly rich context for every request. We could then make highly dynamic decisions based on the combined identities and claims of the end-user, the calling workload, and the specific transaction. This moves beyond traditional role-based access control to a powerful, context-aware authorization model fit for complex, multi-party interactions. You can even imagine introducing risk data into this evaluation.