Category: System Administration

Fedora: Disk Cleanup

Useful commands for disk cleanup …

Subfolder size excluding specific folders

[root@FVP05 ~]# du -shx --exclude=/mnt --exclude=/proc /*
0 /afs
0 /bin
312M /boot
2.1M /ca
8.0K /cacert.pem
4.0K /careq.pem
0 /certs
0 /crl
0 /dev
48M /etc
37M /home
0 /lib
0 /lib64
0 /media
0 /newcerts
0 /openhab
954M /opt
4.0K /private
457M /root
1.2M /run
120K /SampleCode
0 /sbin
0 /srv
0 /swapfile
0 /sys
227M /tmp
8.2G /usr
14G /var

List the largest n RPM installs

[root@FVP05 ~]# rpm -qa –qf ‘%{SIZE}\t%{NAME}\n’ | sort -nr | head -10

488208897 azure-cli
248737290 java-latest-openjdk-headless
238259971 glibc-all-langpacks
182326049 mesa-vulkan-drivers
147275895 llvm-libs
127750222 gcc
106627293 kernel-core
106091788 kernel-core
105915244 nvidia-gpu-firmware
105470864 kernel-modules

And clean up the journal logs

journalctl --vacuum-size=100M

 

SPIFFE: OAuth Token Exchange: Verified Identity Is Not Unlimited Permission

An agent presents two credentials: one representing me and one identifying Agent XYZ. A token service returns an access token stating that Agent XYZ is acting on my behalf.

What prevents the agent from taking that token somewhere I never authorized?

Not the actor claim alone. Secure delegation requires verified input credentials, controlled issuance, restricted output tokens, and enforcement by the receiving application. OAuth token exchange supplies the protocol; it does not automatically determine what I intended.

The RFC behind token exchange

RFC 8693, OAuth 2.0 Token Exchange, defines an OAuth-based Security Token Service, or STS. A client submits existing security tokens and requests a new token suitable for a particular purpose. The exchange can change token format, target audience, or authorization context, including representing delegation or impersonation.

The distinction matters:

  • Impersonation: the recipient sees the subject’s identity without necessarily distinguishing the intermediary.
  • Delegation: the token preserves the subject and identifies the party acting for that subject.

For our agent scenario, delegation is the useful model: Lisa remains the authorization subject, while Agent XYZ is recorded as the actor.

How an exchange works

An illustrative request to an STS token endpoint contains:

grant_type=urn:ietf:params:oauth:grant-type:token-exchange

subject_token=<Lisa’s eligible access token>

subject_token_type=urn:ietf:params:oauth:token-type:access_token

actor_token=<Agent XYZ’s supported identity token>

actor_token_type=urn:ietf:params:oauth:token-type:jwt

requested_token_type=urn:ietf:params:oauth:token-type:access_token

audience=case-management-api

scope=cases.read cases.update

 

The subject_token provides the subject’s security context; the optional actor_token identifies the proposed actor. audience, resource, and scope describe requested targets and permissions. These are requests, not issuer obligations. Client authentication is a separate consideration from submitting either token.

The conceptual flow is:

Existing credentials + requested target and permissions

|

v

Security Token Service

├─ Validate credentials

├─ Evaluate exchange policy

├─ Establish delegated authority

└─ Issue a constrained token

|

v

Resource API

├─ Validate issued token

└─ Authorize this operation

 

An exchange bridges security contexts; it is not simply a JWT re-signing operation. RFC 8693 explicitly limits its scope to the exchange protocol rather than defining every deployment’s trust and authorization policy.

The exchanger must verify—not believe—the inputs

The STS should not accept:

subject = Lisa

actor = Agent XYZ

trust_me = true

 

It must establish those identities from credentials validated under an explicitly configured trust relationship. Token-validation rules depend on the accepted token profile; the API must also validate the resulting token independently. For JWT access tokens using RFC 9068, validation includes the expected token type, issuer, audience, signature, and expiration. (datatracker.ietf.org)

For this deployment, I would require the following issuance controls:

Boundary Required decision
Input trust Is this issuer permitted to supply this kind of identity evidence?
Credential validity Is the token authentic, current, and acceptable in this exchange context?
Actor identity Which actor does the verified credential actually identify?
Exchange eligibility May this client or actor exchange this subject’s credential?
Target authorization May this delegation reach the requested API?
Permission authorization Which requested operations may the output token permit?
Output binding Must the resulting token be bound to a particular presenting key?

 

These are recommended policy requirements—not defaults guaranteed by enabling RFC 8693. Its may_act claim can express actor eligibility, but identifying an eligible actor is still different from authorizing every requested target or operation.

Crucially, the resulting token is normally issued for the resource server to validate, not merely for the exchanger to recognize later. A resource server that trusts the STS must still enforce the token’s intended use.

A signed actor claim is attribution, not consent

An illustrative delegated token might contain:

{

“iss”: “https://identity.example.org”,

“sub”: “user:lisa”,

“aud”: “case-management-api”,

“scope”: “cases.read cases.update”,

“act”: {

“sub”: “spiffe://agents.example.org/agent/xyz”

}

}

 

The issuer asserts that Lisa is the subject and Agent XYZ is the current actor. The signature protects that assertion against modification. The actor claim does not, by itself, establish that Lisa approved a specific case update or requested access to another application.

This is the central distinction:

Who is acting, whose authority applies, and which action was authorized are separate facts.

If the deployment intentionally gives Agent XYZ all of Lisa’s application rights, then an unexpected operation within those rights may be policy-authorized even though Lisa did not intend it. No token format can recover a narrower instruction that the authorization system never captured.

Preventing the “Lisa never asked for that” failure

There are several different failures hiding inside that example. They require different controls.

  1. Using the token at another application

Suppose Agent XYZ receives a token for the case-management API, then presents it to payroll.

Payroll must reject it because payroll is not its intended audience. Sharing an issuer or signing key does not make a token valid for every application. RFC 9700 recommends audience-restricted access tokens to limit this kind of reuse.

For this architecture, prefer one narrowly defined target per token and exact audience validation at each API.

  1. Exchanging it again for an unauthorized application

Audience validation does not help if the agent can ask an STS to convert its case-management token into a payroll token.

The recommended issuance policy is to authorize each permitted exchange edge explicitly:

Lisa delegation + Agent XYZ → case-management: allowed

Lisa delegation + Agent XYZ → payroll:         denied

 

Changing audience is a legitimate purpose of exchange, so the defense is not “never change audience.” It is never let possession of an input token alone authorize an arbitrary audience transition. This follows from the protocol’s separation between the requested target and issuer policy.

  1. Performing an unintended action within the correct API

Audience restriction cannot distinguish “update case 4821” from “update every case Lisa can access.” A broad cases.update scope may be equally insufficient.

RFC 9396, Rich Authorization Requests, defines authorization_details for expressing finer-grained authorization requirements using structured JSON. The application-specific authorization type must define what those details mean and how they are enforced.

For example, a proposed—not standardized—authorization object could be:

{

“type”: “case_operation”,

“actions”: [“update”],

“case_ids”: [“4821”],

“allowed_fields”: [“status”],

“allowed_status_values”: [“resolved”]

}

 

In this design, Lisa approves that operation through a trusted authorization interaction. The STS issues authority no broader than the approved operation, and the API checks the actual resource and requested mutation against it.

RFC 9396 does not automatically add this object to RFC 8693 exchanges. Supporting it requires an agreed issuer/API profile and enforcement implementation. Structured authorization is useful only when the resource server understands and checks it.

  1. Stealing and replaying the token

A bearer token can be used by whoever possesses it. A signed act claim can therefore attribute a stolen token to Agent XYZ even when another party presents it.

Sender-constrained tokens address that problem by requiring proof of possession of an associated key. RFC 9700 recommends these alongside audience restrictions.

RFC 9449, DPoP, provides application-layer sender constraint. The client supplies signed proofs, and the recipient validates the proof and its relationship to the access token.

DPoP proofs include request method and URI information, token binding through ath for protected-resource requests, and freshness/replay controls. But DPoP does not ordinarily bind the business request body or establish Lisa’s approval of its contents.

A legitimate—or compromised—agent holding the bound key can still generate proofs for operations its token permits. Sender constraint prevents a different presenter from simply replaying the token; it does not make the authorized presenter trustworthy.

A practical task-bound delegation design

For the Lisa/Agent XYZ scenario, I would implement the following:

  1. Capture approval outside the agent’s assertions. Store an approved delegation identifying Lisa, Agent XYZ, target application, operations, resources, and expiry.
  2. Require that approval during exchange. Validate both credentials and check the requested output against the stored grant.
  3. Issue narrowly. Restrict audience, operations, object identifiers, lifetime, and presenting key where supported.
  4. Enforce at the API. Validate the token, then compare the actual operation and affected object with the grant.
  5. Control further exchange. Deny unapproved target transitions and privilege expansion.
  6. Record execution. Log subject, actor, delegation identifier, target, resource, authorization decision, and outcome.
  7. Use state where necessary. For one-time approval, atomically consume the authorization at the operation boundary; a unique token identifier alone does not make a token single-use.

This is a proposed deployment architecture combining token exchange, constrained access tokens, and fine-grained authorization—not a claim that RFC 8693 implements these controls automatically.

The takeaway

Token exchange can turn verified credentials into a token trusted by another system. It must not turn identity evidence into unrestricted authority.

For the threat in question, insist on four distinct properties:

  • Verified subject and actor.
  • Authorized issuance for the requested target.
  • Permissions bounded by the approved delegation.
  • Resource-server enforcement of those bounds.

“Agent XYZ acting for Lisa” explains attribution. “Agent XYZ may perform this operation on this resource for Lisa” is the authorization boundary.

SPIFFE: Follow One Request: The Complete Trust-Boundary Walkthrough

An end-to-end walkthrough reveals mistakes that component diagrams hide. Document one successful delegated request, including every credential accepted, every identity transformation, and every independent authorization decision.

The delegated request sequence

1 Lisa → human authorization flow: authenticate and approve delegation
2 XYZ → local SPIRE Workload API: obtain agent credential
3 XYZ → PingFederate STS: subject token + actor evidence + target
4 STS: validate inputs; check pairing, approval, target, permissions
5 STS → XYZ: access token for the tool service
6 XYZ → tool: present token and any required possession proof
7 Tool: validate token; authorize requested operation
8 Tool → STS/API: use an explicitly permitted downstream flow
9 API: independently validate and authorize case/4821 mutation
10 Each boundary: preserve verified attribution and outcome

The published IdP integration separates subject and actor token processing, exchange policy, and access-token-manager mapping. Treat those as distinct review points rather than assuming that one successful token validation authorizes the complete workflow.

Credential-validation matrix

Credential Recipient Required deployment contract
Lisa’s eligible subject token STS subject-token processor Trusted user issuer/profile and exchange eligibility
XYZ JWT-SVID STS actor-token processor Trusted SPIFFE authority; intended STS audience; actor mapping
OAuth client authentication STS client-authentication boundary Authorized client; explicit relationship to actor if required
Tool access token Tool service Its own audience; permitted subject/actor; operation constraints
API access token Resource API API audience; resource and mutation authorization
Transport certificate or DPoP proof Supporting recipient Required key/token binding and proof validation

 

A JWT-SVID identifies its subject using the SPIFFE ID and includes an audience for the intended verifier. It is not automatically an OAuth access token for every API. Acceptance at an STS requires an agreed validation and trust profile.

Trace the identities without collapsing them

{
"sub": "user:lisa",
"aud": "case-management-api",
"client_id": "agent-xyz-client",
"scope": "cases.read cases.update",
"act": {
"sub": "spiffe://agents.example.org/agent/xyz"
},
"delegation_id": "approval-81a6"
}

This is an illustrative output payload, not a complete token profile. delegation_id is an application-defined extension. The outer subject represents Lisa; act identifies the current actor. Client identity identifies the OAuth client. The authenticated transport peer may be a tool service rather than the original agent. Retain those distinctions in policy and logs. RFC 8693 provides delegation semantics; application approval is a separate deployment concern. [6]

Standalone and asynchronous alternatives

For standalone work, authorize XYZ under an agent-specific policy rather than borrowing Lisa’s authority. The API may directly accept SPIFFE authentication or accept an STS-issued token whose subject is the agent. This choice depends on the API’s supported credential profiles, not on a universal SPIFFE requirement.

If the tool receives an opaque token, use trusted introspection and check its result according to the agreed profile. Introspection is not a reason to omit audience or operation checks. Its response and any caching policy become part of the authorization boundary. [7]

For queued work, protect the job’s identity and approval context from modification, then re-evaluate authorization at execution time. A string saying user:lisa in a message is not a credential. Record both the originating agent and the executing worker; do not silently pretend that the worker is still the original transport caller.

Takeaway: each hop must know what evidence it receives, what authority it establishes, and what authority it is allowed to pass onward.

SPIFFE: Who Is Acting? Identity and Delegated Authority for Agents

An agent can perform an operation under its own authority or perform the same operation on behalf of a person. Those are different security events.

“Agent XYZ modified this resource” identifies a machine principal. “Agent XYZ modified this resource using Lisa’s authority” identifies both an authorization subject and an acting party.

SPIFFE supplies the agent’s verifiable workload identity. OAuth token exchange can connect that identity to delegated user authority while preserving the distinction between whose permissions apply and which software exercised them. These are complementary layers, not capabilities SPIFFE automatically combines.

Start with the agent’s workload identity

For this example, Agent XYZ runs as a workload registered with SPIRE:

spiffe://agents.example.org/agent/xyz

SPIRE attests the execution environment and local workload, matches its evidence against registration policy, and delivers the appropriate SVID through the Workload API. The identity belongs to the attested workload—not to an agent name supplied in a prompt or HTTP header.

That distinction suggests an important design rule: identify the execution boundary you actually control.

If a single orchestrator process runs ten logically different agents with access to the same credentials, labeling them with ten names does not create ten independently attested security principals. Where strong separation matters, give the agents distinct workload boundaries and issuance policies; otherwise, treat their logical names and run IDs as application metadata rather than independent cryptographic identities. This follows from the Workload API’s caller-identification model.

Model one: the agent acts as itself

For autonomous work, the application authenticates Agent XYZ and authorizes the agent principal directly.

There are two common integration patterns:

  • Direct SPIFFE authentication: the API accepts an X.509-SVID over mTLS, or a JWT-SVID intended for that API.
  • Identity-to-token exchange: a token service validates the agent’s SPIFFE credential and issues an application access token representing the agent.

A proposed audit record for this model could look like:

{
     "event": "resource.update",
     "identity_mode": "standalone_agent",
     "effective_subject": "spiffe://agents.example.org/agent/xyz",
     "current_actor": "spiffe://agents.example.org/agent/xyz",
     "authorization_principal": "agent-xyz",
     "resource": "case/4821",
     "outcome": "success",
     "request_id": "req-7ec15",
     "agent_run_id": "run-93a2"
}

 

Here, no user’s authority is involved. The application should evaluate its agent-specific policy, not silently substitute the permissions of the person who originally scheduled the job.

Model two: Lisa’s authority, Agent XYZ’s actions

Now suppose Lisa asks Agent XYZ to update a resource.

The desired application semantics are:

Authorization subject: Lisa
Current actor:         Agent XYZ
Permission source:     Lisa’s rights for this application
Audit attribution:     Lisa, acting through Agent XYZ

 

OAuth 2.0 Token Exchange, defined in RFC 8693, provides a protocol for requesting tokens with delegation semantics. Its act claim distinguishes the acting party from the token’s subject.

“Actor token” and “actor claim” are different things

The actor_token is an input to token exchange: evidence identifying the proposed actor.

The act claim is information in the resulting token: the issuer’s assertion identifying the current actor.

In this design:

  • The subject token represents Lisa.
  • The actor token represents Agent XYZ.
  • The issued access token retains Lisa as sub and identifies Agent XYZ in act.sub.

A JWT-SVID can serve as actor evidence if the token service explicitly supports and trusts that profile. Its subject is the agent’s SPIFFE ID, and its audience should identify the token service accepting it. A JWT-SVID is not, merely because it is a JWT, a user-delegated OAuth access token.

The exchange

The architecture is:

Lisa’s authorized delegation
+
Agent XYZ’s verified SPIFFE identity
|
v
Token service / STS
|
v
Access token: subject=Lisa, actor=XYZ
|
v
Resource application

 

An illustrative token-exchange request contains these form fields; client authentication is handled separately under the token service’s configured policy:

grant_type=urn:ietf:params:oauth:grant-type:token-exchange
subject_token=<Lisa's eligible subject token>
subject_token_type=urn:ietf:params:oauth:token-type:access_token
actor_token=<Agent XYZ's JWT-SVID>
actor_token_type=urn:ietf:params:oauth:token-type:jwt
requested_token_type=urn:ietf:params:oauth:token-type:access_token
audience=case-management-api
scope=cases.read cases.update

 

The request asks for delegation; it does not grant it. RFC 8693 also defines may_act, which can express eligibility to become an actor, but the issuer must still apply its delegation policy.

For this implementation, require the STS to check:

  • Lisa’s token is valid and eligible for this exchange.
  • The agent credential is valid for the STS and maps to an approved actor.
  • Agent XYZ may act for Lisa in this application.
  • The requested audience and permissions are permitted.
  • The resulting actor identity comes from verified evidence, never a caller-supplied display name.

These are proposed deployment requirements, not automatic behavior implied by accepting the exchange grant. They implement the issuer-side policy boundary described by RFC 8693.

The resulting access token

An illustrative decoded payload—not a complete access-token profile—is:

{
     "iss": "https://identity.example.org",
     "sub": "user:lisa",
     "aud": "case-management-api",
     "client_id": "agent-xyz-client",
     "scope": "cases.read cases.update",
     "iat": 1793325600,
     "exp": 1793325900,
     "jti": "delegated-token-4b781",
     "act": {
          "sub": "spiffe://agents.example.org/agent/xyz"
     }
}

 

The outer subject remains Lisa. The actor identifies Agent XYZ. client_id identifies the OAuth client and should not be assumed interchangeable with the actor identity.

Can it have all of Lisa’s rights?

Yes—as an explicit application policy, not as an inherent property of act.

For the requested model, the application can evaluate its normal user authorization rules against Lisa while retaining Agent XYZ for attribution. The token must still permit the relevant resource and operation; adding an actor claim does not manufacture permissions or bypass audience restrictions.

A useful implementation policy is:

Effective permissions =
Lisa’s current application permissions
∩ token-authorized operations
∩ delegation policy

 

To preserve all of Lisa’s application rights, the token and delegation policy must allow that set. For narrower automation, restrict them to the task. OAuth security guidance favors audience-restricted, least-privilege tokens rather than broadly reusable authority.

Full-rights delegation has a deliberate consequence: compromising the authorized agent can expose the same application operations Lisa could perform. Actor attribution improves investigation; it is not a privilege boundary.

Programming applications to retain the actor

Issuing the claim is only half the implementation. The application must preserve it through authentication, authorization, execution, and audit.

The following is a recommended application architecture.

  1. Build a verified request identity

At the authentication boundary, validate the access token using the configured issuer, signature policy, intended audience, and temporal checks. Where the API adopts RFC 9068, apply that profile’s validation requirements rather than merely decoding a JWT.

Construct an immutable, request-scoped identity object with fields such as:

effective_subject
current_actor
prior_actors
oauth_client_id
token_issuer
token_id
authorized_scopes
authenticated_transport_peer
delegation_id

 

Recommended rules:

  • Extract the actor only from validated token claims or trusted introspection results.
  • Keep issuer-qualified user identity; a bare sub is not necessarily globally unique.
  • Preserve the SPIFFE trust domain in actor identifiers.
  • Reject malformed actor structures.
  • Do not infer “human request” merely because act is absent.
  • On delegated-only endpoints, require the expected actor information.

These are application controls designed to make the RFC’s subject/actor distinction operational.

  1. Separate permission evaluation from attribution

Business logic should receive both identities, even when authorization intentionally uses only Lisa’s permissions.

For example:

Permission lookup:
subject = user:lisa

Activity attribution:
subject = user:lisa
actor   = spiffe://agents.example.org/agent/xyz

 

Avoid collapsing this into one username field. In the proposed implementation, authorization receives the verified subject and relevant token constraints; audit receives the complete verified identity context.

This separation preserves the purpose of the act claim: distinguishing delegated execution from acting directly as the subject.

  1. Emit structured business events

A proposed event schema:

{
     "event": "case.update",
     "identity_mode": "user_delegation",
     "effective_subject": {
          "issuer": "https://identity.example.org",
          "id": "user:lisa"
     },
     "current_actor": {
          "id": "spiffe://agents.example.org/agent/xyz"
     },
     "oauth_client_id": "agent-xyz-client",
     "token_id": "delegated-token-4b781",
     "delegation_id": "delegation-81a6",
     "request_id": "req-a740",
     "agent_run_id": "run-93a2",
     "action": "case.update",
     "resource": "case/4821",
     "authorization": {
          "decision": "allow",
          "permission_source": "subject",
          "policy_version": "case-policy-17"
     },
     "outcome": "success"
}

 

The field names are a suggested schema, not SPIFFE or OAuth standards.

For this schema, I would require:

  • Both successful operations and denied attempts carry the identity context.
  • The event records the affected business object and committed outcome.
  • Tokens and private keys are excluded from logs.
  • Agent-supplied run IDs are marked as correlation metadata, not authentication evidence.
  • Database audit columns retain both modified_by_subject and modified_by_actor.

A human-readable rendering can then say:

Lisa updated case 4821 through Agent XYZ.

 

The structured event retains the identifiers needed for investigation.

  1. Carry the identity into background execution

Do not let request identity disappear when work moves to a queue or worker.

In the proposed architecture, enqueue a protected job context referencing the verified subject, actor, delegation, and original request. At execution time, obtain or validate authority appropriate to the worker and operation; do not treat an arbitrary queue field such as “user”: “lisa” as permission to act.

Also avoid retaining Lisa’s identity in a mutable global variable: concurrent jobs must not share authorization or audit context.

  1. Preserve delegation across service boundaries

For a chain such as:

Lisa → Agent XYZ → Tool service → Resource API

 

RFC 8693 permits nested actor claims. The outermost actor is the current actor; nested actors represent earlier actors. Previous actors are informational and must not become an alternative source of permissions.

An illustrative claim at the resource API might be:

{
     "sub": "user:lisa",
     "act": {
          "sub": "spiffe://services.example.org/tool/case-editor",
          "act": {
               "sub": "spiffe://agents.example.org/agent/xyz"
          }
     }
}

 

For this design, log the current actor and retained history, and correlate each hop. Never authorize by taking the union of every actor’s permissions.

Attribution is not proof that the actor presented the token

A signed act claim says the issuer associated Agent XYZ with the delegated token. A bearer token can nevertheless be presented by whoever possesses it. Actor attribution alone does not prevent replay.

For stronger attribution, use sender-constrained access tokens where supported. RFC 8705 binds a token to an mTLS client certificate through cnf.x5t#S256; the resource server verifies that the presenting certificate matches the binding.

With rotating SPIFFE certificates, that binding is to the specific certificate, not simply its SPIFFE ID. The implementation must coordinate access-token renewal and certificate rotation. TLS termination must also preserve a trustworthy validation boundary; an untrusted forwarded certificate header is not equivalent to an authenticated peer. These follow from RFC 8705’s certificate-binding mechanism.

The takeaway

For agent identity, keep three questions separate:

  1. Which workload is this? SPIFFE provides the verifiable identity.
  2. Whose authority is being exercised? Delegated tokens preserve the user as subject.
  3. Which software exercised that authority? The actor claim preserves attribution.

Then make the application record all three at the business-event boundary.

The goal is not merely an access token containing Agent XYZ’s name. It is an authorization and audit model that can reliably distinguish Lisa acting directly, Agent XYZ acting independently, and Agent XYZ exercising Lisa’s delegated authority.

SPIFFE: Who Is Allowed to Become Agent XYZ? Attestation and Identity Issuance

The first security question is not whether a certificate or token can be verified. It is whether the system should have issued that identity in the first place. An attacker who satisfies an overly broad issuance policy can receive authentic credentials; signature verification will then work exactly as designed.

Node evidence and workload evidence are separate

SPIRE uses node attestation to establish an agent’s eligibility and workload attestation to determine the identities available to local callers. Registration entries associate a SPIFFE ID with selectors and a parent identity. Agents obtain relevant entries and compare caller evidence with them.

For architecture review, identify the evidence producer, the administrator able to influence it, and the verifier relying on it. A cloud instance identity, a Kubernetes service-account assignment, and a local process UID have different provenance and compromise assumptions. Do not treat three labels derived from one mutable source as three independent factors.

An illustrative registration policy

identity: spiffe://agents.example.org/agent/xyz
parent: <eligible attested node or node group>
required workload evidence:
namespace: agents-prod
service_account: agent-xyz
credential lifetime: <reviewed deployment setting

Namespace and service-account evidence can be useful, but ask who can create a pod using that account. If a developer can choose the privileged account while creating an arbitrary pod, the selectors alone do not distinguish the intended workload from the developer’s replacement. Add controls at the deployment boundary: reviewed manifests, admission policy, appropriately scoped RBAC, and protected automation identities. These are complementary infrastructure controls, not properties supplied by SPIRE.

Evidence or control Who may influence it? Review question
Namespace/service-account assignment Pod creators and deployment automation Can an unrelated workload use XYZ’s account?
Unix process UID Host administrators and privileged processes Can the attacker execute as that UID?
Registration entry SPIRE registration administrators/controllers Can a broad entry issue privileged identities?
Node enrollment Infrastructure and attestation administrators Can an unauthorized node become eligible?
Workload API access Host/container isolation administrators Can another process obtain or steal the credential?

 

Choose the identity boundary deliberately

A SPIFFE ID often represents a service or deployment with many replicas. It is not necessarily a unique process-instance identifier. A single orchestrator running multiple logical agents with shared credentials does not create independently attested identities merely by assigning different agent names. Use isolated workloads and distinct policies where separate security principals are required. Preserve execution IDs as audit metadata rather than presenting them as attestation evidence. The Workload API identifies local callers under its implementation’s security boundary.

Attestation establishes eligibility under configured evidence rules; it is not a behavioral verdict. Prompt injection, malicious dependencies, or compromised application logic may all exist inside an eligible workload. Credential theft and local isolation also remain in the threat model.

Configuration-review checklist

  • Enumerate every registration entry that can issue XYZ’s identity, including controller-generated entries.
  • Map every selector to its evidence source and modification privileges.
  • Test an unauthorized workload that intentionally resembles XYZ.
  • Document whether replicas share an identity and how individual runs are correlated.
  • Separate registration administration from ordinary application deployment wherever practical.
  • Require review of broad selector changes and retain a recoverable history of issuance policy.

Takeaway: issuance policy is an authorization boundary. Reviewing the SPIFFE ID string without reviewing who can satisfy its evidence is an incomplete security review.

SPIFFE: Giving Software an Identity It Can Prove

A service connecting to another service needs to answer a deceptively difficult question: what is the caller, and why should I believe it?

SPIFFE and SPIRE address that question with cryptographically verifiable workload identities, issued at runtime rather than provisioned as long-lived application secrets. SPIFFE defines the identity standards and interfaces; SPIRE implements the attestation, issuance, and rotation machinery. Together, they provide an identity layer that can operate across heterogeneous infrastructure.

Why this exists: the bootstrap problem

Consider an application retrieving a database password from a secrets manager. Moving the password out of a configuration file is useful, but the application still needs to authenticate to the secrets manager. Where does that initial credential come from?

This is the secret-zero problem: protecting a credential often requires another credential. SPIRE approaches it through secure introduction—using evidence about the workload and its execution environment to determine which identity it may receive. It is not a secrets manager; its identities can instead authenticate workloads to a secrets manager.

The same identity machinery supports service-to-service authentication. SPIRE delivers short-lived, automatically rotated credentials suitable for mutual TLS, either directly to applications or to proxies acting on their behalf. The objective is not to invent a replacement for TLS, but to automate the trustworthy introduction and credential lifecycle that TLS requires.

SPIFFE is the contract; SPIRE is the machinery

SPIFFE, the Secure Production Identity Framework for Everyone, defines standards for workload identifiers, verifiable identity documents, trust material, and APIs through which workloads obtain and use their identities. SPIRE, the SPIFFE Runtime Environment, is a reference implementation that adds node and workload attestation, identity registration, signing, and credential renewal. Other implementations can participate in the SPIFFE ecosystem; SPIFFE and SPIRE are not interchangeable names.

The central concepts are straightforward, but their security implications matter.

SPIFFE ID: the name, not the credential

A SPIFFE ID is a URI:

spiffe://prod.example.org/payments/settlement-api

Here, prod.example.org is the trust domain, and /payments/settlement-api identifies the workload within it. The identifier is not secret and does not prove identity by itself. Proof comes from a verifiable document carrying that identifier.

A trust domain establishes an identity authority boundary. Its name resembles a DNS name but need not resolve through DNS. An organization might use separate trust domains for independently administered environments rather than treating every cluster as part of one authority.

SVID: the verifiable credential

A SPIFFE Verifiable Identity Document, or SVID, carries the SPIFFE ID in a cryptographically verifiable form. Two foundational formats are X.509-SVIDs and JWT-SVIDs.

An X.509-SVID is a constrained X.509 certificate. Its SPIFFE ID appears in the Subject Alternative Name extension as a URI SAN; the specification requires exactly one URI SAN. In an mTLS deployment, the certificate identifies the workload, while possession of the corresponding private key supplies the cryptographic proof during authentication.

A JWT-SVID supports token-based authentication, particularly across application-layer boundaries. Unlike certificate-based TLS authentication, a JWT-SVID is a bearer credential: a recipient can potentially replay it to another service accepting its audience. Audience restrictions limit that exposure but do not turn it into proof-of-possession authentication.

Trust bundle: the verification material

A workload also needs the public trust material required to verify its peers. SPIFFE distributes this through trust bundles, containing the relevant certificates or public keys for an issuing trust domain. A bundle is verification material—not a collection of workload private keys.

Workload API: the local delivery interface

The SPIFFE Workload API is a protobuf-defined gRPC interface through which workloads retrieve credentials and trust material. Crucially, the workload does not need to present a pre-provisioned application secret to use it. The implementation must identify the caller; SPIRE does so using local workload attestation, including inspection of operating-system metadata.

That distinction is fundamental: reaching the API is not equivalent to being entitled to an arbitrary identity.

How SPIRE turns evidence into identity

A conventional SPIRE deployment has two principal components:

  • SPIRE Server: maintains identity registration policy and signs SVIDs.
  • SPIRE Agent: runs on workload nodes, attests local callers, and exposes the Workload API.

The server is the identity authority; the agent is a trusted intermediary between that authority and local workloads. SPIRE can operate its own certificate authority or integrate with an upstream authority.

The resulting flow separates two different questions.

  1. Node attestation: may this agent participate?

First, the agent proves its node identity to the server using a configured node-attestation mechanism. The server must establish trust in the agent before relying on its statements about local workloads. Node-attestor plugins allow this introduction to use evidence appropriate to the hosting environment.

This does not eliminate bootstrap trust. It relocates it into the attestation mechanism and the infrastructure supplying its evidence.

  1. Registration: which evidence permits which identity?

The server stores registration entries mapping:

  • A SPIFFE ID.
  • One or more selectors describing eligible workloads.
  • A parent ID establishing the relevant identity relationship.

The server distributes applicable entries to agents, which cache and update them. During workload attestation, an agent compares discovered selectors against those entries to determine which identities the caller may receive.

An illustrative policy might express:

Identity:

spiffe://prod.example.org/payments/settlement-api

Required evidence:

Kubernetes namespace = payments

Kubernetes service account = settlement-api

Placement:

Eligible attested nodes

This is an issuance policy, not an assertion the application makes about itself. Available selectors depend on the configured workload-attestor plugins, and multiple attestation strategies can contribute evidence for one workload.

  1. Workload attestation: what is this local caller?

When a workload contacts the agent, the agent establishes facts about the calling process and its environment. It matches that evidence to registration policy and returns the identities the workload is entitled to use—not merely the identity it requests.

The architectural sequence is:

Node evidence → trusted agent

Local caller evidence → matching registration policy

Matching policy → workload SVID and trust material

The agent obtains and caches SVIDs from the server, exposing the appropriate material locally to eligible workloads. Credential issuance therefore does not require every application to implement its own enrollment protocol against a central CA.

  1. Authentication: prove identity to a peer

For mTLS, workloads use their X.509-SVIDs and private keys to authenticate a connection and use trust bundles to validate the peer. Applications can integrate directly, or Envoy can obtain credentials through SPIRE’s Secret Discovery Service integration. SPIRE streams rotated material to Envoy, which applies it to new connections.

But a trusted certificate is only the beginning of an access decision.

A settlement API may accept credentials issued by the production trust domain while permitting requests only from a particular caller identity. Authentication establishes who is calling; authorization decides what that identity may do. SPIRE supplies the former, while application logic or a policy engine such as OPA supplies the latter.

Federation: recognize another authority without merging it

SPIFFE federation allows workloads to validate identities issued in another trust domain by securely obtaining that domain’s trust bundle. Each domain retains its identity authority; federation does not require sharing private signing keys or collapsing the domains into one namespace.

A useful security interpretation is:

Federation makes another domain’s identities verifiable. Authorization determines which of those identities are acceptable.

Consequently, bundle authenticity and the binding between a trust domain and its bundle are security-critical. Trusting the wrong bundle means trusting the wrong issuer.

What security teams should scrutinize

The following are architectural implications of the attestation and credential model—not properties that deploying SPIRE automatically guarantees:

  • Selector governance is credential-issuance governance. If an attacker can arrange for a workload to satisfy privileged registration selectors, the identity system may issue that privileged identity correctly according to its policy. Review who controls the underlying attributes, not just the selector syntax.
  • Attestation does not guarantee integrity. Matching execution-environment evidence establishes eligibility under policy; it does not demonstrate that the application is uncompromised.
  • Workload isolation remains essential. SPIFFE explicitly assumes sufficient isolation to prevent one workload from stealing another’s issued credentials. The standard does not supply that isolation.
  • Rotation is not containment. Short-lived credentials reduce the useful lifetime of stolen material, but an attacker retaining control of an eligible workload can potentially obtain replacements. Credential lifecycle controls must accompany workload remediation.
  • The identity plane is privileged infrastructure. Servers sign identities, agents determine local eligibility, and bundles establish verification trust. Their protection belongs in the authentication threat model.

The takeaway

SPIFFE standardizes how software names and proves its identity. SPIRE operationalizes that model by connecting infrastructure evidence to issuance policy and continuously delivering usable credentials. Its value is not simply “automatic certificates”; it is a consistent, attestable identity foundation for service authentication and secure introduction.

SPIFFE

I’ve been working on a mechanism that allows agents—and other workloads—to identify themselves without relying on long-lived application secrets. My earlier proposal for workload-managed credentials with very short lifetimes never gained traction. Our existing OAuth client-secret approach establishes that a caller possesses the secret associated with a registered client, but that is not the same as establishing which running workload is presenting it. Rotation is operationally awkward in our environment, and a copied secret can be presented from somewhere other than its intended deployment.

So I’m setting up SPIFFE (Secure Production Identity Framework For Everyone) using SPIRE (SPIFFE Runtime Environment). SPIFFE defines workload identities and their verifiable credentials; SPIRE supplies the server and node-local agents that establish eligibility and issue those credentials. It is better understood as an attestation-based identity issuance system than as a proxy for certificate authentication.

There are two distinct trust decisions. First, the SPIRE server establishes the identity of the node’s agent through node attestation. In my configuration (x509pop), this is a machine certificate. There are, however, many other options. I used a jointoken to set up an initial sandbox, k8s_psat is ideal in a Kubernetes environment, and I could see using Azure/AWS/GCE for machines hosted in one of those environments.

Mechanism What the agent presents Typical fit
aws_iid AWS EC2 instance identity evidence, verified against AWS Agents running on EC2
gcp_iit Google Compute Engine instance identity evidence, verified using GCP APIs Agents running on GCE
azure_imds Azure instance metadata/identity evidence Agents running on Azure VMs
azure_msi A signed token obtained through Azure Managed Service Identity Azure nodes with managed identity enabled
k8s_psat A Kubernetes projected service-account token, verified by the server against the Kubernetes cluster Agents running in Kubernetes; the plugin specifically attests nodes inside Kubernetes
x509pop A provisioned X.509 certificate plus proof of possession of its private key Environments with an existing certificate-provisioning or machine-PKI process.
sshpop SSH host-identity evidence plus proof of possession of the associated private key Environments that provision and manage SSH host certificates/keys
tpm_devid TPM-backed device identity evidence Hardware-backed node identity where compatible TPMs are available
jointoken A pre-provisioned, one-time join token Bootstrap or environments where cloud/hardware attestation isn’t available; the token itself must be provisioned and protected
http_challenge A challenge/response that checks the agent is reachable at a valid DNS name Specific DNS-reachable deployments; it is not equivalent to hardware-backed instance identity

Second, when an application connects to the agent’s local Workload API, the agent establishes facts about the calling workload. Depending on the configured attestors, those facts can include its Unix UID, systemd unit, or Kubernetes namespace and service account. Registration policy determines which SPIFFE identity those facts entitle the workload to receive. The application does not simply say “I am Agent XYZ” and get XYZ’s credentials.

Access to the Workload API socket is therefore necessary in this local integration, but not sufficient: the calling process must also satisfy the identity’s registration policy. The important boundary is which workload may obtain the credential, rather than possession of a pre-provisioned application secret.

There is an important limitation: attestation controls issuance, not every subsequent use. If an attacker steals an issued certificate and its private key—or a bearer JWT-SVID—the credential can potentially be used outside the original workload until it expires. Workload isolation, credential protection, audience restrictions, and downstream authorization remain essential. SPIFFE reduces reliance on long-lived secrets; it does not make credential theft impossible.

 

Term Meaning in this context
SPIFFE ID Workload identifier; not a secret or credential by itself.
SVID SPIFFE Verifiable Identity Document: a cryptographically verifiable identity document carrying a SPIFFE identity.
JWT-SVID SPIFFE JWT identity document with intended audience; not universally an OAuth access token.
SPIRE Workload identity implementation providing attestation and issuance.
STS Security Token Service: validating evidence and issuing tokens under policy.
Subject Principal whose authority is represented by the token.
Actor Party exercising delegated authority; current actor is the outer act.
OAuth client Client registration/authentication identity, distinct from subject and actor.
Delegation grant Protected application approval/authorization context; implementation-specific.
Audience Intended recipient context enforced by the agreed token profile.
Sender constraint Token use requires possession of an associated presenting key.
Revocation window Measured delay before every relevant enforcement point denies authority.

Flatpak – Escaping the Sandbox

We’ve been running Cura from a flatpak because the rpm distributed version was out of date. The big drawback, though, is that this flatpak could not see the files from network mounts. The mount is fine – in fstab, same user account can interact with those files in other applications. Just not this flatpak thing.

Turns out that’s normal – flatpaks operate in a sort of sandbox. You just have to tell it to let an individual flatpak access the location where the network mounts are. In this case, the /mnt path:

flatpack override com.ultimaker.cura --filesystem=/mnt