package main import ( "context" "sync" "github.com/hashicorp/hcl/v2/hclsimple" configv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/service/common/config/v1" workloadattestorv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/plugin/agent/workloadattestor/v1" "github.com/spiffe/spire-plugin-sdk/pluginmain" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) type Plugin struct { workloadattestorv1.UnimplementedWorkloadAttestorServer configv1.UnimplementedConfigServer mu sync.RWMutex attestor *GsapAttestor } func (p *Plugin) Attest(ctx context.Context, req *workloadattestorv1.AttestRequest) (*workloadattestorv1.AttestResponse, error) { p.mu.RLock() a := p.attestor p.mu.RUnlock() if a == nil { return nil, status.Error(codes.FailedPrecondition, "plugin not configured") } selectors, err := a.Attest(ctx, req.Pid) if err != nil { return nil, status.Errorf(codes.Internal, "attestation failed: %v", err) } return &workloadattestorv1.AttestResponse{ SelectorValues: selectors, }, nil } func decodeConfig(data string) (GsapAttestorConfig, error) { var cfg GsapAttestorConfig if err := hclsimple.Decode("plugin.json", []byte(data), nil, &cfg); err != nil { if err2 := hclsimple.Decode("plugin.hcl", []byte(data), nil, &cfg); err2 != nil { return cfg, err2 } } return cfg, nil } func (p *Plugin) Configure(_ context.Context, req *configv1.ConfigureRequest) (*configv1.ConfigureResponse, error) { cfg, err := decodeConfig(req.HclConfiguration) if err != nil { return nil, status.Errorf(codes.InvalidArgument, "failed to decode configuration: %v", err) } a := &GsapAttestor{} if err := a.Configure(cfg); err != nil { return nil, status.Errorf(codes.InvalidArgument, "invalid configuration: %v", err) } p.mu.Lock() p.attestor = a p.mu.Unlock() return &configv1.ConfigureResponse{}, nil } func (p *Plugin) Validate(_ context.Context, req *configv1.ValidateRequest) (*configv1.ValidateResponse, error) { if _, err := decodeConfig(req.HclConfiguration); err != nil { return nil, status.Errorf(codes.InvalidArgument, "failed to decode configuration: %v", err) } return &configv1.ValidateResponse{}, nil } func main() { p := &Plugin{} pluginmain.Serve( workloadattestorv1.WorkloadAttestorPluginServer(p), configv1.ConfigServiceServer(p), ) }