package main import ( "context" "fmt" "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 jsonErr := hclsimple.Decode("plugin.json", []byte(data), nil, &cfg) if jsonErr == nil { return cfg, nil } hclErr := hclsimple.Decode("plugin.hcl", []byte(data), nil, &cfg) if hclErr == nil { return cfg, nil } return cfg, fmt.Errorf("json: %v; hcl: %v; raw input: %q", jsonErr, hclErr, data) } 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), ) }