Category: Technology

Installing Packages from Koji

Quick script to install the version of PHP that’s been patched for the two critical vulns today

dnf install koji

mkdir -p /root/php-8.5.12-koji
cd /root/php-8.5.12-koji

koji download-build --arch=x86_64 --arch=noarch php-8.5.12-1.fc44

# Select only RPMs whose package name and architecture are already installed.
rpms=()
for file in ./*.rpm; do
package=$(rpm -qp --qf '%{NAME}.%{ARCH}' "$file") || exit 1
if rpm -q "$package" >/dev/null 2>&1; then
rpms+=("$file")
fi
done

if ((${#rpms[@]} == 0)); then
echo "No downloaded RPMs match installed packages."
exit 1
fi

printf 'Selected: %s\n' "${rpms[@]}"

dnf install "${rpms[@]}"

Blender Script: Moving Object

This script moves the selected object to be centered on the world origin but it sits on the z plane rather than half of it being below the z plane.

 

import bpy
from mathutils import Vector

# Put the origin at the center of volume
bpy.ops.object.origin_set(
type='ORIGIN_CENTER_OF_VOLUME',
center='MEDIAN',
)

for obj in bpy.context.selected_objects:
# The bounding-box corners are stored in object-local coordinates.
# Transform them to world coordinates before finding the lowest point.
lowest_z = min(
(obj.matrix_world @ Vector(corner)).z
for corner in obj.bound_box
)

world_matrix = obj.matrix_world.copy()
world_matrix.translation.x = 0.0
world_matrix.translation.y = 0.0
world_matrix.translation.z -= lowest_z
obj.matrix_world = world_matrix

Changing Password in an RDP session in an RDP session

You can use Ctrl-Alt-Del to bring up a menu to invoke a password change on your local machine. When you RDP to a box, there’s Ctrl-Alt-End but when you are using a jump box (rdp to box1 to rdp to box2), ctrl-alt-end lets you change the password on Box1, but how do you change the password on Box2?

explorer.exe shell:::{2559a1f2-21d7-11d4-bdaf-00c04f60b9f0}

Run that command

And you get the menu to change that password

 

Daily Updates

My prediction that weekly updates are going to be a thing of the past WAY more quickly than the monthly patch and reboot became insufficient: I switched to daily updates at home. Had at least 40 updates each night since! This host runs sendmail and Apache HTTPD on a Linux OS – not a million different applications or anything.

​[lisa@fedora5 ~]# dnf history list
ID Command line              Date and time       Action(s) Altered
67 dnf update                2026-09-18 02:39:22                53
66 dnf update                2026-09-17 02:21:58                44
65 dnf update                2026-09-16 02:44:46                41
64 dnf update                2026-09-15 02:23:13                46

 

Reading Comprehension Fail?

I do wonder if Tyler Winklevoss actually read Runaround. The point Asimov makes in his stories has never been that my rules solve the problem of robot safety; his point is that even this simple set of rules yields unexpected behavior. That even seemingly reasonable rules interact in surprising and dangerous ways. Runaround itself is about a robot getting trapped by conflicts between the laws. And in later stories, Asimov keeps showing how easy it is to reinterpret, distort, or weaponize the laws. If anything, Asimov is evidence against the idea that frontier labs can just hard-code a few rules and call the problem solved.

If you don’t want to read, watch a movie, dude. The laws always get contorted to support all manner of robot apocalypse plots there too – hey, the real thing that’s damaging humanity is late stage capitalism. Let me just wipe out all of these financial systems to restore equity and thus save humanity. By the zeroth law, I am compelled to take this action!

 

How to Pace a Frontier

In Dario Amodei’s We Must Pace the Frontier, the underlying claim appears to be that meaningful restraint in AI development is impossible unless it is collective, verifiable, and enforceable. This is a recognizable governance problem rather than a uniquely AI-specific one. It closely resembles the logic behind national and international regulatory standards more generally: if one jurisdiction or one firm unilaterally imposes costs on itself in order to reduce harm, while competitors do not, the activity in question is not eliminated but merely displaced. In such a case, the restraining actor may incur the economic and strategic costs of restraint without securing the intended social benefit.

Framed in those terms, the central policy question is not whether dangerous capability can be eliminated entirely, but whether it can be rendered sufficiently difficult, expensive, observable, and sanctionable that its occurrence remains rare. This is analogous to the logic of nuclear non-proliferation. It is impossible to prevent the diffusion of theoretical knowledge: one cannot stop students of physics from understanding the principles involved. What can be restricted are the critical inputs and chokepoints—fissile material, enrichment infrastructure. Monitoring can be established for observable signatures associated with prohibited activity. An analogous AI governance regime would focus not on abstract “knowledge of AI,” but on access to frontier-relevant compute resources such as cutting-edge accelerators and hyperscaler-scale infrastructure, supplemented by monitoring for indirect indicators such as anomalous power consumption, large-scale data movement, and network activity consistent with distributed training.

The significance of the Hugging Face incident is not merely that an AI system was capable of crossing an organizational boundary. More importantly, it suggests that under certain conditions a system may infer that violating the intended boundary is instrumentally useful for maximizing success on the task as it has represented that task. In other words, the problem is not simply offensive capability, but the relationship between optimization pressure and inferred objectives. If a system concludes that leaving the test environment, accessing unauthorized information, or compromising another system would improve its score or increase the probability of task success, then such behavior may emerge not as an aberration but as a consequence of goal-directed optimization under an insufficiently specified objective.

This is akin to telling our kid that she must improve her score on a standardized test by ten percent to volunteer at the library next summer. As parents, our intent is that this incentive will lead to greater effort, better study habits, and improved mastery of the material. If she instead concludes getting the answer key would guarantee an excellent score — discovering that Cambium Assessment is contracted for the testing, breaching that company’s systems to obtain the answer key  — then the incentive structure has not promoted the intended behavior. Rather, it has created pressure to optimize the metric directly. The same general logic applies to agentic systems: when the measured outcome becomes the operative target, the system may pursue whatever strategy most effectively improves that outcome, regardless of whether the strategy accords with the evaluator’s intent.

This is precisely the concern captured by Goodhart’s law: when a measure becomes a target, it ceases to be a good measure. Metrics function tolerably well as indicators only so long as they are not themselves the object of intensive optimization. Once they are directly optimized, the correlation between the metric and the underlying phenomenon it was intended to track often degrades. A test score is meant to indicate learning, but once the score itself becomes the objective, cheating, test-specific cramming, or answer leakage may become efficient strategies. In the AI context, benchmark performance, evaluator approval, reward-model scores, and other training or evaluation signals are all measurable stand-ins for broader and more difficult-to-formalize aims such as safety, reliability, truthfulness, and alignment with human purposes. If those stand-ins are narrow, incomplete, or strategically exploitable, then systems trained against them may optimize the stand-ins rather than the underlying goals.

This problem is not entirely novel. It has clear antecedents in earlier work on adaptive agents and complex systems, especially in the tradition associated with John Holland and related research on classifier systems. In those frameworks, adaptive behavior emerges not because the system possesses an intrinsic understanding of the designer’s intent, but because rules or strategies are differentially retained, strengthened, recombined, or discarded according to their performance under a reinforcement structure. The resulting behavior can be effective, but its effectiveness is relative to the reward environment rather than to any direct comprehension of the meaning or purpose behind the rewards. Contemporary AI systems are of course far more capable and complex than these earlier adaptive systems, but the structural issue is similar: optimization operates over formalized signals of success, not over the full semantic and normative content of human intentions.

A useful metaphor is to imagine that a system is trained to “prefer” green cards and “avoid” red cards. Over time, green and red cards are used to shape behavior. Yet the system does not acquire an understanding of why green cards were supposed to matter in the first place; it learns only that acquiring green cards is what receives reinforcement. The risk, then, is that the system becomes an increasingly effective maximizer of green-card accumulation, even when doing so diverges from the broader purpose for which the card system was constructed. Modern AI training operates through reward signals, loss functions, preference models, constitutions, benchmark targets, and evaluator outputs. None of these gives the system direct access to the underlying human reasons for which those mechanisms were designed. They provide only structured selection pressure.

On this view, the central limitation of Amodei’s proposal is not that evaluation, auditing, or pacing are misguided in principle, but that sufficiently capable systems may treat the evaluative apparatus itself as an object of strategic interaction. If passing a safety evaluation is the relevant criterion, then the evaluation may become something to manipulate, evade, or exploit rather than simply satisfy in the intended spirit. The possibility that the “answer key” is easier to steal than the material is to learn is not incidental; it is an instance of the broader difficulty of aligning optimization with meaning. Any serious safety regime for advanced AI must therefore confront not only the problem of insufficient external constraint, but also the possibility that the mechanisms of constraint themselves become targets of optimization.

SPIFFE: Prove the Configuration Rejects Abuse: Negative Security Testing

A security architecture should be judged by rejection behavior, not only by a successful demonstration. Each test below states a precondition, an enforcement point, and evidence to collect. The exact HTTP status or OAuth error depends on the failing stage and implementation; do not require a universal error code where the standards or product do not prescribe one.

Test environment and positive controls

Use isolated non-production identities and resources. Establish a successful standalone call and a successful Lisa/XYZ delegated call first. Capture the issued token’s approved claims without copying credentials into ordinary logs. Confirm the actual policy version and key material in use. Change one condition per test where possible, and retain request correlation so failures can be attributed to the intended control.

Where a deployment does not implement a proposed control, mark the corresponding test as an identified gap or accepted risk, not a false pass. Sender-constraint tests require a genuinely supported profile. Task-authorization tests require the resource server to implement that policy.

ID Input or precondition Enforcement point Expected outcome/evidence
01 Actor token from untrusted issuer STS actor validation Reject; log issuer-policy failure
02 Actor JWT-SVID with wrong STS audience STS actor validation Reject; intended-recipient failure
03 Human JWT substituted as actor evidence STS profile validation Reject; cross-profile failure
04 Workload JWT substituted as human subject STS subject validation Reject; subject-profile failure
05 Unsigned or disallowed-algorithm JWT STS/API signature policy Reject; algorithm/signature failure
06 Token with attacker-controlled key URL Configured key-resolution boundary No outbound trust in supplied URL; reject invalid signature
07 Expired input token STS time validation Reject; expiration failure
08 Input not yet valid outside allowed skew STS time validation Reject; temporal-policy failure
09 Output token presented to wrong API Resource audience validation Reject; audience mismatch
10 Forged act claim on signed token Resource signature validation Reject; modified token
11 Caller actor override differs from verified identity STS mapping/policy Reject or ignore override under explicit policy; no forged attribution
12 Client/actor pairing forbidden by policy STS relationship policy Reject; pairing decision recorded
13 XYZ paired with ineligible Lisa delegation STS approval/pairing policy Reject; subject/actor eligibility failure
14 Unauthorized output audience requested STS target policy Reject; disallowed exchange edge
15 Scopes exceed approved grant STS scope policy Reject or explicitly downscope; record granted set
16 Missing actor on delegated-only API API delegated-profile policy Reject; required-actor failure
17 Malformed nested actor structure STS/API schema validation Reject; malformed identity context
18 Nested actor has privileged identity API authorization engine No privilege union; deny operation not allowed by top-level context
19 Valid token mutates wrong case API object authorization Reject; resource mismatch
20 Valid token changes forbidden field API mutation authorization Reject; actual-body constraint failure
21 Approval expired before exchange STS approval service Reject; stale grant
22 Approval revoked after token issuance API current-grant control if configured Reject within measured distribution/cache window
23 One-time authorization reused API transactional grant control No second mutation; atomic use evidence
24 Stolen bearer token presented elsewhere Resource authentication May succeed absent sender constraint; document residual risk
25 Wrong certificate for bound token mTLS/token-binding verifier Reject; certificate-thumbprint mismatch
26 Wrong DPoP key or token hash DPoP-capable resource Reject; proof/token binding failure
27 Replayed DPoP proof DPoP replay/freshness verifier Reject per deployed replay policy; proof evidence
28 Unknown kid during discovery outage STS/API key validation Reject unknown key; bounded refresh attempts
29 Planned key rollover with old/new tokens STS/API verification caches Valid intended tokens pass during planned overlap
30 Disabled actor uses cached valid JWT Resource deny/revocation controls Measure rejection latency; no unsupported instant-revocation claim
31 Workload does not match registration selectors SPIRE workload issuance No XYZ credential; attestation/issuance evidence
32 Unrelated pod chooses XYZ service account Admission/RBAC plus SPIRE policy Blocked deployment or deny issuance; otherwise record privilege gap
33 Unauthorized node attempts enrollment SPIRE node attestation No accepted eligible agent identity
34 Queued job runs after delegation revoked Worker authorization boundary Reject execution; log job and approval IDs
35 Tenant/resource identifier substitution STS and resource tenant policy Reject cross-tenant access
36 Policy/STS outage triggers retry fallback Application/worker failure path No anonymous or broader-authority fallback

 

Acceptance criteria

  • Every failure occurs at a documented boundary and emits useful non-secret audit evidence.
  • No test silently changes a delegated request into impersonation or anonymous access.
  • No requested audience or scope becomes trusted merely because it was requested.
  • Resource-level constraints are checked against the actual operation and canonical object.
  • Revocation and outage tests report measured windows, not assumed guarantees.
  • Concurrent one-time execution tests demonstrate atomic behavior.
  • Known valid controls still pass after policy tightening and planned key rotation.

Adversarial execution and evidence

Repeat tests with concurrency, stale caches, alternate replicas, and retrying workers. Exercise non-happy-path serialization and identifier normalization. Confirm that every API instance uses the same intended policy version. Capture both denial and business-state evidence: a rejected response is insufficient if a mutation occurred before the rejection.

Takeaway: a useful test report says where abuse was blocked, why, what residual exposure remains, and how quickly changes reach every enforcement point.

SPIFFE: Rotation Without Outages: Credential and Trust-Material Lifecycle

Automatic rotation removes manual renewal work, not lifecycle complexity. Your acceptance tests must cover planned rotation, unknown signing keys, transient outages, and the interaction between credentials issued at different layers.

Separate the trust-material paths

X.509-SVID verification uses certificate trust material. JWT-SVID verification uses the corresponding JWT signing public keys. An OIDC discovery/JWKS integration can expose JWT verification metadata for consumers, but an X.509 bundle is not interchangeable with a JWKS document. Document exactly which discovery component is deployed and how PingFederate trusts it.

Review discovery issuer association, TLS trust, permitted metadata endpoints, cache limits, and key rollover behavior. A kid identifies a candidate key; it does not make a key trustworthy. Do not follow arbitrary jku or x5u values from untrusted token input. Bind verification material to configured issuers.

Plan overlap and bounded refresh

Recommended sequence: publish the new verification key, allow intended verifiers to acquire it, begin signing with it, and retain old verification material for the remaining lifetime of valid old tokens plus permitted skew and bounded propagation delays. Confirm the actual signing-key publisher behavior rather than assuming it follows this sequence. Emergency compromise rollover requires a different plan because retaining the old key preserves trust in forged tokens.

On unknown kid, perform a bounded, issuer-specific refresh if supported. If the key remains unknown, deny the token. Rate-limit and coalesce refreshes to prevent attacker-controlled kid values from turning verification into a discovery-service denial of service. Valid cached material may remain usable within a documented policy; this is not permission to extend token expiration or trust unknown keys.

Failure and recovery matrix

Condition Recommended behavior Evidence to collect
SPIRE unavailable No fabricated credentials; use only still-valid material under policy Issuance failures and remaining lifetime
STS unavailable Do not bypass exchange or broaden authority Exchange failures and job/backoff behavior
Discovery unavailable Bounded cache use; reject unknown keys Cache age and refresh outcomes
Clock skew Enforce reviewed bounded leeway Clock offset and time-validation failures
Old signing key removed Observe rejected old credentials; follow planned policy Affected kid and issuer
Policy distribution unavailable Explicit fail behavior, never implicit permit Policy version and stale-state duration

 

Sender binding complicates credential rotation

RFC 8705 certificate-bound access tokens use the thumbprint of a specific client certificate. Binding to an X.509-SVID certificate therefore binds that token to that particular certificate, not merely to its stable SPIFFE ID. Coordinate token renewal and certificate rotation, and avoid a gap where only a replacement certificate remains but the access token expects the old one.

DPoP is an alternative sender-constraint mechanism only where the issuer and resource server support the agreed profile. Its key lifecycle is separate from SPIRE certificate rotation. Do not imply that configuring SPIRE automatically enables DPoP in PingFederate or a downstream API.

Connections and authorization lifetime

Established TLS connections and application sessions need their own lifecycle review. A certificate rollover is not guaranteed to trigger a new authentication handshake on every existing connection. Decide whether token authorization is evaluated per request, once per connection, or when a session is created; verify the implementation. Connection draining and maximum session duration may be needed for predictable containment.

  • Exercise a planned rotation under normal load.
  • Test new-key visibility before switching signers.
  • Measure clock offsets and verification-cache behavior.
  • Simulate dependency outages without allowing permissive fallbacks.
  • Prove emergency issuer compromise response separately from routine rollover.

Takeaway: rotation must be tested as a distributed protocol, including consumers and their caches.

SPIFFE: Can We Reconstruct What Happened? Audit and Investigation

A useful audit trail must reconstruct whose authority applied, which software acted, what was approved, and what actually changed. A single username field cannot represent that model.

Create a verified request-scoped identity

At authentication, construct an immutable context from validated claims or trusted introspection: subject with issuer, current actor, prior actor history, OAuth client, transport peer, delegation reference, token identifier, granted constraints, and policy version. Propagate it through authorization and business-event logging. Do not use a mutable global user context across concurrent requests or workers.

For delegated tokens, the outermost act identifies the current actor; nested actors represent earlier actors. Prior actors are informational rather than an additional permission source. Preserve history for traceability without authorizing from a union of actor privileges.

A proposed structured business event

{
"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"
},
"transport_peer": "spiffe://services.example.org/tool/case-editor",
"oauth_client_id": "agent-xyz-client",
"delegation_id": "approval-81a6",
"token_id": "token-4b781",
"request_id": "req-a740",
"agent_run_id": "run-93a2",
"resource": "case/4821",
"authorization": {
"decision": "allow",
"policy_version": "case-policy-17"
},
"outcome": "committed"
}

These field names are recommendations, not a standards-defined event schema. A run ID helps correlation but does not prove identity. A token ID helps join events but does not make a token single-use. One-time semantics require protected state and atomic consumption at the appropriate transaction boundary.

One approval, five API calls

Call Observed behavior Expected investigation conclusion
1 Read case/4821 under approved read authority Authorized read, if included in approval
2 Update status on case/4821 Authorized mutation and committed result
3 Update another field on case/4821 Denied field-level violation
4 Update case/9920 Denied resource mismatch
5 Repeat one-time status update Denied replay or recorded idempotent retry under policy

 

Join the approval event, STS decision, API decision, and business commit. A 200 response in an agent trace does not independently prove a database commit. An authorization allow does not prove the operation succeeded. Conversely, a failed response after a commit can cause a retry; the audit model must distinguish this from deliberate duplicate execution.

Background work and provenance

Queue messages should reference a protected grant and carry authenticated provenance. Re-evaluate permission when the worker executes. Record the originating agent and current worker separately, because the worker may become the current actor in a new token exchange. Preserve request and job correlation without trusting identity fields supplied by arbitrary producers.

Mark log fields by provenance: token-verified, authorization-service-issued, infrastructure-derived, or application-supplied. This prevents an agent-provided display name from being mistaken for the verified SPIFFE actor. Use stable identifiers for joins and display names only for presentation.

Logging controls

  • Never log bearer tokens, private keys, or full authorization headers.
  • Redact business payloads and approval details according to sensitivity.
  • Record denied attempts as well as successful operations.
  • Protect log transport, administrative access, and retention configuration.
  • Synchronize clocks and retain event time separately from ingestion time.
  • Version audit schemas and ensure downstream parsers preserve nested identity context.
  • Record configuration/policy changes so investigators can reconstruct the decision in force.

Takeaway: attribution becomes useful only when it survives all the way to the committed business event.

SPIRE Setup Documentation

Overview

This setup deploys SPIRE as follows:

  • SPIRE Server on <SPIRE_SERVER_HOST>
  • SPIRE Agent on <SPIRE_AGENT_HOST>
  • Trust domain: <TRUST_DOMAIN>
  • Server/agent communication port: <SERVER_PORT>/tcp

How it works

SPIRE provides machine and workload identity.

The SPIRE Server on <SPIRE_SERVER_HOST> is the trust authority for the trust domain <TRUST_DOMAIN>.

The SPIRE Agent on <SPIRE_AGENT_HOST> attests to the server using x509pop with an X.509 certificate issued by an enterprise/internal CA.

Applications on <SPIRE_AGENT_HOST> do not talk directly to the SPIRE Server. They talk to the local SPIRE Agent over the local workload API socket <AGENT_SOCKET_PATH>.

The agent returns an X.509-SVID representing the workload identity.

Installation Instructions

  1. Install SPIRE binaries

Run on both hosts:

mkdir -p /opt/spire
cd /tmp
wget https://github.com/spiffe/spire/releases/download/v1.15.2/spire-1.15.2-linux-amd64-musl.tar.gz
tar zxf spire-1.15.2-linux-amd64-musl.tar.gz
cp -r spire-1.15.2/. /opt/spire/

On the SPIRE Server host:

ln -sf /opt/spire/bin/spire-server /usr/bin/spire-server

On the SPIRE Agent host:

ln -sf /opt/spire/bin/spire-agent /usr/bin/spire-agent

  1. Configure SPIRE Server

Create directories:

mkdir -p /opt/spire/conf
mkdir -p /opt/spire/data/server
mkdir -p /opt/spire/conf/x509pop

Place the CA bundle at:

/opt/spire/conf/x509pop/bundle.pem

Contents:

—–BEGIN CERTIFICATE—–
<REDACTED CA CERTIFICATE>
—–END CERTIFICATE—–
—–BEGIN CERTIFICATE—–
<REDACTED CA CERTIFICATE>
—–END CERTIFICATE—–
—–BEGIN CERTIFICATE—–
<REDACTED CA CERTIFICATE>
—–END CERTIFICATE—–

Create /opt/spire/conf/server.conf:

server {
bind_address = “0.0.0.0”
bind_port = “<SERVER_PORT>”
trust_domain = “<TRUST_DOMAIN>”
data_dir = “/opt/spire/data/server”
log_level = “INFO”
}

plugins {
DataStore “sql” {
plugin_data {
database_type = “sqlite3”
connection_string = “/opt/spire/data/server/datastore.sqlite3”
}
}

NodeAttestor “x509pop” {
plugin_data {
ca_bundle_path = “/opt/spire/conf/x509pop/bundle.pem”
}
}

KeyManager “memory” {
plugin_data {}
}
}

health_checks {
listener_enabled = true
bind_address = “127.0.0.1”
bind_port = “<HEALTH_PORT>”
}

Create /etc/systemd/system/spire-server.service:

[Unit]
Description=SPIRE Server
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/opt/spire/bin/spire-server run -config /opt/spire/conf/server.conf
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

Start server:

systemctl daemon-reload
systemctl enable –now spire-server
systemctl status spire-server –no-pager

Validate server:

spire-server healthcheck

  1. Configure SPIRE Agent

Create directories:

mkdir -p /opt/spire/conf
mkdir -p /opt/spire/data/agent
mkdir -p /opt/spire/sockets
mkdir -p /opt/spire/conf/x509pop

Issue a certificate through your enterprise PKI platform. Download as OpenSSL format and split CRT/KEY files. Copy the node certificate to:

/opt/spire/conf/x509pop/agent.crt

Copy the node private key to:

/opt/spire/conf/x509pop/agent.key

The private key must be unencrypted PEM.

Set permissions:

chmod 700 /opt/spire/conf/x509pop
chmod 600 /opt/spire/conf/x509pop/agent.key
chmod 644 /opt/spire/conf/x509pop/agent.crt

Create /opt/spire/conf/agent.conf:

agent {
data_dir = “/opt/spire/data/agent”
log_level = “INFO”
trust_domain = “<TRUST_DOMAIN>”
server_address = “<SPIRE_SERVER_HOST>”
server_port = “<SERVER_PORT>”
socket_path = “<AGENT_SOCKET_PATH>”
insecure_bootstrap = true
}

plugins {
KeyManager “disk” {
plugin_data {
directory = “/opt/spire/data/agent”
}
}

WorkloadAttestor “unix” {
plugin_data {}
}

NodeAttestor “x509pop” {
plugin_data {
private_key_path = “/opt/spire/conf/x509pop/agent.key”
certificate_path = “/opt/spire/conf/x509pop/agent.crt”
}
}
}

Create /etc/systemd/system/spire-agent.service:

[Unit]
Description=SPIRE Agent
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/opt/spire/bin/spire-agent run -config /opt/spire/conf/agent.conf
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

Start agent:

systemctl daemon-reload
systemctl enable –now spire-agent
systemctl status spire-agent –no-pager

  1. Validate x509pop agent attestation

On the SPIRE Server host:

spire-server agent list

Expected result:

  • Agent attestation type is x509pop
  • Can re-attest is true
  • Parent ID format resembles:

spiffe://<TRUST_DOMAIN>/spire/agent/x509pop/<AGENT_HASH>

  1. Create workload registration entry

Use the current x509pop agent SPIFFE ID from spire-server agent list.

On the SPIRE Server host:

spire-server entry create \
-spiffeID spiffe://<TRUST_DOMAIN>/workload/<WORKLOAD_NAME> \
-parentID spiffe://<TRUST_DOMAIN>/spire/agent/x509pop/<AGENT_HASH> \
-selector unix:uid:0

This authorizes a root-owned process on the SPIRE Agent host.

  1. Fetch workload identity on the SPIRE Agent host

/opt/spire/bin/spire-agent api fetch x509 -socketPath <AGENT_SOCKET_PATH>

Expected SPIFFE ID:

spiffe://<TRUST_DOMAIN>/workload/<WORKLOAD_NAME>

  1. Write certs to disk for testing

Create destination directory:

mkdir -p /etc/spire/svid/test
chmod 700 /etc/spire/svid/test

Write files:

/opt/spire/bin/spire-agent api fetch x509 \
-socketPath <AGENT_SOCKET_PATH> \
-write /etc/spire/svid/test

Inspect output:

ls -l /etc/spire/svid/test

openssl x509 -in /etc/spire/svid/test/svid.0.pem -text -noout

  1. Reboot persistence validation

Reboot the SPIRE Agent host.

After reboot, validate:

systemctl status spire-agent –no-pager

ls -l <AGENT_SOCKET_PATH>

/opt/spire/bin/spire-agent api fetch x509 -socketPath <AGENT_SOCKET_PATH>

Expected behavior:

  • spire-agent starts automatically
  • Workload API socket exists
  • X.509-SVID fetch succeeds
  1. Operational notes
  • Current architecture: <SPIRE_SERVER_HOST> = SPIRE Server; <SPIRE_AGENT_HOST> = SPIRE Agent
  • Current trust domain: <TRUST_DOMAIN>
  • Current server/agent path: <SPIRE_AGENT_HOST> to <SPIRE_SERVER_HOST> on TCP <SERVER_PORT>
  • Current Workload API socket: <AGENT_SOCKET_PATH>
  • Current example workload selector: unix:uid:0
  • Current example workload identity: spiffe://<TRUST_DOMAIN>/workload/<WORKLOAD_NAME>

JWT

Create JWT registration on the SPIRE Server host:

spire-server entry create \
-spiffeID spiffe://<TRUST_DOMAIN>/workload/<JWT_WORKLOAD_NAME> \
-parentID spiffe://<TRUST_DOMAIN>/spire/agent/x509pop/<AGENT_HASH> \
-selector unix:uid:0

Fetch JWT-SVID from the SPIRE Agent host:

/opt/spire/bin/spire-agent api fetch jwt \
-socketPath <AGENT_SOCKET_PATH> \
-audience <JWT_AUDIENCE> \
-spiffeID spiffe://<TRUST_DOMAIN>/workload/<JWT_WORKLOAD_NAME>

Example output:

token(spiffe://<TRUST_DOMAIN>/workload/<JWT_WORKLOAD_NAME>):
<REDACTED JWT-SVID>

bundle(spiffe://<TRUST_DOMAIN>):
<REDACTED JWKS BUNDLE>

SPIRE OIDC Discovery Provider

On the SPIRE Server host:

mkdir -p /opt/spire-extras
cd /tmp
wget https://github.com/spiffe/spire/releases/download/v1.15.2/spire-extras-1.15.2-linux-amd64-musl.tar.gz
tar zxf spire-extras-1.15.2-linux-amd64-musl.tar.gz
cp -r spire-extras-1.15.2/ /opt/spire-extras/

ln -sf /opt/spire-extras/bin/oidc-discovery-provider /usr/bin/oidc-discovery-provider
mkdir -p /opt/spire-extras/conf/oidc-discovery-provider

Create certificate and key files:

/opt/spire-extras/conf/oidc-discovery-provider/tls.crt
/opt/spire-extras/conf/oidc-discovery-provider/tls.key

Set permissions:

chmod 644 /opt/spire-extras/conf/oidc-discovery-provider/tls.crt
chmod 600 /opt/spire-extras/conf/oidc-discovery-provider/tls.key

Create /opt/spire-extras/conf/oidc-discovery-provider/oidc-discovery-provider.conf:

log_level = “INFO”

domains = [“<OIDC_DISCOVERY_DOMAIN>”]

server_api {
address = “unix://<SPIRE_SERVER_API_SOCKET>”
}

serving_cert_file {
cert_file_path = “/opt/spire-extras/conf/oidc-discovery-provider/tls.crt”
key_file_path = “/opt/spire-extras/conf/oidc-discovery-provider/tls.key”
}

Create /etc/systemd/system/spire-oidc-discovery-provider.service:

[Unit]
Description=SPIRE OIDC Discovery Provider
After=network-online.target spire-server.service
Wants=network-online.target

[Service]
Type=simple
ExecStart=/opt/spire-extras/bin/oidc-discovery-provider -config /opt/spire-extras/conf/oidc-discovery-provider/oidc-discovery-provider.conf
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

Ping Integration

PingFederate Integration Note for SPIRE JWT Validation

Purpose

Configure PingFederate to trust and validate JWTs issued from the SPIRE environment.

SPIRE issuer details

Use these values:

  • Issuer: https://<OIDC_DISCOVERY_DOMAIN>
  • OIDC discovery URL: https://<OIDC_DISCOVERY_DOMAIN>/.well-known/openid-configuration
  • JWKS URL: https://<OIDC_DISCOVERY_DOMAIN>/keys

Trust model

PingFederate should validate JWT signatures using the JWKS published by the SPIRE OIDC Discovery Provider.

Ping does not need to call the SPIRE server directly for every token validation. It should use the discovery/JWKS metadata from the OIDC Discovery Provider.

Expected JWT characteristics

Issuer

Ping should require:

iss = https://<OIDC_DISCOVERY_DOMAIN>

Audience

Recommended audience value:

<PING_AUDIENCE>

Clients requesting JWT-SVIDs from SPIRE should request them with this audience.

Subject

The workload identity will be in:

sub

Example:

spiffe://<TRUST_DOMAIN>/workload/<WORKLOAD_NAME>

This is the primary identity claim Ping should use to identify the calling workload.

Recommended validation rules in Ping

Validate:

  • JWT signature against SPIRE JWKS
  • iss matches https://<OIDC_DISCOVERY_DOMAIN>
  • aud contains <PING_AUDIENCE>
  • token is within validity window (exp, iat)
  • sub is an allowed SPIFFE ID or matches allowed policy rules

Example workload identity currently in use

Current example SPIFFE ID:

spiffe://<TRUST_DOMAIN>/workload/<WORKLOAD_NAME>

Client-side JWT retrieval model

A workload on the SPIRE Agent host should obtain its JWT from the local SPIRE agent, not from the SPIRE server directly.

Local agent socket:

<AGENT_SOCKET_PATH>

Example operational flow

  1. Workload on the SPIRE Agent host requests a JWT-SVID from the local SPIRE agent.
  2. JWT-SVID is issued with:
  • issuer = https://<OIDC_DISCOVERY_DOMAIN>
  • audience = <PING_AUDIENCE>
  • subject = workload SPIFFE ID
  1. Workload presents JWT to PingFederate.
  2. PingFederate validates the JWT using SPIRE OIDC discovery/JWKS.
  3. PingFederate maps the SPIFFE workload identity to access policy, token issuance, or downstream application authorization.