From 74e2c98f07f92f1f135331903cc6ab4d0e264794 Mon Sep 17 00:00:00 2001 From: Igor Rodionov Date: Thu, 21 Aug 2025 23:01:56 +0200 Subject: [PATCH 1/2] chore: Update README.yaml with AI --- .gitignore | 4 +- AGENTS.md | 35 ++++++ Makefile | 8 -- README.md | 299 +++++++++++++++++++++++++++----------------------- README.yaml | 284 +++++++++++++++-------------------------------- atmos.yaml | 11 ++ src/README.md | 186 +++++++++++++++---------------- 7 files changed, 393 insertions(+), 434 deletions(-) create mode 100644 AGENTS.md delete mode 100644 Makefile create mode 100644 atmos.yaml diff --git a/.gitignore b/.gitignore index 2fdee06..edeabaf 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,9 @@ aws-assumed-role/ *.iml .direnv .envrc -.atmos/ +.cache +.atmos + # Compiled and auto-generated files # Note that the leading "**/" appears necessary for Docker even if not for Git diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..8deadc1 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,35 @@ +# Repository Guidelines + +## Project Structure & Module Organization +- `src/`: Terraform component (`main.tf`, `variables.tf`, `outputs.tf`, `providers.tf`, `versions.tf`, `context.tf`). This is the source of truth. +- `test/`: Go Terratest suite using Atmos fixtures (`component_test.go`, `fixtures/`, `test_suite.yaml`). Tests deploy/destroy real AWS resources. +- `README.yaml`: Source for the generated `README.md` (via atmos + terraform-docs). +- `.github/`: CI/CD, Renovate/Dependabot, labels, and automerge settings. +- `docs/`: Project docs (if any). Keep lightweight and current. + +## Build, Test, and Development Commands +- To install atmos read this docs https://github.com/cloudposse/atmos +- `atmos docs generate readme`: Regenerate `README.md` from `README.yaml` and terraform source. +- `atmos docs generate readme-simple`: Regenerate `src/README.md` from `README.yaml` and terraform source. +- `atmos test run`: Run Terratest suite in `test/` (uses Atmos fixtures; creates and destroys AWS resources). +- Pre-commit locally: `pre-commit install && pre-commit run -a` (runs `terraform_fmt`, `terraform_docs`, `tflint`). +- TFLint plugin setup: `tflint --init` (uses `.tflint.hcl`). + +## Coding Style & Naming Conventions +- Indentation: Terraform 2 spaces; YAML/Markdown 2 spaces. +- Terraform: prefer lower_snake_case for variables/locals; keep resources/data sources descriptive and aligned with Cloud Posse null-label patterns. +- Lint/format: `terraform fmt -recursive`, TFLint rules per `.tflint.hcl`. Do not commit formatting or lint violations. + +## Testing Guidelines +- Framework: Go Terratest with `github.com/cloudposse/test-helpers` and `atmos` fixtures. +- Location/naming: put tests in `test/` and name files `*_test.go`. Add scenarios under `test/fixtures/stacks/catalog/usecase/`. +- Run: `atmos test run`. Ensure AWS credentials are configured; tests may incur AWS costs and will clean up after themselves. + +## Commit & Pull Request Guidelines +- Commits: follow Conventional Commits (e.g., `feat:`, `fix:`, `chore(deps):`, `docs:`). Keep messages concise and scoped. +- PRs: include a clear description, linked issues, and any behavioral changes. Update `README.yaml` when inputs/outputs change and run `atmos docs generate readme`. +- CI: ensure pre-commit, TFLint, and tests pass. Avoid unrelated changes in the same PR. + +## Security & Configuration Tips +- Never commit secrets. Configure AWS credentials/role assumption externally; the provider setup in `src/providers.tf` supports role assumption via the `iam_roles` module. +- Global quotas must be applied in `us-east-1`; place in the `gbl` stack and set `region: us-east-1` in `vars`. diff --git a/Makefile b/Makefile deleted file mode 100644 index 8a6d902..0000000 --- a/Makefile +++ /dev/null @@ -1,8 +0,0 @@ --include $(shell curl -sSL -o .build-harness "https://cloudposse.tools/build-harness"; echo .build-harness) - -all: init readme - -test:: - @echo "🚀 Starting tests..." - ./test/run.sh - @echo "✅ All tests passed." diff --git a/README.md b/README.md index 8b8dff2..6a4d95a 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,11 @@ Project Banner
-

-Latest ReleaseSlack Community

+ + +

Latest ReleaseSlack CommunityGet Support + +

-This component is responsible for provisioning an RunsOn (https://runs-on.com/). +Component: `runs-on` -After deploying this component, you will need to install the RunsOn app to GitHub. See the -[RunsOn documentation](https://runs-on.com/guides/install/#3-github-app-registration) for more information. +This component provisions RunsOn for GitHub Actions self-hosted runners. After deploying this +component, install the RunsOn GitHub App in your organization to enable runner registration. +See the RunsOn documentation for GitHub App installation and configuration details. -## Compatibility +Compatibility: Requires RunsOn CloudFormation template version 2.8.2 or newer due to output changes. -Due to output changes, this component only works with version 2.8.2+ of the RunsOn CloudFormation template. -## Usage -**Stack Level**: Regional +> [!TIP] +> #### 👽 Use Atmos with Terraform +> Cloud Posse uses [`atmos`](https://atmos.tools) to easily orchestrate multiple environments using Terraform.
+> Works with [Github Actions](https://atmos.tools/integrations/github-actions/), [Atlantis](https://atmos.tools/integrations/atlantis), or [Spacelift](https://atmos.tools/integrations/spacelift). +> +>
+> Watch demo of using Atmos with Terraform +>
+> Example of running atmos to manage infrastructure from our Quick Start tutorial. +>
+ -### Defaults -Regardless of the networking style, you should have these defaults in common: -(`runs-on/defaults.yaml`) + +## Usage + +Stack Level: Regional + +Defaults (runs-on/defaults.yaml) ```yaml components: @@ -61,17 +76,17 @@ components: timeout_in_minutes: 30 # template_url: https://runs-on.s3.eu-west-1.amazonaws.com/cloudformation/template.yaml # See latest version and changelog at https://runs-on.com/changelog/ - template_url: https://runs-on.s3.eu-west-1.amazonaws.com/cloudformation/template-v2.8.3.yaml + template_url: https://runs-on.s3.eu-west-1.amazonaws.com/cloudformation/template-v2.8.3.yaml parameters: AppCPU: 256 AppMemory: 512 EmailAddress: developer@cloudposse.com # Environments let you run multiple Stacks in one organization and segregate resources. - # If you specify an environment, then all the jobs must also specify the which environment they are running in. + # If you specify an environment, then all the jobs must also specify which environment they are running in. # To keep things simple, we use the default environment ("production") and leave the `env` label unset in the workflow. EncryptEbs: true # With the default value of SSHAllowed: true, the runners that are placed in a public subnet - # will allow ingress on port 22. This is highly abused (scanners running constantly looking for vulernable SSH servers) + # will allow ingress on port 22. This is highly abused (scanners running constantly looking for vulnerable SSH servers) # and should not be allowed. If you need access to the runners, use Session Manager (SSM). SSHAllowed: false LicenseKey: @@ -81,14 +96,12 @@ components: VpcFlowLogRetentionInDays: 14 ``` +Embedded networking (RunsOn managed VPC) -### Embedded networking (Runs On managed VPC) - -When no VPC details are set, the component will create a new VPC and subnets for you. This is done via the CloudFormation template. - -Note, you should set the `VpcCidrBlock` parameter to the CIDR block of the VPC that will be created. +When no VPC details are set, the component will create a new VPC and subnets via the CloudFormation template. +Set the `VpcCidrBlock` parameter to the CIDR block of the VPC that will be created. -(`runs-on.yaml`) +(runs-on.yaml) ```yaml import: @@ -109,11 +122,11 @@ components: VpcCidrBlock: 10.100.0.0/16 ``` -### External networking (Use existing VPC) +External networking (Use existing VPC) -When you want to use an existing VPC, you can set the `vpc_id`, `subnet_ids`, and `security_group_id` variables. +Use an existing VPC by setting `vpc_id`, `subnet_ids`, and `security_group_id`. -(`_defaults.yaml`) +(_defaults.yaml) ```yaml terraform: @@ -122,7 +135,7 @@ terraform: name: auto/ssm ``` -(`runs-on.yaml`) +(runs-on.yaml) ```yaml import: @@ -140,8 +153,8 @@ components: component: runs-on vars: networking_stack: external - # There are other ways to get the vpc_id, subnet_ids, and security_group_id. You can - # Harcode + # There are other ways to get the vpc_id, subnet_ids, and security_group_id. + # Hardcode # Use Atmos KV Store # Use atmos !terraform.output yaml function vpc_id: !store auto/ssm vpc vpc_id @@ -149,21 +162,13 @@ components: security_group_id: !store auto/ssm vpc default_security_group_id ``` -
-(DEPRECATED) Configuring with Transit Gateway - -It's important to note that the embedded networking will require some customization to work with Transit Gateway. +(DEPRECATED) Configuring with Transit Gateway -The following configuration assumes you are using the Cloud Posse Components for Transit Gateway -([tgw/hub](https://docs.cloudposse.com/components/library/aws/tgw/hub/) & -[tgw/spoke](https://docs.cloudposse.com/components/library/aws/tgw/spoke/)). +The embedded networking requires customization to work with Transit Gateway. +Using Cloud Posse components for TGW ([tgw/hub] and [tgw/spoke]), the outputs of this component include +the same outputs as the `vpc` component (RunsOn creates a VPC and subnets). -The outputs of this component contain the same outputs as the `vpc` component. This is because the runs-on -cloudformation stack creates a VPC and subnets. - -First we need to update the TGW/Hub - this stores information about the VPCs that are allowed to be used by TGW Spokes. - -Assuming your TGW/Hub lives in the `core-network` account and your Runs-On is deployed to `core-auto` (`tgw-hub.yaml`) +Update the TGW Hub to store allowed VPCs (example tgw-hub.yaml): ```yaml vars: @@ -178,51 +183,49 @@ vars: ```yaml components: -terraform: - tgw/hub/defaults: - metadata: - type: abstract - component: tgw/hub - vars: - enabled: true - name: tgw-hub - tags: - Team: sre - Service: tgw-hub + terraform: + tgw/hub/defaults: + metadata: + type: abstract + component: tgw/hub + vars: + enabled: true + name: tgw-hub + tags: + Team: sre + Service: tgw-hub - tgw/hub: - metadata: - inherits: - - tgw/hub/defaults - component: tgw/hub - vars: - connections: - - account: - tenant: core - stage: network - - account: - tenant: core - stage: auto - vpc_component_names: - - vpc - - runs-on - - account: - tenant: plat - stage: sandbox - - account: - tenant: plat - stage: dev - - account: - tenant: plat - stage: staging - - account: - tenant: plat - stage: prod + tgw/hub: + metadata: + inherits: + - tgw/hub/defaults + component: tgw/hub + vars: + connections: + - account: + tenant: core + stage: network + - account: + tenant: core + stage: auto + vpc_component_names: + - vpc + - runs-on + - account: + tenant: plat + stage: sandbox + - account: + tenant: plat + stage: dev + - account: + tenant: plat + stage: staging + - account: + tenant: plat + stage: prod ``` -We then need to create a spoke that refers to the VPC created by Runs-On. - -(`tgw-spoke.yaml`) +Create a TGW spoke that refers to the RunsOn VPC (example tgw-spoke.yaml): ```yaml tgw/spoke/runs-on: @@ -258,11 +261,7 @@ tgw/spoke/runs-on: stage: prod ``` -Finally we need to update the spokes of the TGW/Spokes to allow Runs-On traffic to the other accounts. - -Typically this includes `core-auto`, `core-network`, and your platform accounts. - -(`tgw-spoke.yaml`) +Update other TGW spokes to allow RunsOn traffic (example tgw-spoke.yaml): ```yaml tgw/spoke: @@ -271,30 +270,40 @@ Typically this includes `core-auto`, `core-network`, and your platform accounts. - tgw/spoke-defaults vars: connections: - ... + # ... vpc_component_names: - vpc - runs-on - ... + # ... ``` -
-# Terraform Docs - - +> [!IMPORTANT] +> In Cloud Posse's examples, we avoid pinning modules to specific versions to prevent discrepancies between the documentation +> and the latest released versions. However, for your own projects, we strongly advise pinning each module to the exact version +> you're using. This practice ensures the stability of your infrastructure. Additionally, we recommend implementing a systematic +> approach for updating versions to avoid unexpected changes. + + + + + + + + + ## Requirements | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.0.0 | -| [aws](#requirement\_aws) | >= 4.9.0 | +| [aws](#requirement\_aws) | >= 4.9.0, < 6.0.0 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 4.9.0 | +| [aws](#provider\_aws) | >= 4.9.0, < 6.0.0 | ## Modules @@ -302,7 +311,7 @@ Typically this includes `core-auto`, `core-network`, and your platform accounts. |------|--------|---------| | [cloudformation\_stack](#module\_cloudformation\_stack) | cloudposse/cloudformation-stack/aws | 0.7.1 | | [iam\_policy](#module\_iam\_policy) | cloudposse/iam-policy/aws | 2.0.2 | -| [iam\_roles](#module\_iam\_roles) | cloudposse/iam-roles/aws | 0.10.0 | +| [iam\_roles](#module\_iam\_roles) | ../account-map/modules/iam-roles | n/a | | [security\_group](#module\_security\_group) | cloudposse/security-group/aws | 2.2.0 | | [this](#module\_this) | cloudposse/label/null | 0.25.0 | @@ -320,32 +329,32 @@ Typically this includes `core-auto`, `core-network`, and your platform accounts. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| [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 | -| [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 | +| [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 | +| [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 | | [capabilities](#input\_capabilities) | A list of capabilities. Valid values: CAPABILITY\_IAM, CAPABILITY\_NAMED\_IAM, CAPABILITY\_AUTO\_EXPAND | `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 | -| [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 | +| [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 | +| [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 | -| [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 | -| [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 | -| [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 | +| [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 | +| [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 | +| [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 | | [networking\_stack](#input\_networking\_stack) | Let RunsOn manage your networking stack (`embedded`), or use a vpc under your control (`external`). Null will default to whatever the template used as default. If you select `external`, you will need to provide the VPC ID, the subnet IDs, and optionally the security group ID, and make sure your whole networking setup is compatible with RunsOn (see https://runs-on.com/networking/embedded-vs-external/ for more details). To get started quickly, we recommend using the 'embedded' option. | `string` | `"embedded"` | no | | [on\_failure](#input\_on\_failure) | Action to be taken if stack creation fails. This must be one of: `DO_NOTHING`, `ROLLBACK`, or `DELETE` | `string` | `"ROLLBACK"` | no | | [parameters](#input\_parameters) | Key-value map of input parameters for the Stack Set template. (\_e.g.\_ map("BusinessUnit","ABC") | `map(string)` | `{}` | no | | [policy\_body](#input\_policy\_body) | Structure containing the stack policy body | `string` | `""` | 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 | +| [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 | | [region](#input\_region) | AWS Region | `string` | n/a | yes | | [security\_group\_id](#input\_security\_group\_id) | Security group ID. If not set, a new security group will be created. | `string` | `null` | no | -| [security\_group\_rules](#input\_security\_group\_rules) | Security group rules. These are either added to the security passed in, or added to the security group created when var.security\_group\_id is not set. Types include `ingress` and `egress`. |
list(object({
type = string
from_port = number
to_port = number
protocol = string
cidr_blocks = list(string)
}))
| `null` | no | +| [security\_group\_rules](#input\_security\_group\_rules) | Security group rules. These are either added to the security passed in, or added to the security group created when var.security\_group\_id is not set. Types include `ingress` and `egress`. |
list(object({
type = string
from_port = number
to_port = number
protocol = string
cidr_blocks = list(string)
}))
| `null` | 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) | Subnet IDs | `list(string)` | `null` | no | -| [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 | +| [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 | | [template\_url](#input\_template\_url) | Amazon S3 bucket URL location of a file containing the CloudFormation template body. Maximum file size: 460,800 bytes | `string` | n/a | yes | | [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 | | [timeout\_in\_minutes](#input\_timeout\_in\_minutes) | The amount of time that can pass before the stack status becomes `CREATE_FAILED` | `number` | `30` | no | @@ -366,44 +375,32 @@ Typically this includes `core-auto`, `core-network`, and your platform accounts. | [security\_group\_id](#output\_security\_group\_id) | Security group ID | | [vpc\_cidr](#output\_vpc\_cidr) | CIDR of the VPC created by RunsOn CloudFormation Stack | | [vpc\_id](#output\_vpc\_id) | ID of the VPC created by RunsOn CloudFormation Stack | - - - -## References - -- [cloudposse/terraform-aws-components](https://github.com/cloudposse/terraform-aws-components/tree/main/modules/cloudtrail) - - Cloud Posse's upstream component - -[](https://cpco.io/homepage?utm_source=github&utm_medium=readme&utm_campaign=cloudposse-terraform-components/aws-runs-on&utm_content=) - - -> [!TIP] -> #### 👽 Use Atmos with Terraform -> Cloud Posse uses [`atmos`](https://atmos.tools) to easily orchestrate multiple environments using Terraform.
-> Works with [Github Actions](https://atmos.tools/integrations/github-actions/), [Atlantis](https://atmos.tools/integrations/atlantis), or [Spacelift](https://atmos.tools/integrations/spacelift). -> ->
-> Watch demo of using Atmos with Terraform ->
-> Example of running atmos to manage infrastructure from our Quick Start tutorial. -> + +## Related Projects +Check out these related projects. +- [Cloud Posse Terraform Modules](https://docs.cloudposse.com/modules/) - Our collection of reusable Terraform modules used by our reference architectures. +- [Atmos](https://atmos.tools) - Atmos is like docker-compose but for your infrastructure +## References -## Related Projects +For additional context, refer to some of these links. -Check out these related projects. +- [RunsOn](https://runs-on.com/) - +- [Install RunsOn GitHub App](https://runs-on.com/guides/install/#3-github-app-registration) - +- [RunsOn Changelog](https://runs-on.com/changelog/) - +- [Embedded vs External Networking](https://runs-on.com/networking/embedded-vs-external/) - +- [Cloud Posse TGW Hub component](https://docs.cloudposse.com/components/library/aws/tgw/hub/) - +- [Cloud Posse TGW Spoke component](https://docs.cloudposse.com/components/library/aws/tgw/spoke/) - -- [Cloud Posse Terraform Modules](https://docs.cloudposse.com/modules/) - Our collection of reusable Terraform modules used by our reference architectures. -- [Atmos](https://atmos.tools) - Atmos is like docker-compose but for your infrastructure > [!TIP] @@ -470,6 +467,38 @@ In general, PRs are welcome. We follow the typical "fork-and-pull" Git workflow. **NOTE:** Be sure to merge the latest changes from "upstream" before making a pull request! + +## Running Terraform Tests + +We use [Atmos](https://atmos.tools) to streamline how Terraform tests are run. It centralizes configuration and wraps common test workflows with easy-to-use commands. + +All tests are located in the [`test/`](test) folder. + +Under the hood, tests are powered by Terratest together with our internal [Test Helpers](https://github.com/cloudposse/test-helpers) library, providing robust infrastructure validation. + +Setup dependencies: +- Install Atmos ([installation guide](https://atmos.tools/install/)) +- Install Go [1.24+ or newer](https://go.dev/doc/install) +- Install Terraform or OpenTofu + +To run tests: + +- Run all tests: + ```sh + atmos test run + ``` +- Clean up test artifacts: + ```sh + atmos test clean + ``` +- Explore additional test options: + ```sh + atmos test --help + ``` +The configuration for test commands is centrally managed. To review what's being imported, see the [`atmos.yaml`](https://raw.githubusercontent.com/cloudposse/.github/refs/heads/main/.github/atmos/terraform-module.yaml) file. + +Learn more about our [automated testing in our documentation](https://docs.cloudposse.com/community/contribute/automated-testing/) or implementing [custom commands](https://atmos.tools/core-concepts/custom-commands/) with atmos. + ### 🌎 Slack Community Join our [Open Source Community](https://cpco.io/slack?utm_source=github&utm_medium=readme&utm_campaign=cloudposse-terraform-components/aws-runs-on&utm_content=slack) on Slack. It's **FREE** for everyone! Our "SweetOps" community is where you get to talk with others who share a similar vision for how to rollout and manage infrastructure. This is the best place to talk shop, ask questions, solicit feedback, and work together as a community to build totally *sweet* infrastructure. diff --git a/README.yaml b/README.yaml index 5071a99..59430c6 100644 --- a/README.yaml +++ b/README.yaml @@ -1,7 +1,6 @@ name: "aws-runs-on" # Canonical GitHub repo github_repo: "cloudposse-terraform-components/aws-runs-on" - tags: - component/runs-on - layer/github @@ -29,27 +28,20 @@ related: description: "Atmos is like docker-compose but for your infrastructure" url: "https://atmos.tools" contributors: [] # If included generates contribs - # Short description of this project -description: |- - This component is responsible for provisioning an RunsOn (https://runs-on.com/). - - After deploying this component, you will need to install the RunsOn app to GitHub. See the - [RunsOn documentation](https://runs-on.com/guides/install/#3-github-app-registration) for more information. - - ## Compatibility - - Due to output changes, this component only works with version 2.8.2+ of the RunsOn CloudFormation template. - - ## Usage - - **Stack Level**: Regional +description: | + Component: `runs-on` - ### Defaults + This component provisions RunsOn for GitHub Actions self-hosted runners. After deploying this + component, install the RunsOn GitHub App in your organization to enable runner registration. + See the RunsOn documentation for GitHub App installation and configuration details. - Regardless of the networking style, you should have these defaults in common: + Compatibility: Requires RunsOn CloudFormation template version 2.8.2 or newer due to output changes. +# How to use this project +usage: | + Stack Level: Regional - (`runs-on/defaults.yaml`) + Defaults (runs-on/defaults.yaml) ```yaml components: @@ -66,17 +58,17 @@ description: |- timeout_in_minutes: 30 # template_url: https://runs-on.s3.eu-west-1.amazonaws.com/cloudformation/template.yaml # See latest version and changelog at https://runs-on.com/changelog/ - template_url: https://runs-on.s3.eu-west-1.amazonaws.com/cloudformation/template-v2.8.3.yaml + template_url: https://runs-on.s3.eu-west-1.amazonaws.com/cloudformation/template-v2.8.3.yaml parameters: AppCPU: 256 AppMemory: 512 EmailAddress: developer@cloudposse.com # Environments let you run multiple Stacks in one organization and segregate resources. - # If you specify an environment, then all the jobs must also specify the which environment they are running in. + # If you specify an environment, then all the jobs must also specify which environment they are running in. # To keep things simple, we use the default environment ("production") and leave the `env` label unset in the workflow. EncryptEbs: true # With the default value of SSHAllowed: true, the runners that are placed in a public subnet - # will allow ingress on port 22. This is highly abused (scanners running constantly looking for vulernable SSH servers) + # will allow ingress on port 22. This is highly abused (scanners running constantly looking for vulnerable SSH servers) # and should not be allowed. If you need access to the runners, use Session Manager (SSM). SSHAllowed: false LicenseKey: @@ -86,14 +78,12 @@ description: |- VpcFlowLogRetentionInDays: 14 ``` + Embedded networking (RunsOn managed VPC) - ### Embedded networking (Runs On managed VPC) + When no VPC details are set, the component will create a new VPC and subnets via the CloudFormation template. + Set the `VpcCidrBlock` parameter to the CIDR block of the VPC that will be created. - When no VPC details are set, the component will create a new VPC and subnets for you. This is done via the CloudFormation template. - - Note, you should set the `VpcCidrBlock` parameter to the CIDR block of the VPC that will be created. - - (`runs-on.yaml`) + (runs-on.yaml) ```yaml import: @@ -114,11 +104,11 @@ description: |- VpcCidrBlock: 10.100.0.0/16 ``` - ### External networking (Use existing VPC) + External networking (Use existing VPC) - When you want to use an existing VPC, you can set the `vpc_id`, `subnet_ids`, and `security_group_id` variables. + Use an existing VPC by setting `vpc_id`, `subnet_ids`, and `security_group_id`. - (`_defaults.yaml`) + (_defaults.yaml) ```yaml terraform: @@ -127,7 +117,7 @@ description: |- name: auto/ssm ``` - (`runs-on.yaml`) + (runs-on.yaml) ```yaml import: @@ -145,8 +135,8 @@ description: |- component: runs-on vars: networking_stack: external - # There are other ways to get the vpc_id, subnet_ids, and security_group_id. You can - # Harcode + # There are other ways to get the vpc_id, subnet_ids, and security_group_id. + # Hardcode # Use Atmos KV Store # Use atmos !terraform.output yaml function vpc_id: !store auto/ssm vpc vpc_id @@ -154,21 +144,13 @@ description: |- security_group_id: !store auto/ssm vpc default_security_group_id ``` -
- (DEPRECATED) Configuring with Transit Gateway - - It's important to note that the embedded networking will require some customization to work with Transit Gateway. + (DEPRECATED) Configuring with Transit Gateway - The following configuration assumes you are using the Cloud Posse Components for Transit Gateway - ([tgw/hub](https://docs.cloudposse.com/components/library/aws/tgw/hub/) & - [tgw/spoke](https://docs.cloudposse.com/components/library/aws/tgw/spoke/)). + The embedded networking requires customization to work with Transit Gateway. + Using Cloud Posse components for TGW ([tgw/hub] and [tgw/spoke]), the outputs of this component include + the same outputs as the `vpc` component (RunsOn creates a VPC and subnets). - The outputs of this component contain the same outputs as the `vpc` component. This is because the runs-on - cloudformation stack creates a VPC and subnets. - - First we need to update the TGW/Hub - this stores information about the VPCs that are allowed to be used by TGW Spokes. - - Assuming your TGW/Hub lives in the `core-network` account and your Runs-On is deployed to `core-auto` (`tgw-hub.yaml`) + Update the TGW Hub to store allowed VPCs (example tgw-hub.yaml): ```yaml vars: @@ -183,51 +165,49 @@ description: |- ```yaml components: - terraform: - tgw/hub/defaults: - metadata: - type: abstract - component: tgw/hub - vars: - enabled: true - name: tgw-hub - tags: - Team: sre - Service: tgw-hub + terraform: + tgw/hub/defaults: + metadata: + type: abstract + component: tgw/hub + vars: + enabled: true + name: tgw-hub + tags: + Team: sre + Service: tgw-hub - tgw/hub: - metadata: - inherits: - - tgw/hub/defaults - component: tgw/hub - vars: - connections: - - account: - tenant: core - stage: network - - account: - tenant: core - stage: auto - vpc_component_names: - - vpc - - runs-on - - account: - tenant: plat - stage: sandbox - - account: - tenant: plat - stage: dev - - account: - tenant: plat - stage: staging - - account: - tenant: plat - stage: prod + tgw/hub: + metadata: + inherits: + - tgw/hub/defaults + component: tgw/hub + vars: + connections: + - account: + tenant: core + stage: network + - account: + tenant: core + stage: auto + vpc_component_names: + - vpc + - runs-on + - account: + tenant: plat + stage: sandbox + - account: + tenant: plat + stage: dev + - account: + tenant: plat + stage: staging + - account: + tenant: plat + stage: prod ``` - We then need to create a spoke that refers to the VPC created by Runs-On. - - (`tgw-spoke.yaml`) + Create a TGW spoke that refers to the RunsOn VPC (example tgw-spoke.yaml): ```yaml tgw/spoke/runs-on: @@ -263,11 +243,7 @@ description: |- stage: prod ``` - Finally we need to update the spokes of the TGW/Spokes to allow Runs-On traffic to the other accounts. - - Typically this includes `core-auto`, `core-network`, and your platform accounts. - - (`tgw-spoke.yaml`) + Update other TGW spokes to allow RunsOn traffic (example tgw-spoke.yaml): ```yaml tgw/spoke: @@ -276,107 +252,29 @@ description: |- - tgw/spoke-defaults vars: connections: - ... + # ... vpc_component_names: - vpc - runs-on - ... + # ... ``` -
- - # Terraform Docs - - - - ## Requirements - - | Name | Version | - |------|---------| - | [terraform](#requirement\_terraform) | >= 1.0.0 | - | [aws](#requirement\_aws) | >= 4.9.0 | - - ## Providers - - | Name | Version | - |------|---------| - | [aws](#provider\_aws) | >= 4.9.0 | - - ## Modules - - | Name | Source | Version | - |------|--------|---------| - | [cloudformation\_stack](#module\_cloudformation\_stack) | cloudposse/cloudformation-stack/aws | 0.7.1 | - | [iam\_policy](#module\_iam\_policy) | cloudposse/iam-policy/aws | 2.0.2 | - | [iam\_roles](#module\_iam\_roles) | cloudposse/iam-roles/aws | 0.10.0 | - | [security\_group](#module\_security\_group) | cloudposse/security-group/aws | 2.2.0 | - | [this](#module\_this) | cloudposse/label/null | 0.25.0 | - - ## Resources - - | Name | Type | - |------|------| - | [aws_security_group_rule.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource | - | [aws_nat_gateways.ngws](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/nat_gateways) | data source | - | [aws_subnets.private](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnets) | data source | - | [aws_subnets.public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnets) | data source | - | [aws_vpc.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/vpc) | data source | - - ## Inputs - - | Name | Description | Type | Default | Required | - |------|-------------|------|---------|:--------:| - | [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 | - | [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 | - | [capabilities](#input\_capabilities) | A list of capabilities. Valid values: CAPABILITY\_IAM, CAPABILITY\_NAMED\_IAM, CAPABILITY\_AUTO\_EXPAND | `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 | - | [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 | - | [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 | - | [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 | - | [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 | - | [networking\_stack](#input\_networking\_stack) | Let RunsOn manage your networking stack (`embedded`), or use a vpc under your control (`external`). Null will default to whatever the template used as default. If you select `external`, you will need to provide the VPC ID, the subnet IDs, and optionally the security group ID, and make sure your whole networking setup is compatible with RunsOn (see https://runs-on.com/networking/embedded-vs-external/ for more details). To get started quickly, we recommend using the 'embedded' option. | `string` | `"embedded"` | no | - | [on\_failure](#input\_on\_failure) | Action to be taken if stack creation fails. This must be one of: `DO_NOTHING`, `ROLLBACK`, or `DELETE` | `string` | `"ROLLBACK"` | no | - | [parameters](#input\_parameters) | Key-value map of input parameters for the Stack Set template. (\_e.g.\_ map("BusinessUnit","ABC") | `map(string)` | `{}` | no | - | [policy\_body](#input\_policy\_body) | Structure containing the stack policy body | `string` | `""` | 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 | - | [region](#input\_region) | AWS Region | `string` | n/a | yes | - | [security\_group\_id](#input\_security\_group\_id) | Security group ID. If not set, a new security group will be created. | `string` | `null` | no | - | [security\_group\_rules](#input\_security\_group\_rules) | Security group rules. These are either added to the security passed in, or added to the security group created when var.security\_group\_id is not set. Types include `ingress` and `egress`. |
list(object({
type = string
from_port = number
to_port = number
protocol = string
cidr_blocks = list(string)
}))
| `null` | 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) | Subnet IDs | `list(string)` | `null` | no | - | [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 | - | [template\_url](#input\_template\_url) | Amazon S3 bucket URL location of a file containing the CloudFormation template body. Maximum file size: 460,800 bytes | `string` | n/a | yes | - | [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 | - | [timeout\_in\_minutes](#input\_timeout\_in\_minutes) | The amount of time that can pass before the stack status becomes `CREATE_FAILED` | `number` | `30` | no | - | [vpc\_id](#input\_vpc\_id) | VPC ID | `string` | `null` | no | - - ## Outputs - - | Name | Description | - |------|-------------| - | [id](#output\_id) | ID of the CloudFormation Stack | - | [name](#output\_name) | Name of the CloudFormation Stack | - | [nat\_gateway\_ids](#output\_nat\_gateway\_ids) | NAT Gateway IDs | - | [nat\_instance\_ids](#output\_nat\_instance\_ids) | NAT Instance IDs | - | [outputs](#output\_outputs) | Outputs of the CloudFormation Stack | - | [private\_route\_table\_ids](#output\_private\_route\_table\_ids) | Private subnet route table IDs | - | [private\_subnet\_ids](#output\_private\_subnet\_ids) | Private subnet IDs | - | [public\_subnet\_ids](#output\_public\_subnet\_ids) | Public subnet IDs | - | [security\_group\_id](#output\_security\_group\_id) | Security group ID | - | [vpc\_cidr](#output\_vpc\_cidr) | CIDR of the VPC created by RunsOn CloudFormation Stack | - | [vpc\_id](#output\_vpc\_id) | ID of the VPC created by RunsOn CloudFormation Stack | - - - - ## References - - - [cloudposse/terraform-aws-components](https://github.com/cloudposse/terraform-aws-components/tree/main/modules/cloudtrail) - - Cloud Posse's upstream component - - [](https://cpco.io/homepage?utm_source=github&utm_medium=readme&utm_campaign=cloudposse-terraform-components/aws-runs-on&utm_content=) +# Helpful links +references: + - name: RunsOn + description: "" + url: https://runs-on.com/ + - name: Install RunsOn GitHub App + description: "" + url: https://runs-on.com/guides/install/#3-github-app-registration + - name: RunsOn Changelog + description: "" + url: https://runs-on.com/changelog/ + - name: Embedded vs External Networking + description: "" + url: https://runs-on.com/networking/embedded-vs-external/ + - name: Cloud Posse TGW Hub component + description: "" + url: https://docs.cloudposse.com/components/library/aws/tgw/hub/ + - name: Cloud Posse TGW Spoke component + description: "" + url: https://docs.cloudposse.com/components/library/aws/tgw/spoke/ diff --git a/atmos.yaml b/atmos.yaml new file mode 100644 index 0000000..481c199 --- /dev/null +++ b/atmos.yaml @@ -0,0 +1,11 @@ +# Atmos Configuration — powered by https://atmos.tools +# +# This configuration enables centralized, DRY, and consistent project scaffolding using Atmos. +# +# Included features: +# - Organizational custom commands: https://atmos.tools/core-concepts/custom-commands +# - Automated README generation: https://atmos.tools/cli/commands/docs/generate +# +# Import shared configuration used by all modules +import: + - https://raw.githubusercontent.com/cloudposse-terraform-components/.github/refs/heads/main/.github/atmos/terraform-component.yaml diff --git a/src/README.md b/src/README.md index 55cfc42..38c0f89 100644 --- a/src/README.md +++ b/src/README.md @@ -7,24 +7,19 @@ tags: # Component: `runs-on` -This component is responsible for provisioning an RunsOn (https://runs-on.com/). +Component: `runs-on` -After deploying this component, you will need to install the RunsOn app to GitHub. See the -[RunsOn documentation](https://runs-on.com/guides/install/#3-github-app-registration) for more information. +This component provisions RunsOn for GitHub Actions self-hosted runners. After deploying this +component, install the RunsOn GitHub App in your organization to enable runner registration. +See the RunsOn documentation for GitHub App installation and configuration details. -## Compatibility - -Due to output changes, this component only works with version 2.8.2+ of the RunsOn CloudFormation template. +Compatibility: Requires RunsOn CloudFormation template version 2.8.2 or newer due to output changes. ## Usage -**Stack Level**: Regional - -### Defaults - -Regardless of the networking style, you should have these defaults in common: +Stack Level: Regional -(`runs-on/defaults.yaml`) +Defaults (runs-on/defaults.yaml) ```yaml components: @@ -41,17 +36,17 @@ components: timeout_in_minutes: 30 # template_url: https://runs-on.s3.eu-west-1.amazonaws.com/cloudformation/template.yaml # See latest version and changelog at https://runs-on.com/changelog/ - template_url: https://runs-on.s3.eu-west-1.amazonaws.com/cloudformation/template-v2.8.3.yaml + template_url: https://runs-on.s3.eu-west-1.amazonaws.com/cloudformation/template-v2.8.3.yaml parameters: AppCPU: 256 AppMemory: 512 EmailAddress: developer@cloudposse.com # Environments let you run multiple Stacks in one organization and segregate resources. - # If you specify an environment, then all the jobs must also specify the which environment they are running in. + # If you specify an environment, then all the jobs must also specify which environment they are running in. # To keep things simple, we use the default environment ("production") and leave the `env` label unset in the workflow. EncryptEbs: true # With the default value of SSHAllowed: true, the runners that are placed in a public subnet - # will allow ingress on port 22. This is highly abused (scanners running constantly looking for vulernable SSH servers) + # will allow ingress on port 22. This is highly abused (scanners running constantly looking for vulnerable SSH servers) # and should not be allowed. If you need access to the runners, use Session Manager (SSM). SSHAllowed: false LicenseKey: @@ -61,14 +56,12 @@ components: VpcFlowLogRetentionInDays: 14 ``` +Embedded networking (RunsOn managed VPC) -### Embedded networking (Runs On managed VPC) +When no VPC details are set, the component will create a new VPC and subnets via the CloudFormation template. +Set the `VpcCidrBlock` parameter to the CIDR block of the VPC that will be created. -When no VPC details are set, the component will create a new VPC and subnets for you. This is done via the CloudFormation template. - -Note, you should set the `VpcCidrBlock` parameter to the CIDR block of the VPC that will be created. - -(`runs-on.yaml`) +(runs-on.yaml) ```yaml import: @@ -89,11 +82,11 @@ components: VpcCidrBlock: 10.100.0.0/16 ``` -### External networking (Use existing VPC) +External networking (Use existing VPC) -When you want to use an existing VPC, you can set the `vpc_id`, `subnet_ids`, and `security_group_id` variables. +Use an existing VPC by setting `vpc_id`, `subnet_ids`, and `security_group_id`. -(`_defaults.yaml`) +(_defaults.yaml) ```yaml terraform: @@ -102,7 +95,7 @@ terraform: name: auto/ssm ``` -(`runs-on.yaml`) +(runs-on.yaml) ```yaml import: @@ -120,8 +113,8 @@ components: component: runs-on vars: networking_stack: external - # There are other ways to get the vpc_id, subnet_ids, and security_group_id. You can - # Harcode + # There are other ways to get the vpc_id, subnet_ids, and security_group_id. + # Hardcode # Use Atmos KV Store # Use atmos !terraform.output yaml function vpc_id: !store auto/ssm vpc vpc_id @@ -129,21 +122,13 @@ components: security_group_id: !store auto/ssm vpc default_security_group_id ``` -
-(DEPRECATED) Configuring with Transit Gateway - -It's important to note that the embedded networking will require some customization to work with Transit Gateway. +(DEPRECATED) Configuring with Transit Gateway -The following configuration assumes you are using the Cloud Posse Components for Transit Gateway -([tgw/hub](https://docs.cloudposse.com/components/library/aws/tgw/hub/) & -[tgw/spoke](https://docs.cloudposse.com/components/library/aws/tgw/spoke/)). +The embedded networking requires customization to work with Transit Gateway. +Using Cloud Posse components for TGW ([tgw/hub] and [tgw/spoke]), the outputs of this component include +the same outputs as the `vpc` component (RunsOn creates a VPC and subnets). -The outputs of this component contain the same outputs as the `vpc` component. This is because the runs-on -cloudformation stack creates a VPC and subnets. - -First we need to update the TGW/Hub - this stores information about the VPCs that are allowed to be used by TGW Spokes. - -Assuming your TGW/Hub lives in the `core-network` account and your Runs-On is deployed to `core-auto` (`tgw-hub.yaml`) +Update the TGW Hub to store allowed VPCs (example tgw-hub.yaml): ```yaml vars: @@ -158,51 +143,49 @@ vars: ```yaml components: -terraform: - tgw/hub/defaults: - metadata: - type: abstract - component: tgw/hub - vars: - enabled: true - name: tgw-hub - tags: - Team: sre - Service: tgw-hub + terraform: + tgw/hub/defaults: + metadata: + type: abstract + component: tgw/hub + vars: + enabled: true + name: tgw-hub + tags: + Team: sre + Service: tgw-hub - tgw/hub: - metadata: - inherits: - - tgw/hub/defaults - component: tgw/hub - vars: - connections: - - account: - tenant: core - stage: network - - account: - tenant: core - stage: auto - vpc_component_names: - - vpc - - runs-on - - account: - tenant: plat - stage: sandbox - - account: - tenant: plat - stage: dev - - account: - tenant: plat - stage: staging - - account: - tenant: plat - stage: prod + tgw/hub: + metadata: + inherits: + - tgw/hub/defaults + component: tgw/hub + vars: + connections: + - account: + tenant: core + stage: network + - account: + tenant: core + stage: auto + vpc_component_names: + - vpc + - runs-on + - account: + tenant: plat + stage: sandbox + - account: + tenant: plat + stage: dev + - account: + tenant: plat + stage: staging + - account: + tenant: plat + stage: prod ``` -We then need to create a spoke that refers to the VPC created by Runs-On. - -(`tgw-spoke.yaml`) +Create a TGW spoke that refers to the RunsOn VPC (example tgw-spoke.yaml): ```yaml tgw/spoke/runs-on: @@ -238,11 +221,7 @@ tgw/spoke/runs-on: stage: prod ``` -Finally we need to update the spokes of the TGW/Spokes to allow Runs-On traffic to the other accounts. - -Typically this includes `core-auto`, `core-network`, and your platform accounts. - -(`tgw-spoke.yaml`) +Update other TGW spokes to allow RunsOn traffic (example tgw-spoke.yaml): ```yaml tgw/spoke: @@ -251,18 +230,16 @@ Typically this includes `core-auto`, `core-network`, and your platform accounts. - tgw/spoke-defaults vars: connections: - ... + # ... vpc_component_names: - vpc - runs-on - ... + # ... ``` -
-# Terraform Docs - - + + ## Requirements | Name | Version | @@ -346,12 +323,27 @@ Typically this includes `core-auto`, `core-network`, and your platform accounts. | [security\_group\_id](#output\_security\_group\_id) | Security group ID | | [vpc\_cidr](#output\_vpc\_cidr) | CIDR of the VPC created by RunsOn CloudFormation Stack | | [vpc\_id](#output\_vpc\_id) | ID of the VPC created by RunsOn CloudFormation Stack | - - + + + ## References -- [cloudposse/terraform-aws-components](https://github.com/cloudposse/terraform-aws-components/tree/main/modules/cloudtrail) - - Cloud Posse's upstream component + +- [RunsOn](https://runs-on.com/) - + +- [Install RunsOn GitHub App](https://runs-on.com/guides/install/#3-github-app-registration) - + +- [RunsOn Changelog](https://runs-on.com/changelog/) - + +- [Embedded vs External Networking](https://runs-on.com/networking/embedded-vs-external/) - + +- [Cloud Posse TGW Hub component](https://docs.cloudposse.com/components/library/aws/tgw/hub/) - + +- [Cloud Posse TGW Spoke component](https://docs.cloudposse.com/components/library/aws/tgw/spoke/) - + + + [](https://cpco.io/homepage?utm_source=github&utm_medium=readme&utm_campaign=cloudposse-terraform-components/aws-runs-on&utm_content=) + From 3efe0f8b6dd370b77d398b25af968cd34bd2cc46 Mon Sep 17 00:00:00 2001 From: Igor Rodionov Date: Sat, 23 Aug 2025 02:37:45 +0300 Subject: [PATCH 2/2] Improve README formatting and section headers Updated formatting and section headers in README.yaml for clarity. --- README.yaml | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/README.yaml b/README.yaml index 59430c6..e4ae62f 100644 --- a/README.yaml +++ b/README.yaml @@ -41,7 +41,7 @@ description: | usage: | Stack Level: Regional - Defaults (runs-on/defaults.yaml) + (`runs-on/defaults.yaml`) ```yaml components: @@ -78,12 +78,12 @@ usage: | VpcFlowLogRetentionInDays: 14 ``` - Embedded networking (RunsOn managed VPC) + ### Embedded networking (Runs On managed VPC) When no VPC details are set, the component will create a new VPC and subnets via the CloudFormation template. Set the `VpcCidrBlock` parameter to the CIDR block of the VPC that will be created. - (runs-on.yaml) + (`runs-on.yaml`) ```yaml import: @@ -104,11 +104,11 @@ usage: | VpcCidrBlock: 10.100.0.0/16 ``` - External networking (Use existing VPC) + ### External networking (Use existing VPC) Use an existing VPC by setting `vpc_id`, `subnet_ids`, and `security_group_id`. - (_defaults.yaml) + (`_defaults.yaml`) ```yaml terraform: @@ -117,7 +117,7 @@ usage: | name: auto/ssm ``` - (runs-on.yaml) + (`runs-on.yaml`) ```yaml import: @@ -144,13 +144,16 @@ usage: | security_group_id: !store auto/ssm vpc default_security_group_id ``` - (DEPRECATED) Configuring with Transit Gateway - - The embedded networking requires customization to work with Transit Gateway. - Using Cloud Posse components for TGW ([tgw/hub] and [tgw/spoke]), the outputs of this component include - the same outputs as the `vpc` component (RunsOn creates a VPC and subnets). - - Update the TGW Hub to store allowed VPCs (example tgw-hub.yaml): +
+ (DEPRECATED) Configuring with Transit Gateway + It's important to note that the embedded networking will require some customization to work with Transit Gateway. + The following configuration assumes you are using the Cloud Posse Components for Transit Gateway + ([tgw/hub](https://docs.cloudposse.com/components/library/aws/tgw/hub/) & + [tgw/spoke](https://docs.cloudposse.com/components/library/aws/tgw/spoke/)). + The outputs of this component contain the same outputs as the `vpc` component. This is because the runs-on + cloudformation stack creates a VPC and subnets. + First we need to update the TGW/Hub - this stores information about the VPCs that are allowed to be used by TGW Spokes. + Assuming your TGW/Hub lives in the `core-network` account and your Runs-On is deployed to `core-auto` (`tgw-hub.yaml`) ```yaml vars: @@ -207,7 +210,8 @@ usage: | stage: prod ``` - Create a TGW spoke that refers to the RunsOn VPC (example tgw-spoke.yaml): + We then need to create a spoke that refers to the VPC created by Runs-On. + (`tgw-spoke.yaml`) ```yaml tgw/spoke/runs-on: @@ -243,7 +247,9 @@ usage: | stage: prod ``` - Update other TGW spokes to allow RunsOn traffic (example tgw-spoke.yaml): + Finally we need to update the spokes of the TGW/Spokes to allow Runs-On traffic to the other accounts. + Typically this includes `core-auto`, `core-network`, and your platform accounts. + (`tgw-spoke.yaml`) ```yaml tgw/spoke: @@ -258,6 +264,7 @@ usage: | - runs-on # ... ``` +
# Helpful links references: - name: RunsOn