-
Notifications
You must be signed in to change notification settings - Fork 472
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Include hint field in agent's workload api #3993
Changes from 10 commits
fec0b09
eee2754
a6e5c49
32b80db
a390e1c
86d5514
498790f
846a2fe
5b817f3
38b2cc2
a18dfea
98fa0e6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -31,6 +31,9 @@ func printX509SVID(env *commoncli.Env, svid *X509SVID) { | |
// Print SPIFFE ID first so if we run into a problem, we | ||
// get to know which record it was | ||
env.Printf("SPIFFE ID:\t\t%s\n", svid.SPIFFEID) | ||
if svid.Hint != "" { | ||
env.Printf("Hint:\t\t\t%s\n", svid.Hint) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. looks like it has 3 tabs, but spiffeID has only 2, do you want to add some hierarchy level? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
} | ||
|
||
env.Printf("SVID Valid After:\t%v\n", svid.Certificates[0].NotBefore) | ||
env.Printf("SVID Valid Until:\t%v\n", svid.Certificates[0].NotAfter) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -61,7 +61,8 @@ func New(c Config) *Handler { | |
} | ||
} | ||
|
||
// FetchJWTSVID processes request for a JWT-SVID | ||
// FetchJWTSVID processes request for a JWT-SVID. In case of multiple fetched SVIDs with same hint, the SVID that has the oldest | ||
// associated entry will be returned. | ||
func (h *Handler) FetchJWTSVID(ctx context.Context, req *workload.JWTSVIDRequest) (resp *workload.JWTSVIDResponse, err error) { | ||
log := rpccontext.Logger(ctx) | ||
if len(req.Audience) == 0 { | ||
|
@@ -82,49 +83,31 @@ func (h *Handler) FetchJWTSVID(ctx context.Context, req *workload.JWTSVIDRequest | |
return nil, err | ||
} | ||
|
||
var spiffeIDs []spiffeid.ID | ||
|
||
log = log.WithField(telemetry.Registered, true) | ||
|
||
entries := h.c.Manager.MatchingRegistrationEntries(selectors) | ||
entries = filterRegistrations(entries, log) | ||
|
||
resp = new(workload.JWTSVIDResponse) | ||
|
||
for _, entry := range entries { | ||
if req.SpiffeId != "" && entry.SpiffeId != req.SpiffeId { | ||
continue | ||
} | ||
|
||
spiffeID, err := spiffeid.FromString(entry.SpiffeId) | ||
loopLog := log.WithField(telemetry.SPIFFEID, entry.SpiffeId) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NIT: since loopLog is used only on h.fetchJWTSVID may we remove the break line? and couple both lines? |
||
svid, err := h.fetchJWTSVID(ctx, loopLog, entry, req.Audience) | ||
if err != nil { | ||
log.WithField(telemetry.SPIFFEID, entry.SpiffeId).WithError(err).Error("Invalid requested SPIFFE ID") | ||
return nil, status.Errorf(codes.InvalidArgument, "invalid requested SPIFFE ID: %v", err) | ||
return nil, err | ||
} | ||
|
||
spiffeIDs = append(spiffeIDs, spiffeID) | ||
resp.Svids = append(resp.Svids, svid) | ||
} | ||
|
||
if len(spiffeIDs) == 0 { | ||
if len(resp.Svids) == 0 { | ||
log.WithField(telemetry.Registered, false).Error("No identity issued") | ||
return nil, status.Error(codes.PermissionDenied, "no identity issued") | ||
} | ||
|
||
resp = new(workload.JWTSVIDResponse) | ||
for _, id := range spiffeIDs { | ||
loopLog := log.WithField(telemetry.SPIFFEID, id.String()) | ||
|
||
var svid *client.JWTSVID | ||
svid, err = h.c.Manager.FetchJWTSVID(ctx, id, req.Audience) | ||
if err != nil { | ||
loopLog.WithError(err).Error("Could not fetch JWT-SVID") | ||
return nil, status.Errorf(codes.Unavailable, "could not fetch JWT-SVID: %v", err) | ||
} | ||
resp.Svids = append(resp.Svids, &workload.JWTSVID{ | ||
SpiffeId: id.String(), | ||
Svid: svid.Token, | ||
}) | ||
|
||
ttl := time.Until(svid.ExpiresAt) | ||
loopLog.WithField(telemetry.TTL, ttl.Seconds()).Debug("Fetched JWT SVID") | ||
} | ||
|
||
return resp, nil | ||
} | ||
|
||
|
@@ -214,7 +197,8 @@ func (h *Handler) ValidateJWTSVID(ctx context.Context, req *workload.ValidateJWT | |
}, nil | ||
} | ||
|
||
// FetchX509SVID processes request for an x509 SVID | ||
// FetchX509SVID processes request for a x509 SVID. In case of multiple fetched SVIDs with same hint, the SVID that has the oldest | ||
// associated entry will be returned. | ||
func (h *Handler) FetchX509SVID(_ *workload.X509SVIDRequest, stream workload.SpiffeWorkloadAPI_FetchX509SVIDServer) error { | ||
ctx := stream.Context() | ||
log := rpccontext.Logger(ctx) | ||
|
@@ -238,6 +222,7 @@ func (h *Handler) FetchX509SVID(_ *workload.X509SVIDRequest, stream workload.Spi | |
for { | ||
select { | ||
case update := <-subscriber.Updates(): | ||
update.Identities = filterIdentities(update.Identities, log) | ||
if err := sendX509SVIDResponse(update, stream, log, quietLogging); err != nil { | ||
return err | ||
} | ||
|
@@ -282,6 +267,29 @@ func (h *Handler) FetchX509Bundles(_ *workload.X509BundlesRequest, stream worklo | |
} | ||
} | ||
|
||
func (h *Handler) fetchJWTSVID(ctx context.Context, log logrus.FieldLogger, entry *common.RegistrationEntry, audience []string) (*workload.JWTSVID, error) { | ||
spiffeID, err := spiffeid.FromString(entry.SpiffeId) | ||
if err != nil { | ||
log.WithError(err).Error("Invalid requested SPIFFE ID") | ||
return nil, status.Errorf(codes.InvalidArgument, "invalid requested SPIFFE ID: %v", err) | ||
} | ||
|
||
svid, err := h.c.Manager.FetchJWTSVID(ctx, spiffeID, audience) | ||
if err != nil { | ||
log.WithError(err).Error("Could not fetch JWT-SVID") | ||
return nil, status.Errorf(codes.Unavailable, "could not fetch JWT-SVID: %v", err) | ||
} | ||
|
||
ttl := time.Until(svid.ExpiresAt) | ||
log.WithField(telemetry.TTL, ttl.Seconds()).Debug("Fetched JWT SVID") | ||
|
||
return &workload.JWTSVID{ | ||
SpiffeId: spiffeID.String(), | ||
Svid: svid.Token, | ||
Hint: entry.Hint, | ||
}, nil | ||
} | ||
|
||
func sendX509BundlesResponse(update *cache.WorkloadUpdate, stream workload.SpiffeWorkloadAPI_FetchX509BundlesServer, log logrus.FieldLogger, allowUnauthenticatedVerifiers bool, previousResponse *workload.X509BundlesResponse, quietLogging bool) (*workload.X509BundlesResponse, error) { | ||
if !allowUnauthenticatedVerifiers && !update.HasIdentity() { | ||
if !quietLogging { | ||
|
@@ -391,6 +399,7 @@ func composeX509SVIDResponse(update *cache.WorkloadUpdate) (*workload.X509SVIDRe | |
X509Svid: x509util.DERFromCertificates(identity.SVID), | ||
X509SvidKey: keyData, | ||
Bundle: bundle, | ||
Hint: identity.Entry.Hint, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is there a warranty that entry is not nil? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe so, as you can see on line 391, we are already taking the SPIFFE ID from the entry. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
} | ||
|
||
resp.Svids = append(resp.Svids, svid) | ||
|
@@ -513,3 +522,80 @@ func isClaimAllowed(claim string, allowedClaims map[string]struct{}) bool { | |
return ok | ||
} | ||
} | ||
|
||
func filterIdentities(identities []cache.Identity, log logrus.FieldLogger) []cache.Identity { | ||
var filteredIdentities []cache.Identity | ||
var entries []*common.RegistrationEntry | ||
for _, identity := range identities { | ||
entries = append(entries, identity.Entry) | ||
} | ||
|
||
entriesToRemove := getEntriesToRemove(entries, log) | ||
|
||
for _, identity := range identities { | ||
if _, ok := entriesToRemove[identity.Entry.EntryId]; !ok { | ||
filteredIdentities = append(filteredIdentities, identity) | ||
} | ||
} | ||
|
||
return filteredIdentities | ||
} | ||
|
||
func filterRegistrations(entries []*common.RegistrationEntry, log logrus.FieldLogger) []*common.RegistrationEntry { | ||
var filteredEntries []*common.RegistrationEntry | ||
entriesToRemove := getEntriesToRemove(entries, log) | ||
|
||
for _, entry := range entries { | ||
if _, ok := entriesToRemove[entry.EntryId]; !ok { | ||
filteredEntries = append(filteredEntries, entry) | ||
} | ||
} | ||
|
||
return filteredEntries | ||
} | ||
|
||
func getEntriesToRemove(entries []*common.RegistrationEntry, log logrus.FieldLogger) map[string]bool { | ||
entriesToRemove := make(map[string]bool) | ||
rturner3 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
hintsMap := make(map[string]*common.RegistrationEntry) | ||
|
||
for _, entry := range entries { | ||
if entry.Hint == "" { | ||
continue | ||
} | ||
if entryWithNonUniqueHint, ok := hintsMap[entry.Hint]; ok { | ||
entryToMaintain, entryToRemove := hintTieBreaking(entry, entryWithNonUniqueHint) | ||
|
||
hintsMap[entry.Hint] = entryToMaintain | ||
entriesToRemove[entryToRemove.EntryId] = true | ||
|
||
log.WithFields(logrus.Fields{ | ||
telemetry.Hint: entryToRemove.Hint, | ||
telemetry.RegistrationID: entryToRemove.EntryId, | ||
}).Warn("Ignoring entry with duplicate hint") | ||
} else { | ||
hintsMap[entry.Hint] = entry | ||
} | ||
} | ||
|
||
return entriesToRemove | ||
} | ||
|
||
func hintTieBreaking(entryA *common.RegistrationEntry, entryB *common.RegistrationEntry) (maintain *common.RegistrationEntry, remove *common.RegistrationEntry) { | ||
switch { | ||
case entryA.CreatedAt < entryB.CreatedAt: | ||
maintain = entryA | ||
remove = entryB | ||
case entryA.CreatedAt > entryB.CreatedAt: | ||
maintain = entryB | ||
remove = entryA | ||
default: | ||
if entryA.EntryId < entryB.EntryId { | ||
maintain = entryA | ||
remove = entryB | ||
} else { | ||
maintain = entryB | ||
remove = entryA | ||
} | ||
} | ||
return | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mmm looks like spiffeID here is redundant, since you already printed spiffeID with token
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We also include the spiffe ID in the printed bundle (on line 101), I tried to maintain the same logic here for hint, what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I cant think in another good ouput... so keeping the duplicated SPIFFEID may be good