@@ -242,6 +242,149 @@ def create_azure(
242242 _connect_cloud (name = "azure" , credentials = credentials )
243243
244244
245+ @cloud_create .command (name = "aws" )
246+ def create_aws (
247+ name : str = typer .Option (
248+ None ,
249+ "--name" ,
250+ help = "Name for the IAM user (optional, auto-generated if not provided)"
251+ ),
252+ policy_arn : str = typer .Option (
253+ "arn:aws:iam::aws:policy/AmazonEC2FullAccess" ,
254+ "--policy-arn" ,
255+ help = "IAM policy ARN to attach to the user"
256+ ),
257+ auto_connect : bool = typer .Option (
258+ False ,
259+ "--auto-connect" ,
260+ help = "Automatically connect the created credentials to Cirun"
261+ ),
262+ ):
263+ """Create AWS IAM User credentials for Cirun"""
264+ import os
265+
266+ console = Console ()
267+ error_console = Console (stderr = True , style = "bold red" )
268+
269+ if auto_connect and not os .environ .get ("CIRUN_API_KEY" ):
270+ error_console .print ("Error: CIRUN_API_KEY environment variable is required for --auto-connect" )
271+ raise typer .Exit (code = 1 )
272+
273+ # Check if AWS CLI is installed
274+ try :
275+ subprocess .run (
276+ ["aws" , "--version" ],
277+ capture_output = True ,
278+ check = True
279+ )
280+ except (subprocess .CalledProcessError , FileNotFoundError ):
281+ error_console .print ("Error: AWS CLI is not installed or not found in PATH" )
282+ error_console .print ("Install it from: https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html" )
283+ raise typer .Exit (code = 1 )
284+
285+ # Check caller identity
286+ console .print ("[bold blue]Checking AWS CLI configuration...[/bold blue]" )
287+ try :
288+ result = subprocess .run (
289+ ["aws" , "sts" , "get-caller-identity" , "--output" , "json" ],
290+ capture_output = True ,
291+ check = True ,
292+ text = True
293+ )
294+ caller_identity = json .loads (result .stdout )
295+ except subprocess .CalledProcessError :
296+ error_console .print ("Error: Not authenticated with AWS CLI" )
297+ error_console .print ("Please run: aws configure" )
298+ raise typer .Exit (code = 1 )
299+
300+ # Display account details
301+ console .print ("\n [bold green]AWS Account Details:[/bold green]" )
302+ console .print (f" Account ID: [bold]{ caller_identity .get ('Account' , 'N/A' )} [/bold]" )
303+ console .print (f" ARN: [bold]{ caller_identity .get ('Arn' , 'N/A' )} [/bold]" )
304+ console .print (f" User ID: [bold]{ caller_identity .get ('UserId' , 'N/A' )} [/bold]" )
305+ console .print ("" )
306+
307+ # Generate IAM user name if not provided
308+ if not name :
309+ from datetime import datetime , timezone
310+ name = f"cirun-{ datetime .now (timezone .utc ).strftime ('%Y%m%d-%H%M%S' )} "
311+
312+ # Confirm before creating
313+ typer .confirm (
314+ f"Create IAM user '{ name } ' with policy '{ policy_arn } '?" ,
315+ abort = True ,
316+ )
317+
318+ # Create IAM user
319+ console .print (f"[bold blue]Creating IAM user '[bold green]{ name } [/bold green]'...[/bold blue]" )
320+ try :
321+ subprocess .run (
322+ ["aws" , "iam" , "create-user" , "--user-name" , name ],
323+ capture_output = True ,
324+ check = True ,
325+ text = True
326+ )
327+ except subprocess .CalledProcessError as e :
328+ error_console .print (f"Error creating IAM user: { e .stderr } " )
329+ raise typer .Exit (code = 1 )
330+
331+ # Attach policy
332+ console .print (f"[bold blue]Attaching policy [bold green]{ policy_arn } [/bold green]...[/bold blue]" )
333+ try :
334+ subprocess .run (
335+ [
336+ "aws" , "iam" , "attach-user-policy" ,
337+ "--user-name" , name ,
338+ "--policy-arn" , policy_arn ,
339+ ],
340+ capture_output = True ,
341+ check = True ,
342+ text = True
343+ )
344+ except subprocess .CalledProcessError as e :
345+ error_console .print (f"Error attaching policy: { e .stderr } " )
346+ raise typer .Exit (code = 1 )
347+
348+ # Create access key
349+ console .print ("[bold blue]Creating access key...[/bold blue]" )
350+ try :
351+ result = subprocess .run (
352+ ["aws" , "iam" , "create-access-key" , "--user-name" , name , "--output" , "json" ],
353+ capture_output = True ,
354+ check = True ,
355+ text = True
356+ )
357+ key_data = json .loads (result .stdout ).get ("AccessKey" , {})
358+ except subprocess .CalledProcessError as e :
359+ error_console .print (f"Error creating access key: { e .stderr } " )
360+ raise typer .Exit (code = 1 )
361+
362+ access_key = key_data .get ("AccessKeyId" )
363+ secret_key = key_data .get ("SecretAccessKey" )
364+
365+ # Display credentials
366+ success_console = Console (style = "bold green" )
367+ success_console .rule ("[bold green]" )
368+ success_console .print ("[bold green]✓[/bold green] IAM user created successfully!" )
369+ success_console .print ("" )
370+ success_console .print ("[bold yellow]AWS Credentials for Cirun:[/bold yellow]" )
371+ success_console .print ("" )
372+ success_console .print (f" AWS_ACCESS_KEY_ID: [bold]{ access_key } [/bold]" )
373+ success_console .print (f" AWS_SECRET_ACCESS_KEY: [bold]{ secret_key } [/bold]" )
374+ success_console .print ("" )
375+ success_console .print ("[bold red]⚠️ Save the SECRET_ACCESS_KEY - it won't be shown again![/bold red]" )
376+ success_console .rule ("[bold green]" )
377+
378+ # Auto-connect if requested
379+ if auto_connect :
380+ console .print ("\n [bold blue]Connecting credentials to Cirun...[/bold blue]" )
381+ credentials = {
382+ "access_key" : access_key ,
383+ "secret_key" : secret_key ,
384+ }
385+ _connect_cloud (name = "aws" , credentials = credentials )
386+
387+
245388@cloud_create .command (name = "gcp" )
246389def create_gcp (
247390 name : str = typer .Option (
0 commit comments