{"id":24388146,"url":"https://github.com/masterpointio/terraform-aws-tailscale","last_synced_at":"2026-02-20T13:00:53.569Z","repository":{"id":54783711,"uuid":"317531911","full_name":"masterpointio/terraform-aws-tailscale","owner":"masterpointio","description":"Terraform module to provision a Tailscale Subnet Router into your AWS VPC","archived":false,"fork":false,"pushed_at":"2025-12-03T16:50:21.000Z","size":210,"stargazers_count":51,"open_issues_count":2,"forks_count":16,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-12-06T21:39:53.859Z","etag":null,"topics":["opentofu","opentofu-module","tailscale","terraform","terraform-module"],"latest_commit_sha":null,"homepage":"","language":"HCL","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/masterpointio.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2020-12-01T12:19:56.000Z","updated_at":"2025-12-03T16:50:25.000Z","dependencies_parsed_at":"2026-01-07T07:04:05.290Z","dependency_job_id":null,"html_url":"https://github.com/masterpointio/terraform-aws-tailscale","commit_stats":null,"previous_names":["masterpointio/terraform-aws-tailscale","gowiem/terraform-aws-tailscale"],"tags_count":20,"template":false,"template_full_name":"cloudposse/terraform-example-module","purl":"pkg:github/masterpointio/terraform-aws-tailscale","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/masterpointio%2Fterraform-aws-tailscale","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/masterpointio%2Fterraform-aws-tailscale/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/masterpointio%2Fterraform-aws-tailscale/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/masterpointio%2Fterraform-aws-tailscale/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/masterpointio","download_url":"https://codeload.github.com/masterpointio/terraform-aws-tailscale/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/masterpointio%2Fterraform-aws-tailscale/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29651964,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-20T09:27:29.698Z","status":"ssl_error","status_checked_at":"2026-02-20T09:26:12.373Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["opentofu","opentofu-module","tailscale","terraform","terraform-module"],"created_at":"2025-01-19T13:56:29.842Z","updated_at":"2026-02-20T13:00:53.537Z","avatar_url":"https://github.com/masterpointio.png","language":"HCL","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Banner][banner-image]](https://masterpoint.io/)\n\n# terraform-aws-tailscale\n\n[![Release][release-badge]][latest-release]\n\n💡 Learn more about Masterpoint [below](#who-we-are-𐦂𖨆𐀪𖠋).\n\n## Purpose and Functionality\n\nThis is a Terraform Module to create a simple, autoscaled [Tailscale Subnet Router](https://tailscale.com/kb/1019/subnets/) on EC2 instance along with generated auth key, and its corresponding IAM resources. The instance should cycle itself on a schedule.\n\n## Usage\n\nHere's how to invoke this example module in your projects\n\n```hcl\nmodule \"vpc\" {\n  source  = \"cloudposse/vpc/aws\"\n  version = \"2.1.1\"\n\n  namespace = \"eg\"\n  stage     = \"test\"\n  name      = \"tailscale\"\n\n  ipv4_primary_cidr_block = \"172.16.0.0/16\"\n}\n\nmodule \"subnets\" {\n  source  = \"cloudposse/dynamic-subnets/aws\"\n  version = \"2.4.1\"\n\n  namespace = \"eg\"\n  stage     = \"test\"\n  name      = \"tailscale\"\n\n  availability_zones = [\"us-east-1a\", \"us-east-1b\"]\n\n  vpc_id          = module.vpc.vpc_id\n  igw_id          = [module.vpc.igw_id]\n  ipv4_cidr_block = [module.vpc.vpc_cidr_block]\n}\n\nmodule \"tailscale\" {\n  source  = \"masterpointio/tailscale/aws\"\n  version = \"X.X.X\"\n\n  namespace = \"eg\"\n  stage     = \"test\"\n  name      = \"tailscale\"\n\n  vpc_id           = module.vpc.vpc_id\n  subnet_ids       = module.subnets.private_subnet_ids\n  advertise_routes = [module.vpc.vpc_cidr_block]\n\n  ephemeral = true\n}\n```\n\n## Examples\n\nHere is an example of using this module:\n\n- [`examples/complete`](https://github.com/masterpointio/terraform-aws-tailscale/) - complete example of using this module\n\n## System Logging and Monitoring Setup\n\nOn Linux and other Unix-like systems, Tailscale typically runs as a systemd service, which by default does not rotate logs - potentially allowing system logs to grow until the disk fills.\n\nTo address this, our user data script configures both a maximum journal size and a retention period to ensure logs are periodically purged. We also install the [CloudWatch Agent](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Install-CloudWatch-Agent.html) with its default configuration so that filesystem usage metrics are reported to AWS.\n\n👀 To view these metrics, navigate in the AWS Console to “CWAgent” → “AutoScalingGroupName, ImageId, InstanceId, InstanceType, device, fstype, path” → “disk_used_percent” for the root path “/”.\n\n## Direct and Relayed Connections\n\nTailscale supports two primary types of [connection types](https://tailscale.com/kb/1257/connection-types) for subnet routers:\n\n- **Direct (peer-to-peer)**: Nodes communicate directly with each other when possible, offering better performance and reliability.\n- **Relayed**: Traffic is routed through Tailscale's DERP (Designated Encrypted Relay for Packets) servers when direct connectivity isn't possible (e.g. when the subnet router is in a private VPC subnet).\n\n### Addressing Connection Stability Issues\n\nWe've been using relayed connections for our subnet routers, but we've observed that relayed connections can sometimes cause intermittent connectivity issues, particularly when working with database connections through the Tailscale proxy (see [this issue](https://github.com/cyrilgdn/terraform-provider-postgresql/issues/495) for an example).\n\nThese issues appear as connection timeouts or SOCKS server errors:\n\n```sh\n│ Error: Error connecting to PostgreSQL server dev.example.com (scheme: postgres): socks connect tcp localhost:1055-\u003edev.example.com:5432: unknown error general SOCKS server failure\n│\n│   with data.postgresql_schemas.schemas[\"example\"],\n│   on main.tf line 65, in data \"postgresql_schemas\" \"schemas\":\n│   65: data \"postgresql_schemas\" \"schemas\" {\n│\n╵\nnetstack: decrementing connsInFlightByClient[100.0.108.92] because the packet was not handled; new value is 0\n[RATELIMIT] format(\"netstack: decrementing connsInFlightByClient[%v] because the packet was not handled; new value is %d\")\n```\n\n### Configuring Direct Connections\n\nTo optimize for direct connections in your Tailscale subnet router, follow this example:\n\n```hcl\nlocals {\n  public_subnets = [\"subnet-1234567890\", \"subnet-0987654321\"]\n  vpc_id         = \"vpc-1234567890\"\n  direct_port    = \"41641\"\n}\n\nmodule \"tailscale\" {\n  source  = \"masterpointio/tailscale/aws\"\n  version = \"1.6.0\" # Or later\n  ...\n  # Direct connection configuration\n  subnet_ids = local.public_subnets  # Ensure subnet router is in a public subnet\n\n  additional_security_group_ids = [module.direct_sg.id]            # Attach the security group to the subnet router\n  tailscaled_extra_flags        = [\"--port=${local.direct_port}\"]  # Ensure `tailscaled` listens on the same port as the security group is configured\n\n  context = module.this.context\n}\n\nmodule \"direct_sg\" {\n  source  = \"cloudposse/security-group/aws\"\n  version = \"2.2.0\"\n  enabled = true\n\n  vpc_id     = local.vpc_id\n  attributes = [\"tailscale\", \"direct\"]\n\n  rules = [{\n    key         = \"direct_ingress\"\n    type        = \"ingress\"\n    from_port   = local.direct_port\n    to_port     = local.direct_port\n    protocol    = \"udp\"\n    cidr_blocks = [\"0.0.0.0/0\"]\n    description = \"Allow a direct Tailscale connection from any peer.\"\n  }]\n\n  context = module.this.context\n}\n```\n\nThe above configuration ensures that the subnet router can establish direct connections with other Tailscale nodes:\n\n1. It is in a public subnet and gets a public IP address.\n2. The security group is attached and configured to listen on a fixed port.\n3. The `tailscaled` daemon is configured to listen on the same port as the security group is configured to listen on.\n4. The outgoing UDP and TCP packets on port `443` are permitted. In our example, [`cloudposse/security-group/aws`](https://github.com/cloudposse/terraform-aws-security-group) module allows all egress.\n\n\u003c!-- prettier-ignore-start --\u003e\n\u003c!-- markdownlint-disable MD013 --\u003e\n\u003c!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK --\u003e\n## Requirements\n\n| Name | Version |\n|------|---------|\n| \u003ca name=\"requirement_terraform\"\u003e\u003c/a\u003e [terraform](#requirement\\_terraform) | \u003e= 1.0 |\n| \u003ca name=\"requirement_aws\"\u003e\u003c/a\u003e [aws](#requirement\\_aws) | \u003e= 6.0 |\n| \u003ca name=\"requirement_tailscale\"\u003e\u003c/a\u003e [tailscale](#requirement\\_tailscale) | \u003e= 0.13.7 |\n\n## Providers\n\n| Name | Version |\n|------|---------|\n| \u003ca name=\"provider_aws\"\u003e\u003c/a\u003e [aws](#provider\\_aws) | \u003e= 6.0 |\n| \u003ca name=\"provider_tailscale\"\u003e\u003c/a\u003e [tailscale](#provider\\_tailscale) | \u003e= 0.13.7 |\n\n## Modules\n\n| Name | Source | Version |\n|------|--------|---------|\n| \u003ca name=\"module_ssm_policy\"\u003e\u003c/a\u003e [ssm\\_policy](#module\\_ssm\\_policy) | cloudposse/iam-policy/aws | 2.0.2 |\n| \u003ca name=\"module_ssm_state\"\u003e\u003c/a\u003e [ssm\\_state](#module\\_ssm\\_state) | cloudposse/ssm-parameter-store/aws | 0.13.0 |\n| \u003ca name=\"module_tailscale_subnet_router\"\u003e\u003c/a\u003e [tailscale\\_subnet\\_router](#module\\_tailscale\\_subnet\\_router) | masterpointio/ssm-agent/aws | 1.8.0 |\n| \u003ca name=\"module_this\"\u003e\u003c/a\u003e [this](#module\\_this) | cloudposse/label/null | 0.25.0 |\n\n## Resources\n\n| Name | Type |\n|------|------|\n| [aws_iam_role_policy_attachment.cw_agent](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [aws_iam_role_policy_attachment.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |\n| [tailscale_tailnet_key.default](https://registry.terraform.io/providers/tailscale/tailscale/latest/docs/resources/tailnet_key) | resource |\n\n## Inputs\n\n| Name | Description | Type | Default | Required |\n|------|-------------|------|---------|:--------:|\n| \u003ca name=\"input_additional_security_group_ids\"\u003e\u003c/a\u003e [additional\\_security\\_group\\_ids](#input\\_additional\\_security\\_group\\_ids) | Additional Security Group IDs to associate with the Tailscale Subnet Router EC2 instance. | `list(string)` | `[]` | no |\n| \u003ca name=\"input_additional_security_group_rules\"\u003e\u003c/a\u003e [additional\\_security\\_group\\_rules](#input\\_additional\\_security\\_group\\_rules) | Additional security group rules that will be attached to the primary security group | \u003cpre\u003emap(object({\u003cbr/\u003e    type      = string\u003cbr/\u003e    from_port = number\u003cbr/\u003e    to_port   = number\u003cbr/\u003e    protocol  = string\u003cbr/\u003e\u003cbr/\u003e    description      = optional(string)\u003cbr/\u003e    cidr_blocks      = optional(list(string))\u003cbr/\u003e    ipv6_cidr_blocks = optional(list(string))\u003cbr/\u003e    prefix_list_ids  = optional(list(string))\u003cbr/\u003e    self             = optional(bool)\u003cbr/\u003e  }))\u003c/pre\u003e | `{}` | no |\n| \u003ca name=\"input_additional_tag_map\"\u003e\u003c/a\u003e [additional\\_tag\\_map](#input\\_additional\\_tag\\_map) | Additional key-value pairs to add to each map in `tags_as_list_of_maps`. Not added to `tags` or `id`.\u003cbr/\u003eThis is for some rare cases where resources want additional configuration of tags\u003cbr/\u003eand therefore take a list of maps with tag key, value, and additional configuration. | `map(string)` | `{}` | no |\n| \u003ca name=\"input_additional_tags\"\u003e\u003c/a\u003e [additional\\_tags](#input\\_additional\\_tags) | Additional Tailscale tags to apply to the Tailscale Subnet Router machine in addition to `primary_tag`. These should not include the `tag:` prefix. | `list(string)` | `[]` | no |\n| \u003ca name=\"input_advertise_routes\"\u003e\u003c/a\u003e [advertise\\_routes](#input\\_advertise\\_routes) | The routes (expressed as CIDRs) to advertise as part of the Tailscale Subnet Router.\u003cbr/\u003e  Example: [\"10.0.2.0/24\", \"0.0.1.0/24\"] | `list(string)` | `[]` | no |\n| \u003ca name=\"input_allow_encrypted_uploads_only\"\u003e\u003c/a\u003e [allow\\_encrypted\\_uploads\\_only](#input\\_allow\\_encrypted\\_uploads\\_only) | Whether or not to allow encrypted uploads only. If set to `true` this will create a bucket policy that `Deny` if encryption header is missing in the requests. | `bool` | `false` | no |\n| \u003ca name=\"input_allow_ssl_requests_only\"\u003e\u003c/a\u003e [allow\\_ssl\\_requests\\_only](#input\\_allow\\_ssl\\_requests\\_only) | Whether or not to allow SSL requests only. If set to `true` this will create a bucket policy that `Deny` if SSL is not used in the requests using the `aws:SecureTransport` condition. | `bool` | `false` | no |\n| \u003ca name=\"input_ami\"\u003e\u003c/a\u003e [ami](#input\\_ami) | The AMI to use for the Tailscale Subnet Router EC2 instance.\u003cbr/\u003e  If not provided, the latest Amazon Linux 2 AMI will be used.\u003cbr/\u003e  Note: This will update periodically as AWS releases updates to their AL2 AMI.\u003cbr/\u003e  Pin to a specific AMI if you would like to avoid these updates. | `string` | `\"\"` | no |\n| \u003ca name=\"input_architecture\"\u003e\u003c/a\u003e [architecture](#input\\_architecture) | The architecture of the AMI (e.g., x86\\_64, arm64) | `string` | `\"arm64\"` | no |\n| \u003ca name=\"input_associate_public_ip_address\"\u003e\u003c/a\u003e [associate\\_public\\_ip\\_address](#input\\_associate\\_public\\_ip\\_address) | Associate public IP address with subnet router | `bool` | `null` | no |\n| \u003ca name=\"input_attributes\"\u003e\u003c/a\u003e [attributes](#input\\_attributes) | ID element. Additional attributes (e.g. `workers` or `cluster`) to add to `id`,\u003cbr/\u003ein the order they appear in the list. New attributes are appended to the\u003cbr/\u003eend of the list. The elements of the list are joined by the `delimiter`\u003cbr/\u003eand treated as a single ID element. | `list(string)` | `[]` | no |\n| \u003ca name=\"input_context\"\u003e\u003c/a\u003e [context](#input\\_context) | Single object for setting entire context at once.\u003cbr/\u003eSee description of individual variables for details.\u003cbr/\u003eLeave string and numeric variables as `null` to use default value.\u003cbr/\u003eIndividual variable settings (non-null) override settings in context object,\u003cbr/\u003eexcept for attributes, tags, and additional\\_tag\\_map, which are merged. | `any` | \u003cpre\u003e{\u003cbr/\u003e  \"additional_tag_map\": {},\u003cbr/\u003e  \"attributes\": [],\u003cbr/\u003e  \"delimiter\": null,\u003cbr/\u003e  \"descriptor_formats\": {},\u003cbr/\u003e  \"enabled\": true,\u003cbr/\u003e  \"environment\": null,\u003cbr/\u003e  \"id_length_limit\": null,\u003cbr/\u003e  \"label_key_case\": null,\u003cbr/\u003e  \"label_order\": [],\u003cbr/\u003e  \"label_value_case\": null,\u003cbr/\u003e  \"labels_as_tags\": [\u003cbr/\u003e    \"unset\"\u003cbr/\u003e  ],\u003cbr/\u003e  \"name\": null,\u003cbr/\u003e  \"namespace\": null,\u003cbr/\u003e  \"regex_replace_chars\": null,\u003cbr/\u003e  \"stage\": null,\u003cbr/\u003e  \"tags\": {},\u003cbr/\u003e  \"tenant\": null\u003cbr/\u003e}\u003c/pre\u003e | no |\n| \u003ca name=\"input_create_run_shell_document\"\u003e\u003c/a\u003e [create\\_run\\_shell\\_document](#input\\_create\\_run\\_shell\\_document) | Whether or not to create the SSM-SessionManagerRunShell SSM Document. | `bool` | `true` | no |\n| \u003ca name=\"input_delimiter\"\u003e\u003c/a\u003e [delimiter](#input\\_delimiter) | Delimiter to be used between ID elements.\u003cbr/\u003eDefaults to `-` (hyphen). Set to `\"\"` to use no delimiter at all. | `string` | `null` | no |\n| \u003ca name=\"input_descriptor_formats\"\u003e\u003c/a\u003e [descriptor\\_formats](#input\\_descriptor\\_formats) | Describe additional descriptors to be output in the `descriptors` output map.\u003cbr/\u003eMap of maps. Keys are names of descriptors. Values are maps of the form\u003cbr/\u003e`{\u003cbr/\u003e   format = string\u003cbr/\u003e   labels = list(string)\u003cbr/\u003e}`\u003cbr/\u003e(Type is `any` so the map values can later be enhanced to provide additional options.)\u003cbr/\u003e`format` is a Terraform format string to be passed to the `format()` function.\u003cbr/\u003e`labels` is a list of labels, in order, to pass to `format()` function.\u003cbr/\u003eLabel values will be normalized before being passed to `format()` so they will be\u003cbr/\u003eidentical to how they appear in `id`.\u003cbr/\u003eDefault is `{}` (`descriptors` output will be empty). | `any` | `{}` | no |\n| \u003ca name=\"input_desired_capacity\"\u003e\u003c/a\u003e [desired\\_capacity](#input\\_desired\\_capacity) | Desired number of instances in the Auto Scaling Group | `number` | `1` | no |\n| \u003ca name=\"input_enabled\"\u003e\u003c/a\u003e [enabled](#input\\_enabled) | Set to false to prevent the module from creating any resources | `bool` | `null` | no |\n| \u003ca name=\"input_environment\"\u003e\u003c/a\u003e [environment](#input\\_environment) | ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no |\n| \u003ca name=\"input_ephemeral\"\u003e\u003c/a\u003e [ephemeral](#input\\_ephemeral) | Indicates if the key is ephemeral. | `bool` | `false` | no |\n| \u003ca name=\"input_exit_node_enabled\"\u003e\u003c/a\u003e [exit\\_node\\_enabled](#input\\_exit\\_node\\_enabled) | Advertise Tailscale Subnet Router EC2 instance as exit node. Defaults to false. | `bool` | `false` | no |\n| \u003ca name=\"input_expiry\"\u003e\u003c/a\u003e [expiry](#input\\_expiry) | The expiry of the auth key in seconds. | `number` | `7776000` | no |\n| \u003ca name=\"input_id_length_limit\"\u003e\u003c/a\u003e [id\\_length\\_limit](#input\\_id\\_length\\_limit) | Limit `id` to this many characters (minimum 6).\u003cbr/\u003eSet to `0` for unlimited length.\u003cbr/\u003eSet to `null` for keep the existing setting, which defaults to `0`.\u003cbr/\u003eDoes not affect `id_full`. | `number` | `null` | no |\n| \u003ca name=\"input_instance_type\"\u003e\u003c/a\u003e [instance\\_type](#input\\_instance\\_type) | The instance type to use for the Tailscale Subnet Router EC2 instance. | `string` | `\"t4g.nano\"` | no |\n| \u003ca name=\"input_journald_max_retention_sec\"\u003e\u003c/a\u003e [journald\\_max\\_retention\\_sec](#input\\_journald\\_max\\_retention\\_sec) | The maximum time to store journal entries. | `string` | `\"7d\"` | no |\n| \u003ca name=\"input_journald_system_max_use\"\u003e\u003c/a\u003e [journald\\_system\\_max\\_use](#input\\_journald\\_system\\_max\\_use) | Disk space the journald may use up at most | `string` | `\"200M\"` | no |\n| \u003ca name=\"input_key_pair_name\"\u003e\u003c/a\u003e [key\\_pair\\_name](#input\\_key\\_pair\\_name) | The name of the key-pair to associate with the Tailscale Subnet Router EC2 instance. | `string` | `null` | no |\n| \u003ca name=\"input_label_key_case\"\u003e\u003c/a\u003e [label\\_key\\_case](#input\\_label\\_key\\_case) | Controls the letter case of the `tags` keys (label names) for tags generated by this module.\u003cbr/\u003eDoes not affect keys of tags passed in via the `tags` input.\u003cbr/\u003ePossible values: `lower`, `title`, `upper`.\u003cbr/\u003eDefault value: `title`. | `string` | `null` | no |\n| \u003ca name=\"input_label_order\"\u003e\u003c/a\u003e [label\\_order](#input\\_label\\_order) | The order in which the labels (ID elements) appear in the `id`.\u003cbr/\u003eDefaults to [\"namespace\", \"environment\", \"stage\", \"name\", \"attributes\"].\u003cbr/\u003eYou can omit any of the 6 labels (\"tenant\" is the 6th), but at least one must be present. | `list(string)` | `null` | no |\n| \u003ca name=\"input_label_value_case\"\u003e\u003c/a\u003e [label\\_value\\_case](#input\\_label\\_value\\_case) | Controls the letter case of ID elements (labels) as included in `id`,\u003cbr/\u003eset as tag values, and output by this module individually.\u003cbr/\u003eDoes not affect values of tags passed in via the `tags` input.\u003cbr/\u003ePossible values: `lower`, `title`, `upper` and `none` (no transformation).\u003cbr/\u003eSet this to `title` and set `delimiter` to `\"\"` to yield Pascal Case IDs.\u003cbr/\u003eDefault value: `lower`. | `string` | `null` | no |\n| \u003ca name=\"input_labels_as_tags\"\u003e\u003c/a\u003e [labels\\_as\\_tags](#input\\_labels\\_as\\_tags) | Set of labels (ID elements) to include as tags in the `tags` output.\u003cbr/\u003eDefault is to include all labels.\u003cbr/\u003eTags with empty values will not be included in the `tags` output.\u003cbr/\u003eSet to `[]` to suppress all generated tags.\u003cbr/\u003e**Notes:**\u003cbr/\u003e  The value of the `name` tag, if included, will be the `id`, not the `name`.\u003cbr/\u003e  Unlike other `null-label` inputs, the initial setting of `labels_as_tags` cannot be\u003cbr/\u003e  changed in later chained modules. Attempts to change it will be silently ignored. | `set(string)` | \u003cpre\u003e[\u003cbr/\u003e  \"default\"\u003cbr/\u003e]\u003c/pre\u003e | no |\n| \u003ca name=\"input_max_size\"\u003e\u003c/a\u003e [max\\_size](#input\\_max\\_size) | Maximum number of instances in the Auto Scaling Group. Must be \u003e= desired\\_capacity. | `number` | `2` | no |\n| \u003ca name=\"input_min_size\"\u003e\u003c/a\u003e [min\\_size](#input\\_min\\_size) | Minimum number of instances in the Auto Scaling Group | `number` | `1` | no |\n| \u003ca name=\"input_monitoring_enabled\"\u003e\u003c/a\u003e [monitoring\\_enabled](#input\\_monitoring\\_enabled) | Enable detailed monitoring of instances | `bool` | `true` | no |\n| \u003ca name=\"input_name\"\u003e\u003c/a\u003e [name](#input\\_name) | ID element. Usually the component or solution name, e.g. 'app' or 'jenkins'.\u003cbr/\u003eThis is the only ID element not also included as a `tag`.\u003cbr/\u003eThe \"name\" tag is set to the full `id` string. There is no tag with the value of the `name` input. | `string` | `null` | no |\n| \u003ca name=\"input_namespace\"\u003e\u003c/a\u003e [namespace](#input\\_namespace) | ID element. Usually an abbreviation of your organization name, e.g. 'eg' or 'cp', to help ensure generated IDs are globally unique | `string` | `null` | no |\n| \u003ca name=\"input_preauthorized\"\u003e\u003c/a\u003e [preauthorized](#input\\_preauthorized) | Determines whether or not the machines authenticated by the key will be authorized for the tailnet by default. | `bool` | `true` | no |\n| \u003ca name=\"input_primary_tag\"\u003e\u003c/a\u003e [primary\\_tag](#input\\_primary\\_tag) | The primary tag to apply to the Tailscale Subnet Router machine. Do not include the `tag:` prefix. This must match the OAuth client's tag. If not provided, the module will use the module's ID as the primary tag, which is configured in context.tf | `string` | `null` | no |\n| \u003ca name=\"input_regex_replace_chars\"\u003e\u003c/a\u003e [regex\\_replace\\_chars](#input\\_regex\\_replace\\_chars) | Terraform regular expression (regex) string.\u003cbr/\u003eCharacters matching the regex will be removed from the ID elements.\u003cbr/\u003eIf not set, `\"/[^a-zA-Z0-9-]/\"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no |\n| \u003ca name=\"input_reusable\"\u003e\u003c/a\u003e [reusable](#input\\_reusable) | Indicates if the key is reusable or single-use. | `bool` | `true` | no |\n| \u003ca name=\"input_session_logging_enabled\"\u003e\u003c/a\u003e [session\\_logging\\_enabled](#input\\_session\\_logging\\_enabled) | To enable CloudWatch and S3 session logging or not.\u003cbr/\u003e  Note this does not apply to SSH sessions as AWS cannot log those sessions. | `bool` | `true` | no |\n| \u003ca name=\"input_session_logging_kms_key_alias\"\u003e\u003c/a\u003e [session\\_logging\\_kms\\_key\\_alias](#input\\_session\\_logging\\_kms\\_key\\_alias) | Alias name for `session_logging` KMS Key.\u003cbr/\u003e  This is only applied if 2 conditions are met: (1) `session_logging_kms_key_arn` is unset,\u003cbr/\u003e  (2) `session_logging_encryption_enabled` = true. | `string` | `\"alias/session_logging\"` | no |\n| \u003ca name=\"input_session_logging_ssm_document_name\"\u003e\u003c/a\u003e [session\\_logging\\_ssm\\_document\\_name](#input\\_session\\_logging\\_ssm\\_document\\_name) | Name for `session_logging` SSM document.\u003cbr/\u003e  This is only applied if 2 conditions are met: (1) `session_logging_enabled` = true,\u003cbr/\u003e  (2) `create_run_shell_document` = true. | `string` | `\"SSM-SessionManagerRunShell-Tailscale\"` | no |\n| \u003ca name=\"input_ssh_enabled\"\u003e\u003c/a\u003e [ssh\\_enabled](#input\\_ssh\\_enabled) | Enable SSH access to the Tailscale Subnet Router EC2 instance. Defaults to true. | `bool` | `true` | no |\n| \u003ca name=\"input_ssm_policy_name\"\u003e\u003c/a\u003e [ssm\\_policy\\_name](#input\\_ssm\\_policy\\_name) | The name of the SSM policy to create.\u003cbr/\u003e  This is used to attach the SSM policy to the Tailscale Subnet Router EC2 instance.\u003cbr/\u003e  This is only applied if `ssm_state_enabled` is true.\u003cbr/\u003e  Multiple instances of this module can be used in the same account by setting a unique `ssm_policy_name` for each instance. | `string` | `\"ssm\"` | no |\n| \u003ca name=\"input_ssm_state_enabled\"\u003e\u003c/a\u003e [ssm\\_state\\_enabled](#input\\_ssm\\_state\\_enabled) | Control if tailscaled state is stored in AWS SSM (including preferences and keys).\u003cbr/\u003eThis tells the Tailscale daemon to write + read state from SSM,\u003cbr/\u003ewhich unlocks important features like retaining the existing tailscale machine name.\u003cbr/\u003eSee more in the [docs](https://tailscale.com/kb/1278/tailscaled#flags-to-tailscaled). | `bool` | `false` | no |\n| \u003ca name=\"input_stage\"\u003e\u003c/a\u003e [stage](#input\\_stage) | ID element. Usually used to indicate role, e.g. 'prod', 'staging', 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no |\n| \u003ca name=\"input_subnet_ids\"\u003e\u003c/a\u003e [subnet\\_ids](#input\\_subnet\\_ids) | The Subnet IDs which the Tailscale Subnet Router EC2 instance will run in. These *should* be private subnets. | `list(string)` | n/a | yes |\n| \u003ca name=\"input_tags\"\u003e\u003c/a\u003e [tags](#input\\_tags) | Additional tags (e.g. `{'BusinessUnit': 'XYZ'}`).\u003cbr/\u003eNeither the tag keys nor the tag values will be modified by this module. | `map(string)` | `{}` | no |\n| \u003ca name=\"input_tailscale_set_extra_flags\"\u003e\u003c/a\u003e [tailscale\\_set\\_extra\\_flags](#input\\_tailscale\\_set\\_extra\\_flags) | Extra flags to pass to `tailscale set` after `tailscale up` for persistent preference changes that don't require reauthentication.\u003cbr/\u003eSee more in the [docs](https://tailscale.com/docs/reference/tailscale-cli#set). | `list(string)` | `[]` | no |\n| \u003ca name=\"input_tailscale_up_extra_flags\"\u003e\u003c/a\u003e [tailscale\\_up\\_extra\\_flags](#input\\_tailscale\\_up\\_extra\\_flags) | Extra flags to pass to `tailscale up` for advanced configuration.\u003cbr/\u003eSee more in the [docs](https://tailscale.com/kb/1241/tailscale-up). | `list(string)` | `[]` | no |\n| \u003ca name=\"input_tailscaled_extra_flags\"\u003e\u003c/a\u003e [tailscaled\\_extra\\_flags](#input\\_tailscaled\\_extra\\_flags) | Extra flags to pass to Tailscale daemon for advanced configuration. Example: [\"--state=mem:\"]\u003cbr/\u003eSee more in the [docs](https://tailscale.com/kb/1278/tailscaled#flags-to-tailscaled). | `list(string)` | `[]` | no |\n| \u003ca name=\"input_tenant\"\u003e\u003c/a\u003e [tenant](#input\\_tenant) | ID element \\_(Rarely used, not included by default)\\_. A customer identifier, indicating who this instance of a resource is for | `string` | `null` | no |\n| \u003ca name=\"input_user_data\"\u003e\u003c/a\u003e [user\\_data](#input\\_user\\_data) | The user\\_data to use for the Tailscale Subnet Router EC2 instance.\u003cbr/\u003e  You can use this to automate installation of all the required command line tools. | `string` | `\"\"` | no |\n| \u003ca name=\"input_vpc_id\"\u003e\u003c/a\u003e [vpc\\_id](#input\\_vpc\\_id) | The ID of the VPC which the Tailscale Subnet Router EC2 instance will run in. | `string` | n/a | yes |\n\n## Outputs\n\n| Name | Description |\n|------|-------------|\n| \u003ca name=\"output_autoscaling_group_id\"\u003e\u003c/a\u003e [autoscaling\\_group\\_id](#output\\_autoscaling\\_group\\_id) | The ID of the Tailscale Subnet Router EC2 instance Autoscaling Group. |\n| \u003ca name=\"output_instance_name\"\u003e\u003c/a\u003e [instance\\_name](#output\\_instance\\_name) | The name tag value of the Tailscale Subnet Router EC2 instance. |\n| \u003ca name=\"output_launch_template_id\"\u003e\u003c/a\u003e [launch\\_template\\_id](#output\\_launch\\_template\\_id) | The ID of the Tailscale Subnet Router EC2 instance Launch Template. |\n| \u003ca name=\"output_security_group_id\"\u003e\u003c/a\u003e [security\\_group\\_id](#output\\_security\\_group\\_id) | The ID of the Tailscale Subnet Router EC2 instance Security Group. |\n\u003c!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK --\u003e\n\u003c!-- markdownlint-enable MD013 --\u003e\n\u003c!-- prettier-ignore-end --\u003e\n\n## Built By\n\nPowered by the [Masterpoint team](https://masterpoint.io/who-we-are/) and driven forward by contributions from the community ❤️\n\n[![Contributors][contributors-image]][contributors-url]\n\n## Contribution Guidelines\n\nContributions are welcome and appreciated!\n\nFound an issue or want to request a feature? [Open an issue][issues-url]\n\nWant to fix a bug you found or add some functionality? Fork, clone, commit, push, and PR — we'll check it out.\n\n## Who We Are 𐦂𖨆𐀪𖠋\n\nEstablished in 2016, Masterpoint is a team of experienced software and platform engineers specializing in Infrastructure as Code (IaC). We provide expert guidance to organizations of all sizes, helping them leverage the latest IaC practices to accelerate their engineering teams.\n\n### Our Mission\n\nOur mission is to simplify cloud infrastructure so developers can innovate faster, safer, and with greater confidence. By open-sourcing tools and modules that we use internally, we aim to contribute back to the community, promoting consistency, quality, and security.\n\n### Our Commitments\n\n- 🌟 **Open Source**: We live and breathe open source, contributing to and maintaining hundreds of projects across multiple organizations.\n- 🌎 **1% for the Planet**: Demonstrating our commitment to environmental sustainability, we are proud members of [1% for the Planet](https://www.onepercentfortheplanet.org), pledging to donate 1% of our annual sales to environmental nonprofits.\n- 🇺🇦 **1% Towards Ukraine**: With team members and friends affected by the ongoing [Russo-Ukrainian war](https://en.wikipedia.org/wiki/Russo-Ukrainian_War), we donate 1% of our annual revenue to invasion relief efforts, supporting organizations providing aid to those in need. [Here's how you can help Ukraine with just a few clicks](https://masterpoint.io/updates/supporting-ukraine/).\n\n## Connect With Us\n\nWe're active members of the community and are always publishing content, giving talks, and sharing our hard earned expertise. Here are a few ways you can see what we're up to:\n\n[![LinkedIn][linkedin-badge]][linkedin-url] [![Newsletter][newsletter-badge]][newsletter-url] [![Blog][blog-badge]][blog-url] [![YouTube][youtube-badge]][youtube-url]\n\n... and be sure to connect with our founder, [Matt Gowie](https://www.linkedin.com/in/gowiem/).\n\n## License\n\n[Apache License, Version 2.0][license-url].\n\n[![Open Source Initiative][osi-image]][license-url]\n\nCopyright © 2016-2026 [Masterpoint Consulting LLC](https://masterpoint.io/)\n\n\u003c!-- MARKDOWN LINKS \u0026 IMAGES --\u003e\n\n[banner-image]: https://masterpoint-public.s3.us-west-2.amazonaws.com/v2/standard-long-fullcolor.png\n[license-url]: https://opensource.org/license/apache-2-0\n[osi-image]: https://i0.wp.com/opensource.org/wp-content/uploads/2023/03/cropped-OSI-horizontal-large.png?fit=250%2C229\u0026ssl=1\n[linkedin-badge]: https://img.shields.io/badge/LinkedIn-Follow-0A66C2?style=for-the-badge\u0026logoColor=white\n[linkedin-url]: https://www.linkedin.com/company/masterpoint-consulting\n[blog-badge]: https://img.shields.io/badge/Blog-IaC_Insights-55C1B4?style=for-the-badge\u0026logoColor=white\n[blog-url]: https://masterpoint.io/updates/\n[newsletter-badge]: https://img.shields.io/badge/Newsletter-Subscribe-ECE295?style=for-the-badge\u0026logoColor=222222\n[newsletter-url]: https://newsletter.masterpoint.io/\n[youtube-badge]: https://img.shields.io/badge/YouTube-Subscribe-D191BF?style=for-the-badge\u0026logo=youtube\u0026logoColor=white\n[youtube-url]: https://www.youtube.com/channel/UCeeDaO2NREVlPy9Plqx-9JQ\n[release-badge]: https://img.shields.io/github/v/release/masterpointio/terraform-aws-tailscale?color=0E383A\u0026label=Release\u0026style=for-the-badge\u0026logo=github\u0026logoColor=white\n[latest-release]: https://github.com/masterpointio/terraform-aws-tailscale/releases/latest\n[contributors-image]: https://contrib.rocks/image?repo=masterpointio/terraform-aws-tailscale\n[contributors-url]: https://github.com/masterpointio/terraform-aws-tailscale/graphs/contributors\n[issues-url]: https://github.com/masterpointio/terraform-aws-tailscale/issues\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmasterpointio%2Fterraform-aws-tailscale","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmasterpointio%2Fterraform-aws-tailscale","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmasterpointio%2Fterraform-aws-tailscale/lists"}