Skip to content

External trust

This page documents establishing external trust for workloads using Cofide Connect. What we mean by this is having some system (presumably another workload), that is not Connect-enabled and possibly not even SPIFFE-aware, trust Connect-enabled workloads (i.e., be able to authenticate them). In the general identity space, this establishment of trust is called federation of trust domains. Notably, in many cases, this will not be a SPIFFE federation due to prevalence of identity systems based on OAuth2 and OpenID Connect (OIDC) standards.

For federation between trust zones managed by Connect, see Federation. The below assumes that the other system does not have identity managed by Connect.

The exact mechanism of establishing trust depends on the target system. This is regardless of the standard of federation (SPIFFE, OIDC). This page serves as a collection of known systems that can be made to trust SPIFFE-enabled workloads, with relevant details assuming the use of Connect.

As a reminder, in SPIFFE there are currently two identity presentation implementations:

  • X.509 — used primarily in TLS/mTLS
  • JWT — used primarily in HTTP (over a TLS/mTLS channel)

In non-SPIFFE identity implementations, it is often one or the other that is supported and not both. For example, WebPKI relies solely on X.509, while OAuth2/OIDC are token-based (with JWT as an example of a readable access token, mandatory for an OIDC ID Token).

As OAuth2/OIDC rely on tokens for presentation of identity, the established trust relies solely on JWT signing keys. TLS (most often WebPKI-based) is usually used to authenticate the source of JWT signing keys.

Connect exposes a compatible OIDC endpoint for each trust zone. It can be obtained using the get_oidc_endpoint shell function below:

Terminal window
function get_oidc_endpoint {
local trust_zone="$1"
local bundle_endpoint=$(cofidectl trust-zone status "${trust_zone}" | grep "Endpoint" | cut -d'|' -f2 | xargs)
local oidc_endpoint=$(echo "$bundle_endpoint" | sed 's/bundle/oidc/g' | sed 's|https://||')
echo "$oidc_endpoint"
}

get_oidc_endpoint takes the trust zone’s name as its sole argument and can be called like this:

Terminal window
get_oidc_endpoint my-trust-zone

OIDC federation with cloud and SaaS providers

Section titled “OIDC federation with cloud and SaaS providers”

Cloud and SaaS providers often provide support for OIDC federation but also rely on their custom tokens when communicating with their services. They support exchanging external tokens (especially JWTs) for their custom tokens (which may or may not be OAuth2) via a system most commonly called STS (Security/Secure Token Service). This is similar to (but more limited than) the capabilities of Cofide Credex.

Code Example: aws-oidc in cofide-demos

See more on the example’s pattern itself in Communication patterns.

In case of AWS, to obtain the AWS token to talk to AWS services, it is necessary to exchange another token in the AWS STS via an AssumeRoleWithWebIdentity call. The JWT-SVID acts as an OIDC ID Token. Cofide Connect acts as the trusted OIDC identity provider, and AWS STS validates the token against the keys in the Connect trust bundle store. On success, STS issues temporary AWS credentials scoped to the IAM role.

---
title: AWS OIDC Federation (JWT-SVID → AWS token)
config:
  theme: neo
---
architecture-beta
    group trust_zone_1(cloud)[Production Trust Zone]
    group aws(cloud)[AWS]
    group connect(cloud)[Cofide Connect]
    service consumer(server)[Consumer] in trust_zone_1
    service spiffe_1(database)[SPIFFE Workload API] in trust_zone_1
    service sts(server)[AWS STS] in aws
    service bundle_store(database)[Trust Bundle Store] in connect

    consumer:T --> B:spiffe_1
    consumer:R --> L:sts
    sts:T --> B:bundle_store

For this trust, AWS is configured via its IAM service. Two resources are affected:

  • A dedicated AWS IAM OIDC provider is created. It trusts the Cofide Connect OIDC endpoint for the trust zone.
  • An IAM role is configured with an AssumeRoleWithWebIdentity trust policy that matches the consumer workload’s SPIFFE ID and JWT audience.

Here is a Terraform snippet showcasing the necessary resources (the role’s own policies are omitted for brevity as they are irrelevant for the trust itself):

resource "aws_iam_openid_connect_provider" "trust_zone" {
url = "https://${var.oidc_endpoint_for_trust_zone}"
client_id_list = [
var.audience
]
}
resource "aws_iam_role" "desired_role" {
name = "desired-role-name"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRoleWithWebIdentity"
Effect = "Allow"
Principal = {
Federated = aws_iam_openid_connect_provider.trust_zone.arn
}
Condition = {
StringEquals = {
"${var.oidc_endpoint_for_trust_zone}:aud" = var.audience,
"${var.oidc_endpoint_for_trust_zone}:sub" = var.spiffe_id
}
}
}
]
})
}

Required variables:

  • oidc_endpoint_for_trust_zone is the trust zone’s OIDC endpoint exposed by Connect (without the https:// scheme); it also serves as the iss claim in issued JWT-SVIDs (after restoring the scheme); it can be obtained easily using the mentioned get_oidc_endpoint shell function
  • audience is the unique audience used for this particular exchange; due to the bearer nature of JWT-SVIDs, it is highly recommended to keep it different from any other audiences in use; this is the audience that the application must request from the SPIFFE Workload API
  • spiffe_id is the full SPIFFE ID (e.g., spiffe://trust.domain/any/other/components) of the workload that is to be granted access to this particular role

Code Example: gcp-oidc in cofide-demos

See more on the example’s pattern itself in Communication patterns.

In case of GCP, one can obtain the GCP OAuth2 token compatible with most GCP services via the sole /token endpoint of the GCP STS. The JWT-SVID acts as an OIDC ID Token. Cofide Connect acts as the trusted OIDC identity provider, and GCP STS validates the token against the keys in the Connect trust bundle store. On success, STS issues OAuth2 GCP token with necessary permissions.

---
title: GCP OIDC Federation (JWT-SVID → GCP OAuth2 token)
config:
  theme: neo
---
architecture-beta
    group trust_zone_1(cloud)[Production Trust Zone]
    group gcp(cloud)[GCP]
    group connect(cloud)[Cofide Connect]
    service consumer(server)[Consumer] in trust_zone_1
    service spiffe_1(database)[SPIFFE Workload API] in trust_zone_1
    service sts(server)[GCP STS] in gcp
    service bundle_store(database)[Trust Bundle Store] in connect

    consumer:T --> B:spiffe_1
    consumer:R --> L:sts
    sts:T --> B:bundle_store

For this trust, GCP is configured via its IAM service. Two resources are affected:

  • A GCP IAM Workload Identity Pool is created. While it can be shared, it is recommended to dedicate it to a single provider to avoid subject clashes.
  • A dedicated GCP IAM Workload Identity Pool Provider is created. It points to the Cofide Connect OIDC endpoint for the trust zone and configures attribute mappings (from JWT-SVID claims to GCP IAM’s OAuth2 tokens).

The permissions can then be set utilising a special principal syntax. For example, the identities can be referenced by subject:

principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/subject/SUBJECT

Where SUBJECT denotes the mapped sub claim (which is the SPIFFE ID here).

Alternatively, service account impersonation can be utilised.

Here is a Terraform snippet showcasing the necessary resources (an example GCS role membership is given to showcase the use of SPIFFE ID for authorization):

resource "google_iam_workload_identity_pool" "trust_zone" {
workload_identity_pool_id = "example"
}
resource "google_iam_workload_identity_pool_provider" "trust_zone" {
workload_identity_pool_id = google_iam_workload_identity_pool.trust_zone.workload_identity_pool_id
workload_identity_pool_provider_id = "example"
attribute_mapping = {
"google.subject" = "assertion.sub"
}
oidc {
issuer_uri = "https://${var.oidc_endpoint_for_trust_zone}"
allowed_audiences = [var.audience]
}
}
data "google_project" "project" {
}
resource "google_storage_bucket_iam_member" "member" {
bucket = "MY_BUCKET"
role = "roles/storage.admin"
member = "principal://iam.googleapis.com/projects/${data.google_project.project.number}/locations/global/workloadIdentityPools/${google_iam_workload_identity_pool.trust_zone.workload_identity_pool_id}/subject/${var.spiffe_id}"
}

Required variables:

  • oidc_endpoint_for_trust_zone is the trust zone’s OIDC endpoint exposed by Connect (without the https:// scheme); it also serves as the iss claim in issued JWT-SVIDs (after restoring the scheme); it can be obtained easily using the mentioned get_oidc_endpoint shell function
  • audience is the unique audience used for this particular exchange; due to the bearer nature of JWT-SVIDs, it is highly recommended to keep it different from any other audiences in use; this is the audience that the application must request from the SPIFFE Workload API
  • spiffe_id is the full SPIFFE ID (e.g., spiffe://trust.domain/any/other/components) of the workload that is to be granted access to this particular role

Anthropic Claude is an example of a SaaS provider offering OIDC federation. It is also realised using the token exchange pattern.

Current instructions can be found at Claude’s docs’ Workload Identity Federation and SPIFFE pages. In case of Connect-based deployments, the section on SPIRE configuration should be skipped. The referenced issuer URL for the trust zone can be obtained with the aforementioned get_oidc_endpoint shell function instead.

Certain systems may allow for establishing trust based on X.509 certificate authorities (CAs). This may or may not utilise mTLS.

AWS provides this functionality via IAM Roles Anywhere which relies on token exchange like their OIDC federation. The X.509 certificate is used to sign the request for an AWS token.

While X.509 certificates may be preferred in certain cases to JWTs (due to the bearer nature of the latter), this approach has a downside in that there is no support for automatic rotation of trust anchors.

GCP supports X.509-based Workload Identity Federation (with trust at the mTLS layer) in addition to OIDC federation. This mTLS approach relies on one side on WebPKI and SPIFFE on the other.

While X.509 certificates may be preferred in certain cases to JWTs (due to the bearer nature of the latter), this approach has a downside in that there is no support for automatic rotation of trust anchors.

GCP workloads SPIFFE federation (limited, in preview)

Section titled “GCP workloads SPIFFE federation (limited, in preview)”

GCP offers native SPIFFE X.509 identity issuance for their GCE and GKE offerings. It is based on the Certificate Authority Service. Notably, there is no support for JWT-SVIDs nor access to GCP services.

This SPIFFE implementation can trust other X.509 SPIFFE trust domains by appropriately configuring trust-config. However, the trust anchor must be configured manually, upfront and it can’t be updated dynamically afterwards. This implementation does not utilise standard SPIFFE mechanisms for federation. Thus, it is currently not recommended to be used for establishing trust with other SPIFFE domains, including Connect-managed.