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

Add http node attestor #4909

Merged
merged 56 commits into from
Aug 6, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
b322773
Add http challenge node attestor
kfox1111 May 10, 2024
f08d9d2
Fix various issues so it works again after refactor
kfox1111 May 11, 2024
009166f
Fix some issues
kfox1111 May 11, 2024
7caac6f
Fix some issues
kfox1111 May 11, 2024
3e68d07
Fix some issues
kfox1111 May 11, 2024
baaa4f6
Fix some issues
kfox1111 May 11, 2024
029f117
Fix some issues
kfox1111 May 11, 2024
82af10b
Fix some issues
kfox1111 May 11, 2024
86fbf7c
Fix some issues
kfox1111 May 11, 2024
727c5f9
Implement tofu. Incorperate feedback
kfox1111 May 15, 2024
9f42248
Fix some lint bits
kfox1111 May 16, 2024
76d761f
More lint
kfox1111 May 16, 2024
a693947
More lint
kfox1111 May 16, 2024
28dc797
Merge branch 'main' into http
kfox1111 May 16, 2024
6416f01
Merge branch 'main' into http
kfox1111 May 30, 2024
9e8897e
Apply suggestions from code review
kfox1111 Jun 5, 2024
fdfc837
Incorperate feedback
kfox1111 Jun 5, 2024
f8bc768
Merge branch 'http' of https://github.com/kfox1111/spire into http
kfox1111 Jun 5, 2024
b5a439e
Incorperate feedback
kfox1111 Jun 5, 2024
0656513
Incorperate feedback
kfox1111 Jun 5, 2024
6a94dfd
Fix example
kfox1111 Jun 5, 2024
4e8133e
Incorperate feedback
kfox1111 Jun 10, 2024
b0df1d6
Incorperate feedback
kfox1111 Jun 10, 2024
0c1d254
Incorperate feedback
kfox1111 Jun 11, 2024
effb6b3
Fix lint issues
kfox1111 Jun 12, 2024
d6f3b6a
Fix lint issues
kfox1111 Jun 12, 2024
6cdb65b
Fix 404 issue
kfox1111 Jun 17, 2024
98d7363
Fix lint issue
kfox1111 Jun 17, 2024
623ed12
Fix issue with protocol
kfox1111 Jun 18, 2024
968e90e
Merge branch 'main' into http
kfox1111 Jun 18, 2024
0e7dd47
Remove tempate
kfox1111 Jun 22, 2024
b687049
Apply suggestions from code review
kfox1111 Jun 22, 2024
1caaaec
Merge branch 'main' into http
kfox1111 Jun 22, 2024
069bb2b
Fix typo
kfox1111 Jun 22, 2024
69edbe1
Add some unit tests
kfox1111 Jun 24, 2024
41f1e74
Add a bunch of httpchallenge server plugin tests
kfox1111 Jul 16, 2024
92e72d5
Add some more tests
kfox1111 Jul 16, 2024
151d3c3
Test server works
kfox1111 Jul 17, 2024
b6c4a41
Add tofu checks
kfox1111 Jul 17, 2024
f00d02f
Add httpchallenge agent tests
kfox1111 Jul 19, 2024
81b205a
Incorperate feedback
kfox1111 Jul 19, 2024
501a957
gofmt files
kfox1111 Jul 19, 2024
a404aa3
Apply suggestions from code review
kfox1111 Jul 19, 2024
5ab497d
Fix lint issues
kfox1111 Jul 19, 2024
b5caee3
Fix lint issues
kfox1111 Jul 19, 2024
1af2187
Fix test
kfox1111 Jul 19, 2024
a2c0385
Incorperate feedback. Add localhost block.
kfox1111 Jul 20, 2024
be2b414
Fix test
kfox1111 Jul 20, 2024
2bec5df
Add test for localhost test. Incorperate feedback
kfox1111 Jul 20, 2024
4c95d25
Incorperate feedback
kfox1111 Jul 20, 2024
2ac078f
Fix lint issue
kfox1111 Jul 20, 2024
32f8f04
Merge branch 'main' into http
kfox1111 Jul 20, 2024
f47af5c
Merge branch 'main' into http
kfox1111 Jul 23, 2024
f596796
Update doc/plugin_server_nodeattestor_http_challenge.md
kfox1111 Aug 5, 2024
2880654
Merge branch 'main' into http
kfox1111 Aug 5, 2024
3dae7a2
Incorperate feedback
kfox1111 Aug 5, 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
Prev Previous commit
Next Next commit
Implement tofu. Incorperate feedback
Signed-off-by: Kevin Fox <Kevin.Fox@pnnl.gov>
  • Loading branch information
kfox1111 committed May 15, 2024
commit 727c5f96439524c804ba1d4f947c87bdd269aecd
19 changes: 16 additions & 3 deletions doc/plugin_server_nodeattestor_http_challenge.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ spiffe://<trust_domain>/spire/agent/http_challenge/<hostname>
|-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------|
| `dns_patterns` | A list of regular expressions to apply to the hostname being attested. If none match, attestation will fail. If unset, all hostnames are allowed. | |
Copy link
Member

Choose a reason for hiding this comment

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

nit : allowed_dns_patterns

It also isn't clear what it means to "apply" the regex, i.e., we should be clear that the hostname must match at least one pattern.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I took a stab at rewording. Please rereview to see if its more clear

| `required_port` | Set to a port number to require clients to listen only on that port. If unset, all port numbers are allowed | |
| `allow_non_root_ports` | Set to true to allow ports >= 1024 to be used by the agents with the advertised_port | false |
| `allow_non_root_ports` | Set to true to allow ports >= 1024 to be used by the agents with the advertised_port | true |
| `agent_path_template` | A URL path portion format of Agent's SPIFFE ID. Describe in text/template format. | "{{ .PluginName }}/{{ .HostName }}" |
kfox1111 marked this conversation as resolved.
Show resolved Hide resolved
| `tofu` | Trust on first use of the successful challenge. Can only be disabled if allow_non_root_ports=false or required_port < 1024 | true |

A sample configuration:

Expand All @@ -38,8 +39,8 @@ A sample configuration:

## Selectors

| Selector | Example | Description |
|----------|--------------------------------|------------------------|
| Selector | Example | Description |
|----------|------------------------------------------|------------------------|
| Hostname | `http_challenge:hostname:p1.example.com` | The Subject's Hostname |

## Agent Path Template
Expand All @@ -54,3 +55,15 @@ Some useful values are:
| .PluginName | The name of the plugin. |
| .HostName | The hostname of the agent attested. |
| .TrustDomain | The configured trust domain. |

## Security Considerations

Generally, tcp ports are accessable to any user of the node. As a result, it is possible for non-agent code running on a node to attest to the SPIRE Server, allowing it to obtain any workload identity that the node is authorized to run.
kfox1111 marked this conversation as resolved.
Show resolved Hide resolved
kfox1111 marked this conversation as resolved.
Show resolved Hide resolved

To mitigate the associated risk, the `http_challenge` node attestor implements multiple features that can be used to minimize the risk.
kfox1111 marked this conversation as resolved.
Show resolved Hide resolved

Trust On First Use (or TOFU) is one such option. For any given node, attestation may occur only once when enabled. Subsequent attestation attempts will be rejected.

With TOFU, it is still possible for non-agent code to complete node attestation before SPIRE Agent can, however this condition is easily and quickly detectable as SPIRE Agent will fail to start, and both SPIRE Agent and SPIRE Server will log the occurrence. Such cases should be investigated as possible security incidents.

You also can require the port to be a trusted port that only trusted user such as root can open (port number < 1024).
43 changes: 42 additions & 1 deletion pkg/server/plugin/nodeattestor/httpchallenge/httpchallenge.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
"sync"

"github.com/hashicorp/hcl"
"github.com/hashicorp/go-hclog"
"github.com/spiffe/go-spiffe/v2/spiffeid"
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"
"github.com/spiffe/spire/pkg/common/catalog"
"github.com/spiffe/spire/pkg/common/plugin/httpchallenge"
nodeattestorbase "github.com/spiffe/spire/pkg/server/plugin/nodeattestor/base"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
Expand All @@ -39,21 +41,26 @@
allowNonRootPorts bool
dnsPatterns []*regexp.Regexp
agentNamePattern *regexp.Regexp
tofu bool
}

type Config struct {
DNSPatterns []string `hcl:"dns_patterns"`
RequiredPort *int `hcl:"required_port"`
AllowNonRootPorts *bool `hcl:"allow_non_root_ports"`
AgentPathTemplate string `hcl:"agent_path_template"`
TOFU *bool `hcl:"tofu"`
}

type Plugin struct {
nodeattestorbase.Base
nodeattestorv1.UnsafeNodeAttestorServer
configv1.UnsafeConfigServer

m sync.Mutex
config *configuration

log hclog.Logger
}

func New() *Plugin {
Expand Down Expand Up @@ -144,12 +151,19 @@
return status.Errorf(codes.Internal, "failed to make spiffe id: %v", err)
}


if config.tofu {
if err := p.AssessTOFU(stream.Context(), spiffeid.String(), p.log); err != nil {
return err
}
}

return stream.Send(&nodeattestorv1.AttestResponse{
Response: &nodeattestorv1.AttestResponse_AgentAttributes{
AgentAttributes: &nodeattestorv1.AgentAttributes{
SpiffeId: spiffeid.String(),
SelectorValues: buildSelectorValues(attestationData.HostName),
CanReattest: true,
CanReattest: !config.tofu,
},
},
})
Expand Down Expand Up @@ -195,18 +209,45 @@
allowNonRootPorts = *hclConfig.AllowNonRootPorts
}

tofu := true
if hclConfig.TOFU != nil {
tofu = *hclConfig.TOFU
}

mustUseTOFU := false
// User has explicitly asked for a required port that is untrusted
if hclConfig.RequiredPort != nil && *hclConfig.RequiredPort >= 1024 {

Check failure on line 219 in pkg/server/plugin/nodeattestor/httpchallenge/httpchallenge.go

View workflow job for this annotation

GitHub Actions / lint (linux)

ifElseChain: rewrite if-else to switch statement (gocritic)

Check failure on line 219 in pkg/server/plugin/nodeattestor/httpchallenge/httpchallenge.go

View workflow job for this annotation

GitHub Actions / lint (windows)

ifElseChain: rewrite if-else to switch statement (gocritic)
mustUseTOFU = true
// User has just chosen the defaults, any port is allowed
} else if hclConfig.AllowNonRootPorts == nil && hclConfig.RequiredPort == nil {
mustUseTOFU = true
// User explicitly set AllowNonRootPorts to true and no requried port specified
} else if hclConfig.AllowNonRootPorts != nil && *hclConfig.AllowNonRootPorts && hclConfig.RequiredPort == nil {
mustUseTOFU = true
}

if tofu == false && mustUseTOFU {

Check failure on line 229 in pkg/server/plugin/nodeattestor/httpchallenge/httpchallenge.go

View workflow job for this annotation

GitHub Actions / lint (linux)

S1002: should omit comparison to bool constant, can be simplified to `!tofu` (gosimple)

Check failure on line 229 in pkg/server/plugin/nodeattestor/httpchallenge/httpchallenge.go

View workflow job for this annotation

GitHub Actions / lint (windows)

S1002: should omit comparison to bool constant, can be simplified to `!tofu` (gosimple)
return nil, status.Errorf(codes.InvalidArgument, "you can not turn off trust on first use (TOFU) when non root ports are allowed")
kfox1111 marked this conversation as resolved.
Show resolved Hide resolved
}

p.setConfiguration(&configuration{
trustDomain: trustDomain,
pathTemplate: pathTemplate,
dnsPatterns: dnsPatterns,
requiredPort: hclConfig.RequiredPort,
allowNonRootPorts: allowNonRootPorts,
agentNamePattern: agentNamePattern,
tofu: tofu,
})

return &configv1.ConfigureResponse{}, nil
}

// SetLogger sets this plugin's logger
func (p *Plugin) SetLogger(log hclog.Logger) {
p.log = log
}

func (p *Plugin) getConfig() (*configuration, error) {
p.m.Lock()
defer p.m.Unlock()
Expand Down
Loading