Skip to content

Commit

Permalink
Add: bug fixes and schema changes to aws provider
Browse files Browse the repository at this point in the history
  • Loading branch information
g14a committed Jan 22, 2021
1 parent 3b7b0ef commit bc4aaab
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 203 deletions.
329 changes: 135 additions & 194 deletions terraform/aws/provider_prompt.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,154 +12,99 @@ import (

func ProviderPrompt() {

var promptOrder []string
prompts := map[string]types.TfPrompt{}
fmt.Println()

color.Red("\nWe recommend not providing us your access information.\n" +
"We however assure that we use your information only to create your terraform configuration\n")

prompts["access_key"] = types.TfPrompt{
Label: "Enter your access_key: \nThis is the AWS access key. It must be provided, \n" +
"but it can also be sourced from the AWS_ACCESS_KEY_ID \n" +
"environment variable, or via a shared \ncredentials file if profile is specified",
Prompt: promptui.Prompt{
Label: "",
Mask: '*',
},
}
promptOrder = append(promptOrder, "access_key")

prompts["secret_key"] = types.TfPrompt{
Label: "Enter your secret_key: \nThis is the AWS secret key. It must be provided, \n" +
"but it can also be sourced from the AWS_SECRET_ACCESS_KEY \n" +
"environment variable, or via a shared \ncredentials file if profile is specified",
Prompt: promptui.Prompt{
Label: "",
Mask: '*',
},
}
promptOrder = append(promptOrder, "secret_key")

prompts["profile"] = types.TfPrompt{
Label: "Enter profile:\nThis is the AWS profile name as set in the shared credentials file",
Prompt: promptui.Prompt{
Label: "",
},
}
promptOrder = append(promptOrder, "profile")

prompts["max_retries"] = types.TfPrompt{
Label: "Enter max_retries:\nThis is the maximum number of times an API call is retried, \n" +
"in the case where requests are being throttled or experiencing \n" +
"transient failures. The delay between the subsequent API calls \n" +
"increases exponentially. If omitted, the default value is 25.",
Prompt: promptui.Prompt{
Label: "",
Validate: validators.IntValidator,
},
}
promptOrder = append(promptOrder, "max_retries")

prompts["allowed_account_ids"] = types.TfPrompt{
Label: "Enter allowed_account_ids, eg:[\"a\",\"b\",\"c\"]:\nList of allowed AWS account IDs to prevent you from \n" +
"mistakenly using an incorrect one (and potentially end up destroying \n" +
"a live environment). Conflicts with forbidden_account_ids.",
Prompt: promptui.Prompt{
Label: "",
},
}
promptOrder = append(promptOrder, "allowed_account_ids")

prompts["token"] = types.TfPrompt{
Label: "Enter token: Session token for validating temporary credentials",
Prompt: promptui.Prompt{
Label: "",
},
}
promptOrder = append(promptOrder, "token")

prompts["shared_credentials_file"] = types.TfPrompt{
Label: "Enter shared_credentials_file :\n(Optional) This is the path to the shared " +
"credentials file. If this is not set and a profile is specified," +
" ~/.aws/credentials will be used.",
Prompt: promptui.Prompt{
Label: "",
},
}
promptOrder = append(promptOrder, "shared_credentials_file")

prompts["insecure"] = types.TfPrompt{
Label: "Enter insecure(true/false):\nExplicitly allow the provider to perform \"insecure\" SSL \n" +
"requests(bool).If omitted, the default value is false",
Prompt: promptui.Prompt{
Label: "",
Validate: validators.BoolValidator,
},
}
promptOrder = append(promptOrder, "insecure")

prompts["skip_credentials_validation"] = types.TfPrompt{
Label: "Enter skip_credentials_validation(true/false):\nSkip the credentials validation via the STS API.\n" +
"Useful for AWS API implementations that do not have STS available or implemented.",
Prompt: promptui.Prompt{
Label: "",
Validate: validators.BoolValidator,
},
}

promptOrder = append(promptOrder, "skip_credentials_validation")

prompts["skip_get_ec2_platforms"] = types.TfPrompt{
Label: "Enter skip_get_ec2_platforms(true/false):\nSkip getting the supported EC2 platforms. \n" +
"Used by users that don't have ec2:DescribeAccountAttributes permissions.",
Prompt: promptui.Prompt{
Label: "",
Validate: validators.BoolValidator,
},
}
promptOrder = append(promptOrder, "skip_get_ec2_platforms")

prompts["skip_metadata_api_check"] = types.TfPrompt{
Label: "Enter skip_metadata_api_check(true/false):\nSkip the AWS Metadata API check. \n" +
"Useful for AWS API implementations that do not have a metadata \n" +
"API endpoint. Setting to true prevents Terraform from authenticating via the Metadata API.",
Prompt: promptui.Prompt{
Label: "",
Validate: validators.BoolValidator,
},
}
promptOrder = append(promptOrder, "skip_metadata_api_check")

prompts["skip_requesting_account_id"] = types.TfPrompt{
Label: "Enter skip_requesting_account_id(true/false):\nSkip requesting the account ID. \n" +
"Useful for AWS API implementations that do not \n" +
"have the IAM, STS API, or metadata API.",
Prompt: promptui.Prompt{
Label: "",
Validate: validators.BoolValidator,
},
}
promptOrder = append(promptOrder, "skip_requesting_account_id")

prompts["skip_region_validation"] = types.TfPrompt{
Label: "Enter skip_region_validation(true/false):\nSkip validation of provided region name. \n" +
"Useful for AWS-like implementations that use their own \n" +
"region names or to bypass the validation for regions \nthat aren't publicly available yet.",
Prompt: promptui.Prompt{
Label: "",
Validate: validators.BoolValidator,
},
region, err := RegionPrompt().Run()
if err != nil {
fmt.Println(err)
}
promptOrder = append(promptOrder, "skip_region_validation")

var selectOrder []string
selects := map[string]types.TfSelect{}

selects["region"] = RegionPrompt()

selectOrder = append(selectOrder, "region")
color.Red("\nWe recommend not providing us your access information.\n" +
"We however assure that we use your information only to create your terraform configuration\n")

providerBlock := builder.PSOrder(promptOrder, selectOrder, prompts, selects)
schema := []types.Schema{
{
Field: "access_key",
Ex: "",
Doc: "(Optional) This is the AWS access key. It must be provided, but it can also be sourced from the AWS_ACCESS_KEY_ID environment variable, or via a shared credentials file if profile is specified.",
},
{
Field: "secret_key",
Ex: "",
Doc: "(Optional) This is the AWS secret key. It must be provided, but it can also be sourced from the AWS_SECRET_ACCESS_KEY environment variable, or via a shared credentials file if profile is specified.",
},
{
Field: "profile",
Ex: "",
Doc: "(Optional) This is the AWS profile name as set in the shared credentials file.",
},
{
Field: "shared_credentials_file",
Ex: "",
Doc: "(Optional) This is the path to the shared credentials file. If this is not set and a profile is specified, ~/.aws/credentials will be used.",
},
{
Field: "max_retries",
Ex: "",
Doc: "(Optional) This is the maximum number of times an API call is retried, in the case where requests are being throttled or experiencing transient failures. The delay between the subsequent API calls increases exponentially. If omitted, the default value is 25",
Validator: validators.IntValidator,
},
{
Field: "allowed_account_ids",
Ex: "[\"id1\",\"id2\"]",
Doc: "(Optional) List of allowed AWS account IDs to prevent you from mistakenly using an incorrect one (and potentially end up destroying a live environment). Conflicts with forbidden_account_ids",
},
{
Field: "forbidden_account_ids",
Ex: "[\"id1\",\"id2\"]",
Doc: "(Optional) List of forbidden AWS account IDs to prevent you from mistakenly using the wrong one (and potentially end up destroying a live environment). Conflicts with allowed_account_ids",
},
{
Field: "token",
Ex: "",
Doc: "(Optional) Session token for validating temporary credentials. Typically provided after successful identity federation or Multi-Factor Authentication (MFA) login. With MFA login, this is the session token provided afterward, not the 6 digit MFA code used to get temporary credentials. It can also be sourced from the AWS_SESSION_TOKEN environment variable.",
},
{
Field: "insecure",
Ex: "(true/false)",
Doc: "(Optional) Explicitly allow the provider to perform \"insecure\" SSL requests. If omitted, the default value is false.",
Validator: validators.BoolValidator,
},
{
Field: "skip_credentials_validation",
Ex: "(true/false)",
Doc: "(Optional) Skip the credentials validation via the STS API. Useful for AWS API implementations that do not have STS available or implemented.",
Validator: validators.BoolValidator,
},
{
Field: "skip_get_ec2_platforms",
Ex: "(true/false)",
Doc: "(Optional) Skip getting the supported EC2 platforms. Used by users that don't have ec2:DescribeAccountAttributes permissions.",
Validator: validators.BoolValidator,
},
{
Field: "skip_region_validation",
Ex: "(true/false)",
Doc: "(Optional) Skip validation of provided region name. Useful for AWS-like implementations that use their own region names or to bypass the validation for regions that aren't publicly available yet.",
Validator: validators.BoolValidator,
},
{
Field: "skip_requesting_account_id",
Ex: "(true/false)",
Doc: "(Optional) Skip requesting the account ID. Useful for AWS API implementations that do not have the IAM, STS API, or metadata API." +
"\nCheckout https://registry.terraform.io/providers/hashicorp/aws/latest/docs#skip_requesting_account_id for extra information.",
Validator: validators.BoolValidator,
},
{
Field: "skip_metadata_api_check",
Ex: "(true/false)",
Doc: "(Optional) Skip the AWS Metadata API check. Useful for AWS API implementations that do not have a metadata API endpoint. Setting to true prevents Terraform from authenticating via the Metadata API. You may need to use other authentication methods like static credentials, configuration variables, or environment variables.",
Validator: validators.BoolValidator,
},
}

providerBlock := builder.PSOrder(types.ProvidePS(schema))
providerBlock["region"] = region

color.Yellow("\nConfigure nested settings like assume_role/ignore_tags [y/n]?\n\n", "text")

Expand All @@ -181,70 +126,66 @@ func ProviderPrompt() {
"the following optional arguments:\n1.duration_seconds\n2.external_id\n" +
"3.policy\n4.policy_arns\n5.role_arn\n6.session_name\n7.tags(not supported by this cli yet)\n")

assumeRolePrompts := map[string]types.TfPrompt{}
var nestedOrder []string

assumeRolePrompts["duration_seconds"] = types.TfPrompt{
Label: "\nEnter duration_seconds:\n(Optional) Number of seconds to restrict the assume role session duration.",
Prompt: promptui.Prompt{
Label: "",
Validate: validators.IntValidator,
assumeRoleSchema := []types.Schema{
{
Field: "duration_seconds",
Ex: "",
Doc: "(Optional) Number of seconds to restrict the assume role session duration.",
Validator: validators.IntValidator,
},
}
nestedOrder = append(nestedOrder, "duration_seconds")

assumeRolePrompts["external_id"] = types.TfPrompt{
Label: "Enter external_id:\n(Optional) External identifier to use when assuming the role.",
Prompt: promptui.Prompt{
Label: "",
{
Field: "external_id",
Ex: "",
Doc: "(Optional) External identifier to use when assuming the role.",
},
}
nestedOrder = append(nestedOrder, "external_id")

assumeRolePrompts["session_name"] = types.TfPrompt{
Label: "Enter session_name:\n(Optional) Session name to use when assuming the role.",
Prompt: promptui.Prompt{
Label: "",
{
Field: "policy",
Ex: "",
Doc: "(Optional) IAM Policy JSON describing further restricting permissions for the IAM Role being assumed.",
Validator: validators.JSONValidator,
},
}
nestedOrder = append(nestedOrder, "session_name")

assumeRolePrompts["role_arn"] = types.TfPrompt{
Label: "Enter role_arn:\n(Optional) Amazon Resource Name (ARN) of the IAM Role to assume.",
Prompt: promptui.Prompt{
Label: "",
{
Field: "policy_arns",
Ex: "",
Doc: "(Optional) Set of Amazon Resource Names (ARNs) of IAM Policies describing further restricting permissions for the IAM Role being assumed.",
},
{
Field: "session_name",
Ex: "",
Doc: "(Optional) Session name to use when assuming the role.",
},
{
Field: "tags",
Ex: "k1=v1,k2=v2",
Doc: "(Optional) Map of assume role session tags.",
Validator: validators.RCValidator,
},
{
Field: "transitive_tag_keys",
Ex: "",
Doc: "(Optional) Set of assume role session tag keys to pass to any subsequent sessions.",
},
}
nestedOrder = append(nestedOrder, "role_arn")
selectOrder = append(selectOrder, "assume_role")

providerBlock["assume_role"] = builder.PSOrder(nestedOrder, nil, assumeRolePrompts, nil)

ignoreTagsPrompts := map[string]types.TfPrompt{}
providerBlock["assume_role"] = builder.PSOrder(types.ProvidePS(assumeRoleSchema))

color.Green("\nEnter ignore_tags:\nThe ignore_tags configuration block supports " +
"\n1.keys\n2.key_prefixes\n")

ignoreTagsPrompts["keys"] = types.TfPrompt{
Label: "Enter keys([\"a\",\"b\",\"c\"]):(Optional) List of exact resource tag keys to ignore \nacross all resources handled by this provider." +
"\nCheck https://registry.terraform.io/providers/hashicorp/aws/latest/docs#ignore_tags-configuration-block for more info.",
Prompt: promptui.Prompt{
Label: "",
ignoreTagsSchema := []types.Schema{
{
Field: "keys",
Ex: "[\"a\",\"b\",\"c\"]",
Doc: "(Optional) List of exact resource tag keys to ignore across all resources handled by this provider. This configuration prevents Terraform from returning the tag in any tags attributes and displaying any configuration difference for the tag value. If any resource configuration still has this tag key configured in the tags argument, it will display a perpetual difference until the tag is removed from the argument or ignore_changes is also used.",
},
}
nestedOrder = append(nestedOrder, "keys")

ignoreTagsPrompts["key_prefixes"] = types.TfPrompt{
Label: "Enter key_prefixes([\"a\",\"b\",\"c\"])(Optional) List of resource tag key prefixes to ignore across all resources handled by this provider." +
"\nCheck https://registry.terraform.io/providers/hashicorp/aws/latest/docs#key_prefixes for more info",
Prompt: promptui.Prompt{
Label: "",
{
Field: "key_prefixes",
Ex: "",
Doc: "(Optional) List of resource tag key prefixes to ignore across all resources handled by this provider. This configuration prevents Terraform from returning any tag key matching the prefixes in any tags attributes and displaying any configuration difference for those tag values. If any resource configuration still has a tag matching one of the prefixes configured in the tags argument, it will display a perpetual difference until the tag is removed from the argument or ignore_changes is also used.",
},
}
nestedOrder = append(nestedOrder, "key_prefixes")
selectOrder = append(selectOrder, "ignore_tags")

providerBlock["ignore_tags"] = builder.PSOrder(nestedOrder[len(nestedOrder)-2:], nil, ignoreTagsPrompts, nil)
providerBlock["ignore_tags"] = builder.PSOrder(types.ProvidePS(ignoreTagsSchema))

builder.ProviderBuilder("aws", providerBlock)
}
5 changes: 4 additions & 1 deletion terraform/aws/regions.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package aws

import (
"github.com/fatih/color"
"strings"

"github.com/g14a/tf/types"
Expand All @@ -18,8 +19,10 @@ func GetRegions() []string {

func RegionPrompt() types.TfSelect {

color.Green("Select one of the AWS regions:")

return types.TfSelect{
Label: "Select one of the AWS regions",
Label: "",
Select: promptui.Select{
Label: "",
Size: 20,
Expand Down
Loading

0 comments on commit bc4aaab

Please sign in to comment.