Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
87e2004
Add PR workflow (#28)
Aug 18, 2022
118dccc
Update CODEOWNERS (#29)
Aug 18, 2022
65fb743
Facilitate graceful cleanup
Sep 12, 2022
96cd475
Updating CONTRIBUTING.md with next branch policy
azdagron Feb 1, 2023
63b9635
Credential Composer plugin (#27)
Aug 18, 2022
9e90754
Add forward compat guidance to CredentialComposer
Sep 20, 2022
59c9cfa
Additional CredentialComposer changes
Oct 7, 2022
745c1f0
Add street_address and postal_code to DN
azdagron Feb 3, 2023
70d747a
Update runners to ubuntu 22.04 (#41)
azdagron Feb 21, 2023
c2cff31
Remove NodeResolver plugin (#40)
azdagron Feb 22, 2023
cee3865
Add plugin templates authoring documentation (#47)
guilhermocc Apr 17, 2023
b59b964
Introduce the BundlePublisher interface (#38)
amartinezfayo Feb 24, 2023
bfb5872
Introduce a helper package for BundlePublisher plugins
amartinezfayo Jun 22, 2023
a00e0ad
- Remove unneeded mutex
amartinezfayo Jun 23, 2023
ecd0d59
Update TestStringConversion
amartinezfayo Jun 23, 2023
826fb34
Address PR comments
amartinezfayo Jul 4, 2023
b822971
Have bundleformat package directly under pluginsdk/support
amartinezfayo Jul 21, 2023
a2e5ba6
Update NewFormatter function comment
amartinezfayo Jul 21, 2023
3f1b22c
Add tainted field to upstream authority messages (#39)
May 2, 2023
8f411ea
Add Validate RPC to Config service SDK. (#55)
edwbuck Jul 1, 2024
26e3b31
Update to reflect current SPIRE CODEOWNERS (#62)
amartinezfayo Jul 1, 2025
f9336f1
Add method to stream local bundle updates (#59) (#61)
amartinezfayo Jul 1, 2025
c3f9235
- Update google.golang.org/grpc to v1.74.2
amartinezfayo Aug 7, 2025
3aea7dc
Fix go.mod
amartinezfayo Aug 7, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions .github/workflows/pr_build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: PR Build
on:
pull_request: {}
workflow_dispatch: {}
env:
GO_VERSION: 1.14
permissions:
contents: read

jobs:
lint:
name: lint
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup go
uses: actions/setup-go@v3
with:
go-version: ${{ env.GO_VERSION }}
- name: Tidy check
run: make tidy-check
- name: Generate check
run: make generate-check

unit-test:
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup go
uses: actions/setup-go@v3
with:
go-version: ${{ env.GO_VERSION }}
- name: Run unit tests
run: make test

# This job is just here to make sure that the other jobs have completed
# and is used as a single job to block PR merge from. GH doesn't have a
# way to say "all jobs from this action", which would be ideal.
success:
needs: [unit-test, lint]
runs-on: ubuntu-22.04
steps:
- name: Shout it out
run: echo SUCCESS

2 changes: 1 addition & 1 deletion .go-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.17.6
1.23.12
2 changes: 1 addition & 1 deletion CODEOWNERS
Original file line number Diff line number Diff line change
@@ -1 +1 @@
* @evan2645 @amartinezfayo @azdagron @APTy @rturner3
* @evan2645 @amartinezfayo @sorindumitru @MarcosDY @rturner3
44 changes: 32 additions & 12 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ help:
@echo "$(bold)Usage:$(reset) make $(cyan)<target>$(reset)"
@echo " $(cyan)generate$(reset) - generate gRPC and plugin interface code"
@echo " $(cyan)generate-check$(reset) - ensure generated code is up to date"
@echo " $(cyan)test$(reset) - run unit tests"
@echo
@echo "For verbose output set V=1"
@echo " for example: $(cyan)make V=1$(reset)"
Expand All @@ -39,9 +40,10 @@ plugin-protos := \
proto/spire/plugin/agent/nodeattestor/v1/nodeattestor.proto \
proto/spire/plugin/agent/svidstore/v1/svidstore.proto \
proto/spire/plugin/agent/workloadattestor/v1/workloadattestor.proto \
proto/spire/plugin/server/bundlepublisher/v1/bundlepublisher.proto \
proto/spire/plugin/server/credentialcomposer/v1/credentialcomposer.proto \
proto/spire/plugin/server/keymanager/v1/keymanager.proto \
proto/spire/plugin/server/nodeattestor/v1/nodeattestor.proto \
proto/spire/plugin/server/noderesolver/v1/noderesolver.proto \
proto/spire/plugin/server/notifier/v1/notifier.proto \
proto/spire/plugin/server/upstreamauthority/v1/upstreamauthority.proto \

Expand Down Expand Up @@ -102,12 +104,12 @@ go_bin_dir := $(go_dir)/bin
go_url = https://storage.googleapis.com/golang/go$(go_version).$(os1)-$(arch2).tar.gz
go_path := PATH="$(go_bin_dir):$(PATH)"

golangci_lint_version = v1.27.0
golangci_lint_dir = $(build_dir)/golangci_lint/$(golangci_lint_version)
golangci_lint_bin = $(golangci_lint_dir)/golangci-lint

protoc_version = 3.20.1
ifeq ($(arch2),arm64)
protoc_version = 30.2
ifeq ($(os1),windows)
protoc_url = https://github.com/protocolbuffers/protobuf/releases/download/v$(protoc_version)/protoc-$(protoc_version)-win64.zip
else ifeq ($(arch1),arm64)
protoc_url = https://github.com/protocolbuffers/protobuf/releases/download/v$(protoc_version)/protoc-$(protoc_version)-$(os2)-aarch_64.zip
else ifeq ($(arch1),aarch64)
protoc_url = https://github.com/protocolbuffers/protobuf/releases/download/v$(protoc_version)/protoc-$(protoc_version)-$(os2)-aarch_64.zip
else
protoc_url = https://github.com/protocolbuffers/protobuf/releases/download/v$(protoc_version)/protoc-$(protoc_version)-$(os2)-$(arch1).zip
Expand All @@ -120,7 +122,7 @@ protoc_gen_go_base_dir := $(build_dir)/protoc-gen-go
protoc_gen_go_dir := $(protoc_gen_go_base_dir)/$(protoc_gen_go_version)-go$(go_version)
protoc_gen_go_bin := $(protoc_gen_go_dir)/protoc-gen-go

protoc_gen_go_grpc_version := v1.1.0
protoc_gen_go_grpc_version := v1.5.1
protoc_gen_go_grpc_base_dir := $(build_dir)/protoc-gen-go-grpc
protoc_gen_go_grpc_dir := $(protoc_gen_go_grpc_base_dir)/$(protoc_gen_go_grpc_version)-go$(go_version)
protoc_gen_go_grpc_bin := $(protoc_gen_go_grpc_dir)/protoc-gen-go-grpc
Expand All @@ -146,6 +148,24 @@ else
@echo "Git repository is clean."
endif

#############################################################################
# Code cleanliness
#############################################################################

.PHONY: tidy tidy-check lint lint-code
tidy: | go-check
$(E)$(go_path) go mod tidy
$(E)cd proto/spire; $(go_path) go mod tidy

tidy-check:
ifneq ($(git_dirty),)
$(error tidy-check must be invoked on a clean repository)
endif
@echo "Running go tidy..."
$(E)$(MAKE) tidy
@echo "Ensuring git repository is clean..."
$(E)$(MAKE) git-clean-check

#############################################################################
# Test Targets
#############################################################################
Expand Down Expand Up @@ -251,6 +271,7 @@ endif
# correct go binary.
go-check:
ifneq (go$(go_version), $(shell $(go_path) go version 2>/dev/null | cut -f3 -d' '))
@echo "go_url:" $(go_url)
@echo "Installing go$(go_version)..."
$(E)rm -rf $(dir $(go_dir))
$(E)mkdir -p $(go_dir)
Expand All @@ -274,10 +295,9 @@ $(protoc_gen_go_bin): | go-check

$(protoc_gen_go_grpc_bin): | go-check
@echo "Installing protoc-gen-go-grpc $(protoc_gen_go_grpc_version)..."
$(E)rm -rf $(protoc_gen_go_grpc_base_dir)
$(E)mkdir -p $(protoc_gen_go_grpc_dir)
$(E)echo "module tools" > $(protoc_gen_go_grpc_dir)/go.mod
$(E)cd $(protoc_gen_go_grpc_dir) && GOBIN=$(protoc_gen_go_grpc_dir) $(go_path) go get google.golang.org/grpc/cmd/protoc-gen-go-grpc@$(protoc_gen_go_grpc_version)
@rm -rf $(protoc_gen_go_grpc_base_dir)
@mkdir -p $(protoc_gen_go_grpc_dir)
@GOBIN=$(protoc_gen_go_grpc_dir) $(go_path) go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@$(protoc_gen_go_grpc_version)

$(protoc_gen_go_spire_bin): $(wildcard ./cmd/protoc-gen-go-spire/*) | go-check
@echo "Installing protoc-gen-go-spire..."
Expand Down
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,14 @@ There are three types of interfaces:

### Server

| Plugin | Versions | Description | Template |
| ------ | -------- | ----------- | ----------- |
| KeyManager | [v1](proto/spire/plugin/server/keymanager/v1/keymanager.proto) | Manages private keys and performs signing operations. | [link](templates/server/keymanager) |
| NodeAttestor | [v1](proto/spire/plugin/server/nodeattestor/v1/nodeattestor.proto) | Performs the server side of the node attestation flow. | [link](templates/server/nodeattestor) |
| NodeResolver | [v1](proto/spire/plugin/server/noderesolver/v1/noderesolver.proto) | Provides additional selectors for attested nodes. | [link](templates/server/noderesolver) |
| Notifier | [v1](proto/spire/plugin/server/notifier/v1/notifier.proto) | Notifies external systems of certain SPIRE events. | [link](templates/server/notifier) |
| UpstreamAuthority | [v1](proto/spire/plugin/server/upstreamauthority/v1/upstreamauthority.proto) | Plugs SPIRE into an upstream PKI. | [link](templates/server/upstreamauthority) |
| Plugin | Versions | Description | Template |
| ------ | -------- | ----------- | ----------- |
| BundlePublisher | [v1](proto/spire/plugin/server/bundlepublisher/v1/bundlepublisher.proto) | Publishes a trust bundle to a store. | [link](templates/server/bundlepublisher) |
| CredentialComposer | [v1](proto/spire/plugin/server/credentialcomposer/v1/credentialcomposer.proto) | Allows customization of SVID and CA attributes. | [link](templates/server/credentialcomposer) |
| KeyManager | [v1](proto/spire/plugin/server/keymanager/v1/keymanager.proto) | Manages private keys and performs signing operations. | [link](templates/server/keymanager) |
| NodeAttestor | [v1](proto/spire/plugin/server/nodeattestor/v1/nodeattestor.proto) | Performs the server side of the node attestation flow. | [link](templates/server/nodeattestor) |
| Notifier | [v1](proto/spire/plugin/server/notifier/v1/notifier.proto) | Notifies external systems of certain SPIRE events. | [link](templates/server/notifier) |
| UpstreamAuthority | [v1](proto/spire/plugin/server/upstreamauthority/v1/upstreamauthority.proto) | Plugs SPIRE into an upstream PKI. | [link](templates/server/upstreamauthority) |


## Services
Expand Down
49 changes: 46 additions & 3 deletions docs/AUTHORING.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,34 @@
This document gives guidance for authoring plugins.

SPIRE plugins implement one and only one plugin _type_ (e.g. KeyManager). They
also implement zero or more services.
also implement zero or more services. Below is a list of plugin types, alongside templates that can be used as a base
for authoring plugins.

## Templates
Each template contains a go file that can be used as a starting point for authoring plugins. A test file is also
provided for each template; the test file contains a test suite that can be used to verify that the plugin has been
loaded and is working as expected using [plugintest](https://pkg.go.dev/github.com/spiffe/spire-plugin-sdk/plugintest).

### Agent

| Plugin | Description | Template |
|------------------|-------------------------------------------------------|---------------------------------------------|
| KeyManager | Manages private keys and performs signing operations. | [link](../templates/agent/keymanager) |
| NodeAttestor | Performs the agent side of the node attestation flow. | [link](../templates/agent/nodeattestor) |
| SVIDStore | Stores workload X509-SVIDs to arbitrary destinations. | [link](../templates/agent/svidstore) |
| WorkloadAttestor | Attests workloads and provides selectors. | [link](../templates/agent/workloadattestor) |

### Server

| Plugin | Description | Template |
|--------------------|--------------------------------------------------------|------------------------------------------------|
| KeyManager | Manages private keys and performs signing operations. | [link](../templates/server/keymanager) |
| NodeAttestor | Performs the server side of the node attestation flow. | [link](../templates/server/nodeattestor) |
| Notifier | Notifies external systems of certain SPIRE events. | [link](../templates/server/notifier) |
| UpstreamAuthority | Plugs SPIRE into an upstream PKI. | [link](../templates/server/upstreamauthority) |
| CredentialComposer | Allows customization of SVID and CA attributes. | [link](../templates/server/credentialcomposer) |



## Configuration

Expand Down Expand Up @@ -69,7 +96,7 @@ func main() {
plugin := new(Plugin)
pluginmain.Serve(
keymanagerv1.KeyManagerPluginServer(plugin),
configv1.ConfigPluginServer(plugin), // <-- add the Config service server implementation
configv1.ConfigServiceServer(plugin), // <-- add the Config service server implementation
)
}
```
Expand Down Expand Up @@ -148,6 +175,22 @@ Plugin authors can decide if the lack of support for a specific host service is
an error or not. If the plugin returns an error from BrokerHostServices, the
plugin will fail to load.

## Cleanup

Plugins are separate processes and are terminated when the plugin is unloaded.
However, it may be desirable to perform some graceful cleanup operations.

To facilitate this, if plugin/service implementations implement the io.Closer
interface, then the `Close` method will be invoked before the plugin is
unloaded. No other RPCs will be invoked at any time during or after the `Close`
method is called. Errors returned from `Close` are simply logged and will not
impact any runtime behavior of SPIRE Server.

Implementations of `Close` should avoid long running or blocking behavior.
SPIRE may employ deadlines on the operation and could terminate the plugin
before the cleanup is fully completed if plugin implementations ignore this
advice.

## Unit Testing

The [plugintest](https://pkg.go.dev/github.com/spiffe/spire-plugin-sdk/plugintest)
Expand All @@ -160,7 +203,7 @@ See the package docs for more information.
## Running

The [pluginmain](https://pkg.go.dev/github.com/spiffe/spire-plugin-sdk/pluginmain) package
is used to run the plugin. It takes care of setting up all of the plugin facilities and
is used to run the plugin. It takes care of setting up all the plugin facilities and
wiring up the logger and hostservices.

See the package docs for more information.
33 changes: 18 additions & 15 deletions docs/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,25 +29,28 @@ $ make
If you are adding a new .proto file, you first need to update the `Makefile`
and add the .proto file to the relevant variables.

## Consuming Changes in SPIRE
## Opening PRs

All PRs should target the `next` branch. The `next` branch is a staging area
for all features under development but not ready for release in an official
version of SPIRE.

SPIRE's main branch depends on a pseudo-version of this repository (see
https://golang.org/ref/mod#pseudo-versions).
Changes are cherry-picked into `main` from the `next` branch ahead of an
official SPIRE release. The commits in `main` are tagged with the supporting
SPIRE version.

While a new change in this repository is under development, you can add a
temporary `replace` directive to the SPIRE `go.mod` to allow you to consume the
changes. Care must be taken to not push the `replace` directive change up to
SPIRE.
## Consuming Changes in SPIRE

Once those changes have been merged and you are ready to consume them from
SPIRE, run `go get github.com/spiffe/spire-plugin-sdk@<commit hash>` in the SPIRE
repository. This will update `go.mod` in SPIRE to use the latest pseudo version
with that commit.
While a new change in this repository is under development, you can use [Go
Workspaces](https://go.dev/ref/mod#workspaces) to allow SPIRE to consume the
changes before they are merged into this repository.

When cutting a SPIRE release, this repository is tagged with the SPIRE
release version. The release branch in SPIRE is updated to depend explicitly
on that version (i.e. `go get github.com/spiffe/spire-plugin-sdk@<version>`).
SPIRE's main branch depends on a pseudo-version of this repository based on the
`next` branch (see https://golang.org/ref/mod#pseudo-versions). Once changes
have been merged into the `next` branch, the pseudo-version dependency in the
SPIRE repository can be updated by running `go get
github.com/spiffe/spire-plugin-sdk@next` from the SPIRE repository.

Relying on a pseudo versions means that this repository only needs tags
for the offically released versions, while still allowing SPIRE to work with
for the officially released versions, while still allowing SPIRE to work with
unreleased changes during development.
8 changes: 1 addition & 7 deletions docs/MIGRATING.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,17 +125,11 @@ to couple it to that operation.

The `Attest` RPC request and response fields are now contained within `oneof`'s
to strongly convey the difference in field requirements in requests and
responses during the atestation flow. The attestation payload no longer needs
responses during the attestation flow. The attestation payload no longer needs
to include a type, since that is now inferred by SPIRE from the name of the
plugin. The selectors returned in the final response are selector values only.
The selector type is inferred by SPIRE from the name of the plugin.

### Server NodeResolver

The `Resolve` RPC now handles resolution for a single agent SPIFFE ID instead
of a list of IDs. The response returns selector values only. The selector type
is inferred by SPIRE from the name of the plugin.

### Server Notifier

No substantial changes outside of the migration to plugin SDK types.
Expand Down
34 changes: 31 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,11 +1,39 @@
module github.com/spiffe/spire-plugin-sdk

go 1.14
go 1.23.0

toolchain go1.24.2

require (
github.com/go-jose/go-jose/v3 v3.0.0
github.com/hashicorp/go-hclog v0.15.0
github.com/hashicorp/go-plugin v1.4.0
github.com/hashicorp/hcl v1.0.0
google.golang.org/grpc v1.48.0
google.golang.org/protobuf v1.28.0
github.com/spiffe/go-spiffe/v2 v2.5.0
github.com/stretchr/testify v1.10.0
google.golang.org/grpc v1.74.2
google.golang.org/protobuf v1.36.6
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fatih/color v1.15.0 // indirect
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 // indirect
github.com/oklog/run v1.0.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect
github.com/zeebo/errs v1.4.0 // indirect
golang.org/x/crypto v0.38.0 // indirect
golang.org/x/net v0.40.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/text v0.25.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Loading
Loading