Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat: add separate max token lifetime for administrators#18267

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletionscli/testdata/coder_server_--help.golden
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -332,6 +332,10 @@ NETWORKING / HTTP OPTIONS:
The maximum lifetime duration users can specify when creating an API
token.

--max-admin-token-lifetime duration, $CODER_MAX_ADMIN_TOKEN_LIFETIME (default: 168h0m0s)
The maximum lifetime duration administrators can specify when creating
an API token.

--proxy-health-interval duration, $CODER_PROXY_HEALTH_INTERVAL (default: 1m0s)
The interval in which coderd should be checking the status of
workspace proxies.
Expand Down
4 changes: 4 additions & 0 deletionscli/testdata/server-config.yaml.golden
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -25,6 +25,10 @@ networking:
# The maximum lifetime duration users can specify when creating an API token.
# (default: 876600h0m0s, type: duration)
maxTokenLifetime: 876600h0m0s
# The maximum lifetime duration administrators can specify when creating an API
# token.
# (default: 168h0m0s, type: duration)
maxAdminTokenLifetime: 168h0m0s
# The token expiry duration for browser sessions. Sessions may last longer if they
# are actively making requests, but this functionality can be disabled via
# --disable-session-expiry-refresh.
Expand Down
3 changes: 3 additions & 0 deletionscoderd/apidoc/docs.go
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

3 changes: 3 additions & 0 deletionscoderd/apidoc/swagger.json
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

49 changes: 42 additions & 7 deletionscoderd/apikey.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,6 +18,7 @@ import (
"github.com/coder/coder/v2/coderd/database/dbtime"
"github.com/coder/coder/v2/coderd/httpapi"
"github.com/coder/coder/v2/coderd/httpmw"
"github.com/coder/coder/v2/coderd/rbac"
"github.com/coder/coder/v2/coderd/rbac/policy"
"github.com/coder/coder/v2/coderd/telemetry"
"github.com/coder/coder/v2/codersdk"
Expand DownExpand Up@@ -75,7 +76,7 @@ func (api *API) postToken(rw http.ResponseWriter, r *http.Request) {
}

if createToken.Lifetime != 0 {
err := api.validateAPIKeyLifetime(createToken.Lifetime)
err := api.validateAPIKeyLifetime(ctx, user.ID,createToken.Lifetime)
if err != nil {
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
Message: "Failed to validate create API key request.",
Expand DownExpand Up@@ -338,35 +339,69 @@ func (api *API) deleteAPIKey(rw http.ResponseWriter, r *http.Request) {
// @Success 200 {object} codersdk.TokenConfig
// @Router /users/{user}/keys/tokens/tokenconfig [get]
func (api *API) tokenConfig(rw http.ResponseWriter, r *http.Request) {
values, err := api.DeploymentValues.WithoutSecrets()
user := httpmw.UserParam(r)
maxLifetime, err := api.getMaxTokenLifetime(r.Context(), user.ID)
if err != nil {
httpapi.InternalServerError(rw, err)
httpapi.Write(r.Context(), rw, http.StatusInternalServerError, codersdk.Response{
Message: "Failed to get token configuration.",
Detail: err.Error(),
})
return
}

httpapi.Write(
r.Context(), rw, http.StatusOK,
codersdk.TokenConfig{
MaxTokenLifetime:values.Sessions.MaximumTokenDuration.Value(),
MaxTokenLifetime:maxLifetime,
},
)
}

func (api *API) validateAPIKeyLifetime(lifetime time.Duration) error {
func (api *API) validateAPIKeyLifetime(ctx context.Context, userID uuid.UUID,lifetime time.Duration) error {
if lifetime <= 0 {
return xerrors.New("lifetime must be positive number greater than 0")
}

if lifetime > api.DeploymentValues.Sessions.MaximumTokenDuration.Value() {
maxLifetime, err := api.getMaxTokenLifetime(ctx, userID)
if err != nil {
return xerrors.Errorf("failed to get max token lifetime: %w", err)
}

if lifetime > maxLifetime {
return xerrors.Errorf(
"lifetime must be less than %v",
api.DeploymentValues.Sessions.MaximumTokenDuration,
maxLifetime,
)
}

return nil
}

// getMaxTokenLifetime returns the maximum allowed token lifetime for a user.
// It distinguishes between regular users and owners.
func (api *API) getMaxTokenLifetime(ctx context.Context, userID uuid.UUID) (time.Duration, error) {
subject, _, err := httpmw.UserRBACSubject(ctx, api.Database, userID, rbac.ScopeAll)
if err != nil {
return 0, xerrors.Errorf("failed to get user rbac subject: %w", err)
}

roles, err := subject.Roles.Expand()
if err != nil {
return 0, xerrors.Errorf("failed to expand user roles: %w", err)
}

maxLifetime := api.DeploymentValues.Sessions.MaximumTokenDuration.Value()
for _, role := range roles {
if role.Identifier.Name == codersdk.RoleOwner {
// Owners have a different max lifetime.
maxLifetime = api.DeploymentValues.Sessions.MaximumAdminTokenDuration.Value()
break
}
}

return maxLifetime, nil
}

func (api *API) createAPIKey(ctx context.Context, params apikey.CreateParams) (*http.Cookie, *database.APIKey, error) {
key, sessionToken, err := apikey.Generate(params)
if err != nil {
Expand Down
82 changes: 82 additions & 0 deletionscoderd/apikey_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -144,6 +144,88 @@ func TestTokenUserSetMaxLifetime(t *testing.T) {
require.ErrorContains(t, err, "lifetime must be less")
}

func TestTokenAdminSetMaxLifetime(t *testing.T) {
t.Parallel()

ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel()
dc := coderdtest.DeploymentValues(t)
dc.Sessions.MaximumTokenDuration = serpent.Duration(time.Hour * 24 * 7)
dc.Sessions.MaximumAdminTokenDuration = serpent.Duration(time.Hour * 24 * 14)
client := coderdtest.New(t, &coderdtest.Options{
DeploymentValues: dc,
})
adminUser := coderdtest.CreateFirstUser(t, client)
nonAdminClient, _ := coderdtest.CreateAnotherUser(t, client, adminUser.OrganizationID)

// Admin should be able to create a token with a lifetime longer than the non-admin max.
_, err := client.CreateToken(ctx, codersdk.Me, codersdk.CreateTokenRequest{
Lifetime: time.Hour * 24 * 10,
})
require.NoError(t, err)

// Admin should NOT be able to create a token with a lifetime longer than the admin max.
_, err = client.CreateToken(ctx, codersdk.Me, codersdk.CreateTokenRequest{
Lifetime: time.Hour * 24 * 15,
})
require.Error(t, err)
require.Contains(t, err.Error(), "lifetime must be less")

// Non-admin should NOT be able to create a token with a lifetime longer than the non-admin max.
_, err = nonAdminClient.CreateToken(ctx, codersdk.Me, codersdk.CreateTokenRequest{
Lifetime: time.Hour * 24 * 8,
})
require.Error(t, err)
require.Contains(t, err.Error(), "lifetime must be less")

// Non-admin should be able to create a token with a lifetime shorter than the non-admin max.
_, err = nonAdminClient.CreateToken(ctx, codersdk.Me, codersdk.CreateTokenRequest{
Lifetime: time.Hour * 24 * 6,
})
require.NoError(t, err)
}

func TestTokenAdminSetMaxLifetimeShorter(t *testing.T) {
t.Parallel()

ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel()
dc := coderdtest.DeploymentValues(t)
dc.Sessions.MaximumTokenDuration = serpent.Duration(time.Hour * 24 * 14)
dc.Sessions.MaximumAdminTokenDuration = serpent.Duration(time.Hour * 24 * 7)
client := coderdtest.New(t, &coderdtest.Options{
DeploymentValues: dc,
})
adminUser := coderdtest.CreateFirstUser(t, client)
nonAdminClient, _ := coderdtest.CreateAnotherUser(t, client, adminUser.OrganizationID)

// Admin should NOT be able to create a token with a lifetime longer than the admin max.
_, err := client.CreateToken(ctx, codersdk.Me, codersdk.CreateTokenRequest{
Lifetime: time.Hour * 24 * 8,
})
require.Error(t, err)
require.Contains(t, err.Error(), "lifetime must be less")

// Admin should be able to create a token with a lifetime shorter than the admin max.
_, err = client.CreateToken(ctx, codersdk.Me, codersdk.CreateTokenRequest{
Lifetime: time.Hour * 24 * 6,
})
require.NoError(t, err)

// Non-admin should be able to create a token with a lifetime longer than the admin max.
_, err = nonAdminClient.CreateToken(ctx, codersdk.Me, codersdk.CreateTokenRequest{
Lifetime: time.Hour * 24 * 10,
})
require.NoError(t, err)

// Non-admin should NOT be able to create a token with a lifetime longer than the non-admin max.
_, err = nonAdminClient.CreateToken(ctx, codersdk.Me, codersdk.CreateTokenRequest{
Lifetime: time.Hour * 24 * 15,
})
require.Error(t, err)
require.Contains(t, err.Error(), "lifetime must be less")
}

func TestTokenCustomDefaultLifetime(t *testing.T) {
t.Parallel()

Expand Down
13 changes: 13 additions & 0 deletionscodersdk/deployment.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -468,6 +468,8 @@ type SessionLifetime struct {
DefaultTokenDuration serpent.Duration `json:"default_token_lifetime,omitempty" typescript:",notnull"`

MaximumTokenDuration serpent.Duration `json:"max_token_lifetime,omitempty" typescript:",notnull"`

MaximumAdminTokenDuration serpent.Duration `json:"max_admin_token_lifetime,omitempty" typescript:",notnull"`
}

type DERP struct {
Expand DownExpand Up@@ -2340,6 +2342,17 @@ func (c *DeploymentValues) Options() serpent.OptionSet {
YAML: "maxTokenLifetime",
Annotations: serpent.Annotations{}.Mark(annotationFormatDuration, "true"),
},
{
Name: "Maximum Admin Token Lifetime",
Description: "The maximum lifetime duration administrators can specify when creating an API token.",
Flag: "max-admin-token-lifetime",
Env: "CODER_MAX_ADMIN_TOKEN_LIFETIME",
Default: (7 * 24 * time.Hour).String(),
Value: &c.Sessions.MaximumAdminTokenDuration,
Group: &deploymentGroupNetworkingHTTP,
YAML: "maxAdminTokenLifetime",
Annotations: serpent.Annotations{}.Mark(annotationFormatDuration, "true"),
},
{
Name: "Default Token Lifetime",
Description: "The default lifetime duration for API tokens. This value is used when creating a token without specifying a duration, such as when authenticating the CLI or an IDE plugin.",
Expand Down
1 change: 1 addition & 0 deletionsdocs/reference/api/general.md
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

16 changes: 10 additions & 6 deletionsdocs/reference/api/schemas.md
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

11 changes: 11 additions & 0 deletionsdocs/reference/cli/server.md
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

4 changes: 4 additions & 0 deletionsenterprise/cli/testdata/coder_server_--help.golden
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -333,6 +333,10 @@ NETWORKING / HTTP OPTIONS:
The maximum lifetime duration users can specify when creating an API
token.

--max-admin-token-lifetime duration, $CODER_MAX_ADMIN_TOKEN_LIFETIME (default: 168h0m0s)
The maximum lifetime duration administrators can specify when creating
an API token.

--proxy-health-interval duration, $CODER_PROXY_HEALTH_INTERVAL (default: 1m0s)
The interval in which coderd should be checking the status of
workspace proxies.
Expand Down
1 change: 1 addition & 0 deletionssite/src/api/typesGenerated.ts
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

Loading

[8]ページ先頭

©2009-2025 Movatter.jp