Skip to content

Commit

Permalink
Add more filtering options to entry count/show and agent count/list (#…
Browse files Browse the repository at this point in the history
…4714)

* add filtering options to count command

Signed-off-by: FedeNQ <fedenahuel07@gmail.com>

* add more fields

Signed-off-by: FedeNQ <fedenahuel07@gmail.com>

* Add filtering to entry & agent count/show/list commands

Signed-off-by: FedeNQ <fedenahuel07@gmail.com>

* fix lint

Signed-off-by: FedeNQ <fedenahuel07@gmail.com>

* add more unit test

Signed-off-by: FedeNQ <fedenahuel07@gmail.com>

* Change count & list for entries

Signed-off-by: FedeNQ <fedenahuel07@gmail.com>

* rollback

Signed-off-by: FedeNQ <fedenahuel07@gmail.com>

* fix

Signed-off-by: FedeNQ <fedenahuel07@gmail.com>

* fix lint

Signed-off-by: FedeNQ <fedenahuel07@gmail.com>

* update go.mod & go.sum

Signed-off-by: FedeNQ <fedenahuel07@gmail.com>

* fix windows message

Signed-off-by: FedeNQ <fedenahuel07@gmail.com>

* update agent & entry message

Signed-off-by: FedeNQ <fedenahuel07@gmail.com>

* update agent message

Signed-off-by: FedeNQ <fedenahuel07@gmail.com>

* count entries & agent now uses pagination

Signed-off-by: FedeNQ <fedenahuel07@gmail.com>

* remove comment

Signed-off-by: FedeNQ <fedenahuel07@gmail.com>

* fix lint

Signed-off-by: FedeNQ <fedenahuel07@gmail.com>

* rollback

Signed-off-by: FedeNQ <fedenahuel07@gmail.com>

---------

Signed-off-by: FedeNQ <fedenahuel07@gmail.com>
Signed-off-by: Federico Nahuel Quijada <63385953+FedeNQ@users.noreply.github.com>
  • Loading branch information
FedeNQ authored Mar 27, 2024
1 parent 0d28fe8 commit 0727fa6
Show file tree
Hide file tree
Showing 24 changed files with 1,065 additions and 78 deletions.
20 changes: 20 additions & 0 deletions cmd/spire-server/cli/agent/agent_posix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ var (
Path to the SPIRE Server API socket (default "/tmp/spire-server/private/api.sock")
`
listUsage = `Usage of agent list:
-attestationType string
Filter by attestation type, like join_token or x509pop.
-banned value
Filter based on string received, 'true': banned agents, 'false': not banned agents, other value will return all.
-canReattest value
Filter based on string received, 'true': agents that can reattest, 'false': agents that can't reattest, other value will return all.
-expiresBefore string
Filter by expiration time (format: "2006-01-02 15:04:05 -0700 -07")
-matchSelectorsOn string
The match mode used when filtering by selectors. Options: exact, any, superset and subset (default "superset")
-output value
Expand All @@ -40,8 +48,20 @@ var (
The SPIFFE ID of the agent to evict (agent identity)
`
countUsage = `Usage of agent count:
-attestationType string
Filter by attestation type, like join_token or x509pop.
-banned value
Filter based on string received, 'true': banned agents, 'false': not banned agents, other value will return all.
-canReattest value
Filter based on string received, 'true': agents that can reattest, 'false': agents that can't reattest, other value will return all.
-expiresBefore string
Filter by expiration time (format: "2006-01-02 15:04:05 -0700 -07")
-matchSelectorsOn string
The match mode used when filtering by selectors. Options: exact, any, superset and subset (default "superset")
-output value
Desired output format (pretty, json); default: pretty.
-selector value
A colon-delimited type:value selector. Can be used more than once
-socketPath string
Path to the SPIRE Server API socket (default "/tmp/spire-server/private/api.sock")
`
Expand Down
51 changes: 51 additions & 0 deletions cmd/spire-server/cli/agent/agent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,12 @@ func TestCount(t *testing.T) {
expectedReturnCode: 1,
expectedStderr: common.AddrError,
},
{
name: "Count by expiresBefore: month out of range",
args: []string{"-expiresBefore", "2001-13-05"},
expectedReturnCode: 1,
expectedStderr: "Error: date is not valid: parsing time \"2001-13-05\": month out of range\n",
},
} {
for _, format := range availableFormats {
t.Run(fmt.Sprintf("%s using %s format", tt.name, format), func(t *testing.T) {
Expand Down Expand Up @@ -389,6 +395,45 @@ func TestList(t *testing.T) {
expectedStdoutPretty: "Found 1 attested agent:\n\nSPIFFE ID : spiffe://example.org/spire/agent/agent1",
expectedStdoutJSON: `{"agents":[{"id":{"trust_domain":"example.org","path":"/spire/agent/agent1"},"attestation_type":"","x509svid_serial_number":"","x509svid_expires_at":"0","selectors":[],"banned":false,"can_reattest":true}],"next_page_token":""}`,
},
{
name: "by expiresBefore",
args: []string{"-expiresBefore", "2000-01-01 15:04:05 -0700 -07"},
expectReq: &agentv1.ListAgentsRequest{
Filter: &agentv1.ListAgentsRequest_Filter{
ByExpiresBefore: "2000-01-01 15:04:05 -0700 -07",
},
PageSize: 1000,
},
existentAgents: testAgents,
expectedStdoutPretty: "Found 1 attested agent:\n\nSPIFFE ID : spiffe://example.org/spire/agent/agent1",
expectedStdoutJSON: `{"agents":[{"id":{"trust_domain":"example.org","path":"/spire/agent/agent1"},"attestation_type":"","x509svid_serial_number":"","x509svid_expires_at":"0","selectors":[],"banned":false,"can_reattest":true}],"next_page_token":""}`,
},
{
name: "by banned",
args: []string{"-banned", "true"},
expectReq: &agentv1.ListAgentsRequest{
Filter: &agentv1.ListAgentsRequest_Filter{
ByBanned: wrapperspb.Bool(true),
},
PageSize: 1000,
},
existentAgents: testAgentsWithBanned,
expectedStdoutPretty: "Found 1 attested agent:\n\nSPIFFE ID : spiffe://example.org/spire/agent/banned",
expectedStdoutJSON: `{"agents":[{"id":{"trust_domain":"example.org","path":"/spire/agent/banned"},"attestation_type":"","x509svid_serial_number":"","x509svid_expires_at":"0","selectors":[],"banned":true,"can_reattest":false}],"next_page_token":""}`,
},
{
name: "by canReattest",
args: []string{"-canReattest", "true"},
expectReq: &agentv1.ListAgentsRequest{
Filter: &agentv1.ListAgentsRequest_Filter{
ByCanReattest: wrapperspb.Bool(true),
},
PageSize: 1000,
},
existentAgents: testAgents,
expectedStdoutPretty: "Found 1 attested agent:\n\nSPIFFE ID : spiffe://example.org/spire/agent/agent1",
expectedStdoutJSON: `{"agents":[{"id":{"trust_domain":"example.org","path":"/spire/agent/agent1"},"attestation_type":"","x509svid_serial_number":"","x509svid_expires_at":"0","selectors":[],"banned":false,"can_reattest":true}],"next_page_token":""}`,
},
{
name: "List by selectors: Invalid matcher",
args: []string{"-selector", "foo:bar", "-selector", "bar:baz", "-matchSelectorsOn", "NO-MATCHER"},
Expand All @@ -407,6 +452,12 @@ func TestList(t *testing.T) {
expectedReturnCode: 1,
expectedStderr: common.AddrError,
},
{
name: "List by expiresBefore: month out of range",
args: []string{"-expiresBefore", "2001-13-05"},
expectedReturnCode: 1,
expectedStderr: "Error: date is not valid: parsing time \"2001-13-05\": month out of range\n",
},
} {
for _, format := range availableFormats {
t.Run(fmt.Sprintf("%s using %s format", tt.name, format), func(t *testing.T) {
Expand Down
20 changes: 20 additions & 0 deletions cmd/spire-server/cli/agent/agent_windows_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ var (
Desired output format (pretty, json); default: pretty.
`
listUsage = `Usage of agent list:
-attestationType string
Filter by attestation type, like join_token or x509pop.
-banned value
Filter based on string received, 'true': banned agents, 'false': not banned agents, other value will return all.
-canReattest value
Filter based on string received, 'true': agents that can reattest, 'false': agents that can't reattest, other value will return all.
-expiresBefore string
Filter by expiration time (format: "2006-01-02 15:04:05 -0700 -07")
-matchSelectorsOn string
The match mode used when filtering by selectors. Options: exact, any, superset and subset (default "superset")
-namedPipeName string
Expand All @@ -40,10 +48,22 @@ var (
The SPIFFE ID of the agent to evict (agent identity)
`
countUsage = `Usage of agent count:
-attestationType string
Filter by attestation type, like join_token or x509pop.
-banned value
Filter based on string received, 'true': banned agents, 'false': not banned agents, other value will return all.
-canReattest value
Filter based on string received, 'true': agents that can reattest, 'false': agents that can't reattest, other value will return all.
-expiresBefore string
Filter by expiration time (format: "2006-01-02 15:04:05 -0700 -07")
-matchSelectorsOn string
The match mode used when filtering by selectors. Options: exact, any, superset and subset (default "superset")
-namedPipeName string
Pipe name of the SPIRE Server API named pipe (default "\\spire-server\\private\\api")
-output value
Desired output format (pretty, json); default: pretty.
-selector value
A colon-delimited type:value selector. Can be used more than once
`
showUsage = `Usage of agent show:
-namedPipeName string
Expand Down
86 changes: 84 additions & 2 deletions cmd/spire-server/cli/agent/count.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,39 @@ import (
"errors"
"flag"
"fmt"
"time"

"github.com/mitchellh/cli"
agentv1 "github.com/spiffe/spire-api-sdk/proto/spire/api/server/agent/v1"
"github.com/spiffe/spire-api-sdk/proto/spire/api/types"
"github.com/spiffe/spire/cmd/spire-server/util"
commoncli "github.com/spiffe/spire/pkg/common/cli"
"github.com/spiffe/spire/pkg/common/cliprinter"
"google.golang.org/protobuf/types/known/wrapperspb"
)

type countCommand struct {
env *commoncli.Env
// Type and value are delimited by a colon (:)
// ex. "unix:uid:1000" or "spiffe_id:spiffe://example.org/foo"
selectors commoncli.StringsFlag

// Match used when filtering by selectors
matchSelectorsOn string

// Filters agents to those that are banned.
banned commoncli.BoolFlag

// Filters agents by those expires before.
expiresBefore string

// Filters agents to those matching the attestation type.
attestationType string

// Filters agents that can re-attest.
canReattest commoncli.BoolFlag

env *commoncli.Env

printer cliprinter.Printer
}

Expand All @@ -39,8 +62,61 @@ func (*countCommand) Synopsis() string {

// Run counts attested agents
func (c *countCommand) Run(ctx context.Context, _ *commoncli.Env, serverClient util.ServerClient) error {
filter := &agentv1.CountAgentsRequest_Filter{}
if len(c.selectors) > 0 {
matchBehavior, err := parseToSelectorMatch(c.matchSelectorsOn)
if err != nil {
return err
}

selectors := make([]*types.Selector, len(c.selectors))
for i, sel := range c.selectors {
selector, err := util.ParseSelector(sel)
if err != nil {
return fmt.Errorf("error parsing selector %q: %w", sel, err)
}
selectors[i] = selector
}
filter.BySelectorMatch = &types.SelectorMatch{
Selectors: selectors,
Match: matchBehavior,
}
}

if c.expiresBefore != "" {
// Parse the time string into a time.Time object
_, err := time.Parse("2006-01-02 15:04:05 -0700 -07", c.expiresBefore)
if err != nil {
return fmt.Errorf("date is not valid: %w", err)
}
filter.ByExpiresBefore = c.expiresBefore
}

if c.attestationType != "" {
filter.ByAttestationType = c.attestationType
}

// 0: all, 1: can't reattest, 2: can reattest
if c.canReattest == 1 {
filter.ByCanReattest = wrapperspb.Bool(false)
}
if c.canReattest == 2 {
filter.ByCanReattest = wrapperspb.Bool(true)
}

// 0: all, 1: no-banned, 2: banned
if c.banned == 1 {
filter.ByBanned = wrapperspb.Bool(false)
}
if c.banned == 2 {
filter.ByBanned = wrapperspb.Bool(true)
}

agentClient := serverClient.NewAgentClient()
countResponse, err := agentClient.CountAgents(ctx, &agentv1.CountAgentsRequest{})

countResponse, err := agentClient.CountAgents(ctx, &agentv1.CountAgentsRequest{
Filter: filter,
})
if err != nil {
return err
}
Expand All @@ -49,6 +125,12 @@ func (c *countCommand) Run(ctx context.Context, _ *commoncli.Env, serverClient u
}

func (c *countCommand) AppendFlags(fs *flag.FlagSet) {
fs.Var(&c.selectors, "selector", "A colon-delimited type:value selector. Can be used more than once")
fs.StringVar(&c.attestationType, "attestationType", "", "Filter by attestation type, like join_token or x509pop.")
fs.Var(&c.canReattest, "canReattest", "Filter based on string received, 'true': agents that can reattest, 'false': agents that can't reattest, other value will return all.")
fs.Var(&c.banned, "banned", "Filter based on string received, 'true': banned agents, 'false': not banned agents, other value will return all.")
fs.StringVar(&c.expiresBefore, "expiresBefore", "", "Filter by expiration time (format: \"2006-01-02 15:04:05 -0700 -07\")")
fs.StringVar(&c.matchSelectorsOn, "matchSelectorsOn", "superset", "The match mode used when filtering by selectors. Options: exact, any, superset and subset")
cliprinter.AppendFlagWithCustomPretty(&c.printer, fs, c.env, prettyPrintCount)
}

Expand Down
57 changes: 53 additions & 4 deletions cmd/spire-server/cli/agent/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,32 @@ import (
commoncli "github.com/spiffe/spire/pkg/common/cli"
"github.com/spiffe/spire/pkg/common/cliprinter"
"github.com/spiffe/spire/pkg/common/idutil"
"google.golang.org/protobuf/types/known/wrapperspb"
)

type listCommand struct {
env *commoncli.Env
// Type and value are delimited by a colon (:)
// ex. "unix:uid:1000" or "spiffe_id:spiffe://example.org/foo"
selectors commoncli.StringsFlag
// Match used when filtering agents by selectors

// Match used when filtering by selectors
matchSelectorsOn string
printer cliprinter.Printer

// Filters agents to those that are banned.
banned commoncli.BoolFlag

// Filters agents by those expires before.
expiresBefore string

// Filters agents to those matching the attestation type.
attestationType string

// Filters agents that can re-attest.
canReattest commoncli.BoolFlag

env *commoncli.Env

printer cliprinter.Printer
}

// NewListCommand creates a new "list" subcommand for "agent" command.
Expand Down Expand Up @@ -68,6 +84,35 @@ func (c *listCommand) Run(ctx context.Context, _ *commoncli.Env, serverClient ut
}
}

if c.expiresBefore != "" {
// Parse the time string into a time.Time object
_, err := time.Parse("2006-01-02 15:04:05 -0700 -07", c.expiresBefore)
if err != nil {
return fmt.Errorf("date is not valid: %w", err)
}
filter.ByExpiresBefore = c.expiresBefore
}

if c.attestationType != "" {
filter.ByAttestationType = c.attestationType
}

// 0: all, 1: can't reattest, 2: can reattest
if c.canReattest == 1 {
filter.ByCanReattest = wrapperspb.Bool(false)
}
if c.canReattest == 2 {
filter.ByCanReattest = wrapperspb.Bool(true)
}

// 0: all, 1: no-banned, 2: banned
if c.banned == 1 {
filter.ByBanned = wrapperspb.Bool(false)
}
if c.banned == 2 {
filter.ByBanned = wrapperspb.Bool(true)
}

agentClient := serverClient.NewAgentClient()

pageToken := ""
Expand All @@ -91,8 +136,12 @@ func (c *listCommand) Run(ctx context.Context, _ *commoncli.Env, serverClient ut
}

func (c *listCommand) AppendFlags(fs *flag.FlagSet) {
fs.StringVar(&c.matchSelectorsOn, "matchSelectorsOn", "superset", "The match mode used when filtering by selectors. Options: exact, any, superset and subset")
fs.Var(&c.selectors, "selector", "A colon-delimited type:value selector. Can be used more than once")
fs.StringVar(&c.attestationType, "attestationType", "", "Filter by attestation type, like join_token or x509pop.")
fs.Var(&c.canReattest, "canReattest", "Filter based on string received, 'true': agents that can reattest, 'false': agents that can't reattest, other value will return all.")
fs.Var(&c.banned, "banned", "Filter based on string received, 'true': banned agents, 'false': not banned agents, other value will return all.")
fs.StringVar(&c.expiresBefore, "expiresBefore", "", "Filter by expiration time (format: \"2006-01-02 15:04:05 -0700 -07\")")
fs.StringVar(&c.matchSelectorsOn, "matchSelectorsOn", "superset", "The match mode used when filtering by selectors. Options: exact, any, superset and subset")
cliprinter.AppendFlagWithCustomPretty(&c.printer, fs, c.env, prettyPrintAgents)
}

Expand Down
Loading

0 comments on commit 0727fa6

Please sign in to comment.