Skip to content

Commit

Permalink
Web: add version two endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
kimlisa committed Dec 20, 2024
1 parent ec9d8ca commit b51dded
Show file tree
Hide file tree
Showing 9 changed files with 138 additions and 21 deletions.
1 change: 1 addition & 0 deletions web/packages/build/vite/html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ export function htmlPlugin(target: string): Plugin {

replaceMetaTag('grv_csrf_token', source, result);
replaceMetaTag('grv_bearer_token', source, result);
replaceMetaTag('teleport_version', source, result);

res.setHeader('set-cookie', headers['set-cookie']);
res.writeHead(200, { 'Content-Type': 'text/html' });
Expand Down
1 change: 1 addition & 0 deletions web/packages/teleport/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="grv_csrf_token" content="{{ .XCSRF }}" />
<meta name="grv_bearer_token" content="{{ .Session }}" />
<meta name="teleport_version" content="{{ .Version }}" />
<meta name="robots" content="noindex" />
<link
href="/app/favicon-light.png"
Expand Down
18 changes: 18 additions & 0 deletions web/packages/teleport/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,9 @@ const cfg = {
trustedClustersPath: '/v1/webapi/trustedcluster/:name?',
connectMyComputerLoginsPath: '/v1/webapi/connectmycomputer/logins',

// TODO(kimlisa): DELETE IN 19.0 - replaced by /v2/webapi/token
joinTokenPath: '/v1/webapi/token',
joinTokenPathV2: '/v3/webapi/token',
joinTokenYamlPath: '/v1/webapi/tokens/yaml',
joinTokensPath: '/v1/webapi/tokens',
dbScriptPath: '/scripts/:token/install-database.sh',
Expand Down Expand Up @@ -366,8 +368,11 @@ const cfg = {

eksClustersListPath:
'/v1/webapi/sites/:clusterId/integrations/aws-oidc/:name/eksclusters',
// TODO(kimlisa): DELETE IN 19.0 - replaced by /v2/webapi/sites/:clusterId/integrations/aws-oidc/:name/enrolleksclusters
eksEnrollClustersPath:
'/v1/webapi/sites/:clusterId/integrations/aws-oidc/:name/enrolleksclusters',
eksEnrollClustersPathV2:
'/v2/webapi/sites/:clusterId/integrations/aws-oidc/:name/enrolleksclusters',

ec2InstancesListPath:
'/v1/webapi/sites/:clusterId/integrations/aws-oidc/:name/ec2',
Expand Down Expand Up @@ -577,6 +582,10 @@ const cfg = {
return cfg.api.joinTokenPath;
},

getJoinTokenV2Url() {
return cfg.api.joinTokenPathV2;
},

getJoinTokenYamlUrl() {
return cfg.api.joinTokenYamlPath;
},
Expand Down Expand Up @@ -1088,6 +1097,15 @@ const cfg = {
});
},

getEnrollEksClusterV2Url(integrationName: string): string {
const clusterId = cfg.proxyCluster;

return generatePath(cfg.api.eksEnrollClustersPathV2, {
clusterId,
name: integrationName,
});
},

getListEKSClustersUrl(integrationName: string): string {
const clusterId = cfg.proxyCluster;

Expand Down
2 changes: 1 addition & 1 deletion web/packages/teleport/src/services/agents/make.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ function makeTraces(traces: any): ConnectionDiagnosticTrace[] {
export function makeLabelMapOfStrArrs(labels: ResourceLabel[] = []) {
const m: Record<string, string[]> = {};

labels.forEach(label => {
labels?.forEach(label => {
if (!m[label.name]) {
m[label.name] = [];
}
Expand Down
26 changes: 21 additions & 5 deletions web/packages/teleport/src/services/integrations/integrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import makeNode from '../nodes/makeNode';
import auth, { MfaChallengeScope } from '../auth/auth';
import { App } from '../apps';
import makeApp from '../apps/makeApps';
import { withUnsupportedLabelFeatureErrorConversion } from '../webUiVersion/webUiVersion';

import {
Integration,
Expand Down Expand Up @@ -320,11 +321,26 @@ export const integrationService = {
): Promise<EnrollEksClustersResponse> {
const mfaResponse = await auth.getMfaChallengeResponseForAdminAction(true);

return api.post(
cfg.getEnrollEksClusterUrl(integrationName),
req,
null,
mfaResponse
// TODO(kimlisa): DELETE IN 19.0 - replaced by v2 endpoint.
if (!req.extraLabels?.length) {
return api.post(
cfg.getEnrollEksClusterUrl(integrationName),
req,
null,
mfaResponse
);
}

return (
api
.post(
cfg.getEnrollEksClusterV2Url(integrationName),
req,
null,
mfaResponse
)
// TODO(kimlisa): DELETE IN 19.0
.catch(withUnsupportedLabelFeatureErrorConversion)
);
},

Expand Down
6 changes: 6 additions & 0 deletions web/packages/teleport/src/services/integrations/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import { Label } from 'teleport/types';

import { Node } from '../nodes';
import { ResourceLabel } from '../agents';

/**
* type Integration v. type Plugin:
Expand Down Expand Up @@ -539,6 +540,11 @@ export type EnrollEksClustersRequest = {
region: string;
enableAppDiscovery: boolean;
clusterNames: string[];
/**
* User provided labels.
* Only supported with V2 endpoint
*/
extraLabels?: ResourceLabel[];
};

export type EnrollEksClustersResponse = {
Expand Down
52 changes: 38 additions & 14 deletions web/packages/teleport/src/services/joinToken/joinToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import api from 'teleport/services/api';
import cfg from 'teleport/config';

import { makeLabelMapOfStrArrs } from '../agents/make';
import { withUnsupportedLabelFeatureErrorConversion } from '../webUiVersion/webUiVersion';

import makeJoinToken from './makeJoinToken';
import { JoinToken, JoinRule, JoinTokenRequest } from './types';
Expand All @@ -32,20 +33,43 @@ class JoinTokenService {
req: JoinTokenRequest,
signal: AbortSignal = null
): Promise<JoinToken> {
return api
.post(
cfg.getJoinTokenUrl(),
{
roles: req.roles,
join_method: req.method || 'token',
allow: makeAllowField(req.rules || []),
suggested_agent_matcher_labels: makeLabelMapOfStrArrs(
req.suggestedAgentMatcherLabels
),
},
signal
)
.then(makeJoinToken);
// TODO(kimlisa): DELETE IN 19.0 - replaced by v2 endpoint.
if (!req.suggestedLabels?.length) {
return api
.post(
cfg.getJoinTokenUrl(),
{
roles: req.roles,
join_method: req.method || 'token',
allow: makeAllowField(req.rules || []),
suggested_agent_matcher_labels: makeLabelMapOfStrArrs(
req.suggestedAgentMatcherLabels
),
},
signal
)
.then(makeJoinToken);
}

return (
api
.post(
cfg.getJoinTokenV2Url(),
{
roles: req.roles,
join_method: req.method || 'token',
allow: makeAllowField(req.rules || []),
suggested_agent_matcher_labels: makeLabelMapOfStrArrs(
req.suggestedAgentMatcherLabels
),
suggested_labels: makeLabelMapOfStrArrs(req.suggestedLabels),
},
signal
)
.then(makeJoinToken)
// TODO(kimlisa): DELETE IN 19.0
.catch(withUnsupportedLabelFeatureErrorConversion)
);
}

upsertJoinTokenYAML(
Expand Down
11 changes: 10 additions & 1 deletion web/packages/teleport/src/services/joinToken/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ export type CreateJoinTokenRequest = {
export type JoinTokenRequest = {
// roles is a list of join roles, since there can be more than
// one role associated with a token.
roles?: JoinRole[];
roles: JoinRole[];
// rules is a list of allow rules associated with the join token
// and the node using this token must match one of the rules.
rules?: JoinRule[];
Expand All @@ -138,4 +138,13 @@ export type JoinTokenRequest = {
method?: JoinMethod;
// content is the yaml content of the joinToken to be created
content?: string;
/**
* User provided labels.
* SuggestedLabels is a set of labels that resources should set when using this token to enroll
* themselves in the cluster.
* Currently, only node-join scripts create a configuration according to the suggestion.
*
* Only supported with V2 endpoint.
*/
suggestedLabels?: ResourceLabel[];
};
42 changes: 42 additions & 0 deletions web/packages/teleport/src/services/webUiVersion/webUiVersion.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Teleport
* Copyright (C) 2024 Gravitational, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import { ApiError } from '../api/parseError';

export function getWebUiVersion() {
const metaTag = document.querySelector<HTMLMetaElement>(
'[name=teleport_version]'
);
return metaTag?.content || '';
}

export function withUnsupportedLabelFeatureErrorConversion(
err: any
): Promise<any> {
if (err instanceof ApiError) {
if (err.response.status === 404) {
throw new Error(
'We could not complete your request. ' +
'Your proxy may be behind the minimum required version ' +
`(${getWebUiVersion()}) to support adding resource labels. ` +
'Remove labels and try again or upgrade your proxy version.'
);
}
}
throw err;
}

0 comments on commit b51dded

Please sign in to comment.