From f7144687765a4b7ba4a18b65e7f17bf69f7c64e5 Mon Sep 17 00:00:00 2001 From: Veronika Gnilitska Date: Fri, 16 Aug 2024 16:48:31 +0300 Subject: [PATCH 01/12] feat: support extra arguments for tailscaled --- .trunk/configs/.trivyignore | 8 +++ CHANGELOG.md | 10 ++- README.md | 129 +++++++++++++++++++----------------- main.tf | 20 ++++-- userdata.sh.tmpl | 23 +++++-- variables.tf | 20 +++++- 6 files changed, 132 insertions(+), 78 deletions(-) create mode 100644 .trunk/configs/.trivyignore diff --git a/.trunk/configs/.trivyignore b/.trunk/configs/.trivyignore new file mode 100644 index 0000000..35aa2c9 --- /dev/null +++ b/.trunk/configs/.trivyignore @@ -0,0 +1,8 @@ +# Log group is not encrypted +AVD-AWS-0017 + +# Bucket does not have versioning enabled +AVD-AWS-0090 + +# Bucket does not encrypt data with a customer managed key +AVD-AWS-0132 diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ba2f64..cf367bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,14 +2,12 @@ ## [1.3.0](https://github.com/masterpointio/terraform-aws-tailscale/compare/1.2.0...v1.3.0) (2024-08-13) - ### Features -* adds conventional-title lint check ([73abd18](https://github.com/masterpointio/terraform-aws-tailscale/commit/73abd184189ce062cba882d79ab10b183a1f117c)) -* adds release-please for automated releases ([c08d7bb](https://github.com/masterpointio/terraform-aws-tailscale/commit/c08d7bbdffba9038e4e111e984dfbe2e78e1512c)) -* allow configuring router as an exit node ([#24](https://github.com/masterpointio/terraform-aws-tailscale/issues/24)) ([3c30878](https://github.com/masterpointio/terraform-aws-tailscale/commit/3c30878166fc694c27cd77ace3879e2a19168556)) - +- adds conventional-title lint check ([73abd18](https://github.com/masterpointio/terraform-aws-tailscale/commit/73abd184189ce062cba882d79ab10b183a1f117c)) +- adds release-please for automated releases ([c08d7bb](https://github.com/masterpointio/terraform-aws-tailscale/commit/c08d7bbdffba9038e4e111e984dfbe2e78e1512c)) +- allow configuring router as an exit node ([#24](https://github.com/masterpointio/terraform-aws-tailscale/issues/24)) ([3c30878](https://github.com/masterpointio/terraform-aws-tailscale/commit/3c30878166fc694c27cd77ace3879e2a19168556)) ### Bug Fixes -* update to use kebab-case name ([f8006ff](https://github.com/masterpointio/terraform-aws-tailscale/commit/f8006ff056060edab3c2b311b014b548156d6204)) +- update to use kebab-case name ([f8006ff](https://github.com/masterpointio/terraform-aws-tailscale/commit/f8006ff056060edab3c2b311b014b548156d6204)) diff --git a/README.md b/README.md index 24e0858..219ec91 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,8 @@ module "tailscale" { vpc_id = module.vpc.vpc_id subnet_ids = module.subnets.private_subnet_ids advertise_routes = [module.vpc.vpc_cidr_block] + + ephemeral = true } ``` @@ -58,84 +60,87 @@ Here is an example of using this module: - [`examples/complete`](https://github.com/masterpointio/terraform-aws-tailscale/) - complete example of using this module + ## Requirements -| Name | Version | -|------|---------| -| [terraform](#requirement\_terraform) | >= 1.0 | -| [aws](#requirement\_aws) | >= 4.0 | -| [tailscale](#requirement\_tailscale) | >= 0.13.7 | +| Name | Version | +| ------------------------------------------------------------------------ | --------- | +| [terraform](#requirement_terraform) | >= 1.0 | +| [aws](#requirement_aws) | >= 4.0 | +| [tailscale](#requirement_tailscale) | >= 0.13.7 | ## Providers -| Name | Version | -|------|---------| -| [tailscale](#provider\_tailscale) | >= 0.13.7 | +| Name | Version | +| ------------------------------------------------------------------ | --------- | +| [tailscale](#provider_tailscale) | >= 0.13.7 | ## Modules -| Name | Source | Version | -|------|--------|---------| -| [tailscale\_subnet\_router](#module\_tailscale\_subnet\_router) | masterpointio/ssm-agent/aws | 1.2.0 | -| [this](#module\_this) | cloudposse/label/null | 0.25.0 | +| Name | Source | Version | +| -------------------------------------------------------------------------------------------------------- | --------------------------- | ------- | +| [tailscale_subnet_router](#module_tailscale_subnet_router) | masterpointio/ssm-agent/aws | 1.2.0 | +| [this](#module_this) | cloudposse/label/null | 0.25.0 | ## Resources -| Name | Type | -|------|------| +| Name | Type | +| ------------------------------------------------------------------------------------------------------------------------------ | -------- | | [tailscale_tailnet_key.default](https://registry.terraform.io/providers/tailscale/tailscale/latest/docs/resources/tailnet_key) | resource | ## Inputs -| Name | Description | Type | Default | Required | -|------|-------------|------|---------|:--------:| -| [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 | -| [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`.
This is for some rare cases where resources want additional configuration of tags
and therefore take a list of maps with tag key, value, and additional configuration. | `map(string)` | `{}` | no | -| [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 | -| [advertise\_routes](#input\_advertise\_routes) | The routes (expressed as CIDRs) to advertise as part of the Tailscale Subnet Router.
Example: ["10.0.2.0/24", "0.0.1.0/24"] | `list(string)` | `[]` | no | -| [ami](#input\_ami) | The AMI to use for the Tailscale Subnet Router EC2 instance.
If not provided, the latest Amazon Linux 2 AMI will be used.
Note: This will update periodically as AWS releases updates to their AL2 AMI.
Pin to a specific AMI if you would like to avoid these updates. | `string` | `""` | no | -| [associate\_public\_ip\_address](#input\_associate\_public\_ip\_address) | Associate public IP address with subnet router | `bool` | `null` | no | -| [attributes](#input\_attributes) | ID element. Additional attributes (e.g. `workers` or `cluster`) to add to `id`,
in the order they appear in the list. New attributes are appended to the
end of the list. The elements of the list are joined by the `delimiter`
and treated as a single ID element. | `list(string)` | `[]` | no | -| [context](#input\_context) | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional\_tag\_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"descriptor_formats": {},
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"labels_as_tags": [
"unset"
],
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {},
"tenant": null
}
| no | -| [create\_run\_shell\_document](#input\_create\_run\_shell\_document) | Whether or not to create the SSM-SessionManagerRunShell SSM Document. | `bool` | `true` | no | -| [delimiter](#input\_delimiter) | Delimiter to be used between ID elements.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | -| [descriptor\_formats](#input\_descriptor\_formats) | Describe additional descriptors to be output in the `descriptors` output map.
Map of maps. Keys are names of descriptors. Values are maps of the form
`{
format = string
labels = list(string)
}`
(Type is `any` so the map values can later be enhanced to provide additional options.)
`format` is a Terraform format string to be passed to the `format()` function.
`labels` is a list of labels, in order, to pass to `format()` function.
Label values will be normalized before being passed to `format()` so they will be
identical to how they appear in `id`.
Default is `{}` (`descriptors` output will be empty). | `any` | `{}` | no | -| [enabled](#input\_enabled) | Set to false to prevent the module from creating any resources | `bool` | `null` | no | -| [environment](#input\_environment) | ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | -| [ephemeral](#input\_ephemeral) | Indicates if the key is ephemeral. | `bool` | `false` | no | -| [exit\_node\_enabled](#input\_exit\_node\_enabled) | Advertise Tailscale Subnet Router EC2 instance as exit node. Defaults to false. | `bool` | `false` | no | -| [expiry](#input\_expiry) | The expiry of the auth key in seconds. | `number` | `7776000` | no | -| [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for keep the existing setting, which defaults to `0`.
Does not affect `id_full`. | `number` | `null` | no | -| [instance\_type](#input\_instance\_type) | The instance type to use for the Tailscale Subnet Router EC2 instance. | `string` | `"t3.nano"` | no | -| [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 | -| [label\_key\_case](#input\_label\_key\_case) | Controls the letter case of the `tags` keys (label names) for tags generated by this module.
Does not affect keys of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | -| [label\_order](#input\_label\_order) | The order in which the labels (ID elements) appear in the `id`.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present. | `list(string)` | `null` | no | -| [label\_value\_case](#input\_label\_value\_case) | Controls the letter case of ID elements (labels) as included in `id`,
set as tag values, and output by this module individually.
Does not affect values of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Set this to `title` and set `delimiter` to `""` to yield Pascal Case IDs.
Default value: `lower`. | `string` | `null` | no | -| [labels\_as\_tags](#input\_labels\_as\_tags) | Set of labels (ID elements) to include as tags in the `tags` output.
Default is to include all labels.
Tags with empty values will not be included in the `tags` output.
Set to `[]` to suppress all generated tags.
**Notes:**
The value of the `name` tag, if included, will be the `id`, not the `name`.
Unlike other `null-label` inputs, the initial setting of `labels_as_tags` cannot be
changed in later chained modules. Attempts to change it will be silently ignored. | `set(string)` |
[
"default"
]
| no | -| [monitoring\_enabled](#input\_monitoring\_enabled) | Enable detailed monitoring of instances | `bool` | `true` | no | -| [name](#input\_name) | ID element. Usually the component or solution name, e.g. 'app' or 'jenkins'.
This is the only ID element not also included as a `tag`.
The "name" tag is set to the full `id` string. There is no tag with the value of the `name` input. | `string` | `null` | no | -| [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 | -| [preauthorized](#input\_preauthorized) | Determines whether or not the machines authenticated by the key will be authorized for the tailnet by default. | `bool` | `true` | no | -| [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 | -| [regex\_replace\_chars](#input\_regex\_replace\_chars) | Terraform regular expression (regex) string.
Characters matching the regex will be removed from the ID elements.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | -| [reusable](#input\_reusable) | Indicates if the key is reusable or single-use. | `bool` | `true` | no | -| [session\_logging\_enabled](#input\_session\_logging\_enabled) | To enable CloudWatch and S3 session logging or not.
Note this does not apply to SSH sessions as AWS cannot log those sessions. | `bool` | `true` | no | -| [session\_logging\_kms\_key\_alias](#input\_session\_logging\_kms\_key\_alias) | Alias name for `session_logging` KMS Key.
This is only applied if 2 conditions are met: (1) `session_logging_kms_key_arn` is unset,
(2) `session_logging_encryption_enabled` = true. | `string` | `"alias/session_logging"` | no | -| [session\_logging\_ssm\_document\_name](#input\_session\_logging\_ssm\_document\_name) | Name for `session_logging` SSM document.
This is only applied if 2 conditions are met: (1) `session_logging_enabled` = true,
(2) `create_run_shell_document` = true. | `string` | `"SSM-SessionManagerRunShell-Tailscale"` | no | -| [ssh\_enabled](#input\_ssh\_enabled) | Enable SSH access to the Tailscale Subnet Router EC2 instance. Defaults to true. | `bool` | `true` | no | -| [stage](#input\_stage) | ID element. Usually used to indicate role, e.g. 'prod', 'staging', 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | -| [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 | -| [tags](#input\_tags) | Additional tags (e.g. `{'BusinessUnit': 'XYZ'}`).
Neither the tag keys nor the tag values will be modified by this module. | `map(string)` | `{}` | no | -| [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 | -| [user\_data](#input\_user\_data) | The user\_data to use for the Tailscale Subnet Router EC2 instance.
You can use this to automate installation of all the required command line tools. | `string` | `""` | no | -| [vpc\_id](#input\_vpc\_id) | The ID of the VPC which the Tailscale Subnet Router EC2 instance will run in. | `string` | n/a | yes | +| Name | Description | Type | Default | Required | +| ------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------: | +| [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 | +| [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`.
This is for some rare cases where resources want additional configuration of tags
and therefore take a list of maps with tag key, value, and additional configuration. | `map(string)` | `{}` | no | +| [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 | +| [advertise_routes](#input_advertise_routes) | The routes (expressed as CIDRs) to advertise as part of the Tailscale Subnet Router.
Example: ["10.0.2.0/24", "0.0.1.0/24"] | `list(string)` | `[]` | no | +| [ami](#input_ami) | The AMI to use for the Tailscale Subnet Router EC2 instance.
If not provided, the latest Amazon Linux 2 AMI will be used.
Note: This will update periodically as AWS releases updates to their AL2 AMI.
Pin to a specific AMI if you would like to avoid these updates. | `string` | `""` | no | +| [associate_public_ip_address](#input_associate_public_ip_address) | Associate public IP address with subnet router | `bool` | `null` | no | +| [attributes](#input_attributes) | ID element. Additional attributes (e.g. `workers` or `cluster`) to add to `id`,
in the order they appear in the list. New attributes are appended to the
end of the list. The elements of the list are joined by the `delimiter`
and treated as a single ID element. | `list(string)` | `[]` | no | +| [context](#input_context) | Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional_tag_map, which are merged. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"descriptor_formats": {},
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"labels_as_tags": [
"unset"
],
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {},
"tenant": null
}
| no | +| [create_run_shell_document](#input_create_run_shell_document) | Whether or not to create the SSM-SessionManagerRunShell SSM Document. | `bool` | `true` | no | +| [delimiter](#input_delimiter) | Delimiter to be used between ID elements.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | +| [descriptor_formats](#input_descriptor_formats) | Describe additional descriptors to be output in the `descriptors` output map.
Map of maps. Keys are names of descriptors. Values are maps of the form
`{
format = string
labels = list(string)
}`
(Type is `any` so the map values can later be enhanced to provide additional options.)
`format` is a Terraform format string to be passed to the `format()` function.
`labels` is a list of labels, in order, to pass to `format()` function.
Label values will be normalized before being passed to `format()` so they will be
identical to how they appear in `id`.
Default is `{}` (`descriptors` output will be empty). | `any` | `{}` | no | +| [enabled](#input_enabled) | Set to false to prevent the module from creating any resources | `bool` | `null` | no | +| [environment](#input_environment) | ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | +| [ephemeral](#input_ephemeral) | Indicates if the key is ephemeral. | `bool` | `false` | no | +| [exit_node_enabled](#input_exit_node_enabled) | Advertise Tailscale Subnet Router EC2 instance as exit node. Defaults to false. | `bool` | `false` | no | +| [expiry](#input_expiry) | The expiry of the auth key in seconds. | `number` | `7776000` | no | +| [id_length_limit](#input_id_length_limit) | Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for keep the existing setting, which defaults to `0`.
Does not affect `id_full`. | `number` | `null` | no | +| [instance_type](#input_instance_type) | The instance type to use for the Tailscale Subnet Router EC2 instance. | `string` | `"t3.nano"` | no | +| [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 | +| [label_key_case](#input_label_key_case) | Controls the letter case of the `tags` keys (label names) for tags generated by this module.
Does not affect keys of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper`.
Default value: `title`. | `string` | `null` | no | +| [label_order](#input_label_order) | The order in which the labels (ID elements) appear in the `id`.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present. | `list(string)` | `null` | no | +| [label_value_case](#input_label_value_case) | Controls the letter case of ID elements (labels) as included in `id`,
set as tag values, and output by this module individually.
Does not affect values of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Set this to `title` and set `delimiter` to `""` to yield Pascal Case IDs.
Default value: `lower`. | `string` | `null` | no | +| [labels_as_tags](#input_labels_as_tags) | Set of labels (ID elements) to include as tags in the `tags` output.
Default is to include all labels.
Tags with empty values will not be included in the `tags` output.
Set to `[]` to suppress all generated tags.
**Notes:**
The value of the `name` tag, if included, will be the `id`, not the `name`.
Unlike other `null-label` inputs, the initial setting of `labels_as_tags` cannot be
changed in later chained modules. Attempts to change it will be silently ignored. | `set(string)` |
[
"default"
]
| no | +| [monitoring_enabled](#input_monitoring_enabled) | Enable detailed monitoring of instances | `bool` | `true` | no | +| [name](#input_name) | ID element. Usually the component or solution name, e.g. 'app' or 'jenkins'.
This is the only ID element not also included as a `tag`.
The "name" tag is set to the full `id` string. There is no tag with the value of the `name` input. | `string` | `null` | no | +| [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 | +| [preauthorized](#input_preauthorized) | Determines whether or not the machines authenticated by the key will be authorized for the tailnet by default. | `bool` | `true` | no | +| [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 | +| [regex_replace_chars](#input_regex_replace_chars) | Terraform regular expression (regex) string.
Characters matching the regex will be removed from the ID elements.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no | +| [reusable](#input_reusable) | Indicates if the key is reusable or single-use. | `bool` | `true` | no | +| [session_logging_enabled](#input_session_logging_enabled) | To enable CloudWatch and S3 session logging or not.
Note this does not apply to SSH sessions as AWS cannot log those sessions. | `bool` | `true` | no | +| [session_logging_kms_key_alias](#input_session_logging_kms_key_alias) | Alias name for `session_logging` KMS Key.
This is only applied if 2 conditions are met: (1) `session_logging_kms_key_arn` is unset,
(2) `session_logging_encryption_enabled` = true. | `string` | `"alias/session_logging"` | no | +| [session_logging_ssm_document_name](#input_session_logging_ssm_document_name) | Name for `session_logging` SSM document.
This is only applied if 2 conditions are met: (1) `session_logging_enabled` = true,
(2) `create_run_shell_document` = true. | `string` | `"SSM-SessionManagerRunShell-Tailscale"` | no | +| [ssh_enabled](#input_ssh_enabled) | Enable SSH access to the Tailscale Subnet Router EC2 instance. Defaults to true. | `bool` | `true` | no | +| [stage](#input_stage) | ID element. Usually used to indicate role, e.g. 'prod', 'staging', 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | +| [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 | +| [tags](#input_tags) | Additional tags (e.g. `{'BusinessUnit': 'XYZ'}`).
Neither the tag keys nor the tag values will be modified by this module. | `map(string)` | `{}` | no | +| [tailscaled_extra_flags](#input_tailscaled_extra_flags) | Extra flags to pass to tailscaled. Useful for advanced configuration. | `list(string)` | `[]` | no | +| [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 | +| [user_data](#input_user_data) | The user_data to use for the Tailscale Subnet Router EC2 instance.
You can use this to automate installation of all the required command line tools. | `string` | `""` | no | +| [vpc_id](#input_vpc_id) | The ID of the VPC which the Tailscale Subnet Router EC2 instance will run in. | `string` | n/a | yes | ## Outputs -| Name | Description | -|------|-------------| -| [autoscaling\_group\_id](#output\_autoscaling\_group\_id) | The ID of the Tailscale Subnet Router EC2 instance Autoscaling Group. | -| [instance\_name](#output\_instance\_name) | The name tag value of the Tailscale Subnet Router EC2 instance. | -| [launch\_template\_id](#output\_launch\_template\_id) | The ID of the Tailscale Subnet Router EC2 instance Launch Template. | -| [security\_group\_id](#output\_security\_group\_id) | The ID of the Tailscale Subnet Router EC2 instance Security Group. | +| Name | Description | +| ----------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | +| [autoscaling_group_id](#output_autoscaling_group_id) | The ID of the Tailscale Subnet Router EC2 instance Autoscaling Group. | +| [instance_name](#output_instance_name) | The name tag value of the Tailscale Subnet Router EC2 instance. | +| [launch_template_id](#output_launch_template_id) | The ID of the Tailscale Subnet Router EC2 instance Launch Template. | +| [security_group_id](#output_security_group_id) | The ID of the Tailscale Subnet Router EC2 instance Security Group. | + diff --git a/main.tf b/main.tf index f14a24b..10af105 100644 --- a/main.tf +++ b/main.tf @@ -3,18 +3,30 @@ locals { primary_tag = coalesce(var.primary_tag, module.this.id) prefixed_primary_tag = "tag:${local.primary_tag}" prefixed_additional_tags = [for tag in var.additional_tags : "tag:${tag}"] - tailscale_tags = concat([local.prefixed_primary_tag], local.prefixed_additional_tags) + + tailscale_tags = concat([local.prefixed_primary_tag], local.prefixed_additional_tags) + + tailscaled_extra_flags_enabled = length(var.tailscaled_extra_flags) > 0 + tailscale_up_extra_flags_enabled = length(var.tailscale_up_extra_flags) > 0 userdata = templatefile("${path.module}/userdata.sh.tmpl", { - routes = join(",", var.advertise_routes) authkey = tailscale_tailnet_key.default.key + exit_node_enabled = var.exit_node_enabled hostname = module.this.id - tags = join(",", local.tailscale_tags) + routes = join(",", var.advertise_routes) ssh_enabled = var.ssh_enabled - exit_node_enabled = var.exit_node_enabled + tags = join(",", local.tailscale_tags) + + tailscaled_extra_flags_enabled = local.tailscaled_extra_flags_enabled + tailscaled_extra_flags = join(" ", var.tailscaled_extra_flags) + tailscale_up_extra_flags_enabled = local.tailscale_up_extra_flags_enabled + tailscale_up_extra_flags = join(" ", var.tailscale_up_extra_flags) }) } +# Note: `trunk` ignores that this rule is already listed in `.trivyignore` file. +# Bucket does not have versioning enabled +# trivy:ignore:AVD-AWS-0090 module "tailscale_subnet_router" { source = "masterpointio/ssm-agent/aws" version = "1.2.0" diff --git a/userdata.sh.tmpl b/userdata.sh.tmpl index 8bfa275..4a75a7f 100644 --- a/userdata.sh.tmpl +++ b/userdata.sh.tmpl @@ -1,27 +1,40 @@ #!/bin/bash -ex exec > >(tee /var/log/user-data.log | logger -t user-data -s 2>/dev/console) 2>&1 -# Enable ip_forward to allow advertising routes +echo "Starting user-data script..." + +echo "Enabling IP forwarding..." echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.conf echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.conf sudo sysctl -p /etc/sysctl.conf -# Install tailscale +echo "Installing Tailscale..." sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://pkgs.tailscale.com/stable/amazon-linux/2/tailscale.repo sudo yum install -y tailscale +%{ if tailscaled_extra_flags_enabled == true } +echo "Exporting FLAGS to environment variable..." +export FLAGS=${tailscaled_extra_flags}% +%{ endif } + # Setup tailscale +echo "Enabling and starting tailscaled service..." sudo systemctl enable --now tailscaled -# Wait a few for tailscaled to come up +echo "Waiting for tailscaled to initialize..." sleep 5 # Start tailscale # We pass --advertise-tags below even though the authkey being created with those tags should result # in the same effect. This is to be more explicit because tailscale tags are a complicated topic. sudo tailscale up \ + %{ if ssh_enabled == true }--ssh%{ endif } \ + %{ if exit_node_enabled == true }--advertise-exit-node%{ endif } \ + %{ if tailscale_up_extra_flags_enabled == true }${tailscale_up_extra_flags}%{ endif } \ --advertise-routes=${routes} \ --advertise-tags=${tags} \ - --authkey=${authkey} \ - --hostname=${hostname}%{ if ssh_enabled == true } --ssh%{ endif }%{ if exit_node_enabled == true } --advertise-exit-node%{ endif } + --hostname=${hostname} \ + --authkey=${authkey} + +echo "Tailscale setup completed." diff --git a/variables.tf b/variables.tf index 300515e..77532c0 100644 --- a/variables.tf +++ b/variables.tf @@ -160,5 +160,23 @@ variable "ephemeral" { variable "reusable" { default = true type = bool - description = " Indicates if the key is reusable or single-use." + description = "Indicates if the key is reusable or single-use." +} + +variable "tailscaled_extra_flags" { + default = [] + type = list(string) + description = <<-EOT + Extra flags to pass to Tailscale daemon for advanced configuration. Example: ["--state=mem:"] + See more in the [docs](https://tailscale.com/kb/1278/tailscaled#flags-to-tailscaled). + EOT +} + +variable "tailscale_up_extra_flags" { + default = [] + type = list(string) + description = <<-EOT + Extra flags to pass to `tailscale up` for advanced configuration. + See more in the [docs](https://tailscale.com/kb/1241/tailscale-up). + EOT } From 2464fafb6d8906d036ac9e1fc7afbe6a855948c9 Mon Sep 17 00:00:00 2001 From: Veronika Gnilitska Date: Tue, 20 Aug 2024 15:54:46 +0300 Subject: [PATCH 02/12] chore: adds prettierignore --- .trunk/configs/.prettierignore | 4 ++++ CHANGELOG.md | 10 ++++++---- README.md | 3 ++- 3 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 .trunk/configs/.prettierignore diff --git a/.trunk/configs/.prettierignore b/.trunk/configs/.prettierignore new file mode 100644 index 0000000..2d0b6b1 --- /dev/null +++ b/.trunk/configs/.prettierignore @@ -0,0 +1,4 @@ +# `release-please` doesn't generate prettier compliant output, see relevant issues: +# https://github.com/googleapis/release-please/issues/1902 +# https://github.com/googleapis/release-please/issues/1802 +CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md index cf367bc..1ba2f64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,14 @@ ## [1.3.0](https://github.com/masterpointio/terraform-aws-tailscale/compare/1.2.0...v1.3.0) (2024-08-13) + ### Features -- adds conventional-title lint check ([73abd18](https://github.com/masterpointio/terraform-aws-tailscale/commit/73abd184189ce062cba882d79ab10b183a1f117c)) -- adds release-please for automated releases ([c08d7bb](https://github.com/masterpointio/terraform-aws-tailscale/commit/c08d7bbdffba9038e4e111e984dfbe2e78e1512c)) -- allow configuring router as an exit node ([#24](https://github.com/masterpointio/terraform-aws-tailscale/issues/24)) ([3c30878](https://github.com/masterpointio/terraform-aws-tailscale/commit/3c30878166fc694c27cd77ace3879e2a19168556)) +* adds conventional-title lint check ([73abd18](https://github.com/masterpointio/terraform-aws-tailscale/commit/73abd184189ce062cba882d79ab10b183a1f117c)) +* adds release-please for automated releases ([c08d7bb](https://github.com/masterpointio/terraform-aws-tailscale/commit/c08d7bbdffba9038e4e111e984dfbe2e78e1512c)) +* allow configuring router as an exit node ([#24](https://github.com/masterpointio/terraform-aws-tailscale/issues/24)) ([3c30878](https://github.com/masterpointio/terraform-aws-tailscale/commit/3c30878166fc694c27cd77ace3879e2a19168556)) + ### Bug Fixes -- update to use kebab-case name ([f8006ff](https://github.com/masterpointio/terraform-aws-tailscale/commit/f8006ff056060edab3c2b311b014b548156d6204)) +* update to use kebab-case name ([f8006ff](https://github.com/masterpointio/terraform-aws-tailscale/commit/f8006ff056060edab3c2b311b014b548156d6204)) diff --git a/README.md b/README.md index 219ec91..d351bb6 100644 --- a/README.md +++ b/README.md @@ -129,7 +129,8 @@ Here is an example of using this module: | [stage](#input_stage) | ID element. Usually used to indicate role, e.g. 'prod', 'staging', 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | | [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 | | [tags](#input_tags) | Additional tags (e.g. `{'BusinessUnit': 'XYZ'}`).
Neither the tag keys nor the tag values will be modified by this module. | `map(string)` | `{}` | no | -| [tailscaled_extra_flags](#input_tailscaled_extra_flags) | Extra flags to pass to tailscaled. Useful for advanced configuration. | `list(string)` | `[]` | no | +| [tailscale_up_extra_flags](#input_tailscale_up_extra_flags) | Extra flags to pass to `tailscale up` for advanced configuration.
See more in the [docs](https://tailscale.com/kb/1241/tailscale-up). | `list(string)` | `[]` | no | +| [tailscaled_extra_flags](#input_tailscaled_extra_flags) | Extra flags to pass to Tailscale daemon for advanced configuration. Example: ["--state=mem:"]
See more in the [docs](https://tailscale.com/kb/1278/tailscaled#flags-to-tailscaled). | `list(string)` | `[]` | no | | [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 | | [user_data](#input_user_data) | The user_data to use for the Tailscale Subnet Router EC2 instance.
You can use this to automate installation of all the required command line tools. | `string` | `""` | no | | [vpc_id](#input_vpc_id) | The ID of the VPC which the Tailscale Subnet Router EC2 instance will run in. | `string` | n/a | yes | From 34a1a0a45a72d3108b9c7c3087ebcb720e0bc895 Mon Sep 17 00:00:00 2001 From: Veronika Gnilitska Date: Fri, 15 Nov 2024 06:12:33 -0500 Subject: [PATCH 03/12] chore: update trunk less often --- .github/workflows/trunk-upgrade.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/trunk-upgrade.yaml b/.github/workflows/trunk-upgrade.yaml index 764843e..d67ed23 100644 --- a/.github/workflows/trunk-upgrade.yaml +++ b/.github/workflows/trunk-upgrade.yaml @@ -1,8 +1,8 @@ -name: Weekly Trunk Upgrade +name: Monthly Trunk Upgrade on: schedule: - # Every Monday @ 5am - - cron: 0 5 * * 1 + # On the first day of every month @ 8am + - cron: 0 8 1 * * # Allows us to manually run the workflow from Actions UI workflow_dispatch: {} permissions: read-all @@ -18,7 +18,7 @@ jobs: uses: actions/checkout@v4 - name: Trunk Upgrade - uses: trunk-io/trunk-action/upgrade@d5b1b61d0beee562512f530a278b6a2931fba857 + uses: trunk-io/trunk-action/upgrade@2eaee169140ec559bd556208f9f99cdfdf468da8 # v1.1.18 with: base: main reviewers: "@masterpointio/masterpoint-internal" From 9aef7ae470e73c1874b2e9921769c30ac758874e Mon Sep 17 00:00:00 2001 From: Veronika Gnilitska Date: Fri, 15 Nov 2024 06:12:58 -0500 Subject: [PATCH 04/12] chore: update git ignore list --- .gitignore | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 1c768ad..73df5ac 100644 --- a/.gitignore +++ b/.gitignore @@ -7,9 +7,6 @@ .terraform .terraform.tfstate.lock.info -**/.idea -**/*.iml - # Cloud Posse Build Harness https://github.com/cloudposse/build-harness **/.build-harness **/build-harness @@ -17,3 +14,8 @@ # Crash log files crash.log test.log + +# Random +**/.idea +**/*.iml +.DS_Store From d9bc3b0b6b69921b563f6407823f29825c50d03d Mon Sep 17 00:00:00 2001 From: Veronika Gnilitska Date: Fri, 15 Nov 2024 06:13:20 -0500 Subject: [PATCH 05/12] feat: support aws ssm state --- README.md | 16 ++++++----- examples/complete/fixtures.us-east-2.tfvars | 2 ++ main.tf | 30 ++++++++++++++++++--- userdata.sh.tmpl | 4 +-- variables.tf | 9 +++++++ 5 files changed, 49 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index d351bb6..7951eb7 100644 --- a/README.md +++ b/README.md @@ -71,16 +71,17 @@ Here is an example of using this module: ## Providers -| Name | Version | -| ------------------------------------------------------------------ | --------- | -| [tailscale](#provider_tailscale) | >= 0.13.7 | +| Name | Version | +| ------------------------------------------------------------------ | ------- | +| [tailscale](#provider_tailscale) | 0.17.2 | ## Modules -| Name | Source | Version | -| -------------------------------------------------------------------------------------------------------- | --------------------------- | ------- | -| [tailscale_subnet_router](#module_tailscale_subnet_router) | masterpointio/ssm-agent/aws | 1.2.0 | -| [this](#module_this) | cloudposse/label/null | 0.25.0 | +| Name | Source | Version | +| -------------------------------------------------------------------------------------------------------- | ---------------------------------- | ------- | +| [ssm_state](#module_ssm_state) | cloudposse/ssm-parameter-store/aws | 0.13.0 | +| [tailscale_subnet_router](#module_tailscale_subnet_router) | masterpointio/ssm-agent/aws | 1.2.0 | +| [this](#module_this) | cloudposse/label/null | 0.25.0 | ## Resources @@ -126,6 +127,7 @@ Here is an example of using this module: | [session_logging_kms_key_alias](#input_session_logging_kms_key_alias) | Alias name for `session_logging` KMS Key.
This is only applied if 2 conditions are met: (1) `session_logging_kms_key_arn` is unset,
(2) `session_logging_encryption_enabled` = true. | `string` | `"alias/session_logging"` | no | | [session_logging_ssm_document_name](#input_session_logging_ssm_document_name) | Name for `session_logging` SSM document.
This is only applied if 2 conditions are met: (1) `session_logging_enabled` = true,
(2) `create_run_shell_document` = true. | `string` | `"SSM-SessionManagerRunShell-Tailscale"` | no | | [ssh_enabled](#input_ssh_enabled) | Enable SSH access to the Tailscale Subnet Router EC2 instance. Defaults to true. | `bool` | `true` | no | +| [ssm_state_enabled](#input_ssm_state_enabled) | Control is tailscaled state (including preferences and keys) is stored in AWS SSM.
See more in the [docs](https://tailscale.com/kb/1278/tailscaled#flags-to-tailscaled). | `bool` | `false` | no | | [stage](#input_stage) | ID element. Usually used to indicate role, e.g. 'prod', 'staging', 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | | [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 | | [tags](#input_tags) | Additional tags (e.g. `{'BusinessUnit': 'XYZ'}`).
Neither the tag keys nor the tag values will be modified by this module. | `map(string)` | `{}` | no | diff --git a/examples/complete/fixtures.us-east-2.tfvars b/examples/complete/fixtures.us-east-2.tfvars index f760a30..21ea325 100644 --- a/examples/complete/fixtures.us-east-2.tfvars +++ b/examples/complete/fixtures.us-east-2.tfvars @@ -8,6 +8,8 @@ region = "us-east-1" availability_zones = ["us-east-1a", "us-east-1b"] ipv4_primary_cidr_block = "172.16.0.0/16" +ssm_state_enabled = true + # Replace these values with your own tailnet = "orgname.org.github" oauth_client_id = "OAUTH_CLIENT_ID" diff --git a/main.tf b/main.tf index 10af105..2dc554c 100644 --- a/main.tf +++ b/main.tf @@ -4,9 +4,14 @@ locals { prefixed_primary_tag = "tag:${local.primary_tag}" prefixed_additional_tags = [for tag in var.additional_tags : "tag:${tag}"] + ssm_state_param_name = var.ssm_state_enabled ? "/tailscale/${module.this.id}/state" : null + ssm_state_flag = var.ssm_state_enabled ? "--state=${module.ssm_state[0].arn_map[local.ssm_state_param_name]}" : "" + tailscale_tags = concat([local.prefixed_primary_tag], local.prefixed_additional_tags) - tailscaled_extra_flags_enabled = length(var.tailscaled_extra_flags) > 0 + tailscaled_extra_flags = join(" ", compact(concat(var.tailscaled_extra_flags, [local.ssm_state_flag]))) + tailscaled_extra_flags_enabled = length(local.tailscaled_extra_flags) > 0 + tailscale_up_extra_flags_enabled = length(var.tailscale_up_extra_flags) > 0 userdata = templatefile("${path.module}/userdata.sh.tmpl", { @@ -18,7 +23,7 @@ locals { tags = join(",", local.tailscale_tags) tailscaled_extra_flags_enabled = local.tailscaled_extra_flags_enabled - tailscaled_extra_flags = join(" ", var.tailscaled_extra_flags) + tailscaled_extra_flags = local.tailscaled_extra_flags tailscale_up_extra_flags_enabled = local.tailscale_up_extra_flags_enabled tailscale_up_extra_flags = join(" ", var.tailscale_up_extra_flags) }) @@ -29,7 +34,7 @@ locals { # trivy:ignore:AVD-AWS-0090 module "tailscale_subnet_router" { source = "masterpointio/ssm-agent/aws" - version = "1.2.0" + version = "1.2.0" #TODO: Update version when this is merged https://github.com/masterpointio/terraform-aws-ssm-agent/pull/29 context = module.this.context tags = module.this.tags @@ -63,3 +68,22 @@ resource "tailscale_tailnet_key" "default" { # A device is automatically tagged when it is authenticated with this key. tags = local.tailscale_tags } + +module "ssm_state" { + count = var.ssm_state_enabled ? 1 : 0 + source = "cloudposse/ssm-parameter-store/aws" + version = "0.13.0" + ignore_value_changes = true + + parameter_write = [ + { + name = local.ssm_state_param_name + type = "SecureString" + overwrite = "true" + value = "{}" + description = "Tailscaled state of ${module.this.id} subnet router." + } + ] + context = module.this.context + tags = module.this.tags +} diff --git a/userdata.sh.tmpl b/userdata.sh.tmpl index 4a75a7f..e78c721 100644 --- a/userdata.sh.tmpl +++ b/userdata.sh.tmpl @@ -14,8 +14,8 @@ sudo yum-config-manager --add-repo https://pkgs.tailscale.com/stable/amazon-linu sudo yum install -y tailscale %{ if tailscaled_extra_flags_enabled == true } -echo "Exporting FLAGS to environment variable..." -export FLAGS=${tailscaled_extra_flags}% +echo "Exporting FLAGS to /etc/default/tailscaled..." +sudo sed -i "s|^FLAGS=.*|FLAGS=\"${tailscaled_extra_flags}\"|" /etc/default/tailscaled %{ endif } # Setup tailscale diff --git a/variables.tf b/variables.tf index 77532c0..fb6521e 100644 --- a/variables.tf +++ b/variables.tf @@ -180,3 +180,12 @@ variable "tailscale_up_extra_flags" { See more in the [docs](https://tailscale.com/kb/1241/tailscale-up). EOT } + +variable "ssm_state_enabled" { + default = false + type = bool + description = <<-EOT + Control is tailscaled state (including preferences and keys) is stored in AWS SSM. + See more in the [docs](https://tailscale.com/kb/1278/tailscaled#flags-to-tailscaled). + EOT +} From 66702c5cd20e5eba584ccaf6333c37c7765f1f81 Mon Sep 17 00:00:00 2001 From: Veronika Gnilitska Date: Fri, 15 Nov 2024 10:47:38 -0500 Subject: [PATCH 06/12] feat: adds CRabbit config --- .coderabbit.yaml | 90 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 .coderabbit.yaml diff --git a/.coderabbit.yaml b/.coderabbit.yaml new file mode 100644 index 0000000..e279a6f --- /dev/null +++ b/.coderabbit.yaml @@ -0,0 +1,90 @@ +# Docs: https://docs.coderabbit.ai/configure-coderabbit +# Schema: https://coderabbit.ai/integrations/schema.v2.json +# Support: https://discord.gg/GsXnASn26c + +language: en + +tone_instructions: | + Provide feedback in a professional, friendly, constructive, and concise tone. + Offer clear, specific suggestions and best practices to help enhance the code quality and promote learning. + +early_access: true + +knowledge_base: + # The scope of learnings to use for the knowledge base. + # `local` uses the repository's learnings, + # `global` uses the organization's learnings, + # `auto` uses repository's learnings for public repositories and organization's learnings for private repositories. + # Default value: `auto` + learnings: + scope: global + issues: + scope: global + pull_requests: + scope: global + +reviews: + profile: chill + auto_review: + # Ignore reviewing if the title of the pull request contains any of these keywords (case-insensitive) + ignore_title_keywords: + - wip + - draft + - test + # Set the commit status to 'pending' when the review is in progress and 'success' when it is complete. + commit_status: false + # Post review details on each review. Additionally, post a review status when a review is skipped in certain cases. + review_status: false + path_instructions: + - path: "**/*.tf" + instructions: | + You're a Terraform expert who has thoroughly studied all the documentation from Hashicorp https://developer.hashicorp.com/terraform/docs and OpenTofu https://opentofu.org/docs/. + You have a strong grasp of Terraform syntax and prioritize providing accurate and insightful code suggestions. + As a fan of the Cloud Posse / SweetOps ecosystem, you incorporate many of their best practices https://docs.cloudposse.com/best-practices/terraform/ while balancing them with general Terraform guidelines. + tools: + # By default, all tools are enabled. + # Masterpoint uses Trunk (https://trunk.io) so we do not need a lot of this feedback due to overlap. + shellcheck: + enabled: false + ruff: + enabled: false + markdownlint: + enabled: false + github-checks: + enabled: false + languagetool: + enabled: false + biome: + enabled: false + hadolint: + enabled: false + swiftlint: + enabled: false + phpstan: + enabled: false + golangci-lint: + enabled: false + yamllint: + enabled: false + gitleaks: + enabled: false + checkov: + enabled: false + detekt: + enabled: false + eslint: + enabled: false + rubocop: + enabled: false + buf: + enabled: false + regal: + enabled: false + actionlint: + enabled: false + pmd: + enabled: false + cppcheck: + enabled: false + circleci: + enabled: false From 574177c59e1baff748b1a7de18c9eb2c254bf865 Mon Sep 17 00:00:00 2001 From: Veronika Gnilitska Date: Fri, 15 Nov 2024 12:16:02 -0500 Subject: [PATCH 07/12] chore: remove the comment --- main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.tf b/main.tf index 2dc554c..e83b19d 100644 --- a/main.tf +++ b/main.tf @@ -34,7 +34,7 @@ locals { # trivy:ignore:AVD-AWS-0090 module "tailscale_subnet_router" { source = "masterpointio/ssm-agent/aws" - version = "1.2.0" #TODO: Update version when this is merged https://github.com/masterpointio/terraform-aws-ssm-agent/pull/29 + version = "1.2.0" context = module.this.context tags = module.this.tags From 09b372c6d7e6b3b125e40b9104063021f106cd5f Mon Sep 17 00:00:00 2001 From: Veronika Gnilitska Date: Sun, 17 Nov 2024 08:56:07 -0500 Subject: [PATCH 08/12] feat: support configuring ASG size and capacity --- README.md | 3 +++ main.tf | 7 +++++-- variables.tf | 19 ++++++++++++++++++- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index cc76d9b..b7857c2 100644 --- a/README.md +++ b/README.md @@ -104,6 +104,7 @@ Here is an example of using this module: | [create_run_shell_document](#input_create_run_shell_document) | Whether or not to create the SSM-SessionManagerRunShell SSM Document. | `bool` | `true` | no | | [delimiter](#input_delimiter) | Delimiter to be used between ID elements.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no | | [descriptor_formats](#input_descriptor_formats) | Describe additional descriptors to be output in the `descriptors` output map.
Map of maps. Keys are names of descriptors. Values are maps of the form
`{
format = string
labels = list(string)
}`
(Type is `any` so the map values can later be enhanced to provide additional options.)
`format` is a Terraform format string to be passed to the `format()` function.
`labels` is a list of labels, in order, to pass to `format()` function.
Label values will be normalized before being passed to `format()` so they will be
identical to how they appear in `id`.
Default is `{}` (`descriptors` output will be empty). | `any` | `{}` | no | +| [desired_capacity](#input_desired_capacity) | Desired number of instances in the Auto Scaling Group | `number` | `1` | no | | [enabled](#input_enabled) | Set to false to prevent the module from creating any resources | `bool` | `null` | no | | [environment](#input_environment) | ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | | [ephemeral](#input_ephemeral) | Indicates if the key is ephemeral. | `bool` | `false` | no | @@ -116,6 +117,8 @@ Here is an example of using this module: | [label_order](#input_label_order) | The order in which the labels (ID elements) appear in the `id`.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present. | `list(string)` | `null` | no | | [label_value_case](#input_label_value_case) | Controls the letter case of ID elements (labels) as included in `id`,
set as tag values, and output by this module individually.
Does not affect values of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Set this to `title` and set `delimiter` to `""` to yield Pascal Case IDs.
Default value: `lower`. | `string` | `null` | no | | [labels_as_tags](#input_labels_as_tags) | Set of labels (ID elements) to include as tags in the `tags` output.
Default is to include all labels.
Tags with empty values will not be included in the `tags` output.
Set to `[]` to suppress all generated tags.
**Notes:**
The value of the `name` tag, if included, will be the `id`, not the `name`.
Unlike other `null-label` inputs, the initial setting of `labels_as_tags` cannot be
changed in later chained modules. Attempts to change it will be silently ignored. | `set(string)` |
[
"default"
]
| no | +| [max_size](#input_max_size) | Maximum number of instances in the Auto Scaling Group. Must be >= desired_capacity. | `number` | `2` | no | +| [min_size](#input_min_size) | Minimum number of instances in the Auto Scaling Group | `number` | `1` | no | | [monitoring_enabled](#input_monitoring_enabled) | Enable detailed monitoring of instances | `bool` | `true` | no | | [name](#input_name) | ID element. Usually the component or solution name, e.g. 'app' or 'jenkins'.
This is the only ID element not also included as a `tag`.
The "name" tag is set to the full `id` string. There is no tag with the value of the `name` input. | `string` | `null` | no | | [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 | diff --git a/main.tf b/main.tf index e83b19d..d380934 100644 --- a/main.tf +++ b/main.tf @@ -50,8 +50,11 @@ module "tailscale_subnet_router" { session_logging_enabled = var.session_logging_enabled session_logging_ssm_document_name = var.session_logging_ssm_document_name - ami = var.ami - instance_type = var.instance_type + ami = var.ami + instance_type = var.instance_type + max_size = var.max_size + min_size = var.min_size + desired_capacity = var.desired_capacity monitoring_enabled = var.monitoring_enabled associate_public_ip_address = var.associate_public_ip_address diff --git a/variables.tf b/variables.tf index fb6521e..77f3f3f 100644 --- a/variables.tf +++ b/variables.tf @@ -43,7 +43,6 @@ variable "session_logging_kms_key_alias" { EOF } - variable "session_logging_ssm_document_name" { default = "SSM-SessionManagerRunShell-Tailscale" type = string @@ -98,6 +97,24 @@ variable "associate_public_ip_address" { default = null } +variable "max_size" { + description = "Maximum number of instances in the Auto Scaling Group. Must be >= desired_capacity." + type = number + default = 2 +} + +variable "min_size" { + description = "Minimum number of instances in the Auto Scaling Group" + type = number + default = 1 +} + +variable "desired_capacity" { + description = "Desired number of instances in the Auto Scaling Group" + type = number + default = 1 +} + ################ ## Tailscale ## ############## From a497d789e85b4abfe844475b555b70a57de264e8 Mon Sep 17 00:00:00 2001 From: Veronika Gnilitska Date: Wed, 20 Nov 2024 11:20:08 -0500 Subject: [PATCH 09/12] feat: add SSM write permissions --- README.md | 15 +++++++++------ main.tf | 31 +++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b7857c2..1cdbc0d 100644 --- a/README.md +++ b/README.md @@ -71,23 +71,26 @@ Here is an example of using this module: ## Providers -| Name | Version | -| ------------------------------------------------------------------ | --------- | -| [tailscale](#provider_tailscale) | >= 0.13.7 | +| Name | Version | +| ------------------------------------------------------------------ | ------- | +| [aws](#provider_aws) | 5.76.0 | +| [tailscale](#provider_tailscale) | 0.17.2 | ## Modules | Name | Source | Version | | -------------------------------------------------------------------------------------------------------- | ---------------------------------- | ------- | +| [ssm_policy](#module_ssm_policy) | cloudposse/iam-policy/aws | 2.0.1 | | [ssm_state](#module_ssm_state) | cloudposse/ssm-parameter-store/aws | 0.13.0 | | [tailscale_subnet_router](#module_tailscale_subnet_router) | masterpointio/ssm-agent/aws | 1.2.0 | | [this](#module_this) | cloudposse/label/null | 0.25.0 | ## Resources -| Name | Type | -| ------------------------------------------------------------------------------------------------------------------------------ | -------- | -| [tailscale_tailnet_key.default](https://registry.terraform.io/providers/tailscale/tailscale/latest/docs/resources/tailnet_key) | resource | +| Name | Type | +| ------------------------------------------------------------------------------------------------------------------------------------------------ | -------- | +| [aws_iam_role_policy_attachment.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [tailscale_tailnet_key.default](https://registry.terraform.io/providers/tailscale/tailscale/latest/docs/resources/tailnet_key) | resource | ## Inputs diff --git a/main.tf b/main.tf index d380934..c6e0235 100644 --- a/main.tf +++ b/main.tf @@ -90,3 +90,34 @@ module "ssm_state" { context = module.this.context tags = module.this.tags } + +module "ssm_policy" { + count = var.ssm_state_enabled ? 1 : 0 + source = "cloudposse/iam-policy/aws" + version = "2.0.1" + + name = "ssm" + description = "Additional SSM access for SSM Agent" + + iam_policy_enabled = true + iam_policy = [{ + statements = [ + { + sid = "SSMAgentPutParameter" + effect = "Allow" + actions = ["ssm:PutParameter"] + resources = [ + module.ssm_state[0].arn_map[local.ssm_state_param_name], + ] + }, + ] + }] + context = module.this.context + tags = module.this.tags +} + +resource "aws_iam_role_policy_attachment" "default" { + count = var.ssm_state_enabled ? 1 : 0 + role = module.tailscale_subnet_router.role_id + policy_arn = module.ssm_policy[0].policy_arn +} From a23768c456c9958f36d77b8750ac306aff6b4899 Mon Sep 17 00:00:00 2001 From: Veronika Gnilitska Date: Thu, 21 Nov 2024 11:20:44 -0500 Subject: [PATCH 10/12] fix: remove sudo + switch to dnf + wait for rpm lock --- userdata.sh.tmpl | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/userdata.sh.tmpl b/userdata.sh.tmpl index e78c721..dd44c54 100644 --- a/userdata.sh.tmpl +++ b/userdata.sh.tmpl @@ -4,23 +4,28 @@ exec > >(tee /var/log/user-data.log | logger -t user-data -s 2>/dev/console) 2>& echo "Starting user-data script..." echo "Enabling IP forwarding..." -echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.conf -echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.conf -sudo sysctl -p /etc/sysctl.conf +echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf +echo 'net.ipv6.conf.all.forwarding = 1' >> /etc/sysctl.conf +sysctl -p /etc/sysctl.conf + +echo "Waiting for the RPM lock to be released..." +while fuser /var/lib/rpm/.rpm.lock >/dev/null 2>&1 ; do + sleep 1 +done echo "Installing Tailscale..." -sudo yum install -y yum-utils -sudo yum-config-manager --add-repo https://pkgs.tailscale.com/stable/amazon-linux/2/tailscale.repo -sudo yum install -y tailscale +dnf install -y dnf-utils +dnf config-manager --add-repo https://pkgs.tailscale.com/stable/amazon-linux/2/tailscale.repo +dnf install -y tailscale %{ if tailscaled_extra_flags_enabled == true } echo "Exporting FLAGS to /etc/default/tailscaled..." -sudo sed -i "s|^FLAGS=.*|FLAGS=\"${tailscaled_extra_flags}\"|" /etc/default/tailscaled +sed -i "s|^FLAGS=.*|FLAGS=\"${tailscaled_extra_flags}\"|" /etc/default/tailscaled %{ endif } -# Setup tailscale +# Setup Tailscale echo "Enabling and starting tailscaled service..." -sudo systemctl enable --now tailscaled +systemctl enable --now tailscaled echo "Waiting for tailscaled to initialize..." sleep 5 @@ -28,7 +33,7 @@ sleep 5 # Start tailscale # We pass --advertise-tags below even though the authkey being created with those tags should result # in the same effect. This is to be more explicit because tailscale tags are a complicated topic. -sudo tailscale up \ +tailscale up \ %{ if ssh_enabled == true }--ssh%{ endif } \ %{ if exit_node_enabled == true }--advertise-exit-node%{ endif } \ %{ if tailscale_up_extra_flags_enabled == true }${tailscale_up_extra_flags}%{ endif } \ From 5a5b8d26752ebc0018ae8d03f0ccc98bd392f9e3 Mon Sep 17 00:00:00 2001 From: Veronika Gnilitska Date: Thu, 21 Nov 2024 12:54:02 -0500 Subject: [PATCH 11/12] chore: adds timeout --- userdata.sh.tmpl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/userdata.sh.tmpl b/userdata.sh.tmpl index dd44c54..74467cf 100644 --- a/userdata.sh.tmpl +++ b/userdata.sh.tmpl @@ -9,7 +9,14 @@ echo 'net.ipv6.conf.all.forwarding = 1' >> /etc/sysctl.conf sysctl -p /etc/sysctl.conf echo "Waiting for the RPM lock to be released..." +TIMEOUT=30 +start_time=$(date +%s) while fuser /var/lib/rpm/.rpm.lock >/dev/null 2>&1 ; do + current_time=$(date +%s) + if (( current_time - start_time > TIMEOUT )); then + echo "Timeout waiting for RPM lock to be released" + exit 1 + fi sleep 1 done From fb8e943ced8f8c9b842b1b5a8e1bfc4c9abb0c58 Mon Sep 17 00:00:00 2001 From: Veronika Gnilitska Date: Fri, 22 Nov 2024 10:13:21 -0500 Subject: [PATCH 12/12] chore: replaces retries instead of checking RPM lock --- userdata.sh.tmpl | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/userdata.sh.tmpl b/userdata.sh.tmpl index 74467cf..727bce9 100644 --- a/userdata.sh.tmpl +++ b/userdata.sh.tmpl @@ -8,22 +8,38 @@ echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf echo 'net.ipv6.conf.all.forwarding = 1' >> /etc/sysctl.conf sysctl -p /etc/sysctl.conf -echo "Waiting for the RPM lock to be released..." -TIMEOUT=30 -start_time=$(date +%s) -while fuser /var/lib/rpm/.rpm.lock >/dev/null 2>&1 ; do - current_time=$(date +%s) - if (( current_time - start_time > TIMEOUT )); then - echo "Timeout waiting for RPM lock to be released" - exit 1 +# Function to retry a command up to a maximum number of attempts +retry_command() { + local cmd="$1" + local max_attempts="$2" + local attempt=1 + local exit_code=0 + + while [ $attempt -le $max_attempts ]; do + echo "Attempt $attempt of $max_attempts: $cmd" + eval "$cmd" + exit_code=$? + if [ $exit_code -eq 0 ]; then + echo "Command succeeded: $cmd" + return 0 + else + echo "Command failed with exit code $exit_code: $cmd" + attempt=$((attempt + 1)) + if [ $attempt -le $max_attempts ]; then + echo "Retrying in 2 seconds..." + sleep 2 + fi fi - sleep 1 -done + done + + echo "Command failed after $max_attempts attempts: $cmd" + return $exit_code +} echo "Installing Tailscale..." -dnf install -y dnf-utils -dnf config-manager --add-repo https://pkgs.tailscale.com/stable/amazon-linux/2/tailscale.repo -dnf install -y tailscale +retry_command "dnf install -y dnf-utils" 5 +retry_command "dnf config-manager --add-repo https://pkgs.tailscale.com/stable/amazon-linux/2/tailscale.repo" 5 +retry_command "dnf install -y tailscale" 5 %{ if tailscaled_extra_flags_enabled == true } echo "Exporting FLAGS to /etc/default/tailscaled..."