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 minimal types for service account TokenRequest API #58027

Merged
merged 2 commits into from Feb 6, 2018

Conversation

mikedanese
Copy link
Member

@mikedanese mikedanese commented Jan 10, 2018

Adds parts of the types in kubernetes/community#1460. ValidityDuration is omitted because we are still discussing how to surface non-expiring tokens but it should be easy to add in a backwards compatibly.

#58790

@kubernetes/sig-auth-api-reviews

@k8s-ci-robot
Copy link
Contributor

@mikedanese: Adding do-not-merge/release-note-label-needed because the release note process has not been followed.

One of the following labels is required "release-note", "release-note-action-required", or "release-note-none".
Please see: https://github.com/kubernetes/community/blob/master/contributors/devel/pull-requests.md#write-release-notes-if-needed.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@k8s-ci-robot k8s-ci-robot added sig/auth Categorizes an issue or PR as relevant to SIG Auth. do-not-merge/release-note-label-needed Indicates that a PR should not merge because it's missing one of the release note labels. size/M Denotes a PR that changes 30-99 lines, ignoring generated files. kind/api-change Categorizes issue or PR as related to adding, removing, or otherwise changing an API cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. labels Jan 10, 2018

// TokenRequestSpec contains client provided parameters of a token request.
type TokenRequestSpec struct {
// Audiences are the intendend audiences of the token. A token issued
Copy link
Contributor

Choose a reason for hiding this comment

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

Describe what "audience" means, including a quick summary and then reference the real spec (JWT or whatever).

Copy link
Contributor

Choose a reason for hiding this comment

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

Subsequent PR would change TokenReview to accept audience?

@liggitt
Copy link
Member

liggitt commented Jan 10, 2018

I expected these types to start in a new version of authentication.k8s.io... v2alpha1, etc

@k8s-ci-robot k8s-ci-robot added size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. and removed size/M Denotes a PR that changes 30-99 lines, ignoring generated files. labels Jan 17, 2018
@mikedanese
Copy link
Member Author

@smarterclayton I planned to modify TokenRequest in a followup PR.

// ValidityDuration is the requested duration of validity of the request. The
// token issuer may return a token with a different validity duration so a
// client needs to check the 'expiration' field in a response.
ValidityDuration metav1.Duration
Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not sure how to cleanly represent in a TokenRequest that a token should never expire since I would like to default this field. Can we either:

  • use an annotation?
  • set a validity duration of 1000 years?

Copy link
Contributor

Choose a reason for hiding this comment

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

Hrm, definitely have never had this before. We could use the pointer for defaulting, but I don't think a negative duration is appropriate, and MaxInt duration is always ugly. If we set a duration of zero as never expire and leave it unset, would that cover it?

Copy link
Member Author

Choose a reason for hiding this comment

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

MaxInt is the openssl x509 approach to non-expiring. I dislike the use of sentinel values, but I think it's better then a NeverExpires bool.

Copy link
Member

Choose a reason for hiding this comment

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

collapsing the unexpiring case to "really really long expiration" does make the API simpler, if a little weird, and still maintains the possibility for a requester to ask for a 1000 year token and be given a 1 month one (reflected in status).

it removes the watershed division between the two types of tokens, which would make it hard to use a different signing key for eternal tokens, which @mikedanese had mentioned in passing

Copy link
Contributor

Choose a reason for hiding this comment

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

So the docs will say "if you don't want it to expire, set a really really high value, like a billion"?

I suspect people will just pick arbitrary values and set them (no one actually goes and looks up maxint). I guess that's fine, although it's not really an intent. I don't want to do IntOrString though.

In the future, if we want to tie the lifetime of the token to a pod, we wouldn't specify that via this API (it would be on the volume source), but something similar may apply. We could say:

type TokenExpirationType string
// Token never expires
const Forever TokenExpirationType = "Forever"
// User requests a time limit
const TimeBound TokenExpirationType = "TimeBound"
// Server determines how long this token should last
const ServerPreferred TokenExpirationType = "ServerPreferred"

type TokenRequestSpec struct {
  Expiration TokenExpirationType
  ExpirationSeconds *int64
}

The status would then have Expiration as a time. We could let presence of ExpirationSeconds default Expiration to TimeBound (although in other places that has caused problems, not sure here it does).

Side note: I wouldn't expect us to use duration here, we should be using seconds.

Copy link
Member Author

Choose a reason for hiding this comment

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

Using service account ID tokens as API access tokens is an abuse. Conflating these two ties our hands with respect to key rotation. If we want to support API access tokens, we should support it as a separate construct. They can still be tied to a service account but we should not tie them to a key that we want to rotate.

My goal here is to support the previous flow, while weening clients onto short lived ID tokens allowing operators to tighten max validity duration of both ID tokens and signing keys. We shouldn't advertise "if you don't want it to expire, set a really really high value, like a billion" in docs. Kubelet should just do it until old clients that depend on this behavior are no longer supported.

If we include "Never" as a valid expiration type clusters will either:

  • Never rotate their ID token signing keys
  • Not support "Never" tokens, and the API is not portable

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok. Then ExpirationSeconds *int64 with an arbitrary high value (our service account tokens today are 1 year).


// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// TokenRequest requests a token for a given service account.
Copy link
Contributor

Choose a reason for hiding this comment

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

To jordans comment, I do think this needs to either be in v1alpha1, or v2alpha1 (technically it could be v1alpha1 since this won't cause us to rev v1 authentication)

Copy link
Member

@liggitt liggitt Jan 19, 2018

Choose a reason for hiding this comment

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

this is tricky, since we're wanting a subresource in api/v1/serviceaccounts/token ... whatever surfaces there sticks forever (hence replicationcontrollers/scale being stuck at extensions/v1beta1 Scale forever)

Copy link
Member Author

Choose a reason for hiding this comment

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

What @liggitt said. I think the best approach is to use authentication.k8s.io/v1 and be pretty confident (e.g. by keeping the API minimal) when we move this feature from alpha to beta. We can then begin to move serviceaccount out of the main API group into authentication.k8s.io/v2alpha1 which will give us a chance to correct any problems we encounter.

Copy link
Contributor

Choose a reason for hiding this comment

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

The old "shrug, we can't solve a hard problem so we'll do the thing we tell people not to do" approach?

I agree the subresource is hard. Maybe we should just call the subresource alphatokenrequest to force it to be clear, and only promote once it's beta (to tokenrequest).

Copy link
Member Author

Choose a reason for hiding this comment

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

Even if we make an /alphatoken we can't support two versions without creating a new version of this API group and leaving v1 sparse. The /token subresource will be alpha feature guarded so having an /alphatoken path during alpha doesn't add much value unless will eventually /token accept a separate type and both are served simultaneously.

Copy link
Contributor

Choose a reason for hiding this comment

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

Since it's behind a gate we can punt on this.

@k8s-ci-robot k8s-ci-robot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. and removed size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. labels Jan 25, 2018
@smarterclayton
Copy link
Contributor

Just the one comment left then

@mikedanese mikedanese added the release-note-none Denotes a PR that doesn't merit a release note. label Feb 1, 2018
@mikedanese mikedanese removed the do-not-merge/release-note-label-needed Indicates that a PR should not merge because it's missing one of the release note labels. label Feb 1, 2018
@mikedanese
Copy link
Member Author

@smarterclayton fixed.


// BoundObjectRef is a reference to an object that the token will be bound to.
// The token will only be valid for as long as the bound objet exists.
BoundObjectRef *BoundObjectReference
Copy link
Contributor

Choose a reason for hiding this comment

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

Feels like a last minute nit, but why not have this just be an owner ref? Node access control?

Copy link
Member Author

@mikedanese mikedanese Feb 2, 2018

Choose a reason for hiding this comment

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

It's an interesting idea that hadn't occurred to me. Some problems i see with owners ref are we would like to enforce a single owner. Potentially thats the purpose of the Controller field.

As documented:

OwnerReference contains enough information to let you identify an owning
object. Currently, an owning object must be in the same namespace, so there
is no namespace field.

This seems vague enough that it might fit.

Copy link
Member Author

@mikedanese mikedanese Feb 5, 2018

Choose a reason for hiding this comment

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

Talking to @liggitt, this doesn't feel like a great fit for a few reasons:

  • Owners references are intended to aid object garbage collection. The semantics are "if all objects in this list are deleted, then this object should be deleted". The semantics we would want for this API are "If any object in this list is deleted, the token should be invalid".
  • We want to limit the number of bound objects, and right now we think we only want to support one. We would need to add specific validation to a generic field to support this.

I would prefer we don't overload owners references here.

// token issuer may return a token with a different validity duration so a
// client needs to check the 'expiration' field in a response.
// +optional
ValidityDuration *int64 `json:"validityDuration" protobuf:"bytes,2,opt,name=validityDuration"`
Copy link
Contributor

Choose a reason for hiding this comment

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

ExpirationSeconds, update the godoc to describe it, and change the status to also be ExpirationSeconds. Also, the godoc on status is also wrong.

Copy link
Member Author

Choose a reason for hiding this comment

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

One is a duration and one is a time. It's a bit confusing to have both with the same name.

Copy link
Contributor

Choose a reason for hiding this comment

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

If it's a time, then it should be a timestamp, and ExpirationTimestamp metav1.Time (akin to DeletionTimestamp). If it's the seconds remaining before expiration, then it should be ExpirationSeconds (like DeletionGracePeriodSeconds, I guess, although that is not calculated). I'm a bit confused why we would make this "seconds remaining before it expires" (which would require it to be virtual).

If it's really a time, I lean towards ExpirationTimestamp in status, in which case this should be ExpirationSeconds in spec (the number of seconds I want this token to last before expiration).

Copy link
Member Author

Choose a reason for hiding this comment

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

I would expect a user to request a duration of time for the token to be valid, (e.g. thirty minutes) and that the status return the time that the token will expire (e.g. unix epoch time 1517854484).

@mikedanese
Copy link
Member Author

@smarterclayton @liggitt fixed.

@smarterclayton
Copy link
Contributor

/lgtm

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Feb 5, 2018
@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: mikedanese, smarterclayton

The full list of commands accepted by this bot can be found here.

Needs approval from an approver in each of these OWNERS Files:

You can indicate your approval by writing /approve in a comment
You can cancel your approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Feb 5, 2018
@smarterclayton
Copy link
Contributor

We probably (before 1.10) need to clearly identity the api guarantees as part of the godoc for the mixed version types

@k8s-github-robot
Copy link

Automatic merge from submit-queue (batch tested with PRs 55986, 59375, 59334, 59348, 58027). If you want to cherry-pick this change to another branch, please follow the instructions here.

@k8s-github-robot k8s-github-robot merged commit 5aa68f5 into kubernetes:master Feb 6, 2018
@mikedanese mikedanese deleted the id-api branch February 6, 2018 05:23
@mikedanese mikedanese added this to Closed in Container Identity Jun 12, 2018
@mikedanese mikedanese moved this from Closed to Done in Container Identity Jun 12, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. kind/api-change Categorizes issue or PR as related to adding, removing, or otherwise changing an API lgtm "Looks good to me", indicates that a PR is ready to be merged. release-note-none Denotes a PR that doesn't merit a release note. sig/auth Categorizes an issue or PR as relevant to SIG Auth. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.
Projects
No open projects
Development

Successfully merging this pull request may close these issues.

None yet

5 participants