5
5
6
6
import * as vscode from 'vscode'
7
7
import * as nls from 'vscode-nls'
8
- const localize = nls . loadMessageBundle ( )
9
8
10
9
import { Settings } from '../shared/settings'
11
- import { showMessageWithCancel } from './utilities/messages'
10
+ import { showConfirmationMessage , showMessageWithCancel } from './utilities/messages'
12
11
import { CancellationError , Timeout } from './utilities/timeoutUtils'
13
12
import { isExtensionInstalled , showInstallExtensionMsg } from './utilities/vsCodeUtils'
14
13
import { VSCODE_EXTENSION_ID , vscodeExtensionMinVersion } from './extensions'
@@ -21,16 +20,28 @@ import { pushIf } from './utilities/collectionUtils'
21
20
import { ChildProcess } from './utilities/childProcess'
22
21
import { IamClient } from './clients/iamClient'
23
22
import { IAM } from 'aws-sdk'
23
+ import { getIdeProperties } from './extensionUtilities'
24
+
25
+ const localize = nls . loadMessageBundle ( )
24
26
25
27
export interface MissingTool {
26
28
readonly name : 'code' | 'ssm' | 'ssh'
27
29
readonly reason ?: string
28
30
}
29
31
32
+ const minimumSsmActions = [
33
+ 'ssmmessages:CreateControlChannel' ,
34
+ 'ssmmessages:CreateDataChannel' ,
35
+ 'ssmmessages:OpenControlChannel' ,
36
+ 'ssmmessages:OpenDataChannel' ,
37
+ ]
38
+
39
+ const policyAttachDelay = 5000
40
+
30
41
export async function openRemoteTerminal ( options : vscode . TerminalOptions , onClose : ( ) => void ) {
31
42
const timeout = new Timeout ( 60000 )
32
43
33
- await showMessageWithCancel ( 'AWS: Starting session ...' , timeout , 1000 )
44
+ await showMessageWithCancel ( 'AWS: Opening remote terminal ...' , timeout , 1000 )
34
45
await withoutShellIntegration ( async ( ) => {
35
46
const terminal = vscode . window . createTerminal ( options )
36
47
@@ -173,13 +184,63 @@ export async function handleMissingTool(tools: Err<MissingTool[]>) {
173
184
export async function getDeniedSsmActions ( client : IamClient , roleArn : string ) : Promise < IAM . EvaluationResult [ ] > {
174
185
const deniedActions = await client . getDeniedActions ( {
175
186
PolicySourceArn : roleArn ,
176
- ActionNames : [
177
- 'ssmmessages:CreateControlChannel' ,
178
- 'ssmmessages:CreateDataChannel' ,
179
- 'ssmmessages:OpenControlChannel' ,
180
- 'ssmmessages:OpenDataChannel' ,
181
- ] ,
187
+ ActionNames : minimumSsmActions ,
182
188
} )
183
189
184
190
return deniedActions
185
191
}
192
+
193
+ export async function promptToAddInlinePolicy ( client : IamClient , roleArn : string ) : Promise < boolean > {
194
+ const promptText = `${
195
+ getIdeProperties ( ) . company
196
+ } Toolkit will add required actions to role ${ roleArn } :\n${ getFormattedSsmActions ( ) } `
197
+ const confirmation = await showConfirmationMessage ( { prompt : promptText , confirm : 'Approve' } )
198
+
199
+ if ( confirmation ) {
200
+ await addInlinePolicyWithDelay ( client , roleArn )
201
+ }
202
+
203
+ return confirmation
204
+ }
205
+
206
+ async function addInlinePolicyWithDelay ( client : IamClient , roleArn : string ) {
207
+ const timeout = new Timeout ( policyAttachDelay )
208
+ const message = `Adding Inline Policy to ${ roleArn } `
209
+ await showMessageWithCancel ( message , timeout )
210
+ await addSsmActionsToInlinePolicy ( client , roleArn )
211
+
212
+ function delay ( ms : number ) {
213
+ return new Promise ( resolve => setTimeout ( resolve , ms ) )
214
+ }
215
+
216
+ await delay ( policyAttachDelay )
217
+ if ( timeout . elapsedTime < policyAttachDelay ) {
218
+ throw new CancellationError ( 'user' )
219
+ }
220
+ timeout . cancel ( )
221
+ }
222
+
223
+ function getFormattedSsmActions ( ) {
224
+ const formattedActions = minimumSsmActions . map ( action => `"${ action } ",\n` ) . reduce ( ( l , r ) => l + r )
225
+
226
+ return formattedActions . slice ( 0 , formattedActions . length - 2 )
227
+ }
228
+
229
+ function getSsmPolicyDocument ( ) {
230
+ return `{
231
+ "Version": "2012-10-17",
232
+ "Statement": {
233
+ "Effect": "Allow",
234
+ "Action": [
235
+ ${ getFormattedSsmActions ( ) }
236
+ ],
237
+ "Resource": "*"
238
+ }
239
+ }`
240
+ }
241
+
242
+ async function addSsmActionsToInlinePolicy ( client : IamClient , roleArn : string ) {
243
+ const policyName = 'AWSVSCodeRemoteConnect'
244
+ const policyDocument = getSsmPolicyDocument ( )
245
+ await client . putRolePolicy ( roleArn , policyName , policyDocument )
246
+ }
0 commit comments