Skip to content

Identity: Move actor JWT/cert minting into the main API - #1315

Open
Taahir Ahmed (ahmedtd) wants to merge 1 commit into
agent-substrate:mainfrom
ahmedtd:merge-broker
Open

Identity: Move actor JWT/cert minting into the main API#1315
Taahir Ahmed (ahmedtd) wants to merge 1 commit into
agent-substrate:mainfrom
ahmedtd:merge-broker

Conversation

@ahmedtd

@ahmedtd Taahir Ahmed (ahmedtd) commented Aug 29, 2026

Copy link
Copy Markdown
Collaborator

This was originally a separate service to make it easy to apply separate authentication and authorization interceptors.

It now seems clear that our authn/z framework will be strong enough to support atelet and external callers in one system (based on OpenFGA).

This change moves the MintJWT and MintCert RPCs into the control API, and removes some inline authz checks that will be handled by our unified authorizer framework.

@ahmedtd

Copy link
Copy Markdown
Collaborator Author

Whoops, this isn't ready to review yet.

@ahmedtd Taahir Ahmed (ahmedtd) changed the title Merge broker Identity: Move actor JWT/cert minting into the main API Sep 3, 2026
@ahmedtd
Taahir Ahmed (ahmedtd) force-pushed the merge-broker branch 2 times, most recently from 943838f to 10a0120 Compare September 4, 2026 20:16
@ahmedtd
Taahir Ahmed (ahmedtd) marked this pull request as ready for review September 4, 2026 20:17
@ahmedtd

Copy link
Copy Markdown
Collaborator Author

Ready for review now

This was originally a separate service to make it easy to apply separate
authentication and authorization interceptors.  It now seems clear that
they should be in controlapi, with the same authn/z handlers chosen
there.

* Remove checks that will be handled in the authorizer framework.
ObjectRef tag = 1;
}

message MintActorJWTRequest {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] missing doc comment here and a few places below (looks like tests are complaining about this)

Comment thread cmd/ateom-gvisor/main.go
CredentialBundlePath: s.workerCredentialBundlePath,
TrustBundlePath: s.podIdentityTrustBundlePath,
ExpectedActorUID: actorUID,
ActorUID: actorUID,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread cmd/ateom-microvm/main.go
TrustBundlePath: s.podIdentityTrustBundlePath,
ExpectedActorUID: actorUID,

ActorUID: actorUID,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if err != nil {
t.Fatalf("CreateActor failed: %v", err)
}
_, err = tc.client.MintActorJWT(t.Context(), &ateapipb.MintActorJWTRequest{

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we check the error here?

return errs
}

func (s *RPCService) MintActorJWT(ctx context.Context, req *ateapipb.MintActorJWTRequest) (*ateapipb.MintActorJWTResponse, error) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old RPC handlers called these auto-generated validation functions like so:


func validateMintJWTRequest(ctx context.Context, req *ateapipb.MintJWTRequest) field.ErrorList {
	// Call the generated validation.
	op := operation.Operation{Type: operation.Create}
	return controlapi.Validate_MintJWTRequest(ctx, op, nil, req, nil)
}

func validateMintCertRequest(ctx context.Context, req *ateapipb.MintCertRequest) field.ErrorList {
	// Call the generated validation.
	op := operation.Operation{Type: operation.Create}
	return controlapi.Validate_MintCertRequest(ctx, op, nil, req, nil)
}

I believe we need to copy that over to enforce the tag-based validation?

}

// We only issue tokens with audience bindings.
if len(req.GetAudience()) == 0 {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old handler also validated the issuer (caller.Issuer != s.actorIdentityJWTIssuer), should we do that in the new handler as well?


// Verify that this actor exists in the store. It doesn't need to be
// running, since we may need to issue JWTs during actor boot / resume.
dbActor, err := s.impl.GetActor(ctx, resources.ActorRefFromObjectRef(req.GetActor()))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, should we check that the actor is in a RUNNING state (or in some set of valid states) before minting tokens or certs for it?

return nil, fmt.Errorf("while retrieving actor: %w", err)
}
if dbActor.GetMetadata().GetUid() != req.GetActorUid() {
return nil, status.Error(codes.Aborted, "conflict; actor has been deleted and recreated")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like egress.renew() only stops retrying on FailedPrecondition or PermissionDenied:

if code == codes.FailedPrecondition || code == codes.PermissionDenied {

Should we add Aborted to the list of codes checked there, or adjust the code returned here, to stop it from retrying?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants