diff --git a/doc/plugin_server_nodeattestor_x509pop.md b/doc/plugin_server_nodeattestor_x509pop.md index 2877a13574..e37c24b49e 100644 --- a/doc/plugin_server_nodeattestor_x509pop.md +++ b/doc/plugin_server_nodeattestor_x509pop.md @@ -47,12 +47,13 @@ A sample configuration: ## Selectors -| Selector | Example | Description | -|------------------|-------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Common Name | `x509pop:subject:cn:example.org` | The Subject's Common Name (see X.500 Distinguished Names) | -| SHA1 Fingerprint | `x509pop:ca:fingerprint:0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33` | The SHA1 fingerprint as a hex string for each cert in the PoP chain, excluding the leaf. | -| SerialNumber | `x509pop:serialnumber:0a1b2c3d4e5f` | The leaf certificate serial number as a lowercase hexadecimal string | -| San | `x509pop:san::` | The san selectors on the leaf certificate. The expected format of the uri san is `x509pop:////`. One selector is exposed per uri san corresponding to x509pop uri scheme. string | +| Selector | Example | Description | +|------------------|-------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Common Name | `x509pop:subject:cn:example.org` | The Subject's Common Name (see X.500 Distinguished Names) | +| SHA1 Fingerprint | `x509pop:ca:fingerprint:0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33` | The SHA1 fingerprint as a hex string for each cert in the PoP chain, excluding the leaf. | +| SerialNumber | `x509pop:serialnumber:0a1b2c3d4e5f` | The leaf certificate serial number as a lowercase hexadecimal string | +| San | `x509pop:san::` | The san selectors on the leaf certificate. The expected format of the uri san is `x509pop:////`. One selector is exposed per uri san corresponding to x509pop uri scheme. string | +| agent_id_parent | `x509pop:agent_id_parent:` | When in SPIFFE mode, the parent ID of the selected agent ID. E.g., `spiffe://spire/agent/x509pop/spire-identity-exchange/1234` yields `x509pop:agent_id_parent:spiffe://spire/agent/x509pop/spire-identity-exchange` | ## SVID Path Prefix diff --git a/pkg/server/plugin/nodeattestor/x509pop/x509pop.go b/pkg/server/plugin/nodeattestor/x509pop/x509pop.go index f7c9ec3fac..7d948c4cf3 100644 --- a/pkg/server/plugin/nodeattestor/x509pop/x509pop.go +++ b/pkg/server/plugin/nodeattestor/x509pop/x509pop.go @@ -313,11 +313,23 @@ func (p *Plugin) Attest(stream nodeattestorv1.NodeAttestor_AttestServer) error { return status.Errorf(codes.Internal, "failed to make spiffe id: %v", err) } + selectors := buildSelectorValues(leaf, chains, sanSelectors) + + if config.mode == "spiffe" { + agentIDStr := spiffeid.String() + + if lastSlash := strings.LastIndex(agentIDStr, "/"); lastSlash != -1 { + parentID := agentIDStr[:lastSlash] + parentID = strings.TrimSuffix(parentID, "/") + selectors = append(selectors, "agent_id_parent:"+parentID) + } + } + return stream.Send(&nodeattestorv1.AttestResponse{ Response: &nodeattestorv1.AttestResponse_AgentAttributes{ AgentAttributes: &nodeattestorv1.AgentAttributes{ SpiffeId: spiffeid.String(), - SelectorValues: buildSelectorValues(leaf, chains, sanSelectors), + SelectorValues: selectors, CanReattest: true, }, }, diff --git a/pkg/server/plugin/nodeattestor/x509pop/x509pop_test.go b/pkg/server/plugin/nodeattestor/x509pop/x509pop_test.go index 7f40c87fe5..e95f484162 100644 --- a/pkg/server/plugin/nodeattestor/x509pop/x509pop_test.go +++ b/pkg/server/plugin/nodeattestor/x509pop/x509pop_test.go @@ -91,11 +91,12 @@ func (s *Suite) SetupTest() { func (s *Suite) TestAttestSuccess() { tests := []struct { - desc string - giveConfig string - expectAgentID string - certs [][]byte - serialnumber string + desc string + giveConfig string + expectAgentID string + certs [][]byte + serialnumber string + expectAgentIDParentSelector bool }{ { desc: "default success (ca_bundle_path)", @@ -126,11 +127,12 @@ func (s *Suite) TestAttestSuccess() { serialnumber: "serialnumber:0a1b2c3d4e5f", }, { - desc: "success with spiffe exchange", - expectAgentID: "spiffe://example.org/spire/agent/x509pop/testhost", - giveConfig: s.createConfigurationModeSPIFFE(""), - certs: s.svidExchange, - serialnumber: "serialnumber:0a1b2c3d4e7f", + desc: "success with spiffe exchange", + expectAgentID: "spiffe://example.org/spire/agent/x509pop/testhost", + giveConfig: s.createConfigurationModeSPIFFE(""), + expectAgentIDParentSelector: true, + certs: s.svidExchange, + serialnumber: "serialnumber:0a1b2c3d4e7f", }, { desc: "success with custom X509pop san selectors", @@ -182,6 +184,14 @@ func (s *Suite) TestAttestSuccess() { {Type: "x509pop", Value: "san:environment:production"}, {Type: "x509pop", Value: "san:key:path/to/value"}, } + + if tt.expectAgentIDParentSelector { + expectedSelectors = append(expectedSelectors, &common.Selector{ + Type: "x509pop", + Value: "agent_id_parent:spiffe://example.org/spire/agent/x509pop", + }) + } + spirecommonutil.SortSelectors(expectedSelectors) spirecommonutil.SortSelectors(result.Selectors)