Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

x509pop server plugin support for servers trust bundle #5572

Merged
merged 56 commits into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
0a9b0d4
x509pop server plugin support for servers trust bundle
kfox1111 Oct 13, 2024
38e9850
Fix some lint things
kfox1111 Oct 13, 2024
b03cd79
Incorperate feedback
kfox1111 Oct 15, 2024
483d2de
Merge branch 'main' into x509pop-trustbundle
kfox1111 Oct 15, 2024
dd8f394
Merge branch 'main' into x509pop-trustbundle
kfox1111 Oct 19, 2024
0c9aa54
Try to fix test
kfox1111 Oct 19, 2024
040e70d
Merge branch 'x509pop-trustbundle' of https://github.com/kfox1111/spi…
kfox1111 Oct 19, 2024
6ea18ad
Try to fix test
kfox1111 Oct 19, 2024
01e9c3f
Try to fix test
kfox1111 Oct 19, 2024
2cb1529
Merge branch 'main' into x509pop-trustbundle
kfox1111 Oct 23, 2024
44e1cbf
Merge branch 'main' into x509pop-trustbundle
kfox1111 Oct 23, 2024
6359989
Merge branch 'main' into x509pop-trustbundle
kfox1111 Oct 23, 2024
a881a47
Merge branch 'main' into x509pop-trustbundle
kfox1111 Oct 24, 2024
fe5bb17
Add some better defaults and doc updates
kfox1111 Oct 25, 2024
487100d
Incorperate feedback
kfox1111 Oct 25, 2024
4b06fab
Fix test
kfox1111 Oct 26, 2024
d55f40d
Fix lint
kfox1111 Oct 26, 2024
c12860b
Fix lint issue
kfox1111 Oct 26, 2024
6ecc0b8
Fix lint issue
kfox1111 Oct 26, 2024
bf95562
Merge branch 'main' into x509pop-trustbundle
kfox1111 Oct 28, 2024
cf1cb52
Merge branch 'main' into x509pop-trustbundle
kfox1111 Oct 29, 2024
b7f77d0
Merge branch 'main' into x509pop-trustbundle
kfox1111 Oct 30, 2024
289ae88
Merge branch 'main' into x509pop-trustbundle
kfox1111 Oct 30, 2024
66c21d3
Merge branch 'main' into x509pop-trustbundle
kfox1111 Oct 31, 2024
d34d912
Trim prefix off automatically
kfox1111 Oct 31, 2024
4d94054
Merge branch 'main' into x509pop-trustbundle
kfox1111 Oct 31, 2024
4c6ee68
Merge branch 'main' into x509pop-trustbundle
kfox1111 Oct 31, 2024
21f2075
Merge branch 'main' into x509pop-trustbundle
kfox1111 Nov 1, 2024
e476ccf
Merge branch 'main' into x509pop-trustbundle
kfox1111 Nov 2, 2024
dbb120d
Merge branch 'main' into x509pop-trustbundle
kfox1111 Nov 4, 2024
7a8b778
Apply suggestions from code review
kfox1111 Nov 5, 2024
de1611a
Update doc/plugin_server_nodeattestor_x509pop.md
kfox1111 Nov 5, 2024
331f003
Incorperate feedback
kfox1111 Nov 6, 2024
bed2c85
Fix merge conflict
kfox1111 Nov 6, 2024
941236b
Incorperate feedback
kfox1111 Nov 6, 2024
bdf284a
Incorperate feedback
kfox1111 Nov 6, 2024
037ac50
Merge branch 'main' into x509pop-trustbundle
kfox1111 Nov 6, 2024
2f1166d
Incorperate feedback
kfox1111 Nov 6, 2024
aab491a
fmt
kfox1111 Nov 6, 2024
378bdda
Merge branch 'main' into x509pop-trustbundle
kfox1111 Nov 8, 2024
b7eea56
Merge branch 'main' into x509pop-trustbundle
kfox1111 Dec 5, 2024
9f6b9f7
Apply suggestions from code review
kfox1111 Dec 10, 2024
f1385d4
Merge branch 'main' into x509pop-trustbundle
kfox1111 Dec 10, 2024
e4313e3
Add logging
kfox1111 Dec 12, 2024
ee6e679
Merge branch 'main' into x509pop-trustbundle
kfox1111 Dec 12, 2024
c599b12
Add some tests
kfox1111 Dec 12, 2024
7820d1a
Merge branch 'x509pop-trustbundle' of https://github.com/kfox1111/spi…
kfox1111 Dec 12, 2024
fd6a320
Merge branch 'main' into x509pop-trustbundle
kfox1111 Dec 12, 2024
b2c3cdf
Add some new test certs
kfox1111 Dec 13, 2024
78e61eb
Initial x509 spiffe test
kfox1111 Dec 13, 2024
40e94ac
Merge branch 'x509pop-trustbundle' of https://github.com/kfox1111/spi…
kfox1111 Dec 13, 2024
1c75f36
Add some failure testing too
kfox1111 Dec 13, 2024
238edcb
Add no bundle test. Cleanup
kfox1111 Dec 13, 2024
2b5c884
Fix lint
kfox1111 Dec 13, 2024
021a90b
More lint
kfox1111 Dec 13, 2024
50ebc2b
Merge branch 'main' into x509pop-trustbundle
kfox1111 Dec 13, 2024
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: 1 addition & 0 deletions doc/plugin_server_nodeattestor_x509pop.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ spiffe://<trust_domain>/spire/agent/x509pop/<fingerprint>

| Configuration | Description | Default |
|-----------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------|
| `spire_trust_bundle` | If true, use the spire servers own trust bundle to use for validation. | |
| `ca_bundle_path` | The path to the trusted CA bundle on disk. The file must contain one or more PEM blocks forming the set of trusted root CA's for chain-of-trust verification. If the CA certificates are in more than one file, use `ca_bundle_paths` instead. | |
| `ca_bundle_paths` | A list of paths to trusted CA bundles on disk. The files must contain one or more PEM blocks forming the set of trusted root CA's for chain-of-trust verification. | |
| `agent_path_template` | A URL path portion format of Agent's SPIFFE ID. Describe in text/template format. | `"{{ .PluginName}}/{{ .Fingerprint }}"` |
Expand Down
109 changes: 82 additions & 27 deletions pkg/server/plugin/nodeattestor/x509pop/x509pop.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@ import (
"context"
"crypto/x509"
"encoding/json"
"fmt"
"sync"
"time"

"github.com/hashicorp/hcl"
"github.com/spiffe/go-spiffe/v2/spiffeid"
"github.com/spiffe/spire-plugin-sdk/pluginsdk"
identityproviderv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/hostservice/server/identityprovider/v1"
nodeattestorv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/plugin/server/nodeattestor/v1"
configv1 "github.com/spiffe/spire-plugin-sdk/proto/spire/service/common/config/v1"
"github.com/spiffe/spire/pkg/common/agentpathtemplate"
Expand Down Expand Up @@ -35,15 +39,17 @@ func builtin(p *Plugin) catalog.BuiltIn {
}

type Config struct {
SPIRETrustBundle bool `hcl:"spire_trust_bundle"`
CABundlePath string `hcl:"ca_bundle_path"`
CABundlePaths []string `hcl:"ca_bundle_paths"`
AgentPathTemplate string `hcl:"agent_path_template"`
}

type configuration struct {
trustDomain spiffeid.TrustDomain
trustBundle *x509.CertPool
pathTemplate *agentpathtemplate.Template
SPIRETrustBundle bool
trustDomain spiffeid.TrustDomain
trustBundle *x509.CertPool
pathTemplate *agentpathtemplate.Template
}

func buildConfig(coreConfig catalog.CoreConfig, hclText string, status *pluginconf.Status) *configuration {
Expand All @@ -53,26 +59,28 @@ func buildConfig(coreConfig catalog.CoreConfig, hclText string, status *pluginco
return nil
}

var caPaths []string
if hclConfig.CABundlePath != "" && len(hclConfig.CABundlePaths) > 0 {
status.ReportError("only one of ca_bundle_path or ca_bundle_paths can be configured, not both")
}
if hclConfig.CABundlePath != "" {
caPaths = []string{hclConfig.CABundlePath}
} else {
caPaths = hclConfig.CABundlePaths
}
if len(caPaths) == 0 {
status.ReportError("one of ca_bundle_path or ca_bundle_paths must be configured")
}

var trustBundles []*x509.Certificate
for _, caPath := range caPaths {
certs, err := util.LoadCertificates(caPath)
if err != nil {
status.ReportErrorf("unable to load trust bundle %q: %v", caPath, err)
if !hclConfig.SPIRETrustBundle {
kfox1111 marked this conversation as resolved.
Show resolved Hide resolved
var caPaths []string
if hclConfig.CABundlePath != "" && len(hclConfig.CABundlePaths) > 0 {
status.ReportError("only one of ca_bundle_path or ca_bundle_paths can be configured, not both")
Comment on lines +73 to +74
Copy link
Collaborator

Choose a reason for hiding this comment

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

is not the same error happens in line 80?
may we return here instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm.... The check here checks if both are configured. The check at 80 ensures at least one is configured. Both are needed I think.

I was thinking status.ReportError was fatal. Is it not? Maybe all the ReportError's here then need retruns?

Copy link
Collaborator

Choose a reason for hiding this comment

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

mmm, it is like if both are configured, you must never get the second one right?
status.Report is not a fatal, but just adding a list of errors, than then are used in configure or verify,
but this approach has a good win than you can get the complete list of errors to resolve all together,
but it makes very hard to follow and see dependency errors...
In any case we are fine for now

}
if hclConfig.CABundlePath != "" {
caPaths = []string{hclConfig.CABundlePath}
} else {
caPaths = hclConfig.CABundlePaths
}
if len(caPaths) == 0 {
status.ReportError("one of ca_bundle_path or ca_bundle_paths must be configured")
}

for _, caPath := range caPaths {
certs, err := util.LoadCertificates(caPath)
if err != nil {
status.ReportErrorf("unable to load trust bundle %q: %v", caPath, err)
}
trustBundles = append(trustBundles, certs...)
}
trustBundles = append(trustBundles, certs...)
}

pathTemplate := x509pop.DefaultAgentPathTemplate
Expand All @@ -85,9 +93,10 @@ func buildConfig(coreConfig catalog.CoreConfig, hclText string, status *pluginco
}

newConfig := &configuration{
trustDomain: coreConfig.TrustDomain,
trustBundle: util.NewCertPool(trustBundles...),
pathTemplate: pathTemplate,
trustDomain: coreConfig.TrustDomain,
trustBundle: util.NewCertPool(trustBundles...),
pathTemplate: pathTemplate,
SPIRETrustBundle: hclConfig.SPIRETrustBundle,
}

return newConfig
Expand All @@ -97,14 +106,51 @@ type Plugin struct {
nodeattestorv1.UnsafeNodeAttestorServer
configv1.UnsafeConfigServer

m sync.Mutex
config *configuration
m sync.Mutex
config *configuration
identityProvider identityproviderv1.IdentityProviderServiceClient
trustBundle *x509.CertPool
}

func New() *Plugin {
return &Plugin{}
}

func (p *Plugin) BrokerHostServices(broker pluginsdk.ServiceBroker) error {
if !broker.BrokerClient(&p.identityProvider) {
return status.Errorf(codes.FailedPrecondition, "IdentityProvider host service is required")
}
go func() {
ctx := context.Background()
sleep := 1 * time.Second
Copy link
Member

Choose a reason for hiding this comment

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

Rather than kick off a goroutine that may or may not be run after the IdentityProvider host service is ready, it would be better to lazily initialize this in the first call to Attest.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

fmt.Printf(" Thingy init\n")
kfox1111 marked this conversation as resolved.
Show resolved Hide resolved
for {
resp, err := p.identityProvider.FetchX509Identity(ctx, &identityproviderv1.FetchX509IdentityRequest{})
if err != nil {
fmt.Printf(" Thingy: %s\n", err)
} else {
var trustBundles []*x509.Certificate
for _, rawcert := range resp.Bundle.X509Authorities {
certificates, err := x509.ParseCertificates(rawcert.Asn1)
if err == nil {
trustBundles = append(trustBundles, certificates...)
}
}
if len(trustBundles) > 0 {
fmt.Printf(" Thingy trust bundles found %d\n", len(trustBundles))
p.m.Lock()
p.trustBundle = util.NewCertPool(trustBundles...)
p.m.Unlock()
sleep = 15 * time.Second
}
}
time.Sleep(sleep)
fmt.Printf(" Thingy loop\n")
}
}()
return nil
}

func (p *Plugin) Attest(stream nodeattestorv1.NodeAttestor_AttestServer) error {
req, err := stream.Recv()
if err != nil {
Expand Down Expand Up @@ -143,12 +189,21 @@ func (p *Plugin) Attest(stream nodeattestorv1.NodeAttestor_AttestServer) error {
intermediates.AddCert(intermediate)
}

trustBundle := config.trustBundle
if config.SPIRETrustBundle {
p.m.Lock()
trustBundle = p.trustBundle
}

// verify the chain of trust
chains, err := leaf.Verify(x509.VerifyOptions{
Intermediates: intermediates,
Roots: config.trustBundle,
Roots: trustBundle,
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
})
if config.SPIRETrustBundle {
p.m.Unlock()
}
if err != nil {
return status.Errorf(codes.PermissionDenied, "certificate verification failed: %v", err)
}
Expand Down
Loading