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

Fix Assume Start Time Validation #39008

Merged
merged 5 commits into from Mar 14, 2024
Merged

Fix Assume Start Time Validation #39008

merged 5 commits into from Mar 14, 2024

Conversation

kimlisa
Copy link
Contributor

@kimlisa kimlisa commented Mar 6, 2024

part of #35436

While testing i ran into some issues. Fixes the following:

  • Set modified start time from tctl requests approve (we allowed modifying in client, but was not being set in the backend)
  • Removed incorrect validation in the client, and placed validation near backend (this also avoids us having to repeat validation for other clients like teleterm and web)
  • Correct calculation of maxest start time allowed in the error message when user goes too far
  • Correct start time validation
    • Start time should be after or equal to request creation time
      • Note that creation time will always be set before validation starts so it’ll never be a zero value
        • When creating, we validate after the creation time was set
        • When reviewing or updating, we validate after we retrieve the created request
    • Start time should be before access expiry
    • Start time cannot exceed constants.MaxAssumeStartTimeDuration FROM the creation date (eg: if the const was 1 week max, then the start time cannot exceed one week from creation time, even if access expiry is set for 2 weeks)
  • When printing tsh request, use local date time format to display start time, since access expiry also uses the same format (it was confusing to display two different time formats)

Extra context, we allow modifying assume start time in the following places and is where the validations are placed:

  • CreateAccessRequestV2
  • SubmitAccessReview
  • SetAccessRequestState (used with tctl)

Manual Testing:

# Starting profile:
> Profile URL:        https://proxy.0.0.0.0.nip.io:3080
  Logged in as:       sevy
  Cluster:            im-a-cluster-name
  Roles:              requester
  Kubernetes:         disabled
  Valid until:        2024-03-06 10:59:38 -0800 PST [valid for 12h0m0s]
  Extensions:         login-ip, permit-port-forwarding, permit-pty, private-key-policy

# requesting pass the expiry
$ ./tsh request create --roles=access --assume-start-time=2024-03-09T23:20:50.52Z 
Creating request...
ERROR: assume start time cannot equal or exceed access expiry time at: "2024-03-06T18:59:37Z"

# requesting before the creation time
$ ./tsh request create --roles=access --assume-start-time=2023-03-09T23:20:50.52Z 
Creating request...
ERROR: assume start time has to be greater than: "2024-03-06T07:00:06Z"

# requesting too far into future (currently the const limits to 1 week)
# the max duration was increased in the role to 14 days
$ ./tsh request create --roles=access --assume-start-time=2024-03-13T23:20:50.52Z --max-duration=12d
Creating request...
ERROR: assume start time is too far in the future, latest time allowed "2024-03-13T07:04:25Z"

# valid request and consistent time display
$ ./tsh request create --roles=access --assume-start-time=2024-03-10T23:20:50.52Z --max-duration=13d
Creating request...
Request ID:        018e1294-df3d-7ae5-a00d-7a964e39a54f 
Username:          sevy                                 
Roles:             access                               
Reason:            [none]                               
Reviewers:         [none] (suggested)                   
Access Expires:    2024-03-19 00:05:30                  
Assume Start Time: 2024-03-10 16:20:50                  
Status:            PENDING  

Waiting for request approval...

Approval received, getting updated certificates...

# approved with `tctl requests approve` with a modified start time
ERROR: access request "018e1294-df3d-7ae5-a00d-7a964e39a54f" can not be assumed until 2024-03-07 23:20:50.52 +0000 UTC

changelog: Fixes allowing invalid access request start time date to be set

@kimlisa kimlisa requested a review from jakule March 6, 2024 07:23
@github-actions github-actions bot requested a review from ryanclark March 6, 2024 07:23
@github-actions github-actions bot added size/md tctl tctl - Teleport admin tool tsh tsh - Teleport's command line tool for logging into nodes running Teleport. labels Mar 6, 2024
@kimlisa kimlisa requested review from fspmarshall and removed request for ryanclark and capnspacehook March 6, 2024 07:23
@kimlisa kimlisa changed the title Fix Assume Start Time Fix Assume Start Time Validation Mar 6, 2024
@kimlisa
Copy link
Contributor Author

kimlisa commented Mar 6, 2024

my changelog is lame... i'm still thinking on making it clearer, or should I even add one? i highly doubt anyone's using this feature yet

@gravitational gravitational deleted a comment from github-actions bot Mar 6, 2024
@gravitational gravitational deleted a comment from github-actions bot Mar 6, 2024
@kimlisa kimlisa force-pushed the lisa/fix-assume-start-time branch from b3d57f8 to 14faaba Compare March 6, 2024 07:54
api/types/access_request.go Outdated Show resolved Hide resolved
api/types/access_request.go Outdated Show resolved Hide resolved
)

func TestAssertAccessRequestImplementsResourceWithLabels(t *testing.T) {
ar, err := NewAccessRequest("test", "test", "test")
require.NoError(t, err)
require.Implements(t, (*ResourceWithLabels)(nil), ar)
}

func TestValidateAssumeStartTime(t *testing.T) {
clock := clockwork.NewFakeClock()
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think you really need a fake clock here, as the test is really about working with arbitrary time.Time values.

api/types/access_request_test.go Outdated Show resolved Hide resolved

t.Cleanup(func() { require.NoError(t, requesterClient.Close()) })

clock := clockwork.NewFakeClock()
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do you need this clock? The clock that your fake server is using is going to be a different clock anyway.

lib/auth/access_request_test.go Outdated Show resolved Hide resolved
lib/auth/auth.go Outdated Show resolved Hide resolved
tool/tsh/common/access_request.go Show resolved Hide resolved
@kimlisa kimlisa requested a review from zmb3 March 6, 2024 19:33
@kimlisa kimlisa force-pushed the lisa/fix-assume-start-time branch 2 times, most recently from 4d04132 to 9852ae8 Compare March 6, 2024 20:04
Copy link
Contributor

@jakule jakule left a comment

Choose a reason for hiding this comment

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

A few nits. Overall LGTM


func TestValidateAssumeStartTime(t *testing.T) {
creation := time.Now().UTC()
day := 24 * time.Hour
Copy link
Contributor

Choose a reason for hiding this comment

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

nit:

Suggested change
day := 24 * time.Hour
const day = 24 * time.Hour

{
name: "start time too far in the future",
startTime: creation.Add(constants.MaxAssumeStartDuration + (1 * day)),
errCheck: func(tt require.TestingT, err error, i ...interface{}) {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit:

Suggested change
errCheck: func(tt require.TestingT, err error, i ...interface{}) {
errCheck: func(tt require.TestingT, err error, i ...any) {

}{
{
name: "start time too far in the future",
startTime: creation.Add(constants.MaxAssumeStartDuration + (1 * day)),
Copy link
Contributor

Choose a reason for hiding this comment

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

nit:

Suggested change
startTime: creation.Add(constants.MaxAssumeStartDuration + (1 * day)),
startTime: creation.Add(constants.MaxAssumeStartDuration + day),

createdRequest types.AccessRequest
}

func createAccessRequestWithStartTime(t *testing.T) accessRequestWithStartTime {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: You can add t.Helper() to mark this as a helper function.

@@ -644,7 +644,7 @@ func TestReviewThresholds(t *testing.T) {
propose: approve,
assumeStartTime: clock.Now().UTC().Add(10000 * time.Hour),
errCheck: func(tt require.TestingT, err error, i ...interface{}) {
require.ErrorIs(tt, err, trace.BadParameter("request start time is after expiry"), i...)
require.Contains(tt, err.Error(), "assume start time must be prior to access expiry time", i...)
Copy link
Contributor

Choose a reason for hiding this comment

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

Use require.ErrorContains(t, err, "Error message...") as nil passed here will panic at e.Error() without any sensible error message.

Copy link
Collaborator

@zmb3 zmb3 left a comment

Choose a reason for hiding this comment

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

Approved with suggestions.

func ValidateAssumeStartTime(assumeStartTime time.Time, accessExpiry time.Time, creationTime time.Time) error {
// Guard against requesting a start time before the request creation time.
if assumeStartTime.Before(creationTime) {
return trace.BadParameter("assume start time has to be after: %q", creationTime.Format(time.RFC3339))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
return trace.BadParameter("assume start time has to be after: %q", creationTime.Format(time.RFC3339))
return trace.BadParameter("assume start time has to be after %v", creationTime.Format(time.RFC3339))

I don't know that quoting the creation time is necessary. The quote helps if we want to be able to identify an empty string, but formatting a time will always product a non-empty string.

I also don't think : is necessary - just make it read like a normal sentence.

(don't forget to update your tests if you decide to accept these suggestions)

}
// Guard against requesting a start time after access expiry.
if assumeStartTime.After(accessExpiry) || assumeStartTime.Equal(accessExpiry) {
return trace.BadParameter("assume start time must be prior to access expiry time at: %q",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
return trace.BadParameter("assume start time must be prior to access expiry time at: %q",
return trace.BadParameter("assume start time must be prior to access expiry time at %v",

// should be on or before constants.MaxAssumeStartDuration.
maxAssumableStartTime := creationTime.Add(constants.MaxAssumeStartDuration)
if maxAssumableStartTime.Before(accessExpiry) && assumeStartTime.After(maxAssumableStartTime) {
return trace.BadParameter("assume start time is too far in the future, latest time allowed %q",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
return trace.BadParameter("assume start time is too far in the future, latest time allowed %q",
return trace.BadParameter("assume start time is too far in the future, latest time allowed is %v",

name: "start time too far in the future",
startTime: creation.Add(constants.MaxAssumeStartDuration + day),
errCheck: func(tt require.TestingT, err error, i ...any) {
require.True(tt, trace.IsBadParameter(err), "expected bad parameter, got %v", err)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
require.True(tt, trace.IsBadParameter(err), "expected bad parameter, got %v", err)

The test still holds if you remove this line, right? (same below)

},
}
for _, tc := range testCases {
review.Review.AssumeStartTime = &tc.startTime
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you use t.Run() here to run proper subtests? Otherwise if this test fails we will just see that there was an error on line 1603 and won't be obvious which of the test cases actually failed.

(same goes for below)

The following allows modifying the start time and is where
validation is placed:

- CreateAccessRequestV2
- SubmitAccessReview
- SetAccessRequestState (used with tctl)
@kimlisa kimlisa added this pull request to the merge queue Mar 14, 2024
Merged via the queue into master with commit c04ea7f Mar 14, 2024
38 checks passed
@kimlisa kimlisa deleted the lisa/fix-assume-start-time branch March 14, 2024 03:55
@public-teleport-github-review-bot

@kimlisa See the table below for backport results.

Branch Result
branch/v14 Failed
branch/v15 Failed

kimlisa added a commit that referenced this pull request Mar 14, 2024
kimlisa added a commit that referenced this pull request Mar 14, 2024
github-merge-queue bot pushed a commit that referenced this pull request Mar 23, 2024
* Fix Assume Start Time Validation (#39008)

* Remove checking for max assume start time test (same as max duration)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport/branch/v14 backport/branch/v15 size/md tctl tctl - Teleport admin tool tsh tsh - Teleport's command line tool for logging into nodes running Teleport.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants