@@ -8,7 +8,7 @@ import * as nls from 'vscode-nls'
88const localize = nls . loadMessageBundle ( )
99
1010import { Settings } from '../shared/settings'
11- import { showMessageWithCancel } from './utilities/messages'
11+ import { showConfirmationMessage , showMessageWithCancel } from './utilities/messages'
1212import { CancellationError , Timeout } from './utilities/timeoutUtils'
1313import { isExtensionInstalled , showInstallExtensionMsg } from './utilities/vsCodeUtils'
1414import { VSCODE_EXTENSION_ID , vscodeExtensionMinVersion } from './extensions'
@@ -21,6 +21,9 @@ import { ChildProcess } from './utilities/childProcess'
2121import { findSshPath , getVscodeCliPath } from './utilities/pathFind'
2222import { IamClient } from './clients/iamClient'
2323import { IAM } from 'aws-sdk'
24+ import { getIdeProperties } from './extensionUtilities'
25+
26+ const policyAttachDelay = 5000
2427
2528export interface MissingTool {
2629 readonly name : 'code' | 'ssm' | 'ssh'
@@ -32,6 +35,9 @@ const minimumSsmActions = [
3235 'ssmmessages:CreateDataChannel' ,
3336 'ssmmessages:OpenControlChannel' ,
3437 'ssmmessages:OpenDataChannel' ,
38+ 'ssm:DescribeAssociation' ,
39+ 'ssm:ListAssociations' ,
40+ 'ssm:UpdateInstanceInformation' ,
3541]
3642
3743export async function openRemoteTerminal ( options : vscode . TerminalOptions , onClose : ( ) => void ) {
@@ -175,6 +181,68 @@ export async function handleMissingTool(tools: Err<MissingTool[]>) {
175181 )
176182}
177183
184+ function getFormattedSsmActions ( ) {
185+ const formattedActions = minimumSsmActions . map ( ( action ) => `"${ action } ",\n` ) . reduce ( ( l , r ) => l + r )
186+
187+ return formattedActions . slice ( 0 , formattedActions . length - 2 )
188+ }
189+
190+ /**
191+ * Shows a progress message for adding inline policy to the role, then adds the policy.
192+ * Importantly, it keeps the progress bar up for `policyAttachDelay` additional ms to allow permissions to propagate.
193+ * If user cancels, it throws a CancellationError and stops the process from subsequently opening a connection.
194+ * @param client IamClient to be use to add the permissions.
195+ * @param roleArn Arn of the role the inline policy should be added to.
196+ */
197+ async function addInlinePolicyWithDelay ( client : IamClient , roleArn : string ) {
198+ const timeout = new Timeout ( policyAttachDelay )
199+ const message = `Adding Inline Policy to ${ roleArn } `
200+ await showMessageWithCancel ( message , timeout )
201+ await addSsmActionsToInlinePolicy ( client , roleArn )
202+
203+ function delay ( ms : number ) {
204+ return new Promise ( ( resolve ) => setTimeout ( resolve , ms ) )
205+ }
206+
207+ await delay ( policyAttachDelay )
208+ if ( timeout . elapsedTime < policyAttachDelay ) {
209+ throw new CancellationError ( 'user' )
210+ }
211+ timeout . cancel ( )
212+ }
213+
214+ export async function promptToAddInlinePolicy ( client : IamClient , roleArn : string ) : Promise < boolean > {
215+ const promptText = `${
216+ getIdeProperties ( ) . company
217+ } Toolkit will add required actions to role ${ roleArn } :\n${ getFormattedSsmActions ( ) } `
218+ const confirmation = await showConfirmationMessage ( { prompt : promptText , confirm : 'Approve' } )
219+
220+ if ( confirmation ) {
221+ await addInlinePolicyWithDelay ( client , roleArn )
222+ }
223+
224+ return confirmation
225+ }
226+
227+ async function addSsmActionsToInlinePolicy ( client : IamClient , roleArn : string ) {
228+ const policyName = 'AWSVSCodeRemoteConnect'
229+ const policyDocument = getSsmPolicyDocument ( )
230+ await client . putRolePolicy ( roleArn , policyName , policyDocument )
231+ }
232+
233+ function getSsmPolicyDocument ( ) {
234+ return `{
235+ "Version": "2012-10-17",
236+ "Statement": {
237+ "Effect": "Allow",
238+ "Action": [
239+ ${ getFormattedSsmActions ( ) }
240+ ],
241+ "Resource": "*"
242+ }
243+ }`
244+ }
245+
178246export async function getDeniedSsmActions ( client : IamClient , roleArn : string ) : Promise < IAM . EvaluationResult [ ] > {
179247 const deniedActions = await client . getDeniedActions ( {
180248 PolicySourceArn : roleArn ,
0 commit comments