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

[v14] Fix accesslist tctl #36572

Merged
merged 3 commits into from Jan 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions api/types/accesslist/accesslist.go
Expand Up @@ -450,6 +450,9 @@ func (a *Audit) UnmarshalJSON(data []byte) error {
return trace.Wrap(err)
}

if audit.NextAuditDate == "" {
return nil
}
var err error
a.NextAuditDate, err = time.Parse(time.RFC3339Nano, audit.NextAuditDate)
if err != nil {
Expand Down
68 changes: 53 additions & 15 deletions api/types/accesslist/accesslist_test.go
Expand Up @@ -182,27 +182,65 @@ func TestAuditMarshaling(t *testing.T) {
}

func TestAuditUnmarshaling(t *testing.T) {
raw := map[string]interface{}{
"next_audit_date": "2023-02-02T00:00:00Z",
"recurrence": map[string]interface{}{
"frequency": "3 months",
"day_of_month": "1",
tests := []struct {
name string
input map[string]interface{}
expectedNextAudit time.Time
expectedRecurrence Recurrence
expectedNotificationStart time.Duration
}{
{
name: "with next_audit_date",
input: map[string]interface{}{
"next_audit_date": "2023-02-02T00:00:00Z",
"recurrence": map[string]interface{}{
"frequency": "3 months",
"day_of_month": "1",
},
"notifications": map[string]interface{}{
"start": twoWeeks.String(),
},
},
expectedNextAudit: time.Date(2023, 02, 02, 0, 0, 0, 0, time.UTC),
expectedRecurrence: Recurrence{
Frequency: ThreeMonths,
DayOfMonth: FirstDayOfMonth,
},
expectedNotificationStart: twoWeeks,
},
"notifications": map[string]interface{}{
"start": twoWeeks.String(),
{
name: "without next_audit_date",
input: map[string]interface{}{
"recurrence": map[string]interface{}{
"frequency": "3 months",
"day_of_month": "1",
},
"notifications": map[string]interface{}{
"start": twoWeeks.String(),
},
},
expectedNextAudit: time.Time{},
expectedRecurrence: Recurrence{
Frequency: ThreeMonths,
DayOfMonth: FirstDayOfMonth,
},
expectedNotificationStart: twoWeeks,
},
}

data, err := json.Marshal(&raw)
require.NoError(t, err)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
data, err := json.Marshal(&tt.input)
require.NoError(t, err)

var audit Audit
require.NoError(t, json.Unmarshal(data, &audit))
var audit Audit
require.NoError(t, json.Unmarshal(data, &audit))

require.Equal(t, time.Date(2023, 02, 02, 0, 0, 0, 0, time.UTC), audit.NextAuditDate)
require.Equal(t, ThreeMonths, audit.Recurrence.Frequency)
require.Equal(t, FirstDayOfMonth, audit.Recurrence.DayOfMonth)
require.Equal(t, twoWeeks, audit.Notifications.Start)
require.Equal(t, tt.expectedNextAudit, audit.NextAuditDate)
require.Equal(t, tt.expectedRecurrence, audit.Recurrence)
require.Equal(t, tt.expectedNotificationStart, audit.Notifications.Start)
})
}
}

func TestAccessListDefaults(t *testing.T) {
Expand Down
23 changes: 18 additions & 5 deletions docs/pages/access-controls/access-lists/reference.mdx
Expand Up @@ -72,11 +72,24 @@ spec:
# audit defines how frequently an Access List and its membership must be audited, along
# with the next audit date.
audit:
# Audit frequency defaults to 6 months. Format to golang's time.ParseDuration function:
# https://pkg.go.dev/time#ParseDuration
frequency: 4380h
recurrence:
# Frequency is the frequency between access list reviews.
# Defaults to 6months.
# Possible values are: 1month, 3months, 6months, 1year
frequency: 6months
# DayOfMonth is the day of month subsequent reviews will be scheduled on.
# Defaults to 1.
# Possible values are: 1, 15, last
day_of_month: "1"
# The next time this Access List must be audited by.
next_audit_date: "2024-01-01T00:00:00Z"
# If not set, the next audit date will be picked up automatically.
notifications:
# When the access-request plugins will start to notify before the audit
# deadline. Format to golang's time.ParseDuration function:
# https://pkg.go.dev/time#ParseDuration
# Defaults to two weeks.
start: 336h # two weeks
next_audit_date: "2025-01-01T00:00:00Z"
description: "A description of the Access List and its purpose"
# owners are a list of Teleport users who own the Access List. Provided the owners
# meet the ownership requirements, these users can control membership requirements
Expand Down Expand Up @@ -126,4 +139,4 @@ above) and run `tctl create <filename>`. Access Lists can be updated by using `t
`tctl` also supports a subset of Access List focused commands under the `tctl acl` subcommand.
Through these you can list Access Lists, get information about a particular Access Lists, and manage
Access List users. To see more details, run `tctl acl --help`. More detail can be seen in the
[CLI Reference](../../reference/cli.mdx).
[CLI Reference](../../reference/cli.mdx).
27 changes: 27 additions & 0 deletions tool/tctl/common/collection.go
Expand Up @@ -30,6 +30,7 @@ import (
devicepb "github.com/gravitational/teleport/api/gen/proto/go/teleport/devicetrust/v1"
loginrulepb "github.com/gravitational/teleport/api/gen/proto/go/teleport/loginrule/v1"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/api/types/accesslist"
"github.com/gravitational/teleport/api/types/discoveryconfig"
"github.com/gravitational/teleport/api/types/externalauditstorage"
"github.com/gravitational/teleport/api/types/secreports"
Expand Down Expand Up @@ -1320,3 +1321,29 @@ func (c *serverInfoCollection) writeText(w io.Writer, verbose bool) error {
_, err := t.AsBuffer().WriteTo(w)
return trace.Wrap(err)
}

type accessListCollection struct {
accessLists []*accesslist.AccessList
}

func (c *accessListCollection) resources() []types.Resource {
r := make([]types.Resource, len(c.accessLists))
for i, resource := range c.accessLists {
r[i] = resource
}
return r
}

func (c *accessListCollection) writeText(w io.Writer, verbose bool) error {
t := asciitable.MakeTable([]string{"Name", "Title", "Review Frequency", "Next Audit Date"})
for _, al := range c.accessLists {
t.AddRow([]string{
al.GetName(),
al.Spec.Title,
al.Spec.Audit.Recurrence.Frequency.String(),
al.Spec.Audit.NextAuditDate.Format(time.RFC822),
})
}
_, err := t.AsBuffer().WriteTo(w)
return trace.Wrap(err)
}
11 changes: 11 additions & 0 deletions tool/tctl/common/resource_command.go
Expand Up @@ -42,6 +42,7 @@ import (
loginrulepb "github.com/gravitational/teleport/api/gen/proto/go/teleport/loginrule/v1"
"github.com/gravitational/teleport/api/internalutils/stream"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/api/types/accesslist"
"github.com/gravitational/teleport/api/types/discoveryconfig"
"github.com/gravitational/teleport/api/types/externalauditstorage"
"github.com/gravitational/teleport/api/types/installers"
Expand Down Expand Up @@ -2270,6 +2271,16 @@ func (rc *ResourceCommand) getCollection(ctx context.Context, client auth.Client
return nil, trace.Wrap(err)
}
return &serverInfoCollection{serverInfos: serverInfos}, nil
case types.KindAccessList:
if rc.ref.Name != "" {
resource, err := client.AccessListClient().GetAccessList(ctx, rc.ref.Name)
if err != nil {
return nil, trace.Wrap(err)
}
return &accessListCollection{accessLists: []*accesslist.AccessList{resource}}, nil
}
accessLists, err := client.AccessListClient().GetAccessLists(ctx)
return &accessListCollection{accessLists: accessLists}, trace.Wrap(err)
}
return nil, trace.BadParameter("getting %q is not supported", rc.ref.String())
}
Expand Down