├── .github └── workflows │ └── build.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .terraform-version ├── .terraform.lock.hcl ├── .tflint.hcl ├── CHANGELOG.md ├── README.md ├── main.tf ├── outputs.tf ├── scripts ├── aws_cli_runner.sh ├── terraform-module-support.sh └── tflint-support.sh ├── tests ├── Require reworking │ ├── script_removes_all_files │ │ ├── expected_plan_errors.json │ │ ├── expected_variables.json │ │ ├── terraform.tfvars │ │ └── test.sh │ ├── script_retains_all_files │ │ ├── expected_plan_errors.json │ │ ├── expected_variables.json │ │ ├── terraform.tfvars │ │ └── test.sh │ └── test_data_retrieval_with_empty_result │ │ ├── expected_variables.json │ │ ├── terraform.tfvars │ │ └── test.sh ├── aws_error_profile_does_not_exist │ ├── expected_plan_errors.json │ ├── expected_variables.json │ ├── terraform.tfvars │ └── test.sh ├── common.sh ├── terraform_validation_error_external_id_invalid_characters │ ├── expected_plan_errors.json │ ├── expected_variables.json │ ├── terraform.tfvars │ └── test.sh ├── terraform_validation_error_external_id_too_long │ ├── expected_plan_errors.json │ ├── expected_variables.json │ ├── terraform.tfvars │ └── test.sh ├── terraform_validation_error_external_id_too_long_and_invalid_characters │ ├── expected_plan_errors.json │ ├── expected_variables.json │ ├── terraform.tfvars │ └── test.sh ├── terraform_validation_error_external_id_too_short │ ├── expected_plan_errors.json │ ├── expected_variables.json │ ├── terraform.tfvars │ └── test.sh ├── terraform_validation_error_invalid_role_arn │ ├── expected_plan_errors.json │ ├── expected_variables.json │ ├── terraform.tfvars │ └── test.sh ├── terraform_validation_error_profile_does_not_match_regex │ ├── expected_plan_errors.json │ ├── expected_variables.json │ ├── terraform.tfvars │ └── test.sh ├── terraform_validation_error_profile_does_not_start_with_a_letter │ ├── expected_plan_errors.json │ ├── expected_variables.json │ ├── terraform.tfvars │ └── test.sh ├── terraform_validation_error_region_does_not_match_regex │ ├── expected_plan_errors.json │ ├── expected_variables.json │ ├── terraform.tfvars │ └── test.sh ├── terraform_validation_error_role_session_name_invalid_characters │ ├── expected_plan_errors.json │ ├── expected_variables.json │ ├── terraform.tfvars │ └── test.sh ├── terraform_validation_error_role_session_name_too_long │ ├── expected_plan_errors.json │ ├── expected_variables.json │ ├── terraform.tfvars │ └── test.sh ├── terraform_validation_error_role_session_name_too_long_and_invalid_characters │ ├── expected_plan_errors.json │ ├── expected_variables.json │ ├── terraform.tfvars │ └── test.sh ├── terraform_validation_error_role_session_name_too_short │ ├── expected_plan_errors.json │ ├── expected_variables.json │ ├── terraform.tfvars │ └── test.sh ├── test_data_retrieval_with_no_role_arn_and_error │ ├── expected_plan_errors.json │ ├── expected_variables.json │ ├── terraform.tfvars │ └── test.sh ├── test_empty_command │ ├── expected_plan_errors.json │ ├── terraform.tfvars │ └── test.sh ├── test_version_retrieval_will_error │ ├── expected_apply_outputs.json │ ├── terraform.tfvars │ └── test.sh └── tests.sh ├── variables.tf └── versions.tf /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | strategy: 11 | matrix: 12 | terraform_version: 13 | - 1.12.1 14 | - 1.11.3 15 | - 1.10.5 16 | - 1.9.8 17 | - 1.8.5 18 | - 1.7.5 19 | - 1.6.6 20 | 21 | steps: 22 | - name: Checkout code 23 | uses: actions/checkout@v4 24 | 25 | - name: Install tfenv 26 | run: | 27 | git clone https://github.com/tfutils/tfenv.git $HOME/.tfenv 28 | echo "$HOME/.tfenv/bin" >> $GITHUB_PATH 29 | 30 | - name: Install Terraform v${{ matrix.terraform_version }} 31 | run: | 32 | echo ${{ matrix.terraform_version }} > .terraform-version 33 | tfenv install ${{ matrix.terraform_version }} 34 | tfenv use ${{ matrix.terraform_version }} 35 | 36 | - name: Update the test result for 1 file 37 | run: | 38 | AWS_CLI_VERSION=$(aws --version) envsubst '\$AWS_CLI_VERSION' < tests/test_version_retrieval_will_error/expected_apply_outputs.json > temp.json 39 | mv -f temp.json tests/test_version_retrieval_will_error/expected_apply_outputs.json 40 | 41 | - name: Run tests 42 | run: | 43 | tests/tests.sh 44 | 45 | - name: Capture logs 46 | uses: actions/upload-artifact@v4 47 | if: always() 48 | with: 49 | name: logs-${{ matrix.terraform_version }} 50 | path: test-reports/**/* 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /test-reports/ 2 | .idea/ 3 | /PersonalSettingsMakefile 4 | /.env 5 | vendor/ 6 | 7 | .terraform/ 8 | /temp/ 9 | aliased-providers.tf.json 10 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | 3 | - repo: local 4 | hooks: 5 | - id: tflint-setup 6 | always_run: true 7 | args: 8 | - setup 9 | entry: ./scripts/tflint-support.sh 10 | language: system 11 | name: Setup before TFLint 12 | pass_filenames: false 13 | stages: [pre-commit] 14 | 15 | - repo: https://github.com/antonbabenko/pre-commit-terraform 16 | rev: v1.98.0 17 | hooks: 18 | - id: terraform_tflint 19 | stages: [pre-commit] 20 | - id: terraform_fmt 21 | stages: [pre-commit] 22 | - id: terraform_validate 23 | exclude: | 24 | (?x)( 25 | ^.terraform/| 26 | ^modules/| 27 | ^validate/ 28 | ) 29 | stages: [pre-commit] 30 | - id: terraform_docs 31 | args: 32 | - --hook-config=--path-to-file=README.md 33 | - --hook-config=--add-to-existing-file=true 34 | - --hook-config=--create-file-if-not-exist=true 35 | stages: [pre-commit] 36 | 37 | - repo: local 38 | hooks: 39 | - id: tflint-teardown 40 | always_run: true 41 | args: 42 | - teardown 43 | entry: ./scripts/tflint-support.sh 44 | name: Teardown after TFLint 45 | language: system 46 | pass_filenames: false 47 | stages: [pre-commit] 48 | 49 | - repo: local 50 | hooks: 51 | - id: check-changelog-updated 52 | always_run: true 53 | entry: ./scripts/terraform-module-support.sh 54 | files: CHANGELOG.md 55 | language: system 56 | name: Check if CHANGELOG.md is updated before push 57 | stages: [pre-push] 58 | 59 | - repo: https://github.com/pre-commit/pre-commit-hooks 60 | rev: v5.0.0 61 | hooks: 62 | - id: check-added-large-files 63 | stages: [pre-commit] 64 | - id: check-executables-have-shebangs 65 | stages: [pre-commit] 66 | - id: check-json 67 | stages: [pre-commit] 68 | - id: check-merge-conflict 69 | stages: [pre-commit] 70 | - id: check-symlinks 71 | stages: [pre-commit] 72 | - id: check-yaml 73 | stages: [pre-commit] 74 | - id: detect-aws-credentials 75 | args: 76 | - --allow-missing-credentials 77 | stages: [pre-commit] 78 | - id: detect-private-key 79 | stages: [pre-commit] 80 | - id: end-of-file-fixer 81 | stages: [pre-commit] 82 | - id: fix-byte-order-marker 83 | stages: [pre-commit] 84 | - id: pretty-format-json 85 | args: 86 | - --autofix 87 | - --indent=2 88 | - --no-sort-keys 89 | files: .*\.json$ 90 | stages: [pre-commit] 91 | - id: trailing-whitespace 92 | args: 93 | - --markdown-linebreak-ext=md 94 | stages: [pre-commit] 95 | 96 | - repo: https://github.com/jumanjihouse/pre-commit-hook-yamlfmt 97 | rev: 0.2.3 98 | hooks: 99 | - id: yamlfmt 100 | args: 101 | - --implicit_start 102 | - --preserve-quotes 103 | - --mapping=2 104 | - --offset=2 105 | - --sequence=4 106 | - --width=300 107 | stages: [pre-commit] 108 | 109 | - repo: https://github.com/gitleaks/gitleaks 110 | rev: v8.24.2 111 | hooks: 112 | - id: gitleaks 113 | stages: [pre-commit] 114 | -------------------------------------------------------------------------------- /.terraform-version: -------------------------------------------------------------------------------- 1 | 1.12.1 2 | -------------------------------------------------------------------------------- /.terraform.lock.hcl: -------------------------------------------------------------------------------- 1 | # This file is maintained automatically by "terraform init". 2 | # Manual edits may be lost in future updates. 3 | 4 | provider "registry.terraform.io/hashicorp/external" { 5 | version = "2.3.4" 6 | constraints = "~> 2.0" 7 | hashes = [ 8 | "h1:U6W8rgrdmR2pZ2cicFoGOSQ4GXuIf/4EK7s0vTJN7is=", 9 | "h1:XWkRZOLKMjci9/JAtE8X8fWOt7A4u+9mgXSUjc4Wuyo=", 10 | "h1:cCabxnWQ5fX1lS7ZqgUzsvWmKZw9FA7NRxAZ94vcTcc=", 11 | "zh:037fd82cd86227359bc010672cd174235e2d337601d4686f526d0f53c87447cb", 12 | "zh:0ea1db63d6173d01f2fa8eb8989f0809a55135a0d8d424b08ba5dabad73095fa", 13 | "zh:17a4d0a306566f2e45778fbac48744b6fd9c958aaa359e79f144c6358cb93af0", 14 | "zh:298e5408ab17fd2e90d2cd6d406c6d02344fe610de5b7dae943a58b958e76691", 15 | "zh:38ecfd29ee0785fd93164812dcbe0664ebbe5417473f3b2658087ca5a0286ecb", 16 | "zh:59f6a6f31acf66f4ea3667a555a70eba5d406c6e6d93c2c641b81d63261eeace", 17 | "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", 18 | "zh:ad0279dfd09d713db0c18469f585e58d04748ca72d9ada83883492e0dd13bd58", 19 | "zh:c69f66fd21f5e2c8ecf7ca68d9091c40f19ad913aef21e3ce23836e91b8cbb5f", 20 | "zh:d4a56f8c48aa86fc8e0c233d56850f5783f322d6336f3bf1916e293246b6b5d4", 21 | "zh:f2b394ebd4af33f343835517e80fc876f79361f4688220833bc3c77655dd2202", 22 | "zh:f31982f29f12834e5d21e010856eddd19d59cd8f449adf470655bfd19354377e", 23 | ] 24 | } 25 | 26 | provider "registry.terraform.io/hashicorp/local" { 27 | version = "2.5.2" 28 | constraints = "~> 2.0" 29 | hashes = [ 30 | "h1:IyFbOIO6mhikFNL/2h1iZJ6kyN3U00jgkpCLUCThAfE=", 31 | "h1:JlMZD6nYqJ8sSrFfEAH0Vk/SL8WLZRmFaMUF9PJK5wM=", 32 | "h1:p99F1AoV9z51aJ4EdItxz/vLwWIyhx/0Iw7L7sWSH1o=", 33 | "zh:136299545178ce281c56f36965bf91c35407c11897f7082b3b983d86cb79b511", 34 | "zh:3b4486858aa9cb8163378722b642c57c529b6c64bfbfc9461d940a84cd66ebea", 35 | "zh:4855ee628ead847741aa4f4fc9bed50cfdbf197f2912775dd9fe7bc43fa077c0", 36 | "zh:4b8cd2583d1edcac4011caafe8afb7a95e8110a607a1d5fb87d921178074a69b", 37 | "zh:52084ddaff8c8cd3f9e7bcb7ce4dc1eab00602912c96da43c29b4762dc376038", 38 | "zh:71562d330d3f92d79b2952ffdda0dad167e952e46200c767dd30c6af8d7c0ed3", 39 | "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", 40 | "zh:805f81ade06ff68fa8b908d31892eaed5c180ae031c77ad35f82cb7a74b97cf4", 41 | "zh:8b6b3ebeaaa8e38dd04e56996abe80db9be6f4c1df75ac3cccc77642899bd464", 42 | "zh:ad07750576b99248037b897de71113cc19b1a8d0bc235eb99173cc83d0de3b1b", 43 | "zh:b9f1c3bfadb74068f5c205292badb0661e17ac05eb23bfe8bd809691e4583d0e", 44 | "zh:cc4cbcd67414fefb111c1bf7ab0bc4beb8c0b553d01719ad17de9a047adff4d1", 45 | ] 46 | } 47 | -------------------------------------------------------------------------------- /.tflint.hcl: -------------------------------------------------------------------------------- 1 | config { 2 | call_module_type = "all" 3 | force = false 4 | format = "compact" 5 | ignore_module = { 6 | "Invicton-Labs/deepmerge/null" = true 7 | } 8 | } 9 | 10 | tflint { 11 | required_version = ">= 0.56.0" 12 | } 13 | 14 | # Only the AWS plugin is enabled. The Google and Azure plugins are not enabled as we have no current use for them. 15 | plugin "aws" { 16 | enabled = true 17 | source = "github.com/terraform-linters/tflint-ruleset-aws" 18 | version = "0.38.0" 19 | deep_check = true 20 | } 21 | 22 | # 23 | # Please check https://github.com/terraform-linters/tflint-ruleset-terraform/tree/v0.5.0/docs/rules for new rules 24 | # (adjust the version accordingly) 25 | # 26 | 27 | # Use '#' for comments rather than '//'. 28 | rule "terraform_comment_syntax" { 29 | enabled = true 30 | } 31 | 32 | # List items should be accessed using square brackets 33 | rule "terraform_deprecated_index" { 34 | enabled = true 35 | } 36 | 37 | # Interpolation-only expressions are deprecated in Terraform v0.12.14 38 | rule "terraform_deprecated_interpolation" { 39 | enabled = true 40 | } 41 | 42 | # Lookup with 2 arguments is deprecated 43 | rule "terraform_deprecated_lookup" { 44 | enabled = true 45 | } 46 | 47 | # Outputs require a description 48 | rule "terraform_documented_outputs" { 49 | enabled = true 50 | } 51 | 52 | # Variables require a description 53 | rule "terraform_documented_variables" { 54 | enabled = true 55 | } 56 | 57 | # Comparing a collection with an empty list is invalid. To detect an empty collection, check its length 58 | rule "terraform_empty_list_equality" { 59 | enabled = true 60 | } 61 | 62 | # Disallow specifying a git or mercurial repository as a module source without pinning to a version 63 | rule terraform_module_pinned_source { 64 | enabled = true 65 | } 66 | 67 | # Ensure that all modules sourced from a Terraform Registry specify a version 68 | rule "terraform_module_version" { 69 | enabled = true 70 | exact = false # default 71 | } 72 | 73 | # Enforces naming conventions 74 | rule "terraform_naming_convention" { 75 | enabled = true 76 | format = "snake_case" 77 | } 78 | 79 | # Require that all providers specify a source and version constraint through required_providers 80 | rule "terraform_required_providers" { 81 | enabled = true 82 | 83 | # defaults 84 | source = true 85 | version = true 86 | } 87 | 88 | # Disallow terraform declarations without required_version 89 | rule "terraform_required_version" { 90 | enabled = true 91 | } 92 | 93 | # Ensure that a module complies with the Terraform Standard Module Structure / https://www.terraform.io/docs/modules/index.html#standard-module-structure 94 | rule "terraform_standard_module_structure" { 95 | enabled = true 96 | } 97 | 98 | # Disallow variable declarations without type 99 | rule "terraform_typed_variables" { 100 | enabled = true 101 | } 102 | 103 | # Disallow variables, data sources, and locals that are declared but never used 104 | rule terraform_unused_declarations { 105 | enabled = true 106 | } 107 | 108 | # Check that all required_providers are used in the module 109 | rule terraform_unused_required_providers { 110 | enabled = true 111 | } 112 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | # V7.0.1 - 2025/04/28 4 | - Add v1.11.3, and reduced the number of builds to just the latest in the minor versions of Terraform from 1.6.0 onwards. 5 | - Minor reorganization to match [Terraform Standard Module Structure](https://www.terraform.io/docs/modules/index.html#standard-module-structure). 6 | - Small enhancement for TFLint when aliased providers are used. 7 | - Added warning to README.md regarding destructive use. Thank you, [Yves Vogl](https://github.com/digitickets/terraform-aws-cli/issues/25). 8 | 9 | # v7.0.0 - 2024/08/06 10 | - Fix a typo in the description for the `var.external_id`. 11 | - Fix handling of invalid JSON returned from the AWS CLI. Thank you, [홍수민 and horststumpf](https://github.com/digitickets/terraform-aws-cli/pull/19). 12 | - Introduced 2 new outputs: 13 | - `output.result_raw = string` - This will contain the raw output from the AWS CLI call. 14 | - `output.result_was_decoded = bool` - This will indicate if the output from the AWS CLI call was successfully JSON decoded. 15 | 16 | These were introduced as some of the results from the AWS CLI are not JSON decodable. For example `aws ec2 create-tags` returns nothing. 17 | 18 | # v6.1.0 - 2024/01/31 19 | - Added testing for Terraform 1.7+ 20 | - FIX : If `var.profile` and `var.assume_role_arn` are used, then continuing to use `var.profile` invalidates the 21 | assumed role. The `aws_cli_runner.sh` now no longer uses `var.profile` when a role has been successfully assumed. 22 | Thank you, [Garrett Blinkhorn](https://github.com/digitickets/terraform-aws-cli/issues/11). 23 | 24 | # v6.0.2 - 2024/01/31 25 | - FIX : Typo in `aws_cli_runner.sh` when running assuming a role. Thank you, [Garrett Blinkhorn](https://github.com/digitickets/terraform-aws-cli/issues/11). 26 | 27 | # v6.0.1 - 2023/12/22 28 | - Set the minimum version of Terraform to v1.6.0 as that is the lowest version to support `data.lifecycle` block. 29 | 30 | # v6.0.0 - 2023/12/15 31 | - Added error handling for errors generated by the AWS CLI to stop the Terraform Plan. The error is also present in the 32 | `terraform show` output in the `checks[*].instances[*].problems` node (See the 33 | [expected plan errors](tests/aws_error_profile_does_not_exist/expected_plan_errors.json) when an AWS error is 34 | triggered). 35 | - Added a lot of Terraform variable validation to ensure the supplied parameters match the limits imposed by AWS (the 36 | minimum/maximum length, allowable characters, rules on first characters, etc.) 37 | - Rewritten the [AWS CLI Runner script](./scripts/aws_cli_runner.sh) to not need to deal with wrapping parameters in 38 | quotes. 39 | - Rewritten tests, mainly to reduce the amount of effort to configure them in the future. 40 | 41 | ## BACKWARDS INCOMPATIBILITY 42 | 43 | - The `debug_log_filename` variable has been removed. As the new code will generate more files to assist in any 44 | debugging if it becomes necessary, a new variable `alternative_path` has been added. If set, this path will contain 45 | the following files: 46 | 47 | 1. `jq_data.json` - The data managed by `jq` to get the Terraform variables accessible to AWS CLI. 48 | 2. `jq_error.log` - Any errors generated by `jq` whilst attempting to parse the supplied JSON. 49 | 3. `aws_sts.json` - The data returned by AWS when assuming a role. 50 | 4. `aws_sts_error.log` - The full debug and any errors when assuming a role. 51 | 5. `aws_call.json` - The data returned by AWS when running AWS CLI for the required call. 52 | 6. `aws_call_error.log` - The full debug and any errors when running AWS CLI for the required call. 53 | 7. `results.json` - The results of the AWS CLI call that are fed back to Terraform. 54 | 55 | But to reduce the amount of files left behind, as standard, all files except `results.json` are deleted before 56 | Terraform is given the `results.json` file to process. 57 | 58 | If you need to have access to the other files, then setting the environment variable 59 | `MODULE_TERRAFORM_AWS_CLI_RETAIN_LOGS` to `true` will retain all the logs shown above. 60 | 61 | If the `alternative_path` variable is not set, then a default path will be used based upon `./temp/[hash]`. The hash 62 | is the md5 of all the values of the variables supplied to the module. 63 | 64 | # v5.2.0 - 2023/07/20 65 | 66 | - Fixed issue introduce in v5.1.0 regarding the use of `var.external_id`. 67 | - Introduces support for `var.profile` to allow you to supply your own AWS profile. Thank you, [coopengo-glecomte](https://github.com/digitickets/terraform-aws-cli/issues/8). 68 | - Introduces support for `var.region` to allow you to supply your own AWS region. 69 | - Refactored tests due to changes within Terraform. 70 | 71 | # v5.1.0 - 2023/07/20 72 | 73 | - Introduce support for `var.external_id`. Thank you, [Joshua Rosen](https://github.com/digitickets/terraform-aws-cli/pull/6). 74 | 75 | # v5.0.4 - 2022/11/28 76 | 77 | - Allow `var.role_session_name` to be optional. Thank you, [Byron Kim](https://github.com/digitickets/terraform-aws-cli/issues/4). 78 | 79 | # v5.0.3 - 2022/05/31 80 | 81 | - Fix for when the AWS call being made has no output (which is invalid JSON). Thank you, [Yaron Yarimi and Pavel Kargin](https://github.com/digitickets/terraform-aws-cli/issues/3). 82 | 83 | # v5.0.2 - 2022/05/26 84 | 85 | - Fix for when this module is used in an iteration. 86 | 87 | # v5.0.1 - 2022/05/24 88 | 89 | - Explicitly specify output type as json for assume role call. Thank you, [Niranjan Rajendran](https://github.com/digitickets/terraform-aws-cli/pull/2). 90 | 91 | # v5.0.0 - 2022/01/27 92 | 93 | - Fixed incompatibilities with Terraform 1.1.0. 94 | 95 | # v4.1.0 - 2021/10/05 96 | 97 | - Validate role_session_name so that the maximum length is 64 characters and that it must match a specific regex. 98 | 99 | # v4.0.0 - 2021/05/18 100 | 101 | - Set minimum terraform version to 0.15.0. 102 | 103 | # No release required - 2021/03/30 104 | 105 | - Updated tests to use an AWS request that does not require credentials, allowing the full terraform plan and apply 106 | process to be run and tested with the module. 107 | 108 | # v3.1.1 - 2021/03/25 109 | 110 | - Re-releasing as accidentally released v3.0.0 as v3.1.0. 111 | 112 | # v3.1.0 - 2021/03/25 113 | 114 | - Add an optional `debug_log_filename` variable. If supplied, a log file will be produced in the supplied location. This 115 | option enables the `--debug` option of the AWS CLI. Use this in safe environments as potentially sensitive content may 116 | be logged. 117 | - Added [adaptive retry mode](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-retries.html#cli-usage-retries-modes-adaptive) 118 | to help alleviate throttling issues. 119 | 120 | # v3.0.0 - 2020/12/03 121 | 122 | - Set minimum terraform version to 0.14.0. 123 | - Introduced `.terraform.lock.hcl` for versioning of dependencies. 124 | 125 | # v2.0.1 - 2020/09/17 126 | 127 | - Add `depends_on` to enforce the order in which the resources get instantiated / evaluated. 128 | 129 | # v2.0.0 - 2020/09/17 130 | 131 | - Set minimum terraform version to 0.13.0 132 | - Added variable validation to optional `assume_role_arn` to match syntax described in 133 | [IAM Identifiers](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html). 134 | 135 | # v1.3.0 - 2020/08/03 136 | 137 | - Set minimum version of random provider to 2.3.0 138 | 139 | # v1.2.2 - 2020/05/11 140 | 141 | - Updated examples in [README.md](README.md). 142 | 143 | # v1.2.1 - 2020/05/11 144 | 145 | - Updated [README.md](README.md) to reflect `digiticketsgroup/terraforming` image that includes all the required 146 | resources for using this module. 147 | 148 | # v1.2.0 - 2020/05/11 149 | 150 | - Drop down to using `sh` rather than `bash` so this module can operate with Hashicorp Terraform Docker image. 151 | 152 | # v1.1.0 - 2020/05/07 153 | 154 | - Updated examples in README.md with registry path as displayed by registry. 155 | - Updated `assume_role_arn` to reflect that it is optional. 156 | 157 | # v1.0.0 - 2020/05/07 158 | Initial release 159 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/digitickets/terraform-aws-cli/build.yml?style=for-the-badge&logo=github)](https://github.com/digitickets/terraform-aws-cli/actions/workflows/build.yml) 2 | [![GitHub issues](https://img.shields.io/github/issues/digitickets/terraform-aws-cli.svg?style=for-the-badge&logo=github)](https://github.com/digitickets/terraform-aws-cli/issues) 3 | 4 | # terraform-aws-cli 5 | 6 | Run the AWS CLI, with the ability to run under an assumed role, to access resources and properties missing from the 7 | Terraform AWS Provider. 8 | 9 | # Additional requirements 10 | 11 | This module requires a couple of additional tools to operate successfully. 12 | 13 | 1. Amazon Web Service Command Line Interface (`aws`) 14 | : This is available in several forms [here](https://aws.amazon.com/cli/). 15 | As the awscli tool gets updated regularly, any version 2 should be usable, but please try to keep as uptodate as the 16 | functionality included in later versions may be what you need when using this module. If you are not getting the 17 | functionality you require, please read the 18 | [AWS CLI V2 Changelog](https://raw.githubusercontent.com/aws/aws-cli/v2/CHANGELOG.rst) to see if you are just needing 19 | to upgrade. 20 | 21 | 2. JSON processor (`jq`) 22 | : This is available [here](https://stedolan.github.io/jq/). 23 | At least version `jq-1.5` is required but has been tested and actively used with `jq-1.6`. 24 | 25 | # Examples 26 | 27 | ## 1. Get the desired capacity of an autoscaling group. 28 | 29 | If you are using a blue/green style deployment, you would want to create the same number of EC2 instances as you are 30 | replacing. 31 | 32 | ```hcl-terraform 33 | module "current_desired_capacity" { 34 | source = "digitickets/cli/aws" 35 | role_session_name = "GettingDesiredCapacityFor${var.environment}" 36 | aws_cli_commands = ["autoscaling", "describe-auto-scaling-groups"] 37 | aws_cli_query = "AutoScalingGroups[?Tags[?Key==`Name`]|[?Value==`digitickets-${var.environment}-asg-app`]]|[0].DesiredCapacity" 38 | } 39 | ``` 40 | 41 | You can now set the desired capacity of an aws_autoscaling_group: 42 | 43 | ```hcl-terraform 44 | desired_capacity = module.current_desired_capacity.result 45 | ``` 46 | 47 | ## 2. Assuming a role. 48 | 49 | Extending the first example above, assuming a role is as simple as adding an `assume_role_arn` to the module: 50 | 51 | ```hcl-terraform 52 | module "current_desired_capacity" { 53 | source = "digitickets/cli/aws" 54 | assume_role_arn = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/OrganizationAccountAccessRole" 55 | role_session_name = "GettingDesiredCapacityFor${var.environment}" 56 | aws_cli_commands = ["autoscaling", "describe-auto-scaling-groups"] 57 | aws_cli_query = "AutoScalingGroups[?Tags[?Key==`Name`]|[?Value==`digitickets-${var.environment}-asg-app`]]|[0].DesiredCapacity" 58 | } 59 | ``` 60 | 61 | ## 3. Adding your own profile. 62 | 63 | Extending the example above, you can supply your own profile by adding a `profile` to the module: 64 | 65 | ```hcl-terraform 66 | module "current_desired_capacity" { 67 | source = "digitickets/cli/aws" 68 | assume_role_arn = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/OrganizationAccountAccessRole" 69 | role_session_name = "GettingDesiredCapacityFor${var.environment}" 70 | aws_cli_commands = ["autoscaling", "describe-auto-scaling-groups"] 71 | aws_cli_query = "AutoScalingGroups[?Tags[?Key==`Name`]|[?Value==`digitickets-${var.environment}-asg-app`]]|[0].DesiredCapacity" 72 | profile = "your-own-profile" 73 | } 74 | ``` 75 | 76 | ## 4. Adding your external ID. 77 | 78 | Extending the example above, you can supply your own external ID by adding an `external_id` to the module: 79 | 80 | ```hcl-terraform 81 | module "current_desired_capacity" { 82 | source = "digitickets/cli/aws" 83 | assume_role_arn = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/OrganizationAccountAccessRole" 84 | role_session_name = "GettingDesiredCapacityFor${var.environment}" 85 | aws_cli_commands = ["autoscaling", "describe-auto-scaling-groups"] 86 | aws_cli_query = "AutoScalingGroups[?Tags[?Key==`Name`]|[?Value==`digitickets-${var.environment}-asg-app`]]|[0].DesiredCapacity" 87 | profile = "your-own-profile" 88 | external_id = "your-external-id" 89 | } 90 | ``` 91 | 92 | Further information regarding the use of external IDs can be found [here](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user_externalid.html). 93 | 94 | # Warning 95 | 96 | This module uses Terraform's `external` provider to allow an `external` data source to be used to call the AWS CLI tool, 97 | and retrieve information not yet available via the AWS Terraform Provider. 98 | 99 | As per the warnings [here](https://registry.terraform.io/providers/hashicorp/external/latest/docs/data-sources/external), 100 | the `external` data source, and as a consequence, this module, it is expected that this module is used with caution. 101 | 102 | This module is _NOT_ a replacement for the AWS Terraform Provider. 103 | 104 | As per the last paragraph of the warnings from the official documentation regarding the `external` data source... 105 | 106 | "Terraform expects a data source to have _no observable side-effects_, 107 | and will re-run the program each time the state is refreshed." 108 | 109 | If you use this module to perform destructive changes to your AWS environment, then they will be triggered each time a 110 | Terraform plan and apply are run. 111 | 112 | # Terraform requirements, providers, resources, etc. 113 | 114 | 115 | ## Requirements 116 | 117 | | Name | Version | 118 | |------|---------| 119 | | [terraform](#requirement\_terraform) | >= 1.6.0 | 120 | | [external](#requirement\_external) | ~> 2.0 | 121 | | [local](#requirement\_local) | ~> 2.0 | 122 | 123 | ## Providers 124 | 125 | | Name | Version | 126 | |------|---------| 127 | | [external](#provider\_external) | 2.3.4 | 128 | | [local](#provider\_local) | 2.5.2 | 129 | 130 | ## Modules 131 | 132 | No modules. 133 | 134 | ## Resources 135 | 136 | | Name | Type | 137 | |------|------| 138 | | [external_external.awscli_program](https://registry.terraform.io/providers/hashicorp/external/latest/docs/data-sources/external) | data source | 139 | | [local_file.awscli_results_file](https://registry.terraform.io/providers/hashicorp/local/latest/docs/data-sources/file) | data source | 140 | 141 | ## Inputs 142 | 143 | | Name | Description | Type | Default | Required | Validation | 144 | |------|-------------|------|---------|:--------:|------------| 145 | | [alternative\_path](#input\_alternative\_path) | Use an alternative path for all files produced internally | `string` | `""` | no | None | 146 | | [assume\_role\_arn](#input\_assume\_role\_arn) | The ARN of the role being assumed (optional).

The optional ARN must match the format documented in https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html. | `string` | `""` | no | The optional ARN must match the format documented in https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html. | 147 | | [aws\_cli\_commands](#input\_aws\_cli\_commands) | The AWS CLI command, subcommands, and options.

For options that can accept a value, then the following examples are both fine to use:
1. `"--option", "value"`
2. `"--option=value"`

In the event that the value contains a space, it must be wrapped with quotes.
1. `"--option", "'value with a space wrapped in single quotes'"`
2. `"--option='value with a space wrapped in single quotes'"` | `list(string)` | n/a | yes | None | 148 | | [aws\_cli\_query](#input\_aws\_cli\_query) | The `--query` value for the AWS CLI call.

The value for `var.aws_cli_query` is based upon JMESPath, and you can get good information from https://jmespath.org.
If not supplied, then the entire results from the AWS CLI call will be returned. | `string` | `""` | no | None | 149 | | [external\_id](#input\_external\_id) | External id for assuming the role (optional).

The length of optional external\_id, when supplied, must be between 2 and 1224 characters.
The optional external\_id can only contain upper- and lower-case alphanumeric characters with no spaces. You can also include underscores or any of the following characters: `=,.@-`.
The optional external\_id match the regular expression `^[\w=,.@-]*$`. | `string` | `""` | no | The length of optional external\_id, when supplied, must be between 2 and 1224 characters.
The optional external\_id must match the regular expression '^[\w=,.@-]*$'. | 150 | | [profile](#input\_profile) | The specific AWS profile to use (must be configured appropriately and is optional).

The optional profile must start with a letter and can only contain letters, numbers, hyphens, and underscores. | `string` | `""` | no | The optional profile must start with a letter and can only contain letters, numbers, hyphens, and underscores. | 151 | | [region](#input\_region) | The specific AWS region to use.

The region must start with two letters representing the geographical area, followed by one or more letters or digits representing the specific region within that area. | `string` | `""` | no | The optional region must start with two letters representing the geographical area, followed by one or more letters or digits representing the specific region within that area. | 152 | | [role\_session\_name](#input\_role\_session\_name) | The role session name that will be used when assuming a role (optional)

The length of the optional role session name, when supplied, must be between 2 and 64 characters.
The optional role session name can only contain upper- and lower-case alphanumeric characters with no spaces. You can also include underscores or any of the following characters: `=,.@-`.
The optional role session name match the regular expression `^[\w=,.@-]*$`.

If the assume\_role\_arn is supplied, but the role\_session\_name is left empty, an internal default of "AssumingRole" will be used. | `string` | `""` | no | The length of the optional role session name, when supplied, must be between 2 and 64 characters.
The role session name match the regular expression '^[\w=,.@-]*$'. | 153 | 154 | ## Outputs 155 | 156 | | Name | Description | 157 | |------|-------------| 158 | | [result](#output\_result) | The output of the AWS CLI command, if it can be JSON decoded | 159 | | [result\_raw](#output\_result\_raw) | The raw, non JSON decoded output of the AWS CLI command | 160 | | [result\_was\_decoded](#output\_result\_was\_decoded) | Can the output from the AWS CLI command can be JSON decoded | 161 | 162 | 163 | # Docker 164 | 165 | To help with getting this running in a pipeline that uses Docker, the image [digiticketsgroup/terraforming](https://hub.docker.com/repository/docker/digiticketsgroup/terraforming) has Terraform, AWSCLI, and jq all ready to go. 166 | 167 | If you want to build or adapt your own image, then the Dockerfile below is how that image has been built. 168 | 169 | ```Dockerfile 170 | # Based upon https://github.com/aws/aws-cli/blob/2.0.10/docker/Dockerfile 171 | FROM amazonlinux:2 as installer 172 | ARG TERRAFORM_VERSION 173 | RUN yum update -y \ 174 | && yum install -y unzip \ 175 | && curl https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip -o awscli-exe-linux-x86_64.zip \ 176 | && unzip awscli-exe-linux-x86_64.zip \ 177 | # The --bin-dir is specified so that we can copy the 178 | # entire bin directory from the installer stage into 179 | # into /usr/local/bin of the final stage without 180 | # accidentally copying over any other executables that 181 | # may be present in /usr/local/bin of the installer stage. 182 | && ./aws/install --bin-dir /aws-cli-bin/ \ 183 | && curl "https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip" -o terraform.zip \ 184 | && unzip terraform.zip 185 | 186 | FROM amazonlinux:2 187 | COPY --from=installer /usr/local/aws-cli/ /usr/local/aws-cli/ 188 | COPY --from=installer /aws-cli-bin/ /usr/local/bin/ 189 | COPY --from=installer terraform /usr/bin/ 190 | RUN yum update -y \ 191 | && yum install -y less groff jq \ 192 | && yum clean all 193 | 194 | ENTRYPOINT ["/bin/sh"] 195 | ``` 196 | -------------------------------------------------------------------------------- /main.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | joined_aws_cli_command = join(" ", var.aws_cli_commands) 3 | external_program_query = { 4 | assume_role_arn = var.assume_role_arn 5 | role_session_name = length(var.assume_role_arn) > 0 ? var.role_session_name : "" 6 | aws_cli_commands = local.joined_aws_cli_command 7 | aws_cli_query = var.aws_cli_query 8 | external_id = var.external_id 9 | profile = var.profile 10 | region = var.region 11 | } 12 | standard_results_file = format("%s/temp/%s/results.json", path.module, md5(join("-", values(local.external_program_query)))) 13 | alternative_results_file = format("%s/results.json", var.alternative_path) 14 | results_file = length(var.alternative_path) == 0 ? local.standard_results_file : local.alternative_results_file 15 | } 16 | 17 | data "external" "awscli_program" { 18 | program = [ 19 | format("%s/scripts/aws_cli_runner.sh", path.module), 20 | local.results_file 21 | ] 22 | query = local.external_program_query 23 | } 24 | 25 | # Due to the way the Terraform External Provider has various limitations on processing the output of an external 26 | # program, the script that is called creates a separate file and is then referenced via a local_file data block. 27 | # Amongst the chief benefits is that all the data types returned from AWS are not converted to strings for Terraform to 28 | # access. 29 | data "local_file" "awscli_results_file" { 30 | depends_on = [data.external.awscli_program] 31 | filename = local.results_file 32 | 33 | lifecycle { 34 | postcondition { 35 | condition = try(jsondecode(self.content).error, false) == false 36 | error_message = try(jsondecode(self.content).error, "Unknown error") 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /outputs.tf: -------------------------------------------------------------------------------- 1 | output "result" { 2 | depends_on = [data.local_file.awscli_results_file] 3 | description = "The output of the AWS CLI command, if it can be JSON decoded" 4 | value = try(jsondecode(data.local_file.awscli_results_file.content), "") 5 | } 6 | 7 | output "result_raw" { 8 | depends_on = [data.local_file.awscli_results_file] 9 | description = "The raw, non JSON decoded output of the AWS CLI command" 10 | value = data.local_file.awscli_results_file.content 11 | } 12 | 13 | output "result_was_decoded" { 14 | depends_on = [data.local_file.awscli_results_file] 15 | description = "Can the output from the AWS CLI command can be JSON decoded" 16 | value = can(jsondecode(data.local_file.awscli_results_file.content)) 17 | } 18 | -------------------------------------------------------------------------------- /scripts/aws_cli_runner.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Validate required commands 4 | if [ ! -x "$(command -v aws)" ]; then 5 | echo '{"error":"aws cli is not installed"}' 6 | exit 1 7 | fi 8 | if [ ! -x "$(command -v jq)" ]; then 9 | echo '{"error":"jq is not installed"}' 10 | exit 2 11 | fi 12 | 13 | # Validate required results file as the first argument 14 | if [ -z "${1}" ]; then 15 | echo '{"error":"No results filename supplied"}' 16 | exit 3 17 | fi 18 | 19 | # Extract directory from results file name for all logs. 20 | RESULTS_FILE="${1}" 21 | ROOT_DIRECTORY=$(dirname "${RESULTS_FILE}") 22 | 23 | # Build all the paths for all the files. 24 | ## JQ json and error log 25 | JQ_JSON="${ROOT_DIRECTORY}/jq_data.json" 26 | JQ_ERROR_LOG="${ROOT_DIRECTORY}/jq_error.log" 27 | 28 | ## AWS STS json and error log 29 | AWS_STS_JSON="${ROOT_DIRECTORY}/aws_sts.json" 30 | AWS_STS_ERROR_LOG="${ROOT_DIRECTORY}/aws_sts_error.log" 31 | 32 | ## The actual AWS call json and error log 33 | AWS_CALL_JSON="${ROOT_DIRECTORY}/aws_call.json" 34 | AWS_CALL_ERROR_LOG="${ROOT_DIRECTORY}/aws_call_error.log" 35 | 36 | # Remove any files that would match the above list 37 | mkdir -p "${ROOT_DIRECTORY}" 38 | rm -rf \ 39 | "${JQ_JSON}" \ 40 | "${JQ_ERROR_LOG}" \ 41 | "${AWS_STS_JSON}" \ 42 | "${AWS_STS_ERROR_LOG}" \ 43 | "${AWS_CALL_JSON}" \ 44 | "${AWS_CALL_ERROR_LOG}" \ 45 | "${RESULTS_FILE}" \ 46 | 47 | # Get the query and store it 48 | jq -Mcr . >"${JQ_JSON}" 2>"${JQ_ERROR_LOG}" 49 | 50 | # Extract the query attributes 51 | AWS_CLI_COMMANDS=$( jq -r '.aws_cli_commands' "${JQ_JSON}" 2>>"${JQ_ERROR_LOG}") 52 | AWS_CLI_QUERY=$( jq -r '.aws_cli_query' "${JQ_JSON}" 2>>"${JQ_ERROR_LOG}") 53 | ASSUME_ROLE_ARN=$( jq -r '.assume_role_arn' "${JQ_JSON}" 2>>"${JQ_ERROR_LOG}") 54 | ROLE_SESSION_NAME=$(jq -r '.role_session_name' "${JQ_JSON}" 2>>"${JQ_ERROR_LOG}") 55 | EXTERNAL_ID=$( jq -r '.external_id' "${JQ_JSON}" 2>>"${JQ_ERROR_LOG}") 56 | PROFILE_NAME=$( jq -r '.profile' "${JQ_JSON}" 2>>"${JQ_ERROR_LOG}") 57 | REGION_NAME=$( jq -r '.region' "${JQ_JSON}" 2>>"${JQ_ERROR_LOG}") 58 | KEEP_LOGS=$( jq -r '.keep_logs' "${JQ_JSON}" 2>>"${JQ_ERROR_LOG}") 59 | 60 | # Build the required parameters for the AWS calls. 61 | 62 | ## Do we have a profile? 63 | if [ -n "${PROFILE_NAME}" ]; then 64 | AWS_CLI_PROFILE_PARAM="--profile=${PROFILE_NAME}" 65 | fi 66 | 67 | ## Do we have a region? 68 | if [ -n "${REGION_NAME}" ]; then 69 | AWS_CLI_REGION_PARAM="--region=${REGION_NAME}" 70 | fi 71 | 72 | ## Do we need to assume a role? 73 | if [ -n "${ASSUME_ROLE_ARN}" ]; then 74 | 75 | ### Do we have an external ID? 76 | if [ -n "${EXTERNAL_ID}" ]; then 77 | AWS_CLI_EXTERNAL_ID_PARAM="--external-id=${EXTERNAL_ID}" 78 | fi 79 | 80 | ### Get temporary credentials from AWS STS 81 | if ! eval "aws sts assume-role \ 82 | --role-arn ${ASSUME_ROLE_ARN} \ 83 | ${AWS_CLI_EXTERNAL_ID_PARAM:-} \ 84 | --role-session-name ${ROLE_SESSION_NAME:-AssumingRole} \ 85 | --output json \ 86 | --debug \ 87 | ${AWS_CLI_PROFILE_PARAM:-} \ 88 | ${AWS_CLI_REGION_PARAM:-} \ 89 | " \ 90 | >"${AWS_STS_JSON}" \ 91 | 2>"${AWS_STS_ERROR_LOG}"; then 92 | echo '{"error":"The call to AWS to get temporary credentials failed"}' >&2 93 | exit 4 94 | fi 95 | export AWS_ACCESS_KEY_ID=$(jq -r '.Credentials.AccessKeyId' "$AWS_STS_JSON") 96 | export AWS_SECRET_ACCESS_KEY=$(jq -r '.Credentials.SecretAccessKey' "$AWS_STS_JSON") 97 | export AWS_SESSION_TOKEN=$(jq -r '.Credentials.SessionToken' "$AWS_STS_JSON") 98 | 99 | ### Having assumed a role, drop the profile as that will override any credentials retrieved by the assumed role when 100 | ### reused as part of the AWS CLI call. 101 | ### References : 102 | ### 1. https://github.com/digitickets/terraform-aws-cli/issues/11 - Thank you Garrett Blinkhorn. 103 | ### 2. https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_use-resources.html#using-temp-creds-sdk-cli 104 | unset AWS_CLI_PROFILE_PARAM 105 | fi 106 | 107 | # Do we have a query? 108 | if [ -n "${AWS_CLI_QUERY}" ]; then 109 | AWS_CLI_QUERY_PARAM="--query='${AWS_CLI_QUERY}'" 110 | fi 111 | 112 | # Disable any assigned pager 113 | export AWS_PAGER="" 114 | 115 | # Configure adaptive retry mode 116 | export AWS_RETRY_MODE=adaptive 117 | 118 | # Run the AWS_CLI command 119 | AWS_COMMAND_LINE="" 120 | if ! eval "aws \ 121 | ${AWS_CLI_COMMANDS} \ 122 | ${AWS_CLI_PROFILE_PARAM:-} \ 123 | ${AWS_CLI_REGION_PARAM:-} \ 124 | ${AWS_CLI_QUERY_PARAM:-} \ 125 | --output json \ 126 | " \ 127 | >"${AWS_CALL_JSON}" \ 128 | 2> "${AWS_CALL_ERROR_LOG}"; then 129 | # Convert the error into a JSON string and exit 130 | jq -MRcs '{"error":gsub("^\n+|\n+$"; "")}' "${AWS_CALL_ERROR_LOG}" > "${RESULTS_FILE}" 131 | cat "${RESULTS_FILE}" 132 | exit 0 133 | fi 134 | 135 | # All is good. 136 | cp "${AWS_CALL_JSON}" "${RESULTS_FILE}" 137 | echo '{"result":"'"${RESULTS_FILE}"'"}' 138 | 139 | # Clean up, but allow a test mode to retain all files except the result 140 | if [ "${MODULE_TERRAFORM_AWS_CLI_RETAIN_LOGS}" != "true" ]; then 141 | rm -rf \ 142 | "${JQ_JSON}" \ 143 | "${JQ_ERROR_LOG}" \ 144 | "${AWS_STS_JSON}" \ 145 | "${AWS_STS_ERROR_LOG}" \ 146 | "${AWS_CALL_JSON}" \ 147 | "${AWS_CALL_ERROR_LOG}" 148 | fi 149 | -------------------------------------------------------------------------------- /scripts/terraform-module-support.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o pipefail 4 | 5 | # Get the branch being pushed 6 | current_branch=$(git rev-parse --abbrev-ref HEAD) 7 | 8 | # Exit early if the current branch is master 9 | if [ "$current_branch" = "master" ]; then 10 | exit 0 11 | fi 12 | 13 | # Check if CHANGELOG.md is in the list of files supplied by the pre-commit application. 14 | if ! echo "$@" | grep -q "CHANGELOG.md"; then 15 | echo "Warning: You are pushing to '$current_branch' without modifying CHANGELOG.md." 16 | echo "Consider updating the CHANGELOG.md before pushing." 17 | echo "" 18 | echo "You can use the --no-verify option to ignore this restriction." 19 | exit 1 # Fails the push 20 | fi 21 | 22 | exit 0 23 | -------------------------------------------------------------------------------- /scripts/tflint-support.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o pipefail 4 | 5 | validate_credentials() { 6 | if [[ "$AWS_SESSION_TOKEN" == "" ]]; then 7 | echo 'Missing or expired AWS credentials.' >&2 8 | echo 'This may cause TFLint to fail.' >&2 9 | exit 1 10 | fi 11 | } 12 | 13 | setup_tflint() { 14 | terraform-config-inspect --json . | 15 | jq -r ' 16 | [.required_providers[].aliases] 17 | | flatten 18 | | del(.[] | select(. == null)) 19 | | reduce .[] as $entry ( 20 | {}; 21 | .provider[$entry.name] //= [] 22 | | .provider[$entry.name] += [{"alias": $entry.alias}] 23 | )' > aliased-providers.tf.json || true 24 | } 25 | 26 | teardown_tflint() { 27 | rm -f aliased-providers.tf.json 28 | } 29 | 30 | # Check if a function name was provided 31 | if [[ $# -eq 0 ]]; then 32 | echo "Usage: $0 {setup|teardown}" 33 | exit 1 34 | fi 35 | 36 | # Call the function based on the first argument 37 | case "$1" in 38 | setup) 39 | setup_tflint 40 | validate_credentials 41 | ;; 42 | teardown) 43 | teardown_tflint 44 | ;; 45 | *) 46 | echo "Invalid argument: $1" 47 | echo "Usage: $0 {setup|teardown}" 48 | exit 1 49 | ;; 50 | esac 51 | -------------------------------------------------------------------------------- /tests/Require reworking/script_removes_all_files/expected_plan_errors.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "variable": "data.local_file.awscli_results_file", 4 | "problems": [ 5 | "An error occurred (AccessDenied) when calling the ListObjects operation: Access Denied" 6 | ] 7 | } 8 | ] 9 | -------------------------------------------------------------------------------- /tests/Require reworking/script_removes_all_files/expected_variables.json: -------------------------------------------------------------------------------- 1 | { 2 | "alternative_path": "test-reports/script_removes_all_files/aws", 3 | "assume_role_arn": "", 4 | "aws_cli_commands": [ 5 | "s3api", 6 | "list-objects", 7 | "--bucket=ryft-public-sample-data", 8 | "--no-sign-request" 9 | ], 10 | "aws_cli_query": "max_by(Contents, &Size)", 11 | "external_id": "", 12 | "profile": "", 13 | "region": "eu-west-1", 14 | "role_session_name": "" 15 | } 16 | -------------------------------------------------------------------------------- /tests/Require reworking/script_removes_all_files/terraform.tfvars: -------------------------------------------------------------------------------- 1 | aws_cli_commands = ["s3api", "list-objects", "--bucket=ryft-public-sample-data", "--no-sign-request"] 2 | aws_cli_query = "max_by(Contents, &Size)" 3 | region = "eu-west-1" 4 | 5 | alternative_path = "test-reports/script_removes_all_files/aws" 6 | -------------------------------------------------------------------------------- /tests/Require reworking/script_removes_all_files/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export ALLOW_APPLY=true 4 | 5 | function test_setup() { 6 | export MODULE_TERRAFORM_AWS_CLI_RETAIN_LOGS=false 7 | } 8 | 9 | function test_teardown() { 10 | echo "MODULE_TERRAFORM_AWS_CLI_RETAIN_LOGS = ${MODULE_TERRAFORM_AWS_CLI_RETAIN_LOGS}" 11 | ROOT_DIRECTORY="test-reports/${TEST_NAME}/aws" 12 | 13 | # Build all the paths for all the files. 14 | 15 | ## Results file 16 | RESULTS_FILE="${ROOT_DIRECTORY}/results.json" 17 | 18 | ## JQ json and error log 19 | JQ_JSON="${ROOT_DIRECTORY}/jq_data.json" 20 | JQ_ERROR_LOG="${ROOT_DIRECTORY}/jq_error.log" 21 | 22 | ## AWS STS json and error log 23 | AWS_STS_JSON="${ROOT_DIRECTORY}/aws_sts.json" 24 | AWS_STS_ERROR_LOG="${ROOT_DIRECTORY}/aws_sts_error.log" 25 | 26 | ## The actual AWS call json and error log 27 | AWS_CALL_JSON="${ROOT_DIRECTORY}/aws_call.json" 28 | AWS_CALL_ERROR_LOG="${ROOT_DIRECTORY}/aws_call_error.log" 29 | 30 | AWS_SCRIPT_FILENAMES=( 31 | "${JQ_JSON}" "${JQ_ERROR_LOG}" 32 | "${AWS_STS_JSON}" "${AWS_STS_ERROR_LOG}" 33 | "${AWS_CALL_JSON}" "${AWS_CALL_ERROR_LOG}" 34 | ) 35 | 36 | TEST_PASSED=true 37 | for AWS_SCRIPT_FILENAME in "${AWS_SCRIPT_FILENAMES[@]}"; do 38 | if [ -f "${AWS_SCRIPT_FILENAME}" ]; then 39 | echo "Failed to remove '${AWS_SCRIPT_FILENAME}'" | indent 40 | TEST_PASSED=false 41 | fi 42 | done 43 | 44 | if [ ! -f "${RESULTS_FILE}" ]; then 45 | echo "Failed to retain '${RESULTS_FILE}'" | indent 46 | TEST_PASSED=false 47 | fi 48 | 49 | if [ "${TEST_PASSED}" != "true" ]; then 50 | echo "Failed : $TEST_PATH" 51 | exit 1; 52 | fi 53 | } 54 | 55 | . tests/common.sh $0 56 | -------------------------------------------------------------------------------- /tests/Require reworking/script_retains_all_files/expected_plan_errors.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "variable": "data.local_file.awscli_results_file", 4 | "problems": [ 5 | "An error occurred (AccessDenied) when calling the ListObjects operation: Access Denied" 6 | ] 7 | } 8 | ] 9 | -------------------------------------------------------------------------------- /tests/Require reworking/script_retains_all_files/expected_variables.json: -------------------------------------------------------------------------------- 1 | { 2 | "alternative_path": "test-reports/script_retains_all_files/aws", 3 | "assume_role_arn": "", 4 | "aws_cli_commands": [ 5 | "s3api", 6 | "list-objects", 7 | "--bucket=ryft-public-sample-data", 8 | "--no-sign-request" 9 | ], 10 | "aws_cli_query": "max_by(Contents, &Size)", 11 | "external_id": "", 12 | "profile": "", 13 | "region": "eu-west-1", 14 | "role_session_name": "" 15 | } 16 | -------------------------------------------------------------------------------- /tests/Require reworking/script_retains_all_files/terraform.tfvars: -------------------------------------------------------------------------------- 1 | aws_cli_commands = ["s3api", "list-objects", "--bucket=ryft-public-sample-data", "--no-sign-request"] 2 | aws_cli_query = "max_by(Contents, &Size)" 3 | region = "eu-west-1" 4 | 5 | alternative_path = "test-reports/script_retains_all_files/aws" 6 | -------------------------------------------------------------------------------- /tests/Require reworking/script_retains_all_files/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export ALLOW_APPLY=true 4 | 5 | function test_teardown() { 6 | ROOT_DIRECTORY="test-reports/${TEST_NAME}/aws" 7 | 8 | # Build all the paths for all the files. 9 | 10 | ## Results file 11 | RESULTS_FILE="${ROOT_DIRECTORY}/results.json" 12 | 13 | ## JQ json and error log 14 | JQ_JSON="${ROOT_DIRECTORY}/jq_data.json" 15 | JQ_ERROR_LOG="${ROOT_DIRECTORY}/jq_error.log" 16 | 17 | ## AWS STS json and error log 18 | AWS_STS_JSON="${ROOT_DIRECTORY}/aws_sts.json" 19 | AWS_STS_ERROR_LOG="${ROOT_DIRECTORY}/aws_sts_error.log" 20 | 21 | ## The actual AWS call json and error log 22 | AWS_CALL_JSON="${ROOT_DIRECTORY}/aws_call.json" 23 | AWS_CALL_ERROR_LOG="${ROOT_DIRECTORY}/aws_call_error.log" 24 | 25 | # Not all the files are created as the test does not generate these errors 26 | AWS_SCRIPT_FILENAMES=( 27 | "${JQ_JSON}" "${JQ_ERROR_LOG}" 28 | "${AWS_STS_JSON}" "${AWS_STS_ERROR_LOG}" 29 | "${AWS_CALL_JSON}" "${AWS_CALL_ERROR_LOG}" 30 | ) 31 | 32 | TEST_PASSED=true 33 | for AWS_SCRIPT_FILENAME in "${AWS_SCRIPT_FILENAMES[@]}"; do 34 | if [[ ! -f "${AWS_SCRIPT_FILENAME}" ]]; then 35 | echo "Failed to retain '${AWS_SCRIPT_FILENAME}'" | indent 36 | TEST_PASSED=false 37 | fi 38 | done 39 | 40 | if [ ! -f "${RESULTS_FILE}" ]; then 41 | echo "Failed to retain '${RESULTS_FILE}'" | indent 42 | TEST_PASSED=false 43 | fi 44 | 45 | if [ "${TEST_PASSED}" != "true" ]; then 46 | exit 1; 47 | fi 48 | } 49 | 50 | . tests/common.sh $0 51 | -------------------------------------------------------------------------------- /tests/Require reworking/test_data_retrieval_with_empty_result/expected_variables.json: -------------------------------------------------------------------------------- 1 | { 2 | "alternative_path": "test-reports/test_data_retrieval_with_empty_result/aws", 3 | "assume_role_arn": "", 4 | "aws_cli_commands": [ 5 | "guardduty", 6 | "update-detector", 7 | "--finding-publishing-frequency", 8 | "ONE_HOUR", 9 | "--detector-id=" 10 | ], 11 | "aws_cli_query": "", 12 | "external_id": "", 13 | "profile": "", 14 | "region": "", 15 | "role_session_name": "empty_result" 16 | } 17 | -------------------------------------------------------------------------------- /tests/Require reworking/test_data_retrieval_with_empty_result/terraform.tfvars: -------------------------------------------------------------------------------- 1 | // An empty result from AWS 2 | aws_cli_commands = [ 3 | "guardduty", 4 | "update-detector", 5 | "--finding-publishing-frequency", 6 | "ONE_HOUR", 7 | "--detector-id=" 8 | ] 9 | role_session_name = "empty_result" 10 | 11 | alternative_path = "test-reports/test_data_retrieval_with_empty_result/aws" 12 | -------------------------------------------------------------------------------- /tests/Require reworking/test_data_retrieval_with_empty_result/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | function test_setup() { 4 | if [ -f .env ]; then 5 | . .env 6 | export ALLOW_APPLY=true 7 | 8 | EXISTING_DETECTOR_ID=$(aws guardduty list-detectors --query='DetectorIds[0]' | jq -cr .) 9 | 10 | if [ "${EXISTING_DETECTOR_ID}" == "null" ]; then 11 | DETECTOR_ID=$(aws guardduty create-detector --enable --output json | jq -r '.DetectorId') 12 | echo "Created detector : ${DETECTOR_ID}" | indent 13 | else 14 | DETECTOR_ID=${EXISTING_DETECTOR_ID} 15 | echo "Reusing detector : ${DETECTOR_ID}" | indent 16 | fi 17 | 18 | sed -i.bak 's/"--detector-id=.*"/"--detector-id='${DETECTOR_ID}'"/' $(dirname $0)/terraform.tfvars 19 | sed -i.bak 's/"--detector-id=.*"/"--detector-id='${DETECTOR_ID}'"/' $(dirname $0)/expected_variables.json 20 | rm -rf $(dirname $0)/terraform.tfvars.bak 21 | rm -rf $(dirname $0)/expected_variables.json.bak 22 | 23 | else 24 | export ALLOW_PLAN=false 25 | export ALLOW_APPLY=false 26 | echo 'Test skipped as AWS credentials are required in the .env file.' | indent 27 | fi 28 | } 29 | 30 | function test_teardown() { 31 | if [ -f .env ]; then 32 | aws guardduty delete-detector --detector-id $DETECTOR_ID 33 | echo "Deleted detector : ${DETECTOR_ID}" | indent 34 | 35 | DETECTOR_ID=01234567890123456789012345678901 36 | sed -i.bak 's/"--detector-id=.*"/"--detector-id='${DETECTOR_ID}'"/' $(dirname $0)/terraform.tfvars 37 | sed -i.bak 's/"--detector-id=.*"/"--detector-id='${DETECTOR_ID}'"/' $(dirname $0)/expected_variables.json 38 | rm -rf $(dirname $0)/terraform.tfvars.bak 39 | rm -rf $(dirname $0)/expected_variables.json.bak 40 | fi 41 | } 42 | 43 | . tests/common.sh $0 44 | -------------------------------------------------------------------------------- /tests/aws_error_profile_does_not_exist/expected_plan_errors.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "variable": "data.local_file.awscli_results_file", 4 | "problems": [ 5 | "The config profile (non-existent-profile) could not be found" 6 | ] 7 | } 8 | ] 9 | -------------------------------------------------------------------------------- /tests/aws_error_profile_does_not_exist/expected_variables.json: -------------------------------------------------------------------------------- 1 | { 2 | "alternative_path": "test-reports/aws_error_profile_does_not_exist/aws", 3 | "assume_role_arn": "", 4 | "aws_cli_commands": [ 5 | "s3api", 6 | "list-objects", 7 | "--bucket=ryft-public-sample-data", 8 | "--no-sign-request" 9 | ], 10 | "aws_cli_query": "max_by(Contents, &Size)", 11 | "external_id": "", 12 | "profile": "non-existent-profile", 13 | "region": "", 14 | "role_session_name": "" 15 | } 16 | -------------------------------------------------------------------------------- /tests/aws_error_profile_does_not_exist/terraform.tfvars: -------------------------------------------------------------------------------- 1 | aws_cli_commands = ["s3api", "list-objects", "--bucket=ryft-public-sample-data", "--no-sign-request"] 2 | aws_cli_query = "max_by(Contents, &Size)" 3 | profile = "non-existent-profile" 4 | 5 | alternative_path = "test-reports/aws_error_profile_does_not_exist/aws" 6 | -------------------------------------------------------------------------------- /tests/aws_error_profile_does_not_exist/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export ALLOW_APPLY=false 4 | 5 | . tests/common.sh $0 6 | -------------------------------------------------------------------------------- /tests/common.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | function underline() { 4 | U="${1//?/${2:--}}" 5 | echo -e "\n$1\n${U:0:${#1}}\n" 6 | } 7 | 8 | function indent() { 9 | if [ ! -z "$1" ]; then 10 | echo "$1" | sed 's/^/ /' 11 | else 12 | cat - | sed 's/^/ /' 13 | fi 14 | } 15 | 16 | function validate_init() { 17 | if [ ! -f "${TERRAFORM_INIT_LOG}" ]; then 18 | echo "FAILED : ${TERRAFORM_INIT_LOG} failed to be created" 19 | echo '' 20 | exit 11; 21 | fi 22 | 23 | if [ -s "${TERRAFORM_INIT_ERROR_LOG}" ]; then 24 | echo "FAILED : ${TERRAFORM_INIT_ERROR_LOG} is not empty" 25 | echo "" 26 | cat ${TERRAFORM_INIT_ERROR_LOG} | indent 27 | echo '' 28 | exit 12; 29 | fi 30 | } 31 | 32 | function validate_plan() { 33 | jq -r ' 34 | .variables | 35 | walk( 36 | if type == "object" and has("value") then 37 | .value 38 | else 39 | . 40 | end 41 | ) 42 | ' "${TERRAFORM_PLAN_SHOW_JSON}" > "${TERRAFORM_PLAN_SHOW_EXTRACTED_VARIABLES_JSON}" 43 | 44 | if [ -f "${EXPECTED_VARIABLES}" ]; then 45 | DIFFERENCE_IN_EXPECTED_VARIABLES=$(diff -U 3 -W 120 --suppress-common-lines "${EXPECTED_VARIABLES}" "${TERRAFORM_PLAN_SHOW_EXTRACTED_VARIABLES_JSON}") 46 | if [ ! -z "${DIFFERENCE_IN_EXPECTED_VARIABLES}" ]; then 47 | echo 'FAILED : Difference in expected variables' 48 | echo "${DIFFERENCE_IN_EXPECTED_VARIABLES}" | indent 49 | echo '' 50 | exit 21 51 | else 52 | echo 'Variables processed successfully' | indent 53 | fi 54 | fi 55 | 56 | jq -r ' 57 | [ 58 | .checks[] | 59 | select(.status == "fail") | 60 | { 61 | variable: .address.to_display, 62 | problems: .instances[].problems[].message 63 | } 64 | ] | 65 | group_by(.variable) | 66 | map( 67 | { 68 | variable: .[0].variable, 69 | problems: map(.problems) 70 | } 71 | ) | 72 | select(length > 0) 73 | ' "${TERRAFORM_PLAN_SHOW_JSON}" > "${TERRAFORM_PLAN_SHOW_EXTRACTED_ERRORS_JSON}" 74 | 75 | if [ -f "${EXPECTED_ERRORS}" ]; then 76 | DIFFERENCE_IN_EXPECTED_ERRORS=$(diff -U 3 -W 120 --suppress-common-lines "${EXPECTED_ERRORS}" "${TERRAFORM_PLAN_SHOW_EXTRACTED_ERRORS_JSON}") 77 | if [ ! -z "${DIFFERENCE_IN_EXPECTED_ERRORS}" ]; then 78 | echo 'FAILED : Difference in expected errors' 79 | echo "${DIFFERENCE_IN_EXPECTED_ERRORS}" | indent 80 | echo '' 81 | exit 22 82 | else 83 | echo 'Expected errors generated successfully' | indent 84 | fi 85 | else 86 | if [ -s "${TERRAFORM_PLAN_SHOW_EXTRACTED_ERRORS_JSON}" ]; then 87 | echo 'FAILED : Generated unexpected errors' 88 | cat "${TERRAFORM_PLAN_SHOW_EXTRACTED_ERRORS_JSON}" | indent 89 | echo '' 90 | exit 23 91 | else 92 | echo 'No unexpected errors generated' | indent 93 | fi 94 | fi 95 | } 96 | 97 | function validate_apply() { 98 | jq -r ' 99 | .values.outputs | 100 | walk( 101 | if type == "object" and has("value") then 102 | .value 103 | else 104 | . 105 | end 106 | ) 107 | ' "${TERRAFORM_APPLY_SHOW_JSON}" > "${TERRAFORM_APPLY_SHOW_EXTRACTED_OUTPUTS_JSON}" 108 | 109 | if [ -f "${EXPECTED_OUTPUTS}" ]; then 110 | DIFFERENCE_IN_EXPECTED_OUTPUTS=$(diff -U 3 -W 120 --suppress-common-lines "${EXPECTED_OUTPUTS}" "${TERRAFORM_APPLY_SHOW_EXTRACTED_OUTPUTS_JSON}") 111 | if [ ! -z "${DIFFERENCE_IN_EXPECTED_OUTPUTS}" ]; then 112 | echo 'FAILED : Difference in expected outputs' 113 | echo "${DIFFERENCE_IN_EXPECTED_OUTPUTS}" | indent 114 | echo '' 115 | exit 31 116 | else 117 | echo 'Expected outputs generated successfully' | indent 118 | fi 119 | else 120 | if [ -s "${TERRAFORM_APPLY_SHOW_EXTRACTED_OUTPUTS_JSON}" ]; then 121 | echo 'FAILED : Generated unexpected outputs' 122 | cat "${TERRAFORM_APPLY_SHOW_EXTRACTED_OUTPUTS_JSON}" | indent 123 | echo '' 124 | exit 32 125 | else 126 | echo 'No unexpected outputs generated' | indent 127 | fi 128 | fi 129 | } 130 | 131 | function run_function() { 132 | function_name="${1:-true}" 133 | 134 | if type -t "$function_name" > /dev/null; then 135 | echo "Running : $function_name" | indent 136 | "$function_name" 137 | fi 138 | } 139 | 140 | function common_setup() { 141 | TEST_PATH=$(dirname "${1}") 142 | TEST_NAME=$(basename "${TEST_PATH}") 143 | 144 | echo "Start : ${TEST_PATH}" 145 | 146 | TERRAFORM_TFVARS="${TEST_PATH}/terraform.tfvars" 147 | EXPECTED_VARIABLES="${TEST_PATH}/expected_variables.json" 148 | EXPECTED_ERRORS="${TEST_PATH}/expected_plan_errors.json" 149 | EXPECTED_OUTPUTS="${TEST_PATH}/expected_apply_outputs.json" 150 | 151 | ROOT_DIRECTORY="test-reports/${TEST_NAME}/terraform" 152 | mkdir -p "${ROOT_DIRECTORY}" 153 | 154 | ## Terraform init output, errors, and trace 155 | TERRAFORM_INIT_LOG="${ROOT_DIRECTORY}/init.log" 156 | TERRAFORM_INIT_ERROR_LOG="${ROOT_DIRECTORY}/init_error.log" 157 | TERRAFORM_INIT_TRACE_LOG="${ROOT_DIRECTORY}/init_trace.log" 158 | 159 | ## Terraform plan output, errors, and trace 160 | TERRAFORM_PLAN="${ROOT_DIRECTORY}/terraform.plan" 161 | TERRAFORM_PLAN_LOG="${ROOT_DIRECTORY}/plan.log" 162 | TERRAFORM_PLAN_ERROR_LOG="${ROOT_DIRECTORY}/plan_error.log" 163 | TERRAFORM_PLAN_TRACE_LOG="${ROOT_DIRECTORY}/plan_trace.log" 164 | 165 | ## Terraform show json, errors, and trace from plan 166 | TERRAFORM_PLAN_SHOW_JSON="${ROOT_DIRECTORY}/plan_show.json" 167 | TERRAFORM_PLAN_SHOW_ERROR_LOG="${ROOT_DIRECTORY}/plan_show_error.log" 168 | TERRAFORM_PLAN_SHOW_TRACE_LOG="${ROOT_DIRECTORY}/plan_show_trace.log" 169 | 170 | ## Extracted data 171 | TERRAFORM_PLAN_SHOW_EXTRACTED_VARIABLES_JSON="${ROOT_DIRECTORY}/plan_show_extracted_variables.json" 172 | TERRAFORM_PLAN_SHOW_EXTRACTED_ERRORS_JSON="${ROOT_DIRECTORY}/plan_show_extracted_errors.json" 173 | TERRAFORM_APPLY_SHOW_EXTRACTED_OUTPUTS_JSON="${ROOT_DIRECTORY}/apply_show_extracted_outputs.json" 174 | 175 | ## Terraform apply output, errors, and trace 176 | TERRAFORM_APPLY_STATE_FILE="${ROOT_DIRECTORY}/terraform.state" 177 | TERRAFORM_APPLY_LOG="${ROOT_DIRECTORY}/apply.log" 178 | TERRAFORM_APPLY_ERROR_LOG="${ROOT_DIRECTORY}/apply_error.log" 179 | TERRAFORM_APPLY_TRACE_LOG="${ROOT_DIRECTORY}/apply_trace.log" 180 | 181 | ## Terraform show json, errors, and trace from apply 182 | TERRAFORM_APPLY_SHOW_JSON="${ROOT_DIRECTORY}/apply_show.json" 183 | TERRAFORM_APPLY_SHOW_ERROR_LOG="${ROOT_DIRECTORY}/apply_show_error.log" 184 | TERRAFORM_APPLY_SHOW_TRACE_LOG="${ROOT_DIRECTORY}/apply_show_trace.log" 185 | 186 | # Some tests may not be able to be run 187 | export ALLOW_PLAN=true 188 | 189 | # Tell the AWS Script to hold onto all the log files 190 | export MODULE_TERRAFORM_AWS_CLI_RETAIN_LOGS=true 191 | } 192 | 193 | function run_test() { 194 | if [ "${ALLOW_PLAN}" == "true" ]; then 195 | # Turn off coloured Terraform output (makes logs a little easier to read in an IDE) 196 | export TF_CLI_ARGS="-no-color" 197 | 198 | # Enable full trace mode when running Terraform 199 | export TF_LOG=TRACE 200 | 201 | # Initialise Terraform. 202 | TF_LOG_PATH="${TERRAFORM_INIT_TRACE_LOG}" \ 203 | terraform init \ 204 | >"${TERRAFORM_INIT_LOG}" \ 205 | 2> "${TERRAFORM_INIT_ERROR_LOG}" 206 | validate_init 207 | 208 | TF_LOG_PATH="${TERRAFORM_PLAN_TRACE_LOG}" \ 209 | terraform plan \ 210 | -var-file=${TERRAFORM_TFVARS} \ 211 | -out=${TERRAFORM_PLAN} \ 212 | >"${TERRAFORM_PLAN_LOG}" \ 213 | 2> "${TERRAFORM_PLAN_ERROR_LOG}" 214 | 215 | TF_LOG_PATH="${TERRAFORM_PLAN_SHOW_TRACE_LOG}" \ 216 | terraform show \ 217 | -json \ 218 | "${TERRAFORM_PLAN}" \ 219 | >"${TERRAFORM_PLAN_SHOW_JSON}" 220 | validate_plan 221 | 222 | if [ "${ALLOW_APPLY}" == "true" ]; then 223 | TF_LOG_PATH="${TERRAFORM_APPLY_TRACE_LOG}" \ 224 | terraform apply \ 225 | -auto-approve \ 226 | -backup=- \ 227 | -state-out "${TERRAFORM_APPLY_STATE_FILE}" \ 228 | "${TERRAFORM_PLAN}" \ 229 | > "${TERRAFORM_APPLY_LOG}" \ 230 | 2> "${TERRAFORM_APPLY_ERROR_LOG}" 231 | 232 | TF_LOG_PATH="${TERRAFORM_APPLY_SHOW_TRACE_LOG}" \ 233 | terraform show \ 234 | -json \ 235 | "${TERRAFORM_APPLY_STATE_FILE}" \ 236 | >"${TERRAFORM_APPLY_SHOW_JSON}" \ 237 | 2>"${TERRAFORM_APPLY_SHOW_ERROR_LOG}" 238 | 239 | validate_apply 240 | fi 241 | 242 | run_function test_teardown 243 | 244 | echo "Passed : $TEST_PATH" 245 | else 246 | echo "Skipped : $TEST_PATH" 247 | fi 248 | 249 | echo '' 250 | } 251 | 252 | # Prepare everything for running the test that is common to all tests 253 | common_setup "${1}" 254 | 255 | # Prepare anything specific to the actual test (optional function in the tests test.sh script) 256 | run_function test_setup 257 | 258 | # Run the test! This will also, if required, run the optional test_teardown function if that exists. 259 | run_test 260 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_external_id_invalid_characters/expected_plan_errors.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "variable": "var.external_id", 4 | "problems": [ 5 | "The optional external_id must match the regular expression '^[\\w=,.@-]*$'." 6 | ] 7 | } 8 | ] 9 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_external_id_invalid_characters/expected_variables.json: -------------------------------------------------------------------------------- 1 | { 2 | "alternative_path": "test-reports/terraform_validation_error_external_id_invalid_characters/aws", 3 | "assume_role_arn": "", 4 | "aws_cli_commands": [ 5 | "version" 6 | ], 7 | "aws_cli_query": "", 8 | "external_id": "1 space 2", 9 | "profile": "", 10 | "region": "", 11 | "role_session_name": "" 12 | } 13 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_external_id_invalid_characters/terraform.tfvars: -------------------------------------------------------------------------------- 1 | aws_cli_commands = ["version"] 2 | external_id = "1 space 2" 3 | 4 | alternative_path = "test-reports/terraform_validation_error_external_id_invalid_characters/aws" 5 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_external_id_invalid_characters/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export ALLOW_APPLY=false 4 | 5 | . tests/common.sh $0 6 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_external_id_too_long/expected_plan_errors.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "variable": "var.external_id", 4 | "problems": [ 5 | "The length of optional external_id, when supplied, must be between 2 and 1224 characters." 6 | ] 7 | } 8 | ] 9 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_external_id_too_long/expected_variables.json: -------------------------------------------------------------------------------- 1 | { 2 | "alternative_path": "test-reports/terraform_validation_error_external_id_too_long/aws", 3 | "assume_role_arn": "", 4 | "aws_cli_commands": [ 5 | "version" 6 | ], 7 | "aws_cli_query": "", 8 | "external_id": "a1,b2.c3@d4-e5,f6.g7@h8-i9,j10.k11@l12-m13,n14.o15@p16-q17,r18.s19@t20-u21,v22.w23@x24-y25,z26.A27@B28-C29,D30.E31@F32-G33,H34.I35@J36-K37,L38.M39@N40-O41,P42.Q43@R44-S45,T46.U47@V48-W49,X50.Y51@Z52-a53,b54.c55@d56-e57,f58.g59@h60-i61,j62.k63@l64-m65,n66.o67@p68-q69,r70.s71@t72-u73,v74.w75@x76-y77,z78.A79@B80-C81,D82.E83@F84-G85,H86.I87@J88-K89,L90.M91@N92-O93,P94.Q95@R96-S97,T98.U99@V100-W101,X102.Y103@Z104-a105,b106.c107@d108-e109,f110.g111@h112-i113,j114.k115@l116-m117,n118.o119@p120-q121,r122.s123@t124-u125,v126.w127@x128-y129,z130.A131@B132-C133,D134.E135@F136-G137,H138.I139@J140-K141,L142.M143@N144-O145,P146.Q147@R148-S149,T150.U151@V152-W153,X154.Y155@Z156-a157,b158.c159@d160-e161,f162.g163@h164-i165,j166.k167@l168-m169,n170.o171@p172-q173,r174.s175@t176-u177,v178.w179@x180-y181,z182.A183@B184-C185,D186.E187@F188-G189,H190.I191@J192-K193,L194.M195@N196-O197,P198.Q199@R200-S201,T202.U203@V204-W205,X206.Y207@Z208-a209,b210.c211@d212-e213,f214.g215@h216-i217,j218.k219@l220-m221,n222.o223@p224-q225,r226.s227@t228-u229,v230.w231@x232-y233,z234.A235@B236-C237,D238.E239@F240-G241,H242.I243@J244-K245,L246.M247@N248-O249,P250.Q251@R252-S253,T254.U255@V256-W257,X258.Y259@Z260-a261,b262.c263@d264-e265,f266.g26", 9 | "profile": "", 10 | "region": "", 11 | "role_session_name": "" 12 | } 13 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_external_id_too_long/terraform.tfvars: -------------------------------------------------------------------------------- 1 | aws_cli_commands = ["version"] 2 | external_id = "a1,b2.c3@d4-e5,f6.g7@h8-i9,j10.k11@l12-m13,n14.o15@p16-q17,r18.s19@t20-u21,v22.w23@x24-y25,z26.A27@B28-C29,D30.E31@F32-G33,H34.I35@J36-K37,L38.M39@N40-O41,P42.Q43@R44-S45,T46.U47@V48-W49,X50.Y51@Z52-a53,b54.c55@d56-e57,f58.g59@h60-i61,j62.k63@l64-m65,n66.o67@p68-q69,r70.s71@t72-u73,v74.w75@x76-y77,z78.A79@B80-C81,D82.E83@F84-G85,H86.I87@J88-K89,L90.M91@N92-O93,P94.Q95@R96-S97,T98.U99@V100-W101,X102.Y103@Z104-a105,b106.c107@d108-e109,f110.g111@h112-i113,j114.k115@l116-m117,n118.o119@p120-q121,r122.s123@t124-u125,v126.w127@x128-y129,z130.A131@B132-C133,D134.E135@F136-G137,H138.I139@J140-K141,L142.M143@N144-O145,P146.Q147@R148-S149,T150.U151@V152-W153,X154.Y155@Z156-a157,b158.c159@d160-e161,f162.g163@h164-i165,j166.k167@l168-m169,n170.o171@p172-q173,r174.s175@t176-u177,v178.w179@x180-y181,z182.A183@B184-C185,D186.E187@F188-G189,H190.I191@J192-K193,L194.M195@N196-O197,P198.Q199@R200-S201,T202.U203@V204-W205,X206.Y207@Z208-a209,b210.c211@d212-e213,f214.g215@h216-i217,j218.k219@l220-m221,n222.o223@p224-q225,r226.s227@t228-u229,v230.w231@x232-y233,z234.A235@B236-C237,D238.E239@F240-G241,H242.I243@J244-K245,L246.M247@N248-O249,P250.Q251@R252-S253,T254.U255@V256-W257,X258.Y259@Z260-a261,b262.c263@d264-e265,f266.g26" 3 | 4 | alternative_path = "test-reports/terraform_validation_error_external_id_too_long/aws" 5 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_external_id_too_long/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export ALLOW_APPLY=false 4 | 5 | . tests/common.sh $0 6 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_external_id_too_long_and_invalid_characters/expected_plan_errors.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "variable": "var.external_id", 4 | "problems": [ 5 | "The length of optional external_id, when supplied, must be between 2 and 1224 characters.", 6 | "The optional external_id must match the regular expression '^[\\w=,.@-]*$'." 7 | ] 8 | } 9 | ] 10 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_external_id_too_long_and_invalid_characters/expected_variables.json: -------------------------------------------------------------------------------- 1 | { 2 | "alternative_path": "test-reports/terraform_validation_error_external_id_too_long_and_invalid_characters/aws", 3 | "assume_role_arn": "", 4 | "aws_cli_commands": [ 5 | "version" 6 | ], 7 | "aws_cli_query": "", 8 | "external_id": "a1,b2.c3 d4-e5,f6.g7 h8-i9,j10.k11 l12-m13,n14.o15 p16-q17,r18.s19 t20-u21,v22.w23 x24-y25,z26.A27 B28-C29,D30.E31 F32-G33,H34.I35 J36-K37,L38.M39 N40-O41,P42.Q43 R44-S45,T46.U47 V48-W49,X50.Y51 Z52-a53,b54.c55 d56-e57,f58.g59 h60-i61,j62.k63 l64-m65,n66.o67 p68-q69,r70.s71 t72-u73,v74.w75 x76-y77,z78.A79 B80-C81,D82.E83 F84-G85,H86.I87 J88-K89,L90.M91 N92-O93,P94.Q95 R96-S97,T98.U99 V100-W101,X102.Y103 Z104-a105,b106.c107 d108-e109,f110.g111 h112-i113,j114.k115 l116-m117,n118.o119 p120-q121,r122.s123 t124-u125,v126.w127 x128-y129,z130.A131 B132-C133,D134.E135 F136-G137,H138.I139 J140-K141,L142.M143 N144-O145,P146.Q147 R148-S149,T150.U151 V152-W153,X154.Y155 Z156-a157,b158.c159 d160-e161,f162.g163 h164-i165,j166.k167 l168-m169,n170.o171 p172-q173,r174.s175 t176-u177,v178.w179 x180-y181,z182.A183 B184-C185,D186.E187 F188-G189,H190.I191 J192-K193,L194.M195 N196-O197,P198.Q199 R200-S201,T202.U203 V204-W205,X206.Y207 Z208-a209,b210.c211 d212-e213,f214.g215 h216-i217,j218.k219 l220-m221,n222.o223 p224-q225,r226.s227 t228-u229,v230.w231 x232-y233,z234.A235 B236-C237,D238.E239 F240-G241,H242.I243 J244-K245,L246.M247 N248-O249,P250.Q251 R252-S253,T254.U255 V256-W257,X258.Y259 Z260-a261,b262.c263 d264-e265,f266.g26", 9 | "profile": "", 10 | "region": "", 11 | "role_session_name": "" 12 | } 13 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_external_id_too_long_and_invalid_characters/terraform.tfvars: -------------------------------------------------------------------------------- 1 | aws_cli_commands = ["version"] 2 | external_id = "a1,b2.c3 d4-e5,f6.g7 h8-i9,j10.k11 l12-m13,n14.o15 p16-q17,r18.s19 t20-u21,v22.w23 x24-y25,z26.A27 B28-C29,D30.E31 F32-G33,H34.I35 J36-K37,L38.M39 N40-O41,P42.Q43 R44-S45,T46.U47 V48-W49,X50.Y51 Z52-a53,b54.c55 d56-e57,f58.g59 h60-i61,j62.k63 l64-m65,n66.o67 p68-q69,r70.s71 t72-u73,v74.w75 x76-y77,z78.A79 B80-C81,D82.E83 F84-G85,H86.I87 J88-K89,L90.M91 N92-O93,P94.Q95 R96-S97,T98.U99 V100-W101,X102.Y103 Z104-a105,b106.c107 d108-e109,f110.g111 h112-i113,j114.k115 l116-m117,n118.o119 p120-q121,r122.s123 t124-u125,v126.w127 x128-y129,z130.A131 B132-C133,D134.E135 F136-G137,H138.I139 J140-K141,L142.M143 N144-O145,P146.Q147 R148-S149,T150.U151 V152-W153,X154.Y155 Z156-a157,b158.c159 d160-e161,f162.g163 h164-i165,j166.k167 l168-m169,n170.o171 p172-q173,r174.s175 t176-u177,v178.w179 x180-y181,z182.A183 B184-C185,D186.E187 F188-G189,H190.I191 J192-K193,L194.M195 N196-O197,P198.Q199 R200-S201,T202.U203 V204-W205,X206.Y207 Z208-a209,b210.c211 d212-e213,f214.g215 h216-i217,j218.k219 l220-m221,n222.o223 p224-q225,r226.s227 t228-u229,v230.w231 x232-y233,z234.A235 B236-C237,D238.E239 F240-G241,H242.I243 J244-K245,L246.M247 N248-O249,P250.Q251 R252-S253,T254.U255 V256-W257,X258.Y259 Z260-a261,b262.c263 d264-e265,f266.g26" 3 | 4 | alternative_path = "test-reports/terraform_validation_error_external_id_too_long_and_invalid_characters/aws" 5 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_external_id_too_long_and_invalid_characters/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export ALLOW_APPLY=false 4 | 5 | . tests/common.sh $0 6 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_external_id_too_short/expected_plan_errors.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "variable": "var.external_id", 4 | "problems": [ 5 | "The length of optional external_id, when supplied, must be between 2 and 1224 characters." 6 | ] 7 | } 8 | ] 9 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_external_id_too_short/expected_variables.json: -------------------------------------------------------------------------------- 1 | { 2 | "alternative_path": "test-reports/terraform_validation_error_external_id_too_short/aws", 3 | "assume_role_arn": "", 4 | "aws_cli_commands": [ 5 | "version" 6 | ], 7 | "aws_cli_query": "", 8 | "external_id": "1", 9 | "profile": "", 10 | "region": "", 11 | "role_session_name": "" 12 | } 13 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_external_id_too_short/terraform.tfvars: -------------------------------------------------------------------------------- 1 | aws_cli_commands = ["version"] 2 | external_id = "1" 3 | 4 | alternative_path = "test-reports/terraform_validation_error_external_id_too_short/aws" 5 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_external_id_too_short/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export ALLOW_APPLY=false 4 | 5 | . tests/common.sh $0 6 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_invalid_role_arn/expected_plan_errors.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "variable": "var.assume_role_arn", 4 | "problems": [ 5 | "The optional ARN must match the format documented in https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html." 6 | ] 7 | } 8 | ] 9 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_invalid_role_arn/expected_variables.json: -------------------------------------------------------------------------------- 1 | { 2 | "alternative_path": "test-reports/terraform_validation_error_invalid_role_arn/aws", 3 | "assume_role_arn": "bad_arn", 4 | "aws_cli_commands": [ 5 | "version" 6 | ], 7 | "aws_cli_query": "", 8 | "external_id": "", 9 | "profile": "", 10 | "region": "", 11 | "role_session_name": "" 12 | } 13 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_invalid_role_arn/terraform.tfvars: -------------------------------------------------------------------------------- 1 | assume_role_arn = "bad_arn" 2 | aws_cli_commands = ["version"] 3 | 4 | alternative_path = "test-reports/terraform_validation_error_invalid_role_arn/aws" 5 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_invalid_role_arn/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export ALLOW_APPLY=false 4 | 5 | . tests/common.sh $0 6 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_profile_does_not_match_regex/expected_plan_errors.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "variable": "var.profile", 4 | "problems": [ 5 | "The optional profile must start with a letter and can only contain letters, numbers, hyphens, and underscores." 6 | ] 7 | } 8 | ] 9 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_profile_does_not_match_regex/expected_variables.json: -------------------------------------------------------------------------------- 1 | { 2 | "alternative_path": "test-reports/terraform_validation_error_profile_does_not_match_regex/aws", 3 | "assume_role_arn": "", 4 | "aws_cli_commands": [ 5 | "version" 6 | ], 7 | "aws_cli_query": "", 8 | "external_id": "", 9 | "profile": "Spaces are not allowed", 10 | "region": "", 11 | "role_session_name": "" 12 | } 13 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_profile_does_not_match_regex/terraform.tfvars: -------------------------------------------------------------------------------- 1 | aws_cli_commands = ["version"] 2 | profile = "Spaces are not allowed" 3 | 4 | alternative_path = "test-reports/terraform_validation_error_profile_does_not_match_regex/aws" 5 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_profile_does_not_match_regex/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export ALLOW_APPLY=false 4 | 5 | . tests/common.sh $0 6 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_profile_does_not_start_with_a_letter/expected_plan_errors.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "variable": "var.profile", 4 | "problems": [ 5 | "The optional profile must start with a letter and can only contain letters, numbers, hyphens, and underscores." 6 | ] 7 | } 8 | ] 9 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_profile_does_not_start_with_a_letter/expected_variables.json: -------------------------------------------------------------------------------- 1 | { 2 | "alternative_path": "test-reports/terraform_validation_error_profile_does_not_start_with_a_letter/aws", 3 | "assume_role_arn": "", 4 | "aws_cli_commands": [ 5 | "version" 6 | ], 7 | "aws_cli_query": "", 8 | "external_id": "", 9 | "profile": "1digit2many", 10 | "region": "", 11 | "role_session_name": "" 12 | } 13 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_profile_does_not_start_with_a_letter/terraform.tfvars: -------------------------------------------------------------------------------- 1 | aws_cli_commands = ["version"] 2 | profile = "1digit2many" 3 | 4 | alternative_path = "test-reports/terraform_validation_error_profile_does_not_start_with_a_letter/aws" 5 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_profile_does_not_start_with_a_letter/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export ALLOW_APPLY=false 4 | 5 | . tests/common.sh $0 6 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_region_does_not_match_regex/expected_plan_errors.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "variable": "var.region", 4 | "problems": [ 5 | "The optional region must start with two letters representing the geographical area, followed by one or more letters or digits representing the specific region within that area." 6 | ] 7 | } 8 | ] 9 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_region_does_not_match_regex/expected_variables.json: -------------------------------------------------------------------------------- 1 | { 2 | "alternative_path": "test-reports/terraform_validation_error_region_does_not_match_regex/aws", 3 | "assume_role_arn": "", 4 | "aws_cli_commands": [ 5 | "version" 6 | ], 7 | "aws_cli_query": "", 8 | "external_id": "", 9 | "profile": "", 10 | "region": "US East (Ohio) us-east-2", 11 | "role_session_name": "" 12 | } 13 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_region_does_not_match_regex/terraform.tfvars: -------------------------------------------------------------------------------- 1 | aws_cli_commands = ["version"] 2 | region = "US East (Ohio) us-east-2" 3 | 4 | alternative_path = "test-reports/terraform_validation_error_region_does_not_match_regex/aws" 5 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_region_does_not_match_regex/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export ALLOW_APPLY=false 4 | 5 | . tests/common.sh $0 6 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_role_session_name_invalid_characters/expected_plan_errors.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "variable": "var.role_session_name", 4 | "problems": [ 5 | "The role session name match the regular expression '^[\\w=,.@-]*$'." 6 | ] 7 | } 8 | ] 9 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_role_session_name_invalid_characters/expected_variables.json: -------------------------------------------------------------------------------- 1 | { 2 | "alternative_path": "test-reports/terraform_validation_error_role_session_name_invalid_characters/aws", 3 | "assume_role_arn": "", 4 | "aws_cli_commands": [ 5 | "version" 6 | ], 7 | "aws_cli_query": "", 8 | "external_id": "", 9 | "profile": "", 10 | "region": "", 11 | "role_session_name": "1 space 2" 12 | } 13 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_role_session_name_invalid_characters/terraform.tfvars: -------------------------------------------------------------------------------- 1 | aws_cli_commands = ["version"] 2 | role_session_name = "1 space 2" 3 | 4 | alternative_path = "test-reports/terraform_validation_error_role_session_name_invalid_characters/aws" 5 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_role_session_name_invalid_characters/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export ALLOW_APPLY=false 4 | 5 | . tests/common.sh $0 6 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_role_session_name_too_long/expected_plan_errors.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "variable": "var.role_session_name", 4 | "problems": [ 5 | "The length of the optional role session name, when supplied, must be between 2 and 64 characters." 6 | ] 7 | } 8 | ] 9 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_role_session_name_too_long/expected_variables.json: -------------------------------------------------------------------------------- 1 | { 2 | "alternative_path": "test-reports/terraform_validation_error_role_session_name_too_long/aws", 3 | "assume_role_arn": "", 4 | "aws_cli_commands": [ 5 | "version" 6 | ], 7 | "aws_cli_query": "", 8 | "external_id": "", 9 | "profile": "", 10 | "region": "", 11 | "role_session_name": "a1,b2.c3@d4-e5,f6.g7@h8-i9,j10.k11@l12-m13,n14.o15@p16-q17,r18.s1" 12 | } 13 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_role_session_name_too_long/terraform.tfvars: -------------------------------------------------------------------------------- 1 | aws_cli_commands = ["version"] 2 | role_session_name = "a1,b2.c3@d4-e5,f6.g7@h8-i9,j10.k11@l12-m13,n14.o15@p16-q17,r18.s1" 3 | 4 | alternative_path = "test-reports/terraform_validation_error_role_session_name_too_long/aws" 5 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_role_session_name_too_long/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export ALLOW_APPLY=false 4 | 5 | . tests/common.sh $0 6 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_role_session_name_too_long_and_invalid_characters/expected_plan_errors.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "variable": "var.role_session_name", 4 | "problems": [ 5 | "The length of the optional role session name, when supplied, must be between 2 and 64 characters.", 6 | "The role session name match the regular expression '^[\\w=,.@-]*$'." 7 | ] 8 | } 9 | ] 10 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_role_session_name_too_long_and_invalid_characters/expected_variables.json: -------------------------------------------------------------------------------- 1 | { 2 | "alternative_path": "test-reports/terraform_validation_error_role_session_name_too_long_and_invalid_characters/aws", 3 | "assume_role_arn": "", 4 | "aws_cli_commands": [ 5 | "version" 6 | ], 7 | "aws_cli_query": "", 8 | "external_id": "", 9 | "profile": "", 10 | "region": "", 11 | "role_session_name": "a1,b2.c3 d4-e5,f6.g7 h8-i9,j10.k11 l12-m13,n14.o15 p16-q17,r18.s1" 12 | } 13 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_role_session_name_too_long_and_invalid_characters/terraform.tfvars: -------------------------------------------------------------------------------- 1 | aws_cli_commands = ["version"] 2 | role_session_name = "a1,b2.c3 d4-e5,f6.g7 h8-i9,j10.k11 l12-m13,n14.o15 p16-q17,r18.s1" 3 | 4 | alternative_path = "test-reports/terraform_validation_error_role_session_name_too_long_and_invalid_characters/aws" 5 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_role_session_name_too_long_and_invalid_characters/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export ALLOW_APPLY=false 4 | 5 | . tests/common.sh $0 6 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_role_session_name_too_short/expected_plan_errors.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "variable": "var.role_session_name", 4 | "problems": [ 5 | "The length of the optional role session name, when supplied, must be between 2 and 64 characters." 6 | ] 7 | } 8 | ] 9 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_role_session_name_too_short/expected_variables.json: -------------------------------------------------------------------------------- 1 | { 2 | "alternative_path": "test-reports/terraform_validation_error_role_session_name_too_short/aws", 3 | "assume_role_arn": "", 4 | "aws_cli_commands": [ 5 | "version" 6 | ], 7 | "aws_cli_query": "", 8 | "external_id": "", 9 | "profile": "", 10 | "region": "", 11 | "role_session_name": "1" 12 | } 13 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_role_session_name_too_short/terraform.tfvars: -------------------------------------------------------------------------------- 1 | aws_cli_commands = ["version"] 2 | role_session_name = "1" 3 | 4 | alternative_path = "test-reports/terraform_validation_error_role_session_name_too_short/aws" 5 | -------------------------------------------------------------------------------- /tests/terraform_validation_error_role_session_name_too_short/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export ALLOW_APPLY=false 4 | 5 | . tests/common.sh $0 6 | -------------------------------------------------------------------------------- /tests/test_data_retrieval_with_no_role_arn_and_error/expected_plan_errors.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "variable": "data.local_file.awscli_results_file", 4 | "problems": [ 5 | "An error occurred (AccessDenied) when calling the ListObjects operation: Access Denied" 6 | ] 7 | } 8 | ] 9 | -------------------------------------------------------------------------------- /tests/test_data_retrieval_with_no_role_arn_and_error/expected_variables.json: -------------------------------------------------------------------------------- 1 | { 2 | "alternative_path": "test-reports/test_data_retrieval_with_no_role_arn_and_error/aws", 3 | "assume_role_arn": "", 4 | "aws_cli_commands": [ 5 | "s3api", 6 | "list-objects", 7 | "--bucket=ryft-public-sample-data", 8 | "--no-sign-request" 9 | ], 10 | "aws_cli_query": "max_by(Contents, &Size)", 11 | "external_id": "", 12 | "profile": "", 13 | "region": "eu-west-1", 14 | "role_session_name": "" 15 | } 16 | -------------------------------------------------------------------------------- /tests/test_data_retrieval_with_no_role_arn_and_error/terraform.tfvars: -------------------------------------------------------------------------------- 1 | aws_cli_commands = ["s3api", "list-objects", "--bucket=ryft-public-sample-data", "--no-sign-request"] 2 | aws_cli_query = "max_by(Contents, &Size)" 3 | region = "eu-west-1" 4 | 5 | alternative_path = "test-reports/test_data_retrieval_with_no_role_arn_and_error/aws" 6 | -------------------------------------------------------------------------------- /tests/test_data_retrieval_with_no_role_arn_and_error/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export ALLOW_APPLY=true 4 | 5 | . tests/common.sh $0 6 | -------------------------------------------------------------------------------- /tests/test_empty_command/expected_plan_errors.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "variable": "data.local_file.awscli_results_file", 4 | "problems": [ 5 | "usage: aws [options] [ ...] [parameters]\nTo see help text, you can run:\n\n aws help\n aws help\n aws help\n\naws: error: the following arguments are required: command" 6 | ] 7 | } 8 | ] 9 | -------------------------------------------------------------------------------- /tests/test_empty_command/terraform.tfvars: -------------------------------------------------------------------------------- 1 | aws_cli_commands = [] 2 | region = "eu-west-1" 3 | 4 | alternative_path = "test-reports/test_empty_command/aws" 5 | -------------------------------------------------------------------------------- /tests/test_empty_command/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export ALLOW_APPLY=true 4 | 5 | . tests/common.sh $0 6 | -------------------------------------------------------------------------------- /tests/test_version_retrieval_will_error/expected_apply_outputs.json: -------------------------------------------------------------------------------- 1 | { 2 | "result": "", 3 | "result_raw": "$AWS_CLI_VERSION\n", 4 | "result_was_decoded": false 5 | } 6 | -------------------------------------------------------------------------------- /tests/test_version_retrieval_will_error/terraform.tfvars: -------------------------------------------------------------------------------- 1 | aws_cli_commands = [ 2 | "--version", 3 | ] 4 | region = "eu-west-1" 5 | 6 | alternative_path = "test-reports/test_version_retrieval_will_error/aws" 7 | -------------------------------------------------------------------------------- /tests/test_version_retrieval_will_error/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export ALLOW_APPLY=true 4 | 5 | . tests/common.sh $0 6 | -------------------------------------------------------------------------------- /tests/tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | function underline() { 4 | U="${1//?/${2:--}}" 5 | echo -e "\n$1\n${U:0:${#1}}\n" 6 | } 7 | 8 | set -e 9 | rm -rf temp 10 | rm -rf test-reports 11 | 12 | underline 'Running tests' = 13 | 14 | find ./tests -type f -name test.sh -maxdepth 2 | sort | xargs -L 1 bash 15 | -------------------------------------------------------------------------------- /variables.tf: -------------------------------------------------------------------------------- 1 | # Variables related to calling AWS CLI 2 | variable "aws_cli_commands" { 3 | description = <= 2 && length(var.external_id) <= 1224) 56 | error_message = "The length of optional external_id, when supplied, must be between 2 and 1224 characters." 57 | } 58 | 59 | validation { 60 | condition = can(regex("^[\\w=,.@-]*$", var.external_id)) 61 | error_message = "The optional external_id must match the regular expression '^[\\w=,.@-]*$'." 62 | } 63 | } 64 | 65 | variable "profile" { 66 | description = <= 2 && length(var.role_session_name) <= 64) 110 | error_message = "The length of the optional role session name, when supplied, must be between 2 and 64 characters." 111 | } 112 | 113 | validation { 114 | condition = can(regex("^[\\w=,.@-]*$", var.role_session_name)) 115 | error_message = "The role session name match the regular expression '^[\\w=,.@-]*$'." 116 | } 117 | } 118 | 119 | # Variable for debugging 120 | variable "alternative_path" { 121 | description = "Use an alternative path for all files produced internally" 122 | type = string 123 | default = "" 124 | } 125 | -------------------------------------------------------------------------------- /versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.6.0" 3 | required_providers { 4 | external = { 5 | source = "hashicorp/external" 6 | version = "~> 2.0" 7 | } 8 | local = { 9 | source = "hashicorp/local" 10 | version = "~> 2.0" 11 | } 12 | } 13 | } 14 | --------------------------------------------------------------------------------