Skip to content

Commit 980066b

Browse files
vault: integrate linking service identity resolution (#21715)
* vault: link org ids via org resolver * vault: verify workflow owner org linkage * vault: log org identity linking decisions * vault: use get secrets identity fields * vault: resolve get secrets identity from metadata * vault: clean up linker lint issues * chore: run gomodtidy * vault: gate linker behind org id owner flag * vault: tighten get secrets owner checks * vault: fail closed without request identity linker * vault: inline secret owner validation switch Replace secretOwnerValidationTarget struct with a direct switch statement for clearer, more readable owner validation logic. * forward org id through workflow request metadata * apply gomodtidy updates * gate workflow org id forwarding and simplify vault execute * simplify vault execute and clean workflow lint * fix workflow v2 secrets integration test * fix workflow org resolver test setup * simplify workflow org resolution lifecycle * gate workflow org identity propagation * fix workflow v2 gate-aware tests * refine vault linking and workflow org gating * Address workflow review comments
1 parent 61150ff commit 980066b

34 files changed

Lines changed: 969 additions & 123 deletions

File tree

core/capabilities/vault/capability.go

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
vaultcommon "github.com/smartcontractkit/chainlink-common/pkg/capabilities/actions/vault"
1717
"github.com/smartcontractkit/chainlink-common/pkg/capabilities/consensus/requests"
1818
"github.com/smartcontractkit/chainlink-common/pkg/logger"
19+
"github.com/smartcontractkit/chainlink-common/pkg/services/orgresolver"
1920
"github.com/smartcontractkit/chainlink-common/pkg/settings/cresettings"
2021
"github.com/smartcontractkit/chainlink-common/pkg/settings/limits"
2122
"github.com/smartcontractkit/chainlink-common/pkg/types/core"
@@ -31,6 +32,7 @@ type Capability struct {
3132
handler *requests.Handler[*vaulttypes.Request, *vaulttypes.Response]
3233
capabilitiesRegistry core.CapabilitiesRegistry
3334
publicKey *LazyPublicKey
35+
linker *OrgIDToWorkflowOwnerLinker
3436
*RequestValidator
3537
}
3638

@@ -69,6 +71,9 @@ func (s *Capability) Close() error {
6971
if lerr := s.MaxRequestBatchSizeLimiter.Close(); lerr != nil {
7072
err = errors.Join(err, fmt.Errorf("error closing request batch size limiter: %w", lerr))
7173
}
74+
if lerr := s.linker.Close(); lerr != nil {
75+
err = errors.Join(err, fmt.Errorf("error closing org_id linker: %w", lerr))
76+
}
7277

7378
return err
7479
}
@@ -110,13 +115,13 @@ func (s *Capability) Execute(ctx context.Context, request capabilities.Capabilit
110115
return capabilities.CapabilityResponse{}, errors.New("no secret request specified in request")
111116
}
112117

113-
normalizedWorkflowOwner := normalizeOwner(request.Metadata.WorkflowOwner)
114118
for idx, req := range r.Requests {
115119
if req == nil { // defensive: protobuf strips nil elements, but guard against in-process callers
120+
s.lggr.Errorw("get secrets request contains nil secret request", "index", idx)
116121
return capabilities.CapabilityResponse{}, fmt.Errorf("nil secret request at index %d", idx)
117122
}
118-
119-
if req.Id != nil && normalizeOwner(req.Id.Owner) != normalizedWorkflowOwner {
123+
if req.Id != nil && normalizeOwner(req.Id.Owner) != normalizeOwner(request.Metadata.WorkflowOwner) {
124+
s.lggr.Errorw("get secrets request owner mismatch", "index", idx, "secretOwner", req.Id.Owner, "workflowOwner", request.Metadata.WorkflowOwner)
120125
return capabilities.CapabilityResponse{}, fmt.Errorf("secret identifier owner %q does not match workflow owner %q at index %d", req.Id.Owner, request.Metadata.WorkflowOwner, idx)
121126
}
122127
}
@@ -163,6 +168,12 @@ func (s *Capability) CreateSecrets(ctx context.Context, request *vaultcommon.Cre
163168
s.lggr.Debugf("RequestId: [%s] failed validation checks: %s", request.RequestId, err.Error())
164169
return nil, err
165170
}
171+
resolvedIdentity, err := s.resolveRequestIdentity(ctx, request.OrgId, request.WorkflowOwner)
172+
if err != nil {
173+
return nil, err
174+
}
175+
request.OrgId = resolvedIdentity.OrgID
176+
request.WorkflowOwner = resolvedIdentity.WorkflowOwner
166177
return s.handleRequest(ctx, request.RequestId, request)
167178
}
168179

@@ -173,6 +184,12 @@ func (s *Capability) UpdateSecrets(ctx context.Context, request *vaultcommon.Upd
173184
s.lggr.Debugf("RequestId: [%s] failed validation checks: %s", request.RequestId, err.Error())
174185
return nil, err
175186
}
187+
resolvedIdentity, err := s.resolveRequestIdentity(ctx, request.OrgId, request.WorkflowOwner)
188+
if err != nil {
189+
return nil, err
190+
}
191+
request.OrgId = resolvedIdentity.OrgID
192+
request.WorkflowOwner = resolvedIdentity.WorkflowOwner
176193
return s.handleRequest(ctx, request.RequestId, request)
177194
}
178195

@@ -183,6 +200,12 @@ func (s *Capability) DeleteSecrets(ctx context.Context, request *vaultcommon.Del
183200
s.lggr.Debugf("Request: [%s] failed validation checks: %s", request.String(), err.Error())
184201
return nil, err
185202
}
203+
resolvedIdentity, err := s.resolveRequestIdentity(ctx, request.OrgId, request.WorkflowOwner)
204+
if err != nil {
205+
return nil, err
206+
}
207+
request.OrgId = resolvedIdentity.OrgID
208+
request.WorkflowOwner = resolvedIdentity.WorkflowOwner
186209
return s.handleRequest(ctx, request.RequestId, request)
187210
}
188211

@@ -204,6 +227,12 @@ func (s *Capability) ListSecretIdentifiers(ctx context.Context, request *vaultco
204227
s.lggr.Debugf("Request: [%s] failed validation checks: %s", request.String(), err.Error())
205228
return nil, err
206229
}
230+
resolvedIdentity, err := s.resolveRequestIdentity(ctx, request.OrgId, request.WorkflowOwner)
231+
if err != nil {
232+
return nil, err
233+
}
234+
request.OrgId = resolvedIdentity.OrgID
235+
request.WorkflowOwner = resolvedIdentity.WorkflowOwner
207236
return s.handleRequest(ctx, request.RequestId, request)
208237
}
209238

@@ -256,19 +285,37 @@ func (s *Capability) handleRequest(ctx context.Context, requestID string, reques
256285
}
257286
}
258287

288+
// resolveRequestIdentity validates and normalizes the org/workflow-owner pair that the vault plugin consumes.
289+
func (s *Capability) resolveRequestIdentity(ctx context.Context, orgID string, workflowOwner string) (LinkedVaultRequestIdentity, error) {
290+
s.lggr.Debugw("resolving request identity", "orgID", orgID, "workflowOwner", workflowOwner)
291+
linked, err := s.linker.Link(ctx, orgID, workflowOwner)
292+
if err != nil {
293+
s.lggr.Errorw("failed to resolve request identity", "orgID", orgID, "workflowOwner", workflowOwner, "err", err)
294+
return LinkedVaultRequestIdentity{}, err
295+
}
296+
s.lggr.Debugw("resolved request identity", "orgID", linked.OrgID, "workflowOwner", linked.WorkflowOwner)
297+
298+
return linked, nil
299+
}
300+
259301
func NewCapability(
260302
lggr logger.Logger,
261303
clock clockwork.Clock,
262304
expiresAfter time.Duration,
263305
handler *requests.Handler[*vaulttypes.Request, *vaulttypes.Response],
264306
capabilitiesRegistry core.CapabilitiesRegistry,
265307
publicKey *LazyPublicKey,
308+
orgResolver orgresolver.OrgResolver,
266309
limitsFactory limits.Factory,
267310
) (*Capability, error) {
268311
limiter, err := limits.MakeBoundLimiter(limitsFactory, cresettings.Default.VaultRequestBatchSizeLimit)
269312
if err != nil {
270313
return nil, fmt.Errorf("could not create request batch size limiter: %w", err)
271314
}
315+
linker, err := NewOrgIDToWorkflowOwnerLinker(orgResolver, limitsFactory)
316+
if err != nil {
317+
return nil, err
318+
}
272319
ciphertextLimiter, err := limits.MakeUpperBoundLimiter(limitsFactory, cresettings.Default.VaultCiphertextSizeLimit)
273320
if err != nil {
274321
return nil, fmt.Errorf("could not create ciphertext size limiter: %w", err)
@@ -280,6 +327,7 @@ func NewCapability(
280327
handler: handler,
281328
capabilitiesRegistry: capabilitiesRegistry,
282329
publicKey: publicKey,
330+
linker: linker,
283331
RequestValidator: NewRequestValidator(limiter, ciphertextLimiter),
284332
}, nil
285333
}

0 commit comments

Comments
 (0)