terraform-aws-server/variables.tf

398 lines
15 KiB
HCL

# this server module must be aware of the system requirements of the application that will run on it
# this is fundamental to generating servers, you need to know the size and how many servers you need
# with that in mind we also need to know what ports to expose and how to route traffic
# this module is generalized so that it can be used for any application, but tested with rke2 and Rancher in mind
#####
# Feature: image
#####
variable "image_use_strategy" {
type = string
description = <<-EOT
The strategy to use for selecting an image.
This can be "find" to use our selection of types, "select" to select an image by id, or "skip" to do nothing.
If you choose "find" you must set the image_type variable.
If you choose "select" you must set the image variable.
If you select "skip" no image will be created or selected and data will be empty.
If you select "skip" dependent resources will be skipped implicitly (including the server mod).
EOT
default = "find"
validation {
condition = (
contains(["find", "select", "skip"], var.image_use_strategy)
)
error_message = "This must be one of 'find','select', or 'skip'."
}
}
# image select
variable "image" {
type = object({
id = string
user = string
admin_group = string
workfolder = string
})
description = <<-EOT
Custom image object used when selecting an image by id.
This variable is required when the image_use_strategy is "select".
This variable is ignored when the image_use_strategy isn't "select".
Id attribute is required, the others can be "" unless the
direct_access_use_strategy is "ssh".
The id attribute is the AMS image id.
The user attribute is the sudo user which already exists on the image.
The admin_group is the group name for sudo users, eg. "wheel".
The workfolder is a folder that the user has access to that can execute scripts.
On most images this can set to "~" to use the user's home directory,
but on some images (eg. CIS STIG AMIs) a different directory is necessary.
EOT
default = null
}
# image find
variable "image_type" {
type = string
description = <<-EOT
The designation of server "image" from the ./image/types.tf file, this relates the AWS AMI information.
Please be aware that some images require a subscription and will have additional cost over usage of the server.
Current images are:
"sles-15",
"sle-micro-55",
"sle-micro-60",
"sle-micro-61",
"cis-rhel-8",
"ubuntu-22",
"ubuntu-24",
"rocky-9",
"rhel-9",
"liberty-8"
EOT
default = ""
validation {
condition = (
var.image_type == "" ? true : contains([
"sles-15",
"sle-micro-55",
"sle-micro-60",
"sle-micro-61",
"cis-rhel-8",
"ubuntu-22",
"ubuntu-24",
"rocky-9",
"rhel-9",
"liberty-8"
], var.image_type)
)
error_message = <<-EOT
If specified, this must be one of
"sles-15",
"sle-micro-55",
"sle-micro-60",
"sle-micro-61",
"cis-rhel-8",
"ubuntu-22",
"ubuntu-24",
"rocky-9",
"rhel-9",
"liberty-8"
EOT
}
}
#####
# Feature: server
#####
variable "server_use_strategy" {
type = string
description = <<-EOT
The strategy to use for selecting a server.
This can be "create" to create a new server, "select" to select an existing server, or "skip" to do nothing.
If you choose "select" you must provide the id of the server to select.
WARNING! No action will be taken and no resources generated by this module when selecting a server,
all variables except the server_id will be ignored.
If you select "skip" no server will be created or selected and data will be empty.
If you select "skip" dependent resources will be skipped implicitly.
EOT
default = "create"
}
variable "server_id" {
type = string
description = <<-EOT
The id of the AWS Ec2 instance that you want to select.
This should only be used when you want to select an existing server, and not create a new one.
This can be helpful if you want to ensure a server exists and get data about it, without managing it.
This variable is ignored if server_use_strategy isn't "select".
EOT
default = ""
}
variable "server_name" {
type = string
description = <<-EOT
The name to give the server, this will form the local hostname and appear in the AWS ec2 console.
The name will be used as the value for the "Name" tag on the server.
This value is ignored when selecting a server.
EOT
default = ""
}
variable "server_type" {
type = string
description = <<-EOT
The designation of server "type" from the ./server/types.tf file
This will set the cpu, ram, and storage resources available to the server.
Larger types will have higher costs, none of the types listed are in the free tier.
Current types are "small", "medium", "large", "xl", "xxl"
Leave this blank when selecting a server.
EOT
default = ""
validation {
condition = (
var.server_type == "" ? true : contains(["small", "medium", "large", "xl", "xxl"], var.server_type)
)
error_message = "If specified, this must be one of 'small', 'medium', 'large', 'xl', or 'xxl'."
}
}
variable "server_ip_family" {
type = string
description = <<-EOT
The ip family to use for the server, must be one of "ipv4", "dualstack", or "ipv6".
This is mainly determined by the VPC and subnet that you are deploying to,
attempting to deploy a dualstack or ipv6 server to a non-dualstack/ipv6 VPC/subnet will result in failed connections.
WARNING! When this is set to "ipv6" the server running Terraform must have the AWS CLI installed.
This is due to a missing feature in the AWS provider that allows ipv6 instances to be attached to load balancer target groups.
EOT
default = "ipv4"
validation {
condition = contains(["ipv4", "ipv6", "dualstack"], var.server_ip_family)
error_message = "This must be one of 'ipv4', 'dualstack', or 'ipv6'."
}
}
variable "cloudinit_use_strategy" {
type = string
description = <<-EOT
The strategy to use for cloudinit, must be one of "skip", "default", or "specify".
This can be "skip" to skip sending cloudinit, "create" to generate a cloudinit script with defaults,
or "specify" to specify your own cloudinit content.
This is ignored when skipping or selecting a server or when direct_access_use_strategy isn't "ssh".
EOT
validation {
condition = (
var.cloudinit_use_strategy == "" ? true : contains(["skip", "default", "specify"], var.cloudinit_use_strategy)
)
error_message = "If specified, this must be one of 'skip', 'default', or 'specify'."
}
default = "skip"
}
variable "cloudinit_content" {
type = string
description = <<-EOT
Override the default cloud-init config.
This is a yaml formatted string that will be sent as base64 encoded "user-data" to the EC2 api when creating the server.
This should be raw text, the module will handle the base64 encoding.
WARNING!! Some OS configurations prevent cloud-init from writing files, such as STIG CIS AMIs.
EOT
default = ""
sensitive = true
}
#####
# Feature: internal access
#####
# these variables are used to configure how servers connect within the scope of the VPC
variable "subnet_name" {
type = string
description = <<-EOT
The name of the AWS subnet that you want to apply to the server.
This must already exist in AWS, it will not be created by this module.
If you would like help creating a subnet, please see the 'terraform-aws-access' module that we produce.
This uses the "Name" tag on the subnet to select it, this is preferrable to make multi-region deployments easier.
Subnets are tied to a specific availability zone, so when you select a subnet you are also selecting an availability zone.
EOT
default = ""
}
variable "security_group_name" {
type = string
description = <<-EOT
The name of the AWS security group that you want to apply to the server.
This must already exist in AWS, it will not be created by this module.
If you would like help creating a security group, please see the 'terraform-aws-access' module that we produce.
This uses the "Name" tag on the security group to select it, this generalizes the approach for finding objects in AWS.
The name must be unique to all of your objects, you can't have a security group and a load balancer with the same name.
This name can't start with 'sg-', as AWS reserves this prefix for its use.
EOT
default = ""
}
variable "private_ip" {
type = string
description = <<-EOT
An available private ip to assign to the server.
This must be within the subnet assigned to the server.
If one is not set then AWS will assign an ip from the subnet.
This is ignored for ipv6 only servers.
EOT
default = ""
}
#####
# Feature: indirect access
#####
variable "indirect_access_use_strategy" {
type = string
description = <<-EOT
The strategy to use for a load balancer.
This can be "enable" to select an existing load balancer, or "skip" to do nothing.
If you choose "enable" you must provide the name of the load balancer to select in the load_balancer_name variable.
If you choose "skip" no load balancer will be created or selected and data will be empty.
EOT
default = "skip"
validation {
condition = (
contains(["enable", "skip"], var.indirect_access_use_strategy)
)
error_message = "This must be one of 'enable' or 'skip'."
}
}
variable "load_balancer_target_groups" {
type = list(string)
description = <<-EOT
The names of the target groups to attach the server to.
This must be a list of strings, each string is the name of a target group.
This is only used if indirect_access_use_strategy is set to "enable".
The target_group must have a tag "Name" with this exact value.
EOT
default = []
}
#####
# Feature: direct access
#####
# options here are for direct access to the server from outside the VPC, this is not recommended for production
variable "direct_access_use_strategy" {
type = string
description = <<-EOT
The strategy to use for direct access to the server.
This can be "network", "ssh", or "skip".
If you choose 'skip' nothing will be done and server_access_addresses, server_user, ssh_key_content, domain, and eip variables will be ignored.
If you choose "network" only network level access will be created, and server_access_addresses is required.
If you choose "ssh", then network level access will be created as well as ssh access.
To enable ssh access we connect to the server over ssh and run scripts which remove the default user, add a new user,
and add the specified public ssh key to the new user. The server_user variable is required.
Optionally, you may add a domain name or an elastic ip to your server with the add_eip and add_domain variables.
EOT
default = "skip"
validation {
condition = (
contains(["network", "ssh", "skip"], var.direct_access_use_strategy)
)
error_message = "This must be one of 'network', 'ssh', or 'skip'."
}
}
variable "server_access_addresses" {
type = map(object({
port = number
cidrs = list(string)
ip_family = string
protocol = string
}))
default = null
description = <<-EOT
A map of objects with a single port, the cidrs to allow access to that port,
and the protocol to allow for access.
The port is the tcp port number to expose. eg. 80
The cidrs is a list of cidrs to allow to that port. eg ["1.1.1.1/32","2.2.2.2/24"]
The protocol is the tranfer protocol to allow, usually "tcp" or "udp".
Ipv4 addresses will not be able to access ipv6 only servers.
Example:
{
workstation = {
port = 443,
cidrs = ["100.1.1.1/32"],
ip_family = "ipv4"
protocol = "tcp"
}
ci = {
port = 443
cidrs = ["50.1.1.1/32"],
ip_family = "ipv4"
protocol = "tcp"
}
}
EOT
}
variable "server_user" {
type = object({
user = string
aws_keypair_use_strategy = string
ssh_key_name = string
public_ssh_key = string
user_workfolder = string
timeout = number
})
description = <<-EOT
This is required if direct_access_use_strategy is "ssh".
The user specified will be added to the server with passwordless sudo access.
The public_ssh_key will be added to the /home/<user>/.ssh/authorized_keys file.
The timeout value is the number of minutes to wait for setup to complete, defaults to 5.
Some images must have an ssh key passed to the cloud provider when generating the server,
to enable this set the aws_keypair_use_strategy to either "select" or "create".
Select will select the ssh key with the name attribute equal to the "ssh_key_name" specified.
Create will create a new ssh key with the given name and public ssh key. (ssh keypair objects can't have tags).
EOT
default = null
validation {
condition = (var.server_user == null ? true : (length(var.server_user["user"]) <= 32 ? true : false))
error_message = "If specified, user must be 32 characters or less."
}
validation {
condition = (var.server_user == null ? true : (var.server_user["user"] == lower(var.server_user["user"]) ? true : false))
error_message = "If specified, user must be all lower case."
}
validation {
condition = (var.server_user == null ? true : ((var.server_user["aws_keypair_use_strategy"] == "select" && var.server_user["ssh_key_name"] == "") ? false : true))
error_message = "If specified, when selecting a keypair from AWS, the key_name is required."
}
}
variable "add_domain" {
type = bool
description = <<-EOT
When this is true domain_name and domain_zone is required.
This will add a record with the server's public IP address to route53.
You must already have a zone setup and configured properly for this to work.
EOT
default = false
}
variable "domain_name" {
type = string
description = <<-EOT
The domain name to use for the server.
The zone for this domain must already exist in route53.
The domain_zone variable is required when this is set.
EOT
default = ""
}
variable "domain_zone" {
type = string
description = <<-EOT
The zone for the domain name.
The domain_name variable is required when this is set.
EOT
default = ""
}
variable "add_eip" {
type = bool
description = <<-EOT
Set this to true to add an elastic IP to the server.
WARNING! By default, all AWS accounts have a quota of five (5) Elastic IP addresses per Region.
You can change this in your account quota settings.
Some programs (such as kubernetes) require the IP on the primary interface to remain stable,
this can be achieved by specifying the private_ip variable rather than using an elastic IP.
EOT
default = false
}