Gatekeeper (#2572)
* feat(gatekeeper): initial license validation * test(gatekeeper): add license token to tests * chore(gatekeeper): cleanup * chore(gatekeeper): hide from circleci * feat(helm): load license token from secrets * chore(circleci): remove unused env var
This commit is contained in:
@@ -17,6 +17,8 @@ workflows:
|
|||||||
- hotfix*
|
- hotfix*
|
||||||
|
|
||||||
- test-server:
|
- test-server:
|
||||||
|
context:
|
||||||
|
- speckle-server-licensing
|
||||||
filters: &filters-allow-all
|
filters: &filters-allow-all
|
||||||
tags:
|
tags:
|
||||||
# run tests for any commit on any branch, including any tags
|
# run tests for any commit on any branch, including any tags
|
||||||
|
|||||||
@@ -8,4 +8,6 @@ secret:
|
|||||||
name: '.circleci/deployment/manifests/speckle-server.secret.yaml - test s3_secret_key'
|
name: '.circleci/deployment/manifests/speckle-server.secret.yaml - test s3_secret_key'
|
||||||
- match: 9f1d96876edbf847bb792754025ed131374869e60866d5e9c349c9423b37dd09
|
- match: 9f1d96876edbf847bb792754025ed131374869e60866d5e9c349c9423b37dd09
|
||||||
name: '.circleci/deployment/manifests/speckle-server.secret.yaml - test session_secret'
|
name: '.circleci/deployment/manifests/speckle-server.secret.yaml - test session_secret'
|
||||||
|
- match: 9bf360c5ce31170e8e3cb30e275b2c00224dd97b93282491c60fb1665fac3845
|
||||||
|
name: local test license
|
||||||
version: 2
|
version: 2
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ Copyright (c) 2020-present AEC Systems.
|
|||||||
Portions of this software are licensed as follows:
|
Portions of this software are licensed as follows:
|
||||||
|
|
||||||
- All content residing under the "packages/server/modules/workspaces/" directory of this repository is licensed under "The Speckle Enterprise Edition (EE) license".
|
- All content residing under the "packages/server/modules/workspaces/" directory of this repository is licensed under "The Speckle Enterprise Edition (EE) license".
|
||||||
|
- All content residing under the "packages/server/modules/gatekeeper/" directory of this repository is licensed under "The Speckle Enterprise Edition (EE) license".
|
||||||
- Content outside of the above mentioned directories or restrictions above is available under the "Apache License" license as defined below.
|
- Content outside of the above mentioned directories or restrictions above is available under the "Apache License" license as defined below.
|
||||||
|
|
||||||
Apache License
|
Apache License
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
The Speckle Enterprise Edition (EE) license (the “EE License”)
|
||||||
|
|
||||||
|
Copyright (c) 2024-present AEC Systems LTD.
|
||||||
|
|
||||||
|
With regard to the Speckle Software:
|
||||||
|
|
||||||
|
This software and associated documentation files (the "Software") may only be used, if you (and any entity that you represent) have agreed to, and are in compliance with, the AEC Systems Terms of Service, available at https://speckle.systems/terms/ (the “EE Terms”), or other agreement governing the use of the Software, as agreed by you and AEC Systems, and otherwise have a valid Speckle Enterprise Edition subscription for the correct number of user seats. Subject to the foregoing sentence, you are free to modify this Software and publish patches to the Software. You agree that AEC Systems and/or its licensors (as applicable) retain all right, title and interest in and to all such modifications and/or patches, and all such modifications and/or patches may only be used, copied, modified, displayed, distributed, or otherwise exploited with a valid Speckle Enterprise Edition subscription for the correct number of user seats. Notwithstanding the foregoing, you may copy and modify the Software for development and testing purposes, without requiring a subscription. You agree that AEC Systems and/or its licensors (as applicable) retain all right, title and interest in and to all such modifications. You are not granted any other rights beyond what is expressly stated herein. Subject to the foregoing, it is forbidden to copy, merge, publish, distribute, sublicense, and/or sell the Software.
|
||||||
|
|
||||||
|
This EE License applies only to the part of this Software that is not distributed as part of Speckle Community Edition (CE). Any part of this Software distributed as part of Speckle CE or is served client-side as an image, font, cascading stylesheet (CSS), file which produces or is compiled, arranged, augmented, or combined into client-side JavaScript, in whole or in part, is copyrighted under the Apache 2.0 license. The full text of this EE License shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
For all third party components incorporated into the Speckle Software, those components are licensed under the original license provided by the owner of the applicable component.
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { z } from 'zod'
|
||||||
|
|
||||||
|
const EnabledModules = z.object({
|
||||||
|
workspaces: z.boolean()
|
||||||
|
})
|
||||||
|
|
||||||
|
export type EnabledModules = z.infer<typeof EnabledModules>
|
||||||
|
|
||||||
|
export const LicenseTokenClaims = z.object({
|
||||||
|
allowedDomains: z.string().array(),
|
||||||
|
enabledModules: EnabledModules
|
||||||
|
})
|
||||||
|
|
||||||
|
export type LicenseTokenClaims = z.infer<typeof LicenseTokenClaims>
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
import * as jose from 'jose'
|
||||||
|
import {
|
||||||
|
isDevEnv,
|
||||||
|
getServerOrigin,
|
||||||
|
getLicenseToken
|
||||||
|
} from '@/modules/shared/helpers/envHelper'
|
||||||
|
import { LicenseTokenClaims, EnabledModules } from '@/modules/gatekeeper/domain/types'
|
||||||
|
|
||||||
|
type LicensedModuleNames = (keyof EnabledModules)[]
|
||||||
|
|
||||||
|
export const validateLicenseModuleAccess = async ({
|
||||||
|
licenseToken,
|
||||||
|
canonicalUrl,
|
||||||
|
publicKey,
|
||||||
|
requiredModules
|
||||||
|
}: {
|
||||||
|
licenseToken: string
|
||||||
|
canonicalUrl: string
|
||||||
|
publicKey: jose.KeyLike
|
||||||
|
requiredModules: LicensedModuleNames
|
||||||
|
}): Promise<boolean> => {
|
||||||
|
try {
|
||||||
|
const { payload } = await jose.jwtVerify(licenseToken, publicKey)
|
||||||
|
|
||||||
|
const claims = LicenseTokenClaims.safeParse(payload)
|
||||||
|
if (!claims.success) return false
|
||||||
|
|
||||||
|
// make sure we match the allowedDomains
|
||||||
|
if (!claims.data.allowedDomains.includes(canonicalUrl)) return false
|
||||||
|
|
||||||
|
const enabledModules = claims.data.enabledModules
|
||||||
|
for (const moduleName of requiredModules) {
|
||||||
|
if (enabledModules[moduleName as keyof EnabledModules] !== true) return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
} catch (err) {
|
||||||
|
if (err instanceof jose.errors.JOSEError) {
|
||||||
|
// I'm deliberately hiding all internal details here, if any checks fail, its an invalid token
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
let publicKey: jose.KeyLike | undefined
|
||||||
|
|
||||||
|
const getPublicKey = async (): Promise<jose.KeyLike> => {
|
||||||
|
if (!publicKey) {
|
||||||
|
const alg = 'RS256'
|
||||||
|
const publicKeyString = `-----BEGIN PUBLIC KEY-----
|
||||||
|
MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAu3KR87R/7UTLAKqHyzIs
|
||||||
|
00jfLd4jFw6WCKzRQv87QDcu/WAiHzBJtgys7RWmMxCN2wkbpDG80GjSsB+/yRDc
|
||||||
|
cjw5eF+nPYsvCzyQVHaVJnhsa2P2qSXIWucSGnHhpgPkL7Rm5xCCoNzYWmn83S83
|
||||||
|
haw+vYMVURNdcTfj+6vXimRodnDJe644Jna5Xp3hs1PVzuMvDwAUaNQdki/2/0is
|
||||||
|
al3J8WsbtAJcah59flDODPu5BpMwbd0ZgixWBfCOuJvD5T5v7d7di8gY21t7OnJ8
|
||||||
|
1+6zAR3EKKHqWN2Wf8BvwiC8AXjUkSizqLhEnyhDC3IJ9I0zpu7gtqKYdBRj87wz
|
||||||
|
icHb8zyKZq6nxEEk3jxUfNYYy41//w3l9j6trvhFn88fd1ZuIlVq3xS1RC7176UA
|
||||||
|
LoKwZqDMZAJj5sIASmr13eKyuLvFMmB8jBedC4O5iW6FPq/+wnC+Td2TyssdSKi1
|
||||||
|
VUj/fs12T81Xk2HYqxx+qLhSlFA3aocciQNZHvd3muyfAgMBAAE=
|
||||||
|
-----END PUBLIC KEY-----
|
||||||
|
`
|
||||||
|
publicKey = await jose.importSPKI(publicKeyString, alg)
|
||||||
|
}
|
||||||
|
return publicKey
|
||||||
|
}
|
||||||
|
|
||||||
|
export const validateModuleLicense = async ({
|
||||||
|
requiredModules
|
||||||
|
}: {
|
||||||
|
requiredModules: LicensedModuleNames
|
||||||
|
}): Promise<boolean> => {
|
||||||
|
if (isDevEnv()) return true
|
||||||
|
const licenseToken = getLicenseToken()
|
||||||
|
if (!licenseToken) return false
|
||||||
|
const publicKey = await getPublicKey()
|
||||||
|
const canonicalUrl = getServerOrigin()
|
||||||
|
return validateLicenseModuleAccess({
|
||||||
|
licenseToken,
|
||||||
|
canonicalUrl,
|
||||||
|
publicKey,
|
||||||
|
requiredModules
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,194 @@
|
|||||||
|
import type { LicenseTokenClaims } from '@/modules/gatekeeper/domain/types'
|
||||||
|
import { validateLicenseModuleAccess } from '@/modules/gatekeeper/services/validateLicense'
|
||||||
|
import { expect } from 'chai'
|
||||||
|
import cryptoRandomString from 'crypto-random-string'
|
||||||
|
import * as jose from 'jose'
|
||||||
|
|
||||||
|
describe('validateLicense @gatekeeper', () => {
|
||||||
|
describe('validateLicenseModuleAccess', () => {
|
||||||
|
it('fails is the token is giberish', async () => {
|
||||||
|
const alg = 'RS256'
|
||||||
|
const { publicKey } = await jose.generateKeyPair(alg)
|
||||||
|
|
||||||
|
const result = await validateLicenseModuleAccess({
|
||||||
|
licenseToken: cryptoRandomString({ length: 32 }),
|
||||||
|
canonicalUrl: 'https://example.com',
|
||||||
|
publicKey,
|
||||||
|
requiredModules: ['workspaces']
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result).to.be.false
|
||||||
|
})
|
||||||
|
it('fails if the token is signed by another private key', async () => {
|
||||||
|
const canonicalUrl = 'https://example.com'
|
||||||
|
const alg = 'RS256'
|
||||||
|
|
||||||
|
const { publicKey } = await jose.generateKeyPair(alg)
|
||||||
|
|
||||||
|
const claims: LicenseTokenClaims = {
|
||||||
|
allowedDomains: [canonicalUrl],
|
||||||
|
enabledModules: {
|
||||||
|
workspaces: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const { privateKey } = await jose.generateKeyPair(alg)
|
||||||
|
|
||||||
|
const licenseToken = await new jose.SignJWT(claims)
|
||||||
|
.setProtectedHeader({ alg })
|
||||||
|
.setIssuedAt()
|
||||||
|
.sign(privateKey)
|
||||||
|
|
||||||
|
const result = await validateLicenseModuleAccess({
|
||||||
|
licenseToken,
|
||||||
|
canonicalUrl,
|
||||||
|
publicKey,
|
||||||
|
requiredModules: ['workspaces']
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result).to.be.false
|
||||||
|
})
|
||||||
|
it('fails if the token is not in the correct payload format', async () => {
|
||||||
|
const canonicalUrl = 'https://example.com'
|
||||||
|
const alg = 'RS256'
|
||||||
|
|
||||||
|
const { privateKey, publicKey } = await jose.generateKeyPair(alg)
|
||||||
|
|
||||||
|
const claims = {
|
||||||
|
enabledModules: {
|
||||||
|
workspaces: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const licenseToken = await new jose.SignJWT(claims)
|
||||||
|
.setProtectedHeader({ alg })
|
||||||
|
.setIssuedAt()
|
||||||
|
.sign(privateKey)
|
||||||
|
|
||||||
|
const result = await validateLicenseModuleAccess({
|
||||||
|
licenseToken,
|
||||||
|
canonicalUrl,
|
||||||
|
publicKey,
|
||||||
|
requiredModules: ['workspaces']
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result).to.be.false
|
||||||
|
})
|
||||||
|
it('fails if the token domain claim does not include the canonicalUrl', async () => {
|
||||||
|
const canonicalUrl = 'https://example.com'
|
||||||
|
const alg = 'RS256'
|
||||||
|
|
||||||
|
const { privateKey, publicKey } = await jose.generateKeyPair(alg)
|
||||||
|
|
||||||
|
const claims: LicenseTokenClaims = {
|
||||||
|
allowedDomains: ['https://not.allowed'],
|
||||||
|
enabledModules: {
|
||||||
|
workspaces: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const licenseToken = await new jose.SignJWT(claims)
|
||||||
|
.setProtectedHeader({ alg })
|
||||||
|
.setIssuedAt()
|
||||||
|
.sign(privateKey)
|
||||||
|
|
||||||
|
const result = await validateLicenseModuleAccess({
|
||||||
|
licenseToken,
|
||||||
|
canonicalUrl,
|
||||||
|
publicKey,
|
||||||
|
requiredModules: ['workspaces']
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result).to.be.false
|
||||||
|
})
|
||||||
|
it('fails if the token module claims do not enable all the required modules', async () => {
|
||||||
|
const canonicalUrl = 'https://example.com'
|
||||||
|
const alg = 'RS256'
|
||||||
|
|
||||||
|
const { privateKey, publicKey } = await jose.generateKeyPair(alg)
|
||||||
|
|
||||||
|
const claims: LicenseTokenClaims = {
|
||||||
|
allowedDomains: [canonicalUrl],
|
||||||
|
enabledModules: {
|
||||||
|
workspaces: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const licenseToken = await new jose.SignJWT(claims)
|
||||||
|
.setProtectedHeader({ alg })
|
||||||
|
.setIssuedAt()
|
||||||
|
.sign(privateKey)
|
||||||
|
|
||||||
|
const result = await validateLicenseModuleAccess({
|
||||||
|
licenseToken,
|
||||||
|
canonicalUrl,
|
||||||
|
publicKey,
|
||||||
|
requiredModules: ['workspaces']
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result).to.be.false
|
||||||
|
})
|
||||||
|
it('fails if the token string is tampered with', async () => {
|
||||||
|
const canonicalUrl = 'https://example.com'
|
||||||
|
const alg = 'RS256'
|
||||||
|
|
||||||
|
const { privateKey, publicKey } = await jose.generateKeyPair(alg)
|
||||||
|
|
||||||
|
const claims: LicenseTokenClaims = {
|
||||||
|
allowedDomains: [canonicalUrl],
|
||||||
|
enabledModules: {
|
||||||
|
workspaces: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const licenseToken = await new jose.SignJWT(claims)
|
||||||
|
.setProtectedHeader({ alg })
|
||||||
|
.setIssuedAt()
|
||||||
|
.sign(privateKey)
|
||||||
|
|
||||||
|
const hackedToken = licenseToken
|
||||||
|
.split('.')
|
||||||
|
.map((value, index) => {
|
||||||
|
if (index === 1) return `${value}hack`
|
||||||
|
return value
|
||||||
|
})
|
||||||
|
.join('.')
|
||||||
|
|
||||||
|
const result = await validateLicenseModuleAccess({
|
||||||
|
licenseToken: hackedToken,
|
||||||
|
canonicalUrl,
|
||||||
|
publicKey,
|
||||||
|
requiredModules: ['workspaces']
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result).to.be.false
|
||||||
|
})
|
||||||
|
it('succeeds for valid tokens', async () => {
|
||||||
|
const canonicalUrl = 'https://example.com'
|
||||||
|
const alg = 'RS256'
|
||||||
|
|
||||||
|
const { privateKey, publicKey } = await jose.generateKeyPair(alg)
|
||||||
|
|
||||||
|
const claims: LicenseTokenClaims = {
|
||||||
|
allowedDomains: [canonicalUrl],
|
||||||
|
enabledModules: {
|
||||||
|
workspaces: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const licenseToken = await new jose.SignJWT(claims)
|
||||||
|
.setProtectedHeader({ alg })
|
||||||
|
.setIssuedAt()
|
||||||
|
.sign(privateKey)
|
||||||
|
|
||||||
|
const result = await validateLicenseModuleAccess({
|
||||||
|
licenseToken,
|
||||||
|
canonicalUrl,
|
||||||
|
publicKey,
|
||||||
|
requiredModules: ['workspaces']
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(result).to.be.true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -394,6 +394,10 @@ export function getGendoAIAPIEndpoint() {
|
|||||||
|
|
||||||
export const getFeatureFlags = () => Environment.getFeatureFlags()
|
export const getFeatureFlags = () => Environment.getFeatureFlags()
|
||||||
|
|
||||||
|
export function getLicenseToken(): string | undefined {
|
||||||
|
return process.env.LICENSE_TOKEN
|
||||||
|
}
|
||||||
|
|
||||||
export function isEmailEnabled() {
|
export function isEmailEnabled() {
|
||||||
return process.env.EMAIL === 'true'
|
return process.env.EMAIL === 'true'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { getStream, grantStreamPermissions } from '@/modules/core/repositories/s
|
|||||||
import { updateWorkspaceRoleFactory } from '@/modules/workspaces/services/management'
|
import { updateWorkspaceRoleFactory } from '@/modules/workspaces/services/management'
|
||||||
import { getEventBus } from '@/modules/shared/services/eventBus'
|
import { getEventBus } from '@/modules/shared/services/eventBus'
|
||||||
import { getStreams } from '@/modules/core/services/streams'
|
import { getStreams } from '@/modules/core/services/streams'
|
||||||
|
import { validateModuleLicense } from '@/modules/gatekeeper/services/validateLicense'
|
||||||
|
|
||||||
const { FF_WORKSPACES_MODULE_ENABLED } = getFeatureFlags()
|
const { FF_WORKSPACES_MODULE_ENABLED } = getFeatureFlags()
|
||||||
|
|
||||||
@@ -31,6 +32,14 @@ const initRoles = async () => {
|
|||||||
const workspacesModule: SpeckleModule = {
|
const workspacesModule: SpeckleModule = {
|
||||||
async init(_, isInitial) {
|
async init(_, isInitial) {
|
||||||
if (!FF_WORKSPACES_MODULE_ENABLED) return
|
if (!FF_WORKSPACES_MODULE_ENABLED) return
|
||||||
|
const isWorkspaceLicenseValid = await validateModuleLicense({
|
||||||
|
requiredModules: ['workspaces']
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!isWorkspaceLicenseValid)
|
||||||
|
throw new Error(
|
||||||
|
'The workspaces module needs a valid license to run, contact Speckle to get one.'
|
||||||
|
)
|
||||||
moduleLogger.info('⚒️ Init workspaces module')
|
moduleLogger.info('⚒️ Init workspaces module')
|
||||||
|
|
||||||
if (isInitial) {
|
if (isInitial) {
|
||||||
|
|||||||
@@ -72,6 +72,7 @@
|
|||||||
"graphql-scalars": "^1.18.0",
|
"graphql-scalars": "^1.18.0",
|
||||||
"graphql-subscriptions": "^2.0.0",
|
"graphql-subscriptions": "^2.0.0",
|
||||||
"ioredis": "^5.2.2",
|
"ioredis": "^5.2.2",
|
||||||
|
"jose": "^5.6.3",
|
||||||
"knex": "^2.4.1",
|
"knex": "^2.4.1",
|
||||||
"libsodium-wrappers": "^0.7.13",
|
"libsodium-wrappers": "^0.7.13",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
|
|||||||
@@ -566,6 +566,11 @@ Generate the environment variables for Speckle server and Speckle objects deploy
|
|||||||
- name: FF_WORKSPACES_MODULE_ENABLED
|
- name: FF_WORKSPACES_MODULE_ENABLED
|
||||||
value: {{ .Values.featureFlags.workspaceModuleEnabled | quote }}
|
value: {{ .Values.featureFlags.workspaceModuleEnabled | quote }}
|
||||||
|
|
||||||
|
- name: LICENSE_TOKEN
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: "{{ default .Values.secretName .Values.server.licenseTokenSecret.secretName }}"
|
||||||
|
key: {{ default "license_token" .Values.server.licenseTokenSecret.secretKey }}
|
||||||
- name: FF_MULTIPLE_EMAILS_MODULE_ENABLED
|
- name: FF_MULTIPLE_EMAILS_MODULE_ENABLED
|
||||||
value: {{ .Values.featureFlags.multipleEmailsModuleEnabled | quote }}
|
value: {{ .Values.featureFlags.multipleEmailsModuleEnabled | quote }}
|
||||||
|
|
||||||
|
|||||||
@@ -641,6 +641,21 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"licenseTokenSecret": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"secretName": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The name of the Kubernetes Secret containing the Session secret. This is a unique value (can be generated randomly). This is expected to be provided within the Kubernetes cluster as an opaque Kubernetes Secret. Ref: https://kubernetes.io/docs/concepts/configuration/secret/#opaque-secrets",
|
||||||
|
"default": ""
|
||||||
|
},
|
||||||
|
"secretKey": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The key within the Kubernetes Secret holding the Session secret as its value.",
|
||||||
|
"default": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"sessionSecret": {
|
"sessionSecret": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|||||||
@@ -457,6 +457,14 @@ server:
|
|||||||
encryptionKeys:
|
encryptionKeys:
|
||||||
path: '/encryption-keys/keys.json'
|
path: '/encryption-keys/keys.json'
|
||||||
|
|
||||||
|
licenseTokenSecret:
|
||||||
|
## @param server.licenseTokenSecret.secretName The name of the Kubernetes Secret containing the Session secret. This is a unique value (can be generated randomly). This is expected to be provided within the Kubernetes cluster as an opaque Kubernetes Secret. Ref: https://kubernetes.io/docs/concepts/configuration/secret/#opaque-secrets
|
||||||
|
##
|
||||||
|
secretName: ''
|
||||||
|
## @param server.licenseTokenSecret.secretKey The key within the Kubernetes Secret holding the Session secret as its value.
|
||||||
|
##
|
||||||
|
secretKey: ''
|
||||||
|
|
||||||
sessionSecret:
|
sessionSecret:
|
||||||
## @param server.sessionSecret.secretName The name of the Kubernetes Secret containing the Session secret. This is a unique value (can be generated randomly). This is expected to be provided within the Kubernetes cluster as an opaque Kubernetes Secret. Ref: https://kubernetes.io/docs/concepts/configuration/secret/#opaque-secrets
|
## @param server.sessionSecret.secretName The name of the Kubernetes Secret containing the Session secret. This is a unique value (can be generated randomly). This is expected to be provided within the Kubernetes cluster as an opaque Kubernetes Secret. Ref: https://kubernetes.io/docs/concepts/configuration/secret/#opaque-secrets
|
||||||
##
|
##
|
||||||
|
|||||||
@@ -15470,6 +15470,7 @@ __metadata:
|
|||||||
http-proxy-middleware: "npm:v3.0.0-beta.0"
|
http-proxy-middleware: "npm:v3.0.0-beta.0"
|
||||||
ioredis: "npm:^5.2.2"
|
ioredis: "npm:^5.2.2"
|
||||||
ioredis-mock: "npm:^8.9.0"
|
ioredis-mock: "npm:^8.9.0"
|
||||||
|
jose: "npm:^5.6.3"
|
||||||
knex: "npm:^2.4.1"
|
knex: "npm:^2.4.1"
|
||||||
libsodium-wrappers: "npm:^0.7.13"
|
libsodium-wrappers: "npm:^0.7.13"
|
||||||
lodash: "npm:^4.17.21"
|
lodash: "npm:^4.17.21"
|
||||||
@@ -34868,6 +34869,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"jose@npm:^5.6.3":
|
||||||
|
version: 5.6.3
|
||||||
|
resolution: "jose@npm:5.6.3"
|
||||||
|
checksum: 10/829f07b8857221ada1cd112a5ebd084e34748f6e3247f5cb03aca0a1f25dd6a07283c9a4f5b854935bda505e3243405640550f8e9eb46c45b172dc4cb336ac89
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"joycon@npm:^3.1.1":
|
"joycon@npm:^3.1.1":
|
||||||
version: 3.1.1
|
version: 3.1.1
|
||||||
resolution: "joycon@npm:3.1.1"
|
resolution: "joycon@npm:3.1.1"
|
||||||
|
|||||||
Reference in New Issue
Block a user