Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 0 additions & 1 deletion .data/.file

This file was deleted.

8 changes: 5 additions & 3 deletions Dockerfile
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do others make images with custom api & plugin packages?

Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ ARG goversion
FROM --platform=${BUILDPLATFORM} golang:${goversion}-alpine3.22 as base
WORKDIR /spire
RUN apk --no-cache --update add file bash clang lld pkgconfig git make
COPY go.* ./
COPY spire/go.* ./
COPY spire-plugin-sdk/ /spire-plugin-sdk/
COPY spire-api-sdk/ /spire-api-sdk/
# https://go.dev/ref/mod#module-cache
RUN --mount=type=cache,target=/go/pkg/mod go mod download
COPY . .
COPY spire/ .

# xx is a helper for cross-compilation
# when bumping to a new version analyze the new version for security issues
Expand All @@ -31,7 +33,7 @@ RUN --mount=type=cache,target=/root/.cache/go-build \
make build-static git_tag=$TAG git_dirty="" && \
for f in $(find bin -executable -type f); do xx-verify --static $f; done

FROM --platform=${BUILDPLATFORM} scratch AS spire-base
FROM --platform=${BUILDPLATFORM} golang:${goversion}-alpine3.22 AS spire-base
COPY --link --from=builder --chown=root:root --chmod=755 /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
WORKDIR /opt/spire

Expand Down
6 changes: 3 additions & 3 deletions Dockerfile.windows
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ CMD []
# SPIRE Server
FROM spire-base-windows AS spire-server-windows
ENTRYPOINT ["c:/spire/bin/spire-server.exe", "run"]
COPY bin/spire-server.exe C:/spire/bin/spire-server.exe
COPY spire/bin/spire-server.exe C:/spire/bin/spire-server.exe

# SPIRE Agent
FROM spire-base-windows AS spire-agent-windows
ENTRYPOINT ["c:/spire/bin/spire-agent.exe", "run"]
COPY ./bin/spire-agent.exe C:/spire/bin/spire-agent.exe
COPY spire/bin/spire-agent.exe C:/spire/bin/spire-agent.exe

# OIDC Discovery Provider
FROM spire-base-windows AS oidc-discovery-provider-windows
ENTRYPOINT ["c:/spire/bin/oidc-discovery-provider.exe"]
COPY ./bin/oidc-discovery-provider.exe c:/spire/bin/oidc-discovery-provider.exe
COPY spire/bin/oidc-discovery-provider.exe c:/spire/bin/oidc-discovery-provider.exe
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ git_dirty := $(shell git status -s)

protos := \
proto/private/server/journal/journal.proto \
proto/spire/common/common.proto \
proto/spire/common/common.proto

api-protos := \

Expand Down Expand Up @@ -342,7 +342,7 @@ $1: $3 container-builder
--target $2 \
-o type=oci,dest=$2-image.tar \
-f $3 \
.
..

endef

Expand Down Expand Up @@ -373,7 +373,7 @@ $1: $3
--target $2 \
-t $2 -t $2:latest-local \
-f $3 \
.
..

endef

Expand Down Expand Up @@ -477,7 +477,7 @@ endif
.PHONY: dev-shell dev-image

dev-image:
$(E)docker build -t spire-dev -f Dockerfile.dev .
$(E)docker build -t spire-dev -f Dockerfile.dev ..

dev-shell: | go-check
$(E)docker run --rm -v "$(call goenv,GOCACHE)":/root/.cache/go-build -v "$(DIR):/spire" -v "$(call goenv,GOPATH)/pkg/mod":/root/go/pkg/mod -it -h spire-dev spire-dev
Expand Down
10 changes: 10 additions & 0 deletions cmd/spire-agent/cli/run/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ type Config struct {
type agentConfig struct {
DataDir string `hcl:"data_dir"`
AdminSocketPath string `hcl:"admin_socket_path"`
BrokerSocketPath string `hcl:"broker_socket_path"`
InsecureBootstrap bool `hcl:"insecure_bootstrap"`
RebootstrapMode string `hcl:"rebootstrap_mode"`
RebootstrapDelay string `hcl:"rebootstrap_delay"`
Expand Down Expand Up @@ -509,6 +510,15 @@ func NewAgentConfig(c *Config, logOptions []log.Option, allowUnknownConfig bool)
}
ac.AdminBindAddress = adminAddr
}

if c.Agent.hasBrokerAddr() {
brokerAddr, err := c.Agent.getBrokerAddr()
if err != nil {
return nil, err
}
ac.BrokerBindAddress = brokerAddr
}

// Handle join token - read from file if specified
if c.Agent.JoinTokenFile != "" {
tokenBytes, err := os.ReadFile(c.Agent.JoinTokenFile)
Expand Down
35 changes: 35 additions & 0 deletions cmd/spire-agent/cli/run/run_posix.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,30 @@ func (c *agentConfig) hasAdminAddr() bool {
return c.AdminSocketPath != ""
}

func (c *agentConfig) getBrokerAddr() (net.Addr, error) {
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now I'm only supporting UDS, once the Broker API evolves we may allow serving it on TCP too.

socketPathAbs, err := filepath.Abs(c.SocketPath)
if err != nil {
return nil, fmt.Errorf("failed to get absolute path for socket_path: %w", err)
}
brokerSocketPathAbs, err := filepath.Abs(c.BrokerSocketPath)
if err != nil {
return nil, fmt.Errorf("failed to get absolute path for broker_socket_path: %w", err)
}

if strings.HasPrefix(brokerSocketPathAbs, filepath.Dir(socketPathAbs)+"/") {
return nil, errors.New("broker socket cannot be in the same directory or a subdirectory as that containing the Workload API socket")
}

return &net.UnixAddr{
Name: brokerSocketPathAbs,
Net: "unix",
}, nil
}

func (c *agentConfig) hasBrokerAddr() bool {
return c.BrokerSocketPath != ""
}

// validateOS performs posix specific validations of the agent config
func (c *agentConfig) validateOS() error {
if c.Experimental.NamedPipeName != "" {
Expand Down Expand Up @@ -88,5 +112,16 @@ func prepareEndpoints(c *agent.Config) error {
}
}

if c.BrokerBindAddress != nil {
// Create uds dir and parents if not exists
brokerDir := filepath.Dir(c.BrokerBindAddress.String())
if _, statErr := os.Stat(brokerDir); os.IsNotExist(statErr) {
c.Log.WithField("dir", brokerDir).Infof("Creating broker UDS directory")
if err := os.MkdirAll(brokerDir, 0755); err != nil {
return err
}
}
}

return nil
}
8 changes: 8 additions & 0 deletions cmd/spire-agent/cli/run/run_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ func (c *agentConfig) hasAdminAddr() bool {
return c.Experimental.AdminNamedPipeName != ""
}

func (c *agentConfig) getBrokerAddr() (net.Addr, error) {
return nil, errors.New("broker_socket_path is not supported in this platform")
}

func (c *agentConfig) hasBrokerAddr() bool {
return false
}

// validateOS performs windows specific validations of the agent config
func (c *agentConfig) validateOS() error {
if c.SocketPath != "" {
Expand Down
5 changes: 5 additions & 0 deletions conf/agent/agent.conf
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ agent {
socket_path ="/tmp/spire-agent/public/api.sock"
trust_bundle_path = "./conf/agent/dummy_root_ca.crt"
trust_domain = "example.org"

authorized_delegates = [
"spiffe://example.org/broker",
]
broker_socket_path = "/tmp/spire-agent/broker/api.sock"
}

plugins {
Expand Down
3 changes: 3 additions & 0 deletions conf/agent/agent_full.conf
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ agent {
# "spiffe://example.org/authorized_client1",
# ]

# broker_socket_path: Location to bind the SPIFFE Broker Endpoint.
# broker_socket_path = ""

# sds: Optional SDS configuration section.
# sds = {
# # default_svid_name: The TLS Certificate resource name to use for the default
Expand Down
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -329,3 +329,6 @@ require (
sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482 // indirect
sigs.k8s.io/yaml v1.6.0 // indirect
)

replace github.com/spiffe/spire-plugin-sdk => ../spire-plugin-sdk
replace github.com/spiffe/spire-api-sdk => ../spire-api-sdk
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -810,8 +810,6 @@ github.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMps
github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs=
github.com/spiffe/spire-api-sdk v1.2.5-0.20260115194754-bcd1999bdd05 h1:wJPyPSXHtKEc9SuK83sr40OoRSaYUTf1+wncvWvogHE=
github.com/spiffe/spire-api-sdk v1.2.5-0.20260115194754-bcd1999bdd05/go.mod h1:9hXJcMzatM1KwAtBDO3s6HccDCic++/5c2yOc5Iln8Y=
github.com/spiffe/spire-plugin-sdk v1.4.4-0.20251120194148-791bbd274dc7 h1:OAvr7TNirmBpXnAp82cTosuB+JAus5cyFCRqXHE0WHs=
github.com/spiffe/spire-plugin-sdk v1.4.4-0.20251120194148-791bbd274dc7/go.mod h1:QvrRDiBlXiJ7kNd176ZHsF5eklxxeTRgJSu2CXe0MKw=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
Expand Down
19 changes: 19 additions & 0 deletions pkg/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
admin_api "github.com/spiffe/spire/pkg/agent/api"
node_attestor "github.com/spiffe/spire/pkg/agent/attestor/node"
workload_attestor "github.com/spiffe/spire/pkg/agent/attestor/workload"
"github.com/spiffe/spire/pkg/agent/broker"
"github.com/spiffe/spire/pkg/agent/catalog"
"github.com/spiffe/spire/pkg/agent/endpoints"
"github.com/spiffe/spire/pkg/agent/manager"
Expand Down Expand Up @@ -255,6 +256,24 @@ func (a *Agent) Run(ctx context.Context) error {
tasks = append(tasks, adminEndpoints.ListenAndServe)
}

if a.c.BrokerBindAddress != nil {
brokerEndpoints, err := broker.New(&broker.Config{
BindAddr: a.c.BrokerBindAddress,
Manager: manager,
Log: a.c.Log,
Metrics: metrics,
Attestor: workloadAttestor,
TrustDomain: a.c.TrustDomain,
AuthorizedDelegates: a.c.AuthorizedDelegates,
SVIDSource: as,
BundleSource: manager.GetX509Bundle(),
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't sure what's better here, us the attestation result as a bundle source or the one from the manager?

})
if err != nil {
return fmt.Errorf("failed to create broker endpoints: %w", err)
}
tasks = append(tasks, brokerEndpoints.ListenAndServe)
}

if a.c.LogReopener != nil {
tasks = append(tasks, a.c.LogReopener)
}
Expand Down
6 changes: 6 additions & 0 deletions pkg/agent/api/delegatedidentity/v1/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import (
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/protobuf/types/known/anypb"
)

var (
Expand Down Expand Up @@ -870,6 +871,11 @@ func (fa FakeWorkloadPIDAttestor) Attest(_ context.Context, _ int) ([]*common.Se
return fa.selectors, fa.err
}

func (fa FakeWorkloadPIDAttestor) AttestReference(_ context.Context, _ *anypb.Any) ([]*common.Selector, error) {
// TODO(arndt) do we want more logic here?
return fa.selectors, fa.err
}

type FakeManager struct {
manager.Manager

Expand Down
7 changes: 0 additions & 7 deletions pkg/agent/attestor/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,6 @@ const (
roundRobinServiceConfig = `{ "loadBalancingConfig": [ { "round_robin": {} } ] }`
)

type AttestationResult struct {
SVID []*x509.Certificate
Key keymanager.Key
Bundle *spiffebundle.Bundle
Reattestable bool
}

type Attestor interface {
Attest(ctx context.Context) (*AttestationResult, error)
}
Expand Down
40 changes: 40 additions & 0 deletions pkg/agent/attestor/node/result.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package attestor

import (
"crypto/x509"
"fmt"

"github.com/spiffe/go-spiffe/v2/bundle/spiffebundle"
"github.com/spiffe/go-spiffe/v2/bundle/x509bundle"
"github.com/spiffe/go-spiffe/v2/spiffeid"
"github.com/spiffe/go-spiffe/v2/svid/x509svid"
"github.com/spiffe/spire/pkg/agent/plugin/keymanager"
)

// Allow AttestationResult to be used as go-spiffe SVID and bundle sources.
// TODO(arndt): Check whether the key of the agent is ok to be exposed to other parties.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is worth a discussion.

var (
_ x509svid.Source = (*AttestationResult)(nil)
_ x509bundle.Source = (*AttestationResult)(nil)
)

type AttestationResult struct {
SVID []*x509.Certificate
Key keymanager.Key
Bundle *spiffebundle.Bundle
Reattestable bool
}

func (ar *AttestationResult) GetX509SVID() (*x509svid.SVID, error) {
return &x509svid.SVID{
Certificates: ar.SVID,
PrivateKey: ar.Key,
}, nil
}

func (ar *AttestationResult) GetX509BundleForTrustDomain(trustDomain spiffeid.TrustDomain) (*x509bundle.Bundle, error) {
if ar.Bundle.TrustDomain() != trustDomain {
return nil, fmt.Errorf("bundle for trust domain %q not found", trustDomain)
}
return ar.Bundle.X509Bundle(), nil
}
Loading
Loading