Skip to content

Commit b57424a

Browse files
authored
[jwt] Installer configures expiry & issuer WEB-102 (#17314)
* [jwt] Installer configures expiry & issuer * Fix * Fix * retest * Fix * Fix * Fix
1 parent e119c2a commit b57424a

File tree

13 files changed

+126
-55
lines changed

13 files changed

+126
-55
lines changed

components/public-api/go/config/config.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44

55
package config
66

7-
import "github.com/gitpod-io/gitpod/common-go/baseserver"
7+
import (
8+
"github.com/gitpod-io/gitpod/common-go/baseserver"
9+
)
810

911
type Configuration struct {
1012
// PublicURL is the URL under which the API server is publicly reachable
@@ -45,7 +47,13 @@ type RedisConfiguration struct {
4547
}
4648

4749
type AuthConfiguration struct {
48-
PKI AuthPKIConfiguration `json:"pki"`
50+
PKI AuthPKIConfiguration `json:"pki"`
51+
Session SessionConfig `json:"session"`
52+
}
53+
54+
type SessionConfig struct {
55+
LifetimeSeconds int64 `json:"lifetimeSeconds"`
56+
Issuer string `json:"issuer"`
4957
}
5058

5159
type AuthPKIConfiguration struct {

components/server/src/auth/jwt.spec.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import { AuthJWT, sign, verify } from "./jwt";
99
import { Container } from "inversify";
1010
import { Config } from "../config";
1111
import * as crypto from "crypto";
12-
import { GitpodHostUrl } from "@gitpod/gitpod-protocol/lib/util/gitpod-host-url";
1312
import * as chai from "chai";
1413

1514
const expect = chai.expect;
@@ -23,12 +22,15 @@ class TestAuthJWT {
2322
private validatingKeyPair2 = crypto.generateKeyPairSync("rsa", { modulusLength: 2048 });
2423

2524
private config: Config = {
26-
hostUrl: new GitpodHostUrl("https://mp-server-d7650ec945.preview.gitpod-dev.com"),
2725
auth: {
2826
pki: {
2927
signing: toKeyPair("0001", this.signingKeyPair),
3028
validating: [toKeyPair("0002", this.validatingKeyPair1), toKeyPair("0003", this.validatingKeyPair2)],
3129
},
30+
session: {
31+
issuer: "https://mp-server-d7650ec945.preview.gitpod-dev.com",
32+
lifetimeSeconds: 7 * 24 * 60 * 60,
33+
},
3234
},
3335
} as Config;
3436

@@ -76,7 +78,7 @@ class TestAuthJWT {
7678
const encoded = await sign({}, keypair.privateKey, {
7779
algorithm: "RS512",
7880
expiresIn: "1d",
79-
issuer: this.config.hostUrl.toStringWoRootSlash(),
81+
issuer: this.config.auth.session.issuer,
8082
keyid: keypair.id,
8183
subject,
8284
});

components/server/src/auth/jwt.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,16 @@ const algorithm: jsonwebtoken.Algorithm = "RS512";
1414
export class AuthJWT {
1515
@inject(Config) protected config: Config;
1616

17-
async sign(subject: string, payload: object | Buffer, expiresIn: string = `${24 * 7}h`): Promise<string> {
17+
async sign(
18+
subject: string,
19+
payload: object | Buffer,
20+
expirySeconds: number = this.config.auth.session.lifetimeSeconds,
21+
issuer: string = this.config.auth.session.issuer,
22+
): Promise<string> {
1823
const opts: jsonwebtoken.SignOptions = {
1924
algorithm,
20-
expiresIn,
21-
issuer: this.config.hostUrl.toStringWoRootSlash(),
25+
expiresIn: expirySeconds,
26+
issuer,
2227
subject,
2328
keyid: this.config.auth.pki.signing.id,
2429
};

components/server/src/config.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ export type Config = Omit<
5151
publicKey: string;
5252
}[];
5353
};
54+
55+
session: {
56+
lifetimeSeconds: number;
57+
issuer: string;
58+
};
5459
};
5560
};
5661

@@ -250,6 +255,10 @@ export interface ConfigSerialized {
250255

251256
auth: {
252257
pki: AuthPKIConfig;
258+
session: {
259+
lifetimeSeconds: number;
260+
issuer: string;
261+
};
253262
};
254263
}
255264

@@ -394,6 +403,7 @@ export namespace ConfigFile {
394403
},
395404
auth: {
396405
pki: authPKI,
406+
session: config.auth.session,
397407
},
398408
};
399409
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright (c) 2023 Gitpod GmbH. All rights reserved.
2+
// Licensed under the GNU Affero General Public License (AGPL).
3+
// See License.AGPL.txt in the project root for license information.
4+
5+
package auth
6+
7+
import (
8+
"fmt"
9+
"time"
10+
11+
"github.com/gitpod-io/gitpod/installer/pkg/common"
12+
corev1 "k8s.io/api/core/v1"
13+
)
14+
15+
type Config struct {
16+
PKI PKIConfig `json:"pki"`
17+
18+
// Configration parameters for user sessions
19+
Session SessionConfig `json:"session"`
20+
}
21+
22+
type SessionConfig struct {
23+
// How long shoud the session be valid for?
24+
LifetimeSeconds int64 `json:"lifetimeSeconds"`
25+
Issuer string `json:"issuer"`
26+
}
27+
28+
func GetConfig(ctx *common.RenderContext) ([]corev1.Volume, []corev1.VolumeMount, Config) {
29+
volumes, mounts, pki := getPKI()
30+
return volumes, mounts, Config{
31+
PKI: pki,
32+
Session: SessionConfig{
33+
LifetimeSeconds: int64((7 * 24 * time.Hour).Seconds()),
34+
Issuer: fmt.Sprintf("https://%s", ctx.Config.Domain),
35+
},
36+
}
37+
}

install/installer/pkg/components/auth/keypair.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ func keypair(ctx *common.RenderContext) ([]runtime.Object, error) {
5959
}, nil
6060
}
6161

62-
func GetPKI() ([]corev1.Volume, []corev1.VolumeMount, PKIConfig) {
62+
func getPKI() ([]corev1.Volume, []corev1.VolumeMount, PKIConfig) {
6363
dir := "/secrets/auth-pki"
6464
signingDir := path.Join(dir, "signing")
6565

install/installer/pkg/components/public-api-server/configmap.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func configmap(ctx *common.RenderContext) ([]runtime.Object, error) {
4949

5050
_, _, databaseSecretMountPath := common.DatabaseEnvSecret(ctx.Config)
5151

52-
_, _, authPKI := auth.GetPKI()
52+
_, _, authCfg := auth.GetConfig(ctx)
5353

5454
cfg := config.Configuration{
5555
PublicURL: fmt.Sprintf("https://api.%s", ctx.Config.Domain),
@@ -66,11 +66,15 @@ func configmap(ctx *common.RenderContext) ([]runtime.Object, error) {
6666
Auth: config.AuthConfiguration{
6767
PKI: config.AuthPKIConfiguration{
6868
Signing: config.KeyPair{
69-
ID: authPKI.Signing.ID,
70-
PublicKeyPath: authPKI.Signing.PublicKeyPath,
71-
PrivateKeyPath: authPKI.Signing.PrivateKeyPath,
69+
ID: authCfg.PKI.Signing.ID,
70+
PublicKeyPath: authCfg.PKI.Signing.PublicKeyPath,
71+
PrivateKeyPath: authCfg.PKI.Signing.PrivateKeyPath,
7272
},
7373
},
74+
Session: config.SessionConfig{
75+
LifetimeSeconds: authCfg.Session.LifetimeSeconds,
76+
Issuer: authCfg.Session.Issuer,
77+
},
7478
},
7579
Server: &baseserver.Configuration{
7680
Services: baseserver.ServicesConfiguration{

install/installer/pkg/components/public-api-server/configmap_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package public_api_server
77
import (
88
"fmt"
99
"testing"
10+
"time"
1011

1112
"github.com/gitpod-io/gitpod/installer/pkg/components/redis"
1213
"github.com/gitpod-io/gitpod/installer/pkg/config/v1/experimental"
@@ -65,6 +66,10 @@ func TestConfigMap(t *testing.T) {
6566
PrivateKeyPath: "/secrets/auth-pki/signing/tls.key",
6667
},
6768
},
69+
Session: config.SessionConfig{
70+
LifetimeSeconds: int64((24 * 7 * time.Hour).Seconds()),
71+
Issuer: "https://test.domain.everything.awesome.is",
72+
},
6873
},
6974
Server: &baseserver.Configuration{
7075
Services: baseserver.ServicesConfiguration{

install/installer/pkg/components/public-api-server/deployment.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,9 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) {
9292
return nil
9393
})
9494

95-
authPKIVolumes, authPKIMounts, _ := auth.GetPKI()
96-
volumes = append(volumes, authPKIVolumes...)
97-
volumeMounts = append(volumeMounts, authPKIMounts...)
95+
authVolumes, authMounts, _ := auth.GetConfig(ctx)
96+
volumes = append(volumes, authVolumes...)
97+
volumeMounts = append(volumeMounts, authMounts...)
9898

9999
labels := common.CustomizeLabel(ctx, Component, common.TypeMetaDeployment)
100100
return []runtime.Object{

install/installer/pkg/components/server/configmap.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ func configmap(ctx *common.RenderContext) ([]runtime.Object, error) {
189189

190190
_, _, adminCredentialsPath := getAdminCredentials()
191191

192-
_, _, authPKI := auth.GetPKI()
192+
_, _, authCfg := auth.GetConfig(ctx)
193193

194194
// todo(sje): all these values are configurable
195195
scfg := ConfigSerialized{
@@ -291,9 +291,7 @@ func configmap(ctx *common.RenderContext) ([]runtime.Object, error) {
291291
CredentialsPath: adminCredentialsPath,
292292
},
293293
ShowSetupModal: showSetupModal,
294-
Auth: AuthConfig{
295-
PKI: authPKI,
296-
},
294+
Auth: authCfg,
297295
}
298296

299297
fc, err := common.ToJSONString(scfg)

install/installer/pkg/components/server/configmap_test.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package server
77
import (
88
"encoding/json"
99
"testing"
10+
"time"
1011

1112
"github.com/stretchr/testify/assert"
1213
"github.com/stretchr/testify/require"
@@ -31,7 +32,7 @@ func TestConfigMap(t *testing.T) {
3132
JWTSecret string
3233
SessionSecret string
3334
GitHubApp experimental.GithubApp
34-
Auth AuthConfig
35+
Auth auth.Config
3536
}
3637

3738
expectation := Expectation{
@@ -54,18 +55,23 @@ func TestConfigMap(t *testing.T) {
5455
WebhookSecret: "some-webhook-secret",
5556
CertSecretName: "some-cert-secret-name",
5657
},
57-
Auth: AuthConfig{
58+
Auth: auth.Config{
5859
PKI: auth.PKIConfig{
5960
Signing: auth.KeyPair{
6061
ID: "0001",
6162
PrivateKeyPath: "/secrets/auth-pki/signing/tls.key",
6263
PublicKeyPath: "/secrets/auth-pki/signing/tls.crt",
6364
},
6465
},
66+
Session: auth.SessionConfig{
67+
LifetimeSeconds: int64((7 * 24 * time.Hour).Seconds()),
68+
Issuer: "https://awesome.domain",
69+
},
6570
},
6671
}
6772

6873
ctx, err := common.NewRenderContext(config.Config{
74+
Domain: "awesome.domain",
6975
Workspace: config.Workspace{
7076
WorkspaceImage: expectation.WorkspaceImage,
7177
},

install/installer/pkg/components/server/deployment.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -259,9 +259,9 @@ func deployment(ctx *common.RenderContext) ([]runtime.Object, error) {
259259
volumes = append(volumes, adminCredentialsVolume)
260260
volumeMounts = append(volumeMounts, adminCredentialsMount)
261261

262-
authPKIVolumes, authPKIMounts, _ := auth.GetPKI()
263-
volumes = append(volumes, authPKIVolumes...)
264-
volumeMounts = append(volumeMounts, authPKIMounts...)
262+
authVolumes, authMounts, _ := auth.GetConfig(ctx)
263+
volumes = append(volumes, authVolumes...)
264+
volumeMounts = append(volumeMounts, authMounts...)
265265

266266
return []runtime.Object{
267267
&appsv1.Deployment{

install/installer/pkg/components/server/types.go

Lines changed: 26 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -14,32 +14,32 @@ import (
1414

1515
// ConfigSerialized interface from components/server/src/config.ts
1616
type ConfigSerialized struct {
17-
Version string `json:"version"`
18-
HostURL string `json:"hostUrl"`
19-
InstallationShortname string `json:"installationShortname"`
20-
DevBranch string `json:"devBranch"`
21-
InsecureNoDomain bool `json:"insecureNoDomain"`
22-
License string `json:"license"`
23-
DefinitelyGpDisabled bool `json:"definitelyGpDisabled"`
24-
EnableLocalApp bool `json:"enableLocalApp"`
25-
DisableDynamicAuthProviderLogin bool `json:"disableDynamicAuthProviderLogin"`
26-
MaxEnvvarPerUserCount int32 `json:"maxEnvvarPerUserCount"`
27-
MaxConcurrentPrebuildsPerRef int32 `json:"maxConcurrentPrebuildsPerRef"`
28-
MakeNewUsersAdmin bool `json:"makeNewUsersAdmin"`
29-
DefaultBaseImageRegistryWhitelist []string `json:"defaultBaseImageRegistryWhitelist"`
30-
RunDbDeleter bool `json:"runDbDeleter"`
31-
ContentServiceAddr string `json:"contentServiceAddr"`
32-
UsageServiceAddr string `json:"usageServiceAddr"`
33-
IDEServiceAddr string `json:"ideServiceAddr"`
34-
MaximumEventLoopLag float64 `json:"maximumEventLoopLag"`
35-
VSXRegistryUrl string `json:"vsxRegistryUrl"`
36-
StripeSecretsFile string `json:"stripeSecretsFile"`
37-
StripeConfigFile string `json:"stripeConfigFile"`
38-
EnablePayment bool `json:"enablePayment"`
39-
LinkedInSecretsFile string `json:"linkedInSecretsFile"`
40-
PATSigningKeyFile string `json:"patSigningKeyFile"`
41-
ShowSetupModal bool `json:"showSetupModal"`
42-
Auth AuthConfig `json:"auth"`
17+
Version string `json:"version"`
18+
HostURL string `json:"hostUrl"`
19+
InstallationShortname string `json:"installationShortname"`
20+
DevBranch string `json:"devBranch"`
21+
InsecureNoDomain bool `json:"insecureNoDomain"`
22+
License string `json:"license"`
23+
DefinitelyGpDisabled bool `json:"definitelyGpDisabled"`
24+
EnableLocalApp bool `json:"enableLocalApp"`
25+
DisableDynamicAuthProviderLogin bool `json:"disableDynamicAuthProviderLogin"`
26+
MaxEnvvarPerUserCount int32 `json:"maxEnvvarPerUserCount"`
27+
MaxConcurrentPrebuildsPerRef int32 `json:"maxConcurrentPrebuildsPerRef"`
28+
MakeNewUsersAdmin bool `json:"makeNewUsersAdmin"`
29+
DefaultBaseImageRegistryWhitelist []string `json:"defaultBaseImageRegistryWhitelist"`
30+
RunDbDeleter bool `json:"runDbDeleter"`
31+
ContentServiceAddr string `json:"contentServiceAddr"`
32+
UsageServiceAddr string `json:"usageServiceAddr"`
33+
IDEServiceAddr string `json:"ideServiceAddr"`
34+
MaximumEventLoopLag float64 `json:"maximumEventLoopLag"`
35+
VSXRegistryUrl string `json:"vsxRegistryUrl"`
36+
StripeSecretsFile string `json:"stripeSecretsFile"`
37+
StripeConfigFile string `json:"stripeConfigFile"`
38+
EnablePayment bool `json:"enablePayment"`
39+
LinkedInSecretsFile string `json:"linkedInSecretsFile"`
40+
PATSigningKeyFile string `json:"patSigningKeyFile"`
41+
ShowSetupModal bool `json:"showSetupModal"`
42+
Auth auth.Config `json:"auth"`
4343

4444
WorkspaceHeartbeat WorkspaceHeartbeat `json:"workspaceHeartbeat"`
4545
WorkspaceDefaults WorkspaceDefaults `json:"workspaceDefaults"`
@@ -66,10 +66,6 @@ type CodeSyncResources struct {
6666
RevLimit int32 `json:"revLimit"`
6767
}
6868

69-
type AuthConfig struct {
70-
PKI auth.PKIConfig `json:"pki"`
71-
}
72-
7369
type CodeSync struct {
7470
RevLimit int32 `json:"revLimit"`
7571
ContentLimit int32 `json:"contentLimit"`

0 commit comments

Comments
 (0)