From 90462347703bb2f56cc40909d9730a0bcf76fb02 Mon Sep 17 00:00:00 2001 From: Yuhan Li Date: Mon, 21 Feb 2022 17:37:50 +0800 Subject: [PATCH 1/7] Add FetchJWTSVIDs and SubscribeToJWTBundles Signed-off-by: Yuhan Li --- pkg/agent/api/delegatedidentity/v1/service.go | 143 +++++++++++++++++- 1 file changed, 136 insertions(+), 7 deletions(-) diff --git a/pkg/agent/api/delegatedidentity/v1/service.go b/pkg/agent/api/delegatedidentity/v1/service.go index 4ad4cd0b48..6ebe40c1c2 100644 --- a/pkg/agent/api/delegatedidentity/v1/service.go +++ b/pkg/agent/api/delegatedidentity/v1/service.go @@ -5,16 +5,21 @@ import ( "crypto/x509" "fmt" "sort" + "time" "github.com/sirupsen/logrus" + "github.com/spiffe/go-spiffe/v2/spiffeid" delegatedidentityv1 "github.com/spiffe/spire-api-sdk/proto/spire/api/agent/delegatedidentity/v1" "github.com/spiffe/spire-api-sdk/proto/spire/api/types" "github.com/spiffe/spire/pkg/agent/api/rpccontext" workload_attestor "github.com/spiffe/spire/pkg/agent/attestor/workload" + "github.com/spiffe/spire/pkg/agent/client" "github.com/spiffe/spire/pkg/agent/endpoints" "github.com/spiffe/spire/pkg/agent/manager" "github.com/spiffe/spire/pkg/agent/manager/cache" + "github.com/spiffe/spire/pkg/common/bundleutil" "github.com/spiffe/spire/pkg/common/idutil" + "github.com/spiffe/spire/pkg/common/telemetry" "github.com/spiffe/spire/pkg/common/x509util" "github.com/spiffe/spire/pkg/server/api" "github.com/spiffe/spire/proto/spire/common" @@ -33,10 +38,12 @@ type attestor interface { } type Config struct { - Log logrus.FieldLogger - Manager manager.Manager - Attestor workload_attestor.Attestor - AuthorizedDelegates []string + Log logrus.FieldLogger + Manager manager.Manager + Attestor workload_attestor.Attestor + + AllowUnauthenticatedVerifiers bool + AuthorizedDelegates []string } func New(config Config) *Service { @@ -47,9 +54,10 @@ func New(config Config) *Service { } return &Service{ - manager: config.Manager, - attestor: endpoints.PeerTrackerAttestor{Attestor: config.Attestor}, - authorizedDelegates: AuthorizedDelegates, + manager: config.Manager, + attestor: endpoints.PeerTrackerAttestor{Attestor: config.Attestor}, + authorizedDelegates: AuthorizedDelegates, + allowUnauthenticatedVerifiers: config.AllowUnauthenticatedVerifiers, } } @@ -60,6 +68,7 @@ type Service struct { manager manager.Manager attestor attestor + allowUnauthenticatedVerifiers bool // SPIFFE IDs of delegates that are authorized to use this API authorizedDelegates map[string]bool } @@ -245,6 +254,126 @@ func (s *Service) SubscribeToX509Bundles(req *delegatedidentityv1.SubscribeToX50 } } +func (s *Service) FetchJWTSVIDs(ctx context.Context, req *delegatedidentityv1.FetchJWTSVIDsRequest) (resp *delegatedidentityv1.FetchJWTSVIDsResponse, err error) { + + log := rpccontext.Logger(ctx) + if len(req.Audience) == 0 { + log.Error("Missing required audience parameter") + return nil, status.Error(codes.InvalidArgument, "audience must be specified") + } + + if _, err = s.isCallerAuthorized(ctx, log, nil); err != nil { + return nil, err + } + + selectors, err := api.SelectorsFromProto(req.Selectors) + if err != nil { + log.WithError(err).Error("Invalid argument; could not parse provided selectors") + return nil, status.Error(codes.InvalidArgument, "could not parse provided selectors") + } + var spiffeIDs []spiffeid.ID + + log = log.WithField(telemetry.Registered, true) + + identities := s.manager.MatchingIdentities(selectors) + for _, identity := range identities { + + spiffeID, err := spiffeid.FromString(identity.Entry.SpiffeId) + if err != nil { + log.WithField(telemetry.SPIFFEID, identity.Entry.SpiffeId).WithError(err).Error("Invalid requested SPIFFE ID") + return nil, status.Errorf(codes.InvalidArgument, "invalid requested SPIFFE ID: %v", err) + } + + spiffeIDs = append(spiffeIDs, spiffeID) + } + + if len(spiffeIDs) == 0 { + log.WithField(telemetry.Registered, false).Error("No identity issued") + return nil, status.Error(codes.PermissionDenied, "no identity issued") + } + + resp = new(delegatedidentityv1.FetchJWTSVIDsResponse) + for _, id := range spiffeIDs { + loopLog := log.WithField(telemetry.SPIFFEID, id.String()) + + var svid *client.JWTSVID + svid, err = s.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, &types.JWTSVID{ + Token: svid.Token, + Id: &types.SPIFFEID{ + TrustDomain: id.TrustDomain().String(), + Path: id.Path(), + }, + ExpiresAt: svid.ExpiresAt.Unix(), + IssuedAt: svid.IssuedAt.Unix(), + }) + + ttl := time.Until(svid.ExpiresAt) + loopLog.WithField(telemetry.TTL, ttl.Seconds()).Debug("Fetched JWT SVID") + } + + return resp, nil +} + +func (s *Service) SubscribeToJWTBundles(req *delegatedidentityv1.SubscribeToJWTBundlesRequest, stream delegatedidentityv1.DelegatedIdentity_SubscribeToJWTBundlesServer) error { + ctx := stream.Context() + log := rpccontext.Logger(ctx) + cachedSelectors, err := s.isCallerAuthorized(ctx, log, nil) + + if err != nil { + return err + } + + subscriber := s.manager.SubscribeToBundleChanges() + + // send initial update.... + jwtbundles := make(map[string][]byte) + for td, bundle := range subscriber.Value() { + jwksBytes, err := bundleutil.Marshal(bundle, bundleutil.NoX509SVIDKeys(), bundleutil.StandardJWKS()) + if err != nil { + return err + } + jwtbundles[td.IDString()] = jwksBytes + } + + resp := &delegatedidentityv1.SubscribeToJWTBundlesResponse{ + Bundles: jwtbundles, + } + + if err := stream.Send(resp); err != nil { + return err + } + for { + select { + case <-subscriber.Changes(): + if _, err := s.isCallerAuthorized(ctx, log, cachedSelectors); err != nil { + return err + } + for td, bundle := range subscriber.Next() { + jwksBytes, err := bundleutil.Marshal(bundle, bundleutil.NoX509SVIDKeys(), bundleutil.StandardJWKS()) + if err != nil { + return err + } + jwtbundles[td.IDString()] = jwksBytes + } + + resp := &delegatedidentityv1.SubscribeToJWTBundlesResponse{ + Bundles: jwtbundles, + } + + if err := stream.Send(resp); err != nil { + return err + } + case <-ctx.Done(): + return nil + } + } +} + func marshalBundle(certs []*x509.Certificate) []byte { bundle := []byte{} for _, c := range certs { From e2061384bf6f5588934abf96f1f355376c5c7946 Mon Sep 17 00:00:00 2001 From: Yuhan Li Date: Mon, 21 Feb 2022 19:29:06 +0800 Subject: [PATCH 2/7] Remove unused AllowUnauthenticatedVerifiers param Signed-off-by: Yuhan Li --- pkg/agent/api/delegatedidentity/v1/service.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pkg/agent/api/delegatedidentity/v1/service.go b/pkg/agent/api/delegatedidentity/v1/service.go index 6ebe40c1c2..aaa20b7953 100644 --- a/pkg/agent/api/delegatedidentity/v1/service.go +++ b/pkg/agent/api/delegatedidentity/v1/service.go @@ -41,8 +41,6 @@ type Config struct { Log logrus.FieldLogger Manager manager.Manager Attestor workload_attestor.Attestor - - AllowUnauthenticatedVerifiers bool AuthorizedDelegates []string } @@ -57,7 +55,6 @@ func New(config Config) *Service { manager: config.Manager, attestor: endpoints.PeerTrackerAttestor{Attestor: config.Attestor}, authorizedDelegates: AuthorizedDelegates, - allowUnauthenticatedVerifiers: config.AllowUnauthenticatedVerifiers, } } @@ -68,7 +65,6 @@ type Service struct { manager manager.Manager attestor attestor - allowUnauthenticatedVerifiers bool // SPIFFE IDs of delegates that are authorized to use this API authorizedDelegates map[string]bool } From 9341422b4a892e4de4f8b3e23f0ff896bfc59826 Mon Sep 17 00:00:00 2001 From: Yuhan Li Date: Tue, 8 Mar 2022 11:28:37 +0800 Subject: [PATCH 3/7] Add FetchJWTSVIDs and SubscribeToJWTBundles test cases Signed-off-by: Yuhan Li --- pkg/agent/api/delegatedidentity/v1/service.go | 16 +- .../api/delegatedidentity/v1/service_test.go | 215 ++++++++++++++++++ 2 files changed, 222 insertions(+), 9 deletions(-) diff --git a/pkg/agent/api/delegatedidentity/v1/service.go b/pkg/agent/api/delegatedidentity/v1/service.go index aaa20b7953..851f4de5d6 100644 --- a/pkg/agent/api/delegatedidentity/v1/service.go +++ b/pkg/agent/api/delegatedidentity/v1/service.go @@ -38,10 +38,10 @@ type attestor interface { } type Config struct { - Log logrus.FieldLogger - Manager manager.Manager - Attestor workload_attestor.Attestor - AuthorizedDelegates []string + Log logrus.FieldLogger + Manager manager.Manager + Attestor workload_attestor.Attestor + AuthorizedDelegates []string } func New(config Config) *Service { @@ -52,9 +52,9 @@ func New(config Config) *Service { } return &Service{ - manager: config.Manager, - attestor: endpoints.PeerTrackerAttestor{Attestor: config.Attestor}, - authorizedDelegates: AuthorizedDelegates, + manager: config.Manager, + attestor: endpoints.PeerTrackerAttestor{Attestor: config.Attestor}, + authorizedDelegates: AuthorizedDelegates, } } @@ -251,7 +251,6 @@ func (s *Service) SubscribeToX509Bundles(req *delegatedidentityv1.SubscribeToX50 } func (s *Service) FetchJWTSVIDs(ctx context.Context, req *delegatedidentityv1.FetchJWTSVIDsRequest) (resp *delegatedidentityv1.FetchJWTSVIDsResponse, err error) { - log := rpccontext.Logger(ctx) if len(req.Audience) == 0 { log.Error("Missing required audience parameter") @@ -273,7 +272,6 @@ func (s *Service) FetchJWTSVIDs(ctx context.Context, req *delegatedidentityv1.Fe identities := s.manager.MatchingIdentities(selectors) for _, identity := range identities { - spiffeID, err := spiffeid.FromString(identity.Entry.SpiffeId) if err != nil { log.WithField(telemetry.SPIFFEID, identity.Entry.SpiffeId).WithError(err).Error("Invalid requested SPIFFE ID") diff --git a/pkg/agent/api/delegatedidentity/v1/service_test.go b/pkg/agent/api/delegatedidentity/v1/service_test.go index 87868d7616..a0ab288059 100644 --- a/pkg/agent/api/delegatedidentity/v1/service_test.go +++ b/pkg/agent/api/delegatedidentity/v1/service_test.go @@ -13,11 +13,14 @@ import ( "github.com/sirupsen/logrus/hooks/test" "github.com/spiffe/go-spiffe/v2/bundle/spiffebundle" "github.com/spiffe/go-spiffe/v2/spiffeid" + "github.com/spiffe/go-spiffe/v2/svid/jwtsvid" "github.com/spiffe/go-spiffe/v2/svid/x509svid" delegatedidentityv1 "github.com/spiffe/spire-api-sdk/proto/spire/api/agent/delegatedidentity/v1" "github.com/spiffe/spire-api-sdk/proto/spire/api/types" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/spiffe/spire/pkg/agent/client" "github.com/spiffe/spire/pkg/agent/manager" "github.com/spiffe/spire/pkg/agent/manager/cache" "github.com/spiffe/spire/pkg/common/api/middleware" @@ -43,6 +46,9 @@ var ( bundle1 = bundleutil.BundleFromRootCA(trustDomain1, &x509.Certificate{Raw: []byte("AAA")}) bundle2 = bundleutil.BundleFromRootCA(trustDomain2, &x509.Certificate{Raw: []byte("BBB")}) + + jwksBundle1, _ = bundleutil.Marshal(bundle1, bundleutil.NoX509SVIDKeys(), bundleutil.StandardJWKS()) + jwksBundle2, _ = bundleutil.Marshal(bundle2, bundleutil.NoX509SVIDKeys(), bundleutil.StandardJWKS()) ) func TestSubscribeToX509SVIDs(t *testing.T) { @@ -351,6 +357,205 @@ func TestSubscribeToX509Bundles(t *testing.T) { } } +func TestFetchJWTSVIDs(t *testing.T) { + ca := testca.New(t, trustDomain1) + + x509SVID1 := ca.CreateX509SVID(id1) + x509SVID2 := ca.CreateX509SVID(id2) + + for _, tt := range []struct { + testName string + identities []cache.Identity + authSpiffeID []string + audience []string + expectCode codes.Code + expectMsg string + attestErr error + managerErr error + expectTokenIDs []spiffeid.ID + }{ + { + testName: "missing required audience", + expectCode: codes.InvalidArgument, + expectMsg: "audience must be specified", + }, + { + testName: "Attest error", + attestErr: errors.New("ohno"), + audience: []string{"AUDIENCE"}, + expectCode: codes.Internal, + expectMsg: "workload attestation failed", + }, + { + testName: "Access to \"privileged\" admin API denied", + authSpiffeID: []string{"spiffe://example.org/one/wrong"}, + audience: []string{"AUDIENCE"}, + identities: []cache.Identity{ + identityFromX509SVID(x509SVID1), + }, + expectCode: codes.PermissionDenied, + expectMsg: "caller not configured as an authorized delegate", + }, + { + testName: "fetch error", + authSpiffeID: []string{"spiffe://example.org/one"}, + audience: []string{"AUDIENCE"}, + identities: []cache.Identity{ + identityFromX509SVID(x509SVID1), + }, + managerErr: errors.New("ohno"), + expectCode: codes.Unavailable, + expectMsg: "could not fetch JWT-SVID: ohno", + }, + { + testName: "success with one identities", + authSpiffeID: []string{"spiffe://example.org/one"}, + audience: []string{"AUDIENCE"}, + identities: []cache.Identity{ + identityFromX509SVID(x509SVID1), + }, + expectTokenIDs: []spiffeid.ID{x509SVID1.ID}, + }, + { + testName: "success with two identities", + authSpiffeID: []string{"spiffe://example.org/one"}, + audience: []string{"AUDIENCE"}, + identities: []cache.Identity{ + identityFromX509SVID(x509SVID1), + identityFromX509SVID(x509SVID2), + }, + expectTokenIDs: []spiffeid.ID{x509SVID1.ID, x509SVID2.ID}, + }, + } { + tt := tt + t.Run(tt.testName, func(t *testing.T) { + params := testParams{ + CA: ca, + Identities: tt.identities, + AuthSpiffeID: tt.authSpiffeID, + AttestErr: tt.attestErr, + ManagerErr: tt.managerErr, + } + runTest(t, params, + func(ctx context.Context, client delegatedidentityv1.DelegatedIdentityClient) { + selectors := []*types.Selector{{Type: "sa", Value: "foo"}} + resp, err := client.FetchJWTSVIDs(ctx, &delegatedidentityv1.FetchJWTSVIDsRequest{ + Audience: tt.audience, + Selectors: selectors, + }) + + spiretest.RequireGRPCStatus(t, err, tt.expectCode, tt.expectMsg) + if tt.expectCode != codes.OK { + assert.Nil(t, resp) + return + } + var tokenIDs []spiffeid.ID + for _, svid := range resp.Svids { + parsedSVID, err := jwtsvid.ParseInsecure(svid.Token, tt.audience) + require.NoError(t, err, "JWT-SVID token is malformed") + tokenIDs = append(tokenIDs, parsedSVID.ID) + } + assert.Equal(t, tt.expectTokenIDs, tokenIDs) + }) + }) + } +} +func TestSubscribeToJWTBundles(t *testing.T) { + ca := testca.New(t, trustDomain1) + + x509SVID1 := ca.CreateX509SVID(id1) + + for _, tt := range []struct { + testName string + identities []cache.Identity + authSpiffeID []string + expectCode codes.Code + expectMsg string + attestErr error + expectResp []*delegatedidentityv1.SubscribeToJWTBundlesResponse + cacheUpdates map[spiffeid.TrustDomain]*cache.Bundle + }{ + + { + testName: "Attest error", + attestErr: errors.New("ohno"), + expectCode: codes.Internal, + expectMsg: "workload attestation failed", + }, + { + testName: "Access to \"privileged\" admin API denied", + authSpiffeID: []string{"spiffe://example.org/one/wrong"}, + identities: []cache.Identity{ + identityFromX509SVID(x509SVID1), + }, + expectCode: codes.PermissionDenied, + expectMsg: "caller not configured as an authorized delegate", + }, + { + testName: "cache bundle update - one bundle", + authSpiffeID: []string{"spiffe://example.org/one"}, + identities: []cache.Identity{ + identityFromX509SVID(x509SVID1), + }, + cacheUpdates: map[spiffeid.TrustDomain]*cache.Bundle{ + spiffeid.RequireTrustDomainFromString(bundle1.TrustDomainID()): bundle1, + }, + expectResp: []*delegatedidentityv1.SubscribeToJWTBundlesResponse{ + { + Bundles: map[string][]byte{ + bundle1.TrustDomainID(): jwksBundle1, + }, + }, + }, + }, + { + testName: "cache bundle update - two bundles", + authSpiffeID: []string{"spiffe://example.org/one"}, + identities: []cache.Identity{ + identityFromX509SVID(x509SVID1), + }, + cacheUpdates: map[spiffeid.TrustDomain]*cache.Bundle{ + spiffeid.RequireTrustDomainFromString(bundle1.TrustDomainID()): bundle1, + spiffeid.RequireTrustDomainFromString(bundle2.TrustDomainID()): bundle2, + }, + expectResp: []*delegatedidentityv1.SubscribeToJWTBundlesResponse{ + { + Bundles: map[string][]byte{ + bundle1.TrustDomainID(): jwksBundle1, + bundle2.TrustDomainID(): jwksBundle2, + }, + }, + }, + }, + } { + tt := tt + t.Run(tt.testName, func(t *testing.T) { + params := testParams{ + CA: ca, + Identities: tt.identities, + AuthSpiffeID: tt.authSpiffeID, + AttestErr: tt.attestErr, + CacheUpdates: tt.cacheUpdates, + } + runTest(t, params, + func(ctx context.Context, client delegatedidentityv1.DelegatedIdentityClient) { + req := &delegatedidentityv1.SubscribeToJWTBundlesRequest{} + + stream, err := client.SubscribeToJWTBundles(ctx, req) + + require.NoError(t, err) + + for _, multiResp := range tt.expectResp { + resp, err := stream.Recv() + + spiretest.RequireGRPCStatus(t, err, tt.expectCode, tt.expectMsg) + spiretest.RequireProtoEqual(t, multiResp, resp) + } + }) + }) + } +} + type testParams struct { CA *testca.CA Identities []cache.Identity @@ -441,6 +646,16 @@ func (m *FakeManager) SubscribeToCacheChanges(selectors cache.Selectors) cache.S return newFakeSubscriber(m, m.updates) } +func (m *FakeManager) FetchJWTSVID(ctx context.Context, spiffeID spiffeid.ID, audience []string) (*client.JWTSVID, error) { + svid := m.ca.CreateJWTSVID(spiffeID, audience) + if m.err != nil { + return nil, m.err + } + return &client.JWTSVID{ + Token: svid.Marshal(), + }, nil +} + type fakeSubscriber struct { m *FakeManager ch chan *cache.WorkloadUpdate From 49647ca11aca39c5e202fd1a6e73a405c25822ce Mon Sep 17 00:00:00 2001 From: Yuhan Li Date: Thu, 24 Mar 2022 11:52:17 +0800 Subject: [PATCH 4/7] update spire-api-sdk version Signed-off-by: Yuhan Li --- go.mod | 2 +- go.sum | 2 ++ pkg/agent/api/delegatedidentity/v1/service_test.go | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 6e5078bc44..ce8ac686fc 100644 --- a/go.mod +++ b/go.mod @@ -54,7 +54,7 @@ require ( github.com/shirou/gopsutil/v3 v3.22.2 github.com/sirupsen/logrus v1.8.1 github.com/spiffe/go-spiffe/v2 v2.0.0 - github.com/spiffe/spire-api-sdk v1.2.1 + github.com/spiffe/spire-api-sdk v1.2.2-0.20220317172821-e2705b35aa09 github.com/spiffe/spire-plugin-sdk v1.2.1 github.com/stretchr/testify v1.7.1 github.com/uber-go/tally/v4 v4.1.1 diff --git a/go.sum b/go.sum index 9c8575a959..adbf24838d 100644 --- a/go.sum +++ b/go.sum @@ -1225,6 +1225,8 @@ github.com/spiffe/go-spiffe/v2 v2.0.0 h1:y6N7BZAxgaFZYELyrIdxSMm2e2tWpzgQewUts9h github.com/spiffe/go-spiffe/v2 v2.0.0/go.mod h1:TEfgrEcyFhuSuvqohJt6IxENUNeHfndWCCV1EX7UaVk= github.com/spiffe/spire-api-sdk v1.2.1 h1:42i3N6/b2st6Xg1iL6/gzYpLAOMYSklrxsc8bJQ1z34= github.com/spiffe/spire-api-sdk v1.2.1/go.mod h1:UylWypx+g3HPJeelhKiKykUvcTJFw5VKIKaSaCYgpFw= +github.com/spiffe/spire-api-sdk v1.2.2-0.20220317172821-e2705b35aa09 h1:2oavALIvyKv+M9Q2CWoz3UlJn4DT+oAhVO1qIgaq0GA= +github.com/spiffe/spire-api-sdk v1.2.2-0.20220317172821-e2705b35aa09/go.mod h1:73BC0cOGkqRQrqoB1Djk7etxN+bE1ypmzZMkhCQs6kY= github.com/spiffe/spire-plugin-sdk v1.2.1 h1:w8uJ1P6AUQOJBDsNF34BJsL0ly6wtVMHnDJGqk1Y7yM= github.com/spiffe/spire-plugin-sdk v1.2.1/go.mod h1:fzNSP83Z848jZtPQYeZ9qPWZkbSPwmd/JFNux1gxsbM= github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= diff --git a/pkg/agent/api/delegatedidentity/v1/service_test.go b/pkg/agent/api/delegatedidentity/v1/service_test.go index fdb7a72102..6a1a1f39a7 100644 --- a/pkg/agent/api/delegatedidentity/v1/service_test.go +++ b/pkg/agent/api/delegatedidentity/v1/service_test.go @@ -408,7 +408,7 @@ func TestFetchJWTSVIDs(t *testing.T) { expectMsg: "could not fetch JWT-SVID: ohno", }, { - testName: "success with one identities", + testName: "success with one identity", authSpiffeID: []string{"spiffe://example.org/one"}, audience: []string{"AUDIENCE"}, identities: []cache.Identity{ From d99899584547263ae0414b169f1f8987cab54e90 Mon Sep 17 00:00:00 2001 From: Yuhan Li Date: Thu, 24 Mar 2022 12:32:38 +0800 Subject: [PATCH 5/7] Update go.sum Signed-off-by: Yuhan Li --- go.sum | 2 -- 1 file changed, 2 deletions(-) diff --git a/go.sum b/go.sum index adbf24838d..bfc3b46812 100644 --- a/go.sum +++ b/go.sum @@ -1223,8 +1223,6 @@ github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM= github.com/spiffe/go-spiffe/v2 v2.0.0 h1:y6N7BZAxgaFZYELyrIdxSMm2e2tWpzgQewUts9h1hfM= github.com/spiffe/go-spiffe/v2 v2.0.0/go.mod h1:TEfgrEcyFhuSuvqohJt6IxENUNeHfndWCCV1EX7UaVk= -github.com/spiffe/spire-api-sdk v1.2.1 h1:42i3N6/b2st6Xg1iL6/gzYpLAOMYSklrxsc8bJQ1z34= -github.com/spiffe/spire-api-sdk v1.2.1/go.mod h1:UylWypx+g3HPJeelhKiKykUvcTJFw5VKIKaSaCYgpFw= github.com/spiffe/spire-api-sdk v1.2.2-0.20220317172821-e2705b35aa09 h1:2oavALIvyKv+M9Q2CWoz3UlJn4DT+oAhVO1qIgaq0GA= github.com/spiffe/spire-api-sdk v1.2.2-0.20220317172821-e2705b35aa09/go.mod h1:73BC0cOGkqRQrqoB1Djk7etxN+bE1ypmzZMkhCQs6kY= github.com/spiffe/spire-plugin-sdk v1.2.1 h1:w8uJ1P6AUQOJBDsNF34BJsL0ly6wtVMHnDJGqk1Y7yM= From 1c1ea8d0fd126784b9b71438317c08753cd9ecd7 Mon Sep 17 00:00:00 2001 From: Yuhan Li Date: Thu, 31 Mar 2022 14:52:30 +0800 Subject: [PATCH 6/7] Add selectors test case Signed-off-by: Yuhan Li --- pkg/agent/api/delegatedidentity/v1/service.go | 4 +- .../api/delegatedidentity/v1/service_test.go | 42 +++++++++++++++++-- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/pkg/agent/api/delegatedidentity/v1/service.go b/pkg/agent/api/delegatedidentity/v1/service.go index 851f4de5d6..4c1880deeb 100644 --- a/pkg/agent/api/delegatedidentity/v1/service.go +++ b/pkg/agent/api/delegatedidentity/v1/service.go @@ -268,8 +268,6 @@ func (s *Service) FetchJWTSVIDs(ctx context.Context, req *delegatedidentityv1.Fe } var spiffeIDs []spiffeid.ID - log = log.WithField(telemetry.Registered, true) - identities := s.manager.MatchingIdentities(selectors) for _, identity := range identities { spiffeID, err := spiffeid.FromString(identity.Entry.SpiffeId) @@ -282,7 +280,7 @@ func (s *Service) FetchJWTSVIDs(ctx context.Context, req *delegatedidentityv1.Fe } if len(spiffeIDs) == 0 { - log.WithField(telemetry.Registered, false).Error("No identity issued") + log.Error("No identity issued") return nil, status.Error(codes.PermissionDenied, "no identity issued") } diff --git a/pkg/agent/api/delegatedidentity/v1/service_test.go b/pkg/agent/api/delegatedidentity/v1/service_test.go index 6a1a1f39a7..fe7d6e73ff 100644 --- a/pkg/agent/api/delegatedidentity/v1/service_test.go +++ b/pkg/agent/api/delegatedidentity/v1/service_test.go @@ -368,6 +368,7 @@ func TestFetchJWTSVIDs(t *testing.T) { identities []cache.Identity authSpiffeID []string audience []string + selectors []*types.Selector expectCode codes.Code expectMsg string attestErr error @@ -399,6 +400,7 @@ func TestFetchJWTSVIDs(t *testing.T) { { testName: "fetch error", authSpiffeID: []string{"spiffe://example.org/one"}, + selectors: []*types.Selector{{Type: "sa", Value: "foo"}}, audience: []string{"AUDIENCE"}, identities: []cache.Identity{ identityFromX509SVID(x509SVID1), @@ -407,9 +409,43 @@ func TestFetchJWTSVIDs(t *testing.T) { expectCode: codes.Unavailable, expectMsg: "could not fetch JWT-SVID: ohno", }, + { + testName: "selectors missing type", + authSpiffeID: []string{"spiffe://example.org/one"}, + selectors: []*types.Selector{{Type: "", Value: "foo"}}, + audience: []string{"AUDIENCE"}, + identities: []cache.Identity{ + identityFromX509SVID(x509SVID1), + }, + expectCode: codes.InvalidArgument, + expectMsg: "could not parse provided selectors", + }, + { + testName: "selectors missing value", + authSpiffeID: []string{"spiffe://example.org/one"}, + selectors: []*types.Selector{{Type: "sa", Value: ""}}, + audience: []string{"AUDIENCE"}, + identities: []cache.Identity{ + identityFromX509SVID(x509SVID1), + }, + expectCode: codes.InvalidArgument, + expectMsg: "could not parse provided selectors", + }, + { + testName: "selectors type contains ':'", + authSpiffeID: []string{"spiffe://example.org/one"}, + selectors: []*types.Selector{{Type: "sa:bar", Value: "boo"}}, + audience: []string{"AUDIENCE"}, + identities: []cache.Identity{ + identityFromX509SVID(x509SVID1), + }, + expectCode: codes.InvalidArgument, + expectMsg: "could not parse provided selectors", + }, { testName: "success with one identity", authSpiffeID: []string{"spiffe://example.org/one"}, + selectors: []*types.Selector{{Type: "sa", Value: "foo"}}, audience: []string{"AUDIENCE"}, identities: []cache.Identity{ identityFromX509SVID(x509SVID1), @@ -419,6 +455,7 @@ func TestFetchJWTSVIDs(t *testing.T) { { testName: "success with two identities", authSpiffeID: []string{"spiffe://example.org/one"}, + selectors: []*types.Selector{{Type: "sa", Value: "foo"}}, audience: []string{"AUDIENCE"}, identities: []cache.Identity{ identityFromX509SVID(x509SVID1), @@ -438,10 +475,9 @@ func TestFetchJWTSVIDs(t *testing.T) { } runTest(t, params, func(ctx context.Context, client delegatedidentityv1.DelegatedIdentityClient) { - selectors := []*types.Selector{{Type: "sa", Value: "foo"}} resp, err := client.FetchJWTSVIDs(ctx, &delegatedidentityv1.FetchJWTSVIDsRequest{ Audience: tt.audience, - Selectors: selectors, + Selectors: tt.selectors, }) spiretest.RequireGRPCStatus(t, err, tt.expectCode, tt.expectMsg) @@ -647,10 +683,10 @@ func (m *FakeManager) SubscribeToCacheChanges(selectors cache.Selectors) cache.S } func (m *FakeManager) FetchJWTSVID(ctx context.Context, spiffeID spiffeid.ID, audience []string) (*client.JWTSVID, error) { - svid := m.ca.CreateJWTSVID(spiffeID, audience) if m.err != nil { return nil, m.err } + svid := m.ca.CreateJWTSVID(spiffeID, audience) return &client.JWTSVID{ Token: svid.Marshal(), }, nil From b0268a4a18d19d223e3c7b259f0979d58c08d982 Mon Sep 17 00:00:00 2001 From: Yuhan Li Date: Fri, 1 Apr 2022 11:34:34 +0800 Subject: [PATCH 7/7] fix lint problem Signed-off-by: Yuhan Li --- pkg/agent/api/delegatedidentity/v1/service.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/agent/api/delegatedidentity/v1/service.go b/pkg/agent/api/delegatedidentity/v1/service.go index 4c1880deeb..87a2020988 100644 --- a/pkg/agent/api/delegatedidentity/v1/service.go +++ b/pkg/agent/api/delegatedidentity/v1/service.go @@ -108,8 +108,8 @@ func (s *Service) isCallerAuthorized(ctx context.Context, log logrus.FieldLogger func (s *Service) SubscribeToX509SVIDs(req *delegatedidentityv1.SubscribeToX509SVIDsRequest, stream delegatedidentityv1.DelegatedIdentity_SubscribeToX509SVIDsServer) error { ctx := stream.Context() log := rpccontext.Logger(ctx) - cachedSelectors, err := s.isCallerAuthorized(ctx, log, nil) + cachedSelectors, err := s.isCallerAuthorized(ctx, log, nil) if err != nil { return err } @@ -203,8 +203,8 @@ func composeX509SVIDBySelectors(update *cache.WorkloadUpdate) (*delegatedidentit func (s *Service) SubscribeToX509Bundles(req *delegatedidentityv1.SubscribeToX509BundlesRequest, stream delegatedidentityv1.DelegatedIdentity_SubscribeToX509BundlesServer) error { ctx := stream.Context() log := rpccontext.Logger(ctx) - cachedSelectors, err := s.isCallerAuthorized(ctx, log, nil) + cachedSelectors, err := s.isCallerAuthorized(ctx, log, nil) if err != nil { return err } @@ -314,8 +314,8 @@ func (s *Service) FetchJWTSVIDs(ctx context.Context, req *delegatedidentityv1.Fe func (s *Service) SubscribeToJWTBundles(req *delegatedidentityv1.SubscribeToJWTBundlesRequest, stream delegatedidentityv1.DelegatedIdentity_SubscribeToJWTBundlesServer) error { ctx := stream.Context() log := rpccontext.Logger(ctx) - cachedSelectors, err := s.isCallerAuthorized(ctx, log, nil) + cachedSelectors, err := s.isCallerAuthorized(ctx, log, nil) if err != nil { return err }