Exemplo n.º 1
0
        protected Func <Task <Settings> > CreateSettingsInitializer(
            CommandLineApplication cmd,
            bool requireAwsProfile = true
            )
        {
            CommandOption awsProfileOption = null;
            CommandOption awsRegionOption  = null;

            // add misc options
            var tierOption = AddTierOption(cmd);

            if (requireAwsProfile)
            {
                awsProfileOption = cmd.Option("--aws-profile|-P <NAME>", "(optional) Use a specific AWS profile from the AWS credentials file", CommandOptionType.SingleValue);
                awsRegionOption  = cmd.Option("--aws-region <NAME>", "(optional) Use a specific AWS region (default: read from AWS profile)", CommandOptionType.SingleValue);
            }
            var verboseLevelOption = cmd.Option("--verbose|-V[:<LEVEL>]", "(optional) Show verbose output (0=Quiet, 1=Normal, 2=Detailed, 3=Exceptions; Normal if LEVEL is omitted)", CommandOptionType.SingleOrNoValue);
            var noAnsiOutputOption = cmd.Option("--no-ansi", "Disable colored ANSI terminal output", CommandOptionType.NoValue);

            // add hidden testing options
            var awsAccountIdOption         = cmd.Option("--aws-account-id <VALUE>", "(test only) Override AWS account Id (default: read from AWS profile)", CommandOptionType.SingleValue);
            var awsUserArnOption           = cmd.Option("--aws-user-arn <ARN>", "(test only) Override AWS user ARN (default: read from AWS profile)", CommandOptionType.SingleValue);
            var toolVersionOption          = cmd.Option("--cli-version <VALUE>", "(test only) LambdaSharp CLI version for profile", CommandOptionType.SingleValue);
            var deploymentBucketNameOption = cmd.Option("--deployment-bucket-name <NAME>", "(test only) S3 Bucket name used to deploy modules (default: read from LambdaSharp CLI configuration)", CommandOptionType.SingleValue);
            var tierVersionOption          = cmd.Option("--tier-version <VERSION>", "(test only) LambdaSharp tier version (default: read from deployment tier)", CommandOptionType.SingleValue);
            var promptsAsErrorsOption      = cmd.Option("--prompts-as-errors", "(optional) Missing parameters cause an error instead of a prompts (use for CI/CD to avoid unattended prompts)", CommandOptionType.NoValue);

            awsAccountIdOption.ShowInHelpText         = false;
            awsUserArnOption.ShowInHelpText           = false;
            toolVersionOption.ShowInHelpText          = false;
            deploymentBucketNameOption.ShowInHelpText = false;
            tierVersionOption.ShowInHelpText          = false;
            return(async() => {
                // check if ANSI console output needs to be disabled
                if (noAnsiOutputOption.HasValue())
                {
                    Settings.UseAnsiConsole = false;
                }

                // check if experimental caching feature is enabled
                Settings.AllowCaching = string.Equals((Environment.GetEnvironmentVariable("LAMBDASHARP_FEATURE_CACHING") ?? "false"), "true", StringComparison.OrdinalIgnoreCase);

                // initialize logging level
                if (!TryParseEnumOption(verboseLevelOption, Tool.VerboseLevel.Normal, VerboseLevel.Detailed, out Settings.VerboseLevel))
                {
                    // NOTE (2018-08-04, bjorg): no need to add an error message since it's already added by 'TryParseEnumOption'
                    return null;
                }

                // initialize deployment tier
                string tier = tierOption.Value() ?? Environment.GetEnvironmentVariable("LAMBDASHARP_TIER") ?? "";

                // initialize AWS profile
                try {
                    AwsAccountInfo awsAccount = null;
                    IAmazonSimpleSystemsManagement ssmClient = null;
                    IAmazonCloudFormation cfnClient = null;
                    IAmazonKeyManagementService kmsClient = null;
                    IAmazonS3 s3Client = null;
                    IAmazonAPIGateway apiGatewayClient = null;
                    IAmazonIdentityManagementService iamClient = null;
                    IAmazonLambda lambdaClient = null;
                    if (requireAwsProfile)
                    {
                        awsAccount = await InitializeAwsProfile(
                            awsProfileOption.Value(),
                            awsAccountIdOption.Value(),
                            awsRegionOption.Value(),
                            awsUserArnOption.Value(),

                            // TODO (2019-10-08, bjorg): provide option to disable profile caching (or at least force a reset)
                            allowCaching : true
                            );

                        if (awsAccount == null)
                        {
                            return null;
                        }

                        // create AWS clients
                        ssmClient = new AmazonSimpleSystemsManagementClient();
                        cfnClient = new AmazonCloudFormationClient();
                        kmsClient = new AmazonKeyManagementServiceClient();
                        s3Client = new AmazonS3Client();
                        apiGatewayClient = new AmazonAPIGatewayClient();
                        iamClient = new AmazonIdentityManagementServiceClient();
                        lambdaClient = new AmazonLambdaClient();
                    }
                    if (HasErrors)
                    {
                        return null;
                    }

                    // initialize LambdaSharp deployment values
                    var tierVersion = tierVersionOption.Value();
                    var deploymentBucketName = deploymentBucketNameOption.Value();

                    // create a settings instance for each module filename
                    return new Settings {
                        ToolVersion = Version,
                        TierVersion = (tierVersion != null) ? VersionInfo.Parse(tierVersion) : null,
                        Tier = tier,
                        AwsRegion = awsAccount?.Region,
                        AwsAccountId = awsAccount?.AccountId,
                        AwsUserArn = awsAccount?.UserArn,
                        DeploymentBucketName = deploymentBucketName,
                        SsmClient = ssmClient,
                        CfnClient = cfnClient,
                        KmsClient = kmsClient,
                        S3Client = s3Client,
                        ApiGatewayClient = apiGatewayClient,
                        IamClient = iamClient,
                        LambdaClient = lambdaClient,
                        PromptsAsErrors = promptsAsErrorsOption.HasValue()
                    };
                } catch (AmazonClientException e) when(e.Message == "No RegionEndpoint or ServiceURL configured")
                {
                    LogError("AWS profile is missing a region specifier");
                    return null;
                }
            });
        }
Exemplo n.º 2
0
        protected Func <Task <Settings> > CreateSettingsInitializer(
            CommandLineApplication cmd,
            bool requireAwsProfile = true
            )
        {
            CommandOption awsProfileOption = null;
            CommandOption awsRegionOption  = null;

            // add misc options
            var tierOption = cmd.Option("--tier|-T <NAME>", "(optional) Name of deployment tier (default: LAMBDASHARP_TIER environment variable)", CommandOptionType.SingleValue);

            if (requireAwsProfile)
            {
                awsProfileOption = cmd.Option("--aws-profile|-P <NAME>", "(optional) Use a specific AWS profile from the AWS credentials file", CommandOptionType.SingleValue);
                awsRegionOption  = cmd.Option("--aws-region <NAME>", "(optional) Use a specific AWS region (default: read from AWS profile)", CommandOptionType.SingleValue);
            }

            // add hidden testing options
            var awsAccountIdOption         = cmd.Option("--aws-account-id <VALUE>", "(test only) Override AWS account Id (default: read from AWS profile)", CommandOptionType.SingleValue);
            var awsUserArnOption           = cmd.Option("--aws-user-arn <ARN>", "(test only) Override AWS user ARN (default: read from AWS profile)", CommandOptionType.SingleValue);
            var toolVersionOption          = cmd.Option("--cli-version <VALUE>", "(test only) LambdaSharp CLI version for profile", CommandOptionType.SingleValue);
            var deploymentBucketNameOption = cmd.Option("--deployment-bucket-name <NAME>", "(test only) S3 Bucket name used to deploy modules (default: read from LambdaSharp CLI configuration)", CommandOptionType.SingleValue);
            var tierVersionOption          = cmd.Option("--tier-version <VERSION>", "(test only) LambdaSharp tier version (default: read from deployment tier)", CommandOptionType.SingleValue);
            var promptsAsErrorsOption      = cmd.Option("--prompts-as-errors", "(optional) Missing parameters cause an error instead of a prompts (use for CI/CD to avoid unattended prompts)", CommandOptionType.NoValue);

            awsAccountIdOption.ShowInHelpText         = false;
            awsUserArnOption.ShowInHelpText           = false;
            toolVersionOption.ShowInHelpText          = false;
            deploymentBucketNameOption.ShowInHelpText = false;
            tierVersionOption.ShowInHelpText          = false;
            return(async() => {
                // check if experimental caching feature is enabled
                Settings.AllowCaching = string.Equals((Environment.GetEnvironmentVariable("LAMBDASHARP_FEATURE_CACHING") ?? "false"), "true", StringComparison.OrdinalIgnoreCase);

                // initialize deployment tier
                string tier = tierOption.Value() ?? Environment.GetEnvironmentVariable("LAMBDASHARP_TIER") ?? "";

                // initialize AWS profile
                try {
                    AwsAccountInfo awsAccount = null;
                    IAmazonSimpleSystemsManagement ssmClient = null;
                    IAmazonCloudFormation cfnClient = null;
                    IAmazonKeyManagementService kmsClient = null;
                    IAmazonS3 s3Client = null;
                    IAmazonAPIGateway apiGatewayClient = null;
                    IAmazonIdentityManagementService iamClient = null;
                    IAmazonLambda lambdaClient = null;
                    if (requireAwsProfile)
                    {
                        awsAccount = await InitializeAwsProfile(
                            awsProfileOption.Value(),
                            awsAccountIdOption.Value(),
                            awsRegionOption.Value(),
                            awsUserArnOption.Value()
                            );

                        if (awsAccount == null)
                        {
                            return null;
                        }

                        // create AWS clients
                        ssmClient = new AmazonSimpleSystemsManagementClient(AWSConfigs.RegionEndpoint);
                        cfnClient = new AmazonCloudFormationClient(AWSConfigs.RegionEndpoint);
                        kmsClient = new AmazonKeyManagementServiceClient(AWSConfigs.RegionEndpoint);
                        s3Client = new AmazonS3Client(AWSConfigs.RegionEndpoint);
                        apiGatewayClient = new AmazonAPIGatewayClient(AWSConfigs.RegionEndpoint);
                        iamClient = new AmazonIdentityManagementServiceClient(AWSConfigs.RegionEndpoint);
                        lambdaClient = new AmazonLambdaClient(AWSConfigs.RegionEndpoint);
                    }
                    if (HasErrors)
                    {
                        return null;
                    }

                    // initialize LambdaSharp deployment values
                    var tierVersion = tierVersionOption.Value();
                    var deploymentBucketName = deploymentBucketNameOption.Value();

                    // initialize LambdaSharp testing values
                    VersionInfo toolVersion = null;
                    if (toolVersionOption.HasValue())
                    {
                        toolVersion = VersionInfo.Parse(toolVersionOption.Value());
                    }

                    // create a settings instance for each module filename
                    return new Settings(toolVersion ?? Version)
                    {
                        TierVersion = (tierVersion != null) ? VersionInfo.Parse(tierVersion) : null,
                        Tier = tier,
                        AwsRegion = awsAccount?.Region,
                        AwsAccountId = awsAccount?.AccountId,
                        AwsUserArn = awsAccount?.UserArn,
                        DeploymentBucketName = deploymentBucketName,
                        SsmClient = ssmClient,
                        CfnClient = cfnClient,
                        KmsClient = kmsClient,
                        S3Client = s3Client,
                        ApiGatewayClient = apiGatewayClient,
                        IamClient = iamClient,
                        LambdaClient = lambdaClient,
                        PromptsAsErrors = promptsAsErrorsOption.HasValue()
                    };
                } catch (AmazonClientException e) when(e.Message == "No RegionEndpoint or ServiceURL configured")
                {
                    LogError("AWS profile is missing a region specifier");
                    return null;
                }
            });
        }
Exemplo n.º 3
0
        //--- Methods ---
        protected async Task <AwsAccountInfo> InitializeAwsProfile(
            string awsProfile,
            string awsAccountId = null,
            string awsRegion    = null,
            string awsUserArn   = null,
            bool allowCaching   = false
            )
        {
            var stopwatch = Stopwatch.StartNew();
            var cached    = false;

            try {
                // check if .aws/credentials file exists
                if (
                    !File.Exists(CredentialsFilePath) &&
                    (
                        (Environment.GetEnvironmentVariable("AWS_ACCESS_KEY_ID") == null) ||
                        (Environment.GetEnvironmentVariable("AWS_SECRET_ACCESS_KEY") == null)
                    )
                    )
                {
                    LogError($"IMPORTANT: run '{Settings.Lash} init' to create an AWS profile");
                    return(null);
                }

                // initialize AWS profile
                if (awsProfile == null)
                {
                    awsProfile = Settings.AwsProfileEnvironmentVariable;
                }

                // consistently set the AWS profile by setting the AWS_PROFILE/AWS_DEFAULT_PROFILE environment variables
                AWSConfigs.AWSProfileName = awsProfile;
                Environment.SetEnvironmentVariable("AWS_PROFILE", awsProfile);
                Environment.SetEnvironmentVariable("AWS_DEFAULT_PROFILE", awsProfile);

                // check for  cached AWS profile
                var cachedProfile = Path.Combine(Settings.AwsProfileCacheDirectory, "profile.json");
                if (allowCaching && Settings.AllowCaching && File.Exists(cachedProfile) && ((DateTime.UtcNow - File.GetLastWriteTimeUtc(cachedProfile)) < Settings.MaxCacheAge))
                {
                    cached = true;
                    return(JsonConvert.DeserializeObject <AwsAccountInfo>(await File.ReadAllTextAsync(cachedProfile)));
                }

                // determine default AWS region
                if ((awsAccountId == null) || (awsRegion == null) || (awsUserArn == null))
                {
                    // determine AWS region and account
                    try {
                        var stsClient = new AmazonSecurityTokenServiceClient();
                        var response  = await stsClient.GetCallerIdentityAsync(new GetCallerIdentityRequest());

                        awsRegion    = awsRegion ?? stsClient.Config.RegionEndpoint.SystemName ?? "us-east-1";
                        awsAccountId = awsAccountId ?? response.Account;
                        awsUserArn   = awsUserArn ?? response.Arn;
                    } catch (HttpRequestException e) when(e.Message == "No such host is known")
                    {
                        LogError("an Internet connection is required to determine the AWS Account Id and Region");
                        return(null);
                    } catch (Exception e) {
                        LogError("unable to determine the AWS Account Id and Region", e);
                        return(null);
                    }
                }

                // set AWS region for library and spawned processes
                AWSConfigs.AWSRegion = awsRegion;
                Environment.SetEnvironmentVariable("AWS_REGION", awsRegion);
                Environment.SetEnvironmentVariable("AWS_DEFAULT_REGION", awsRegion);
                var result = new AwsAccountInfo {
                    Region    = awsRegion,
                    AccountId = awsAccountId,
                    UserArn   = awsUserArn
                };
                if (allowCaching && Settings.AllowCaching)
                {
                    Directory.CreateDirectory(Path.GetDirectoryName(cachedProfile));
                    await File.WriteAllTextAsync(cachedProfile, JsonConvert.SerializeObject(result));
                }
                return(result);
            } finally {
                Settings.LogInfoPerformance($"InitializeAwsProfile()", stopwatch.Elapsed, cached);
            }
        }
Exemplo n.º 4
0
        //--- Methods ---
        protected async Task <AwsAccountInfo> InitializeAwsProfile(
            string awsProfile,
            string awsAccountId = null,
            string awsRegion    = null,
            string awsUserArn   = null
            )
        {
            Settings.StartLogPerformance("InitializeAwsProfile()");
            var cached = false;

            try {
                // check if .aws/credentials file exists
                var hasAwsAccessKeyId     = Environment.GetEnvironmentVariable("AWS_ACCESS_KEY_ID") != null;
                var hasAwsSecretAccessKey = Environment.GetEnvironmentVariable("AWS_SECRET_ACCESS_KEY") != null;
                if (!File.Exists(CredentialsFilePath) && !(hasAwsAccessKeyId && hasAwsSecretAccessKey))
                {
                    LogError($"IMPORTANT: run '{Settings.Lash} init' to create an AWS profile");
                    return(null);
                }

                // initialize AWS profile
                if (awsProfile == null)
                {
                    awsProfile = Settings.AwsProfileEnvironmentVariable;
                }

                // consistently set the AWS profile by setting the AWS_PROFILE/AWS_DEFAULT_PROFILE environment variables
                AWSConfigs.AWSProfileName = awsProfile;
                Environment.SetEnvironmentVariable("AWS_PROFILE", awsProfile);
                Environment.SetEnvironmentVariable("AWS_DEFAULT_PROFILE", awsProfile);

                // neither AWS_ACCESS_KEY_ID, nor AWS_SECRET_ACCESS_KEY can be set to use the cached profile information
                if (!hasAwsAccessKeyId && !hasAwsSecretAccessKey)
                {
                    var(cachedProfile, cachedProfileTimestamp) = GetCachedProfile(awsProfile);

                    // the cached profile must exist and be newer than the credentials file
                    if (
                        (cachedProfile != null) &&
                        (cachedProfileTimestamp > File.GetLastWriteTimeUtc(CredentialsFilePath))
                        )
                    {
                        cached = true;
                        return(cachedProfile);
                    }
                }

                // determine default AWS region
                if ((awsAccountId == null) || (awsRegion == null) || (awsUserArn == null))
                {
                    // determine AWS region and account
                    try {
                        var stsClient = new AmazonSecurityTokenServiceClient();
                        var response  = await stsClient.GetCallerIdentityAsync(new GetCallerIdentityRequest());

                        awsRegion    = awsRegion ?? stsClient.Config.RegionEndpoint.SystemName ?? "us-east-1";
                        awsAccountId = awsAccountId ?? response.Account;
                        awsUserArn   = awsUserArn ?? response.Arn;
                    } catch (HttpRequestException e) when(e.Message == "No such host is known")
                    {
                        LogError("an Internet connection is required to determine the AWS Account Id and Region");
                        return(null);
                    } catch (Exception e) {
                        LogError("unable to determine the AWS Account Id and Region", e);
                        return(null);
                    }
                }

                // set AWS region for library and spawned processes
                AWSConfigs.AWSRegion = awsRegion;
                Environment.SetEnvironmentVariable("AWS_REGION", awsRegion);
                Environment.SetEnvironmentVariable("AWS_DEFAULT_REGION", awsRegion);
                var result = new AwsAccountInfo {
                    Region    = awsRegion,
                    AccountId = awsAccountId,
                    UserArn   = awsUserArn
                };

                // only store profile if no AWS keys were used
                if (!hasAwsAccessKeyId && !hasAwsSecretAccessKey)
                {
                    CacheProfile(awsProfile, result);
                }
                return(result);
            } finally {
                Settings.StopLogPerformance(cached);
            }
        }