-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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 token list/delete endpoints #42402
Conversation
lib/web/ui/join_token.go
Outdated
// Id is the name of the token | ||
Id string `json:"id"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Id is the name of the token | |
Id string `json:"id"` | |
// ID is the name of the token | |
ID string `json:"id"` |
lib/web/ui/join_token.go
Outdated
// SafeName returns the name of the token, sanitized appropriately for | ||
// join methods where the name is secret. | ||
SafeName string `json:"safeName"` | ||
// Expiry is the time that the token resource expires |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd mention what value to expect for tokens which do not expire.
lib/web/ui/join_token.go
Outdated
|
||
func MakeJoinToken(token types.ProvisionToken) JoinToken { | ||
labels := token.GetSuggestedLabels() | ||
suggestedLabels := make([]Label, len(labels)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestedLabels := make([]Label, len(labels)) | |
suggestedLabels := make([]Label, 0, len(labels)) |
Otherwise suggestedLabels
is going to be twice as long as you expect.
lib/web/join_tokens.go
Outdated
}, nil | ||
} | ||
|
||
func (h *Handler) deleteToken(_ http.ResponseWriter, r *http.Request, params httprouter.Params, ctx *SessionContext) (interface{}, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed you _
'd the ResponseWriter
here, but not in getTokens
. I would be consistent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going to put the w
back in, as that is consistent with the rest of the api. I used the _
because my linter was throwing a warning but now it isn't? weird. oh well!
lib/web/join_tokens_test.go
Outdated
expiry time.Time | ||
} | ||
|
||
func Test_getTokens(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
func Test_getTokens(t *testing.T) { | |
func TestGetTokens(t *testing.T) { |
lib/web/join_tokens_test.go
Outdated
ctx := context.Background() | ||
expiry := time.Now().UTC().Add(30 * time.Minute) | ||
|
||
staticUiToken := ui.JoinToken{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
staticUiToken := ui.JoinToken{ | |
staticUIToken := ui.JoinToken{ |
lib/web/join_tokens.go
Outdated
err = clt.DeleteToken(r.Context(), token) | ||
if err != nil { | ||
return nil, trace.Wrap(err) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💅
err = clt.DeleteToken(r.Context(), token) | |
if err != nil { | |
return nil, trace.Wrap(err) | |
} | |
if err := clt.DeleteToken(r.Context(), token); err != nil { | |
return nil, trace.Wrap(err) | |
} |
lib/web/ui/join_token.go
Outdated
SafeName: token.GetSafeName(), | ||
Expiry: token.Expiry(), | ||
Roles: token.GetRoles(), | ||
IsStatic: token.Expiry().Equal(time.Unix(0, 0).UTC()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure about this one.
A static token is a token that is configured directly into the teleport.yaml
in the auth service. Those exist inside the type types.StaticTokensV2
Which is different from a token with no expiration, which you can create dynamically.
So while static tokens don't have expiration, not all Expiry == 0
are static tokens.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Static tokens are set from the config with zero Unix time (1970-01-01), but if I manually configure a token with no ttl, it's actually set to zero time (0001-01-01) so it's not an ideal distinction but it does work.
Ideally I wanted to use the Origin but it seems the origin for all tokens (in my testing) just return empty string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TIL, thank you.
Can we convert this check into a token's method? I think this distinction should be really close to the token's definition.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean something like making JoinToken.IsStaic() ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes
@@ -547,6 +553,20 @@ func ProvisionTokensFromV1(in []ProvisionTokenV1) []ProvisionToken { | |||
return out | |||
} | |||
|
|||
// ProvisionTokensFromStatic converts static tokens to resource list | |||
func ProvisionTokensFromStatic(in []ProvisionTokenV1) []ProvisionToken { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added this method to replace ProvisionTokensFromV1
and all instances that I could find using the old method had to deal with static tokens. I could have just thrown in this SetOrigin
there but I was worried it would be used for something that isnt a static token. If that isn't the case, I'll remove this new ProvisionTokensFromStatic
method and throw it into the old one. Curious your thoughts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's fine, but it would be better if we changed it at its creation instead of when converting to something else.
So, either on their CheckAndSetDefaults or when parsing the token from the file.
teleport/api/types/statictokens.go
Line 41 in 67a3d64
if err := st.CheckAndSetDefaults(); err != nil { |
teleport/lib/config/fileconf.go
Line 950 in 67a3d64
tokens, err := st.Parse() |
func (p *ProvisionTokenV2) IsStatic() bool { | ||
return p.Origin() == OriginConfigFile | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I added the IsStatic
method but I am not relying on the time anymore (it seemed fickle to me from the start). When we fetch static tokens, we create a new ProvisionToken
from the available static tokens. I've just set their origin to OriginConfiguration
instead of being nil and now IsStatic
just checks if Origin() == OriginConfiguration
. It seems to be more correct and resilient this way. Let me know what you think
AllowRules []string `json:"allowRules,omitempty"` | ||
} | ||
|
||
func MakeJoinToken(token types.ProvisionToken) JoinToken { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit:
what would you say about ConvertToJoinToken ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
all the other "make ui struct" methods for the other UI resources follow the MakeX
pattern so I'll keep it to stay consistent.
} | ||
} | ||
|
||
func MakeJoinTokens(tokens []types.ProvisionToken) (joinTokens []JoinToken) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
func MakeJoinTokens(tokens []types.ProvisionToken) (joinTokens []JoinToken) { | |
func ConvertToJoinTokens(tokens []types.ProvisionToken) (joinTokens []JoinToken) { |
"github.com/gravitational/teleport/api/types" | ||
) | ||
|
||
type JoinToken struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: missing docs.
lib/web/ui/join_token.go
Outdated
for labelKey, labelValues := range labels { | ||
suggestedLabels = append(suggestedLabels, Label{ | ||
Name: labelKey, | ||
Value: strings.Join(labelValues, " "), | ||
}) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a bit breaking way to return labels where labels are joined by space. What if a label contains a space like m = {"zone: []string{"district 1", "district 2"}}
?
Can we reuse ui.makeLabels
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We've decided to remove the suggested labels all together from the UI table, so i'll just remove this code. We will be sending the full json value of the token as well for a "Details" page where this information will be available, but we don't need it in the UI struct individually
lib/web/apiserver.go
Outdated
h.POST("/webapi/token", h.WithAuth(h.createTokenHandle)) | ||
h.GET("/webapi/tokens", h.WithAuth(h.getTokens)) | ||
h.DELETE("/webapi/tokens/:id", h.WithAuth(h.deleteToken)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we hide the :id in the DELETE request body instead of exposing it in URL ?
Let say that a user has permission to list tokens but it don't have permission to delete tokens. And a customer infrastructure tools like:
LB -> Ingress -> Teleport Proxy
Please note that :id == token_secret
in case of static tokens.
When a client calls /webapi/tokens/token_secret
with missing permission to delete secret the Ingress can log the request HTTP Path and expose token_secret in Ingress logs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great idea, i'll make the change! typically DELETE
requests don't have a body and I don't think our client supports it but I'll see how it works
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Decided to send via a custom header as some servers/load balancers might just ignore any request body sent with a DELETE
lib/web/join_tokens.go
Outdated
@@ -53,6 +53,7 @@ import ( | |||
|
|||
const ( | |||
stableCloudChannelRepo = "stable/cloud" | |||
HeaderTokenName = "X-TOKEN-NAME" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be something like X-Teleport-TokenName
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes it should
This PR implements list/delete for tokens in the api the same way as tctl interacts with them. This does not include pagination yet but is currently being used while the feature is in development. Pagination can come in the future in the form of a sort cache, but the endpoints won't change
This PR implements list/delete for tokens in the api the same way as tctl interacts with them. This does not include pagination yet but is currently being used while the feature is in development. Pagination can come in the future in the form of a sort cache, but the endpoints won't change
This PR implements list/delete for tokens in the api the same way as tctl interacts with them. This does not include pagination yet but is currently being used while the feature is in development. Pagination can come in the future in the form of a sort cache, but the endpoints won't change
* Add token list/delete endpoints (#42402) This PR implements list/delete for tokens in the api the same way as tctl interacts with them. This does not include pagination yet but is currently being used while the feature is in development. Pagination can come in the future in the form of a sort cache, but the endpoints won't change * Add token ACL/routes * Add initial join tokens UI * Add Allow and GCP fields to ui join token * Fix missing styled components * Fix empty join token state (#45413) Empty join token responses would show an error instead of an empty list message * Update button case
* Add token list/delete endpoints (#42402) This PR implements list/delete for tokens in the api the same way as tctl interacts with them. This does not include pagination yet but is currently being used while the feature is in development. Pagination can come in the future in the form of a sort cache, but the endpoints won't change * Add token ACL/routes * Add initial join tokens UI * Add Allow and GCP fields to ui join token * Fix missing styled components * Fix empty join token state (#45413) Empty join token responses would show an error instead of an empty list message * Update button case
This PR implements list/delete for tokens in the api the same way as
tctl interacts with them. This does not include pagination yet but is
currently being used while the feature is in development. Pagination can
come in the future in the form of a sort cache, but the endpoints won't
change