Skip to content

Web: Add alternate EC2 auto discover flow using AWS Systems Manager (SSM)#42038

Merged
kimlisa merged 6 commits intomasterfrom
lisa/ssm-flow
May 30, 2024
Merged

Web: Add alternate EC2 auto discover flow using AWS Systems Manager (SSM)#42038
kimlisa merged 6 commits intomasterfrom
lisa/ssm-flow

Conversation

@kimlisa
Copy link
Copy Markdown
Contributor

@kimlisa kimlisa commented May 25, 2024

closes #41002

There are two version of the flow:

  • cloud has discovery service already running for them, so all that needs to be done is create a discovery config
  • self hosted requires manual deploying of teleport service, so there is an additional step where users need to configure a discovery service before creating a discovery config

new selectable tile:

image

creating a discovery config step (cloud + self hosted):

image

configuring a discovery service step for self hosted only

image

changelog: Add an alternate EC2 auto discover flow using AWS Systems Manager as a more scalable method than EICE in the "Enroll New Resource" view in the web UI

// kubeAppDiscovery specifies if Kubernetes App Discovery should be enabled for a discovered cluster.
kubeAppDiscovery?: boolean;
/**
* InstallParams sets the join method when installing on
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* InstallParams sets the join method when installing on
* install sets the join method when installing on

JSDocs above have similar minor issues where the name in the comment doesn't quite match the name in the code.

'TeleportDiscoveryInstaller'
);
const [scriptUrl, setScriptUrl] = useState('');
const [createdToken, setCreatedToken] = useState<JoinToken>();
Copy link
Copy Markdown
Member

@ravicious ravicious May 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's not used for rendering but merely in event handlers, then it could be a ref. This saves an unnecessary re-render and paints a better picture as to how this piece of state is used.

This also simplifies the code a tiny tiny bit, because someone reading the code doesn't have to understand how joinToken differs from createdToken. With a ref there can be a single joinTokenRef.

Patch
diff --git a/web/packages/teleport/src/Discover/Server/DiscoveryConfigSsm/DiscoveryConfigSsm.tsx b/web/packages/teleport/src/Discover/Server/DiscoveryConfigSsm/DiscoveryConfigSsm.tsx
index 32c34ddefa..c622a6607d 100644
--- a/web/packages/teleport/src/Discover/Server/DiscoveryConfigSsm/DiscoveryConfigSsm.tsx
+++ b/web/packages/teleport/src/Discover/Server/DiscoveryConfigSsm/DiscoveryConfigSsm.tsx
@@ -16,7 +16,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-import React, { useState } from 'react';
+import React, { useState, useRef } from 'react';
 import {
   Box,
   Link as ExternalLink,
@@ -70,7 +70,7 @@ export function DiscoveryConfigSsm() {
     'TeleportDiscoveryInstaller'
   );
   const [scriptUrl, setScriptUrl] = useState('');
-  const [createdToken, setCreatedToken] = useState<JoinToken>();
+  const joinTokenRef = useRef<JoinToken>();
   const [showRestOfSteps, setShowRestOfSteps] = useState(false);
 
   const [attempt, createJoinTokenAndDiscoveryConfig, setAttempt] = useAsync(
@@ -80,14 +80,12 @@ export function DiscoveryConfigSsm() {
         // Don't create another token if token was already created.
         // This can happen if creating discovery config attempt failed
         // and the user retries.
-        let joinToken = createdToken;
-        if (!joinToken) {
-          joinToken = await joinTokenService.fetchJoinToken({
+        if (!joinTokenRef.current) {
+          joinTokenRef.current = await joinTokenService.fetchJoinToken({
             roles: ['Node'],
             method: 'iam',
             rules: [{ awsAccountId }],
           });
-          setCreatedToken(joinToken);
         }
 
         const config = await createDiscoveryConfig(clusterId, {
@@ -105,7 +103,7 @@ export function DiscoveryConfigSsm() {
               install: {
                 enrollMode: InstallParamEnrollMode.Script,
                 installTeleport: true,
-                joinToken: joinToken.id,
+                joinToken: joinTokenRef.current.id,
               },
             },
           ],
@@ -138,7 +136,7 @@ export function DiscoveryConfigSsm() {
 
   function clear() {
     setAttempt(makeEmptyAttempt);
-    setCreatedToken(null);
+    joinTokenRef.current = undefined;
   }
 
   return (

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is nice, ty 👍

Comment on lines +22 to +26
Link as ExternalLink,
Text,
Flex,
ButtonSecondary,
Link,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Link is imported twice.

Comment on lines +229 to +271
<Validation>
{({ validator }) => (
<StyledBox mt={4}>
<Text bold>Step 4</Text>
<Box>
<Text typography="subtitle1" mb={1}>
Give a name for the{' '}
<Link
target="_blank"
href="https://docs.aws.amazon.com/systems-manager/latest/userguide/documents.html"
>
AWS SSM Document
</Link>{' '}
that will be created on your behalf. Required to run the
installer script on each discovered instances.
</Text>
<FieldInput
rule={requiredSsmDocument}
label="SSM Document Name"
value={ssmDocumentName}
onChange={e => setSsmDocumentName(e.target.value)}
placeholder="ssm-document-name"
disabled={!!scriptUrl}
/>
</Box>
<ButtonSecondary
onClick={() =>
scriptUrl ? setScriptUrl('') : generateScriptUrl(validator)
}
disabled={!selectedRegion}
>
{scriptUrl ? 'Edit' : 'Next'}
</ButtonSecondary>
</StyledBox>
)}
</Validation>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be an actual <form> with onSubmit and with type="submit" on the button. This way it could be submitted either by clicking the button or inputting some text in the field and then pressing enter.

install?: {
/**
* EnrollMode indicates the mode used to enroll the node into Teleport.
* Valid values: script, eice.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean that Unspecified is not allowed?
If so, I'd specify the type as InstallParamEnrollMode.Script | InstallParamEnrollMode.Eice and remove the comment.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I instead removed the Unspecified enum value instead

};
};

const SharedText = () => (
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to have more meaningful name here.

Comment on lines +32 to +35
export enum InstallParamEnrollMode {
'Unspecified' = 0,
'Script' = 1,
'Eice' = 2,
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
export enum InstallParamEnrollMode {
'Unspecified' = 0,
'Script' = 1,
'Eice' = 2,
}
export enum InstallParamEnrollMode {
Unspecified = 0,
Script = 1,
Eice = 2,
}

@zmb3
Copy link
Copy Markdown
Collaborator

zmb3 commented May 28, 2024

We now have two very similar-looking EC2 tiles on the integrations page. How do we expect users to know which one to click? Do we have a preference? Should we guide users towards our preference in some way?

If I'm new to Teleport and I'm trying to add an EC2 instance, I would probably click "EC2 instance" because it sounds simpler than "EC2 Auto Discover with SSM"

@kimlisa
Copy link
Copy Markdown
Contributor Author

kimlisa commented May 30, 2024

We now have two very similar-looking EC2 tiles on the integrations page. How do we expect users to know which one to click? Do we have a preference? Should we guide users towards our preference in some way?

If I'm new to Teleport and I'm trying to add an EC2 instance, I would probably click "EC2 instance" because it sounds simpler than "EC2 Auto Discover with SSM"

we had a discussion about this today and concluded to remove all support for ec2 instance enrolling with eice method (since it has limitations scale wise) and opted for this single tile instead (since we want auto enrollment to be the default)

image

when user clicks on this tile, the user is presented with an info box that lets user know how to install a single instance if they wish

image

@kimlisa kimlisa force-pushed the lisa/ssm-flow branch 4 times, most recently from 722ebb2 to c339061 Compare May 30, 2024 18:45
@kimlisa kimlisa added this pull request to the merge queue May 30, 2024
Merged via the queue into master with commit bfe1e5f May 30, 2024
@kimlisa kimlisa deleted the lisa/ssm-flow branch May 30, 2024 21:17
@public-teleport-github-review-bot
Copy link
Copy Markdown

@kimlisa See the table below for backport results.

Branch Result
branch/v15 Create PR
branch/v16 Create PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Discover flow for EC2 using Script installation method

4 participants