├── .editorconfig ├── .github └── workflows │ ├── lock.yml │ ├── pr-title.yml │ ├── pre-commit.yml │ ├── release.yml │ └── stale-actions.yaml ├── .gitignore ├── .pre-commit-config.yaml ├── .releaserc.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── UPGRADE-3.0.md ├── examples ├── README.md ├── complete │ ├── README.md │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── session-manager │ ├── README.md │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf └── volume-attachment │ ├── README.md │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── main.tf ├── outputs.tf ├── variables.tf ├── versions.tf └── wrappers ├── README.md ├── main.tf ├── outputs.tf ├── variables.tf └── versions.tf /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | # Uses editorconfig to maintain consistent coding styles 3 | 4 | # top-most EditorConfig file 5 | root = true 6 | 7 | # Unix-style newlines with a newline ending every file 8 | [*] 9 | charset = utf-8 10 | end_of_line = lf 11 | indent_size = 2 12 | indent_style = space 13 | insert_final_newline = true 14 | max_line_length = 80 15 | trim_trailing_whitespace = true 16 | 17 | [*.{tf,tfvars}] 18 | indent_size = 2 19 | indent_style = space 20 | 21 | [*.md] 22 | max_line_length = 0 23 | trim_trailing_whitespace = false 24 | 25 | [Makefile] 26 | tab_width = 2 27 | indent_style = tab 28 | 29 | [COMMIT_EDITMSG] 30 | max_line_length = 0 31 | -------------------------------------------------------------------------------- /.github/workflows/lock.yml: -------------------------------------------------------------------------------- 1 | name: 'Lock Threads' 2 | 3 | on: 4 | schedule: 5 | - cron: '50 1 * * *' 6 | 7 | jobs: 8 | lock: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: dessant/lock-threads@v5 12 | with: 13 | github-token: ${{ secrets.GITHUB_TOKEN }} 14 | issue-comment: > 15 | I'm going to lock this issue because it has been closed for _30 days_ ⏳. This helps our maintainers find and focus on the active issues. 16 | If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further. 17 | issue-inactive-days: '30' 18 | pr-comment: > 19 | I'm going to lock this pull request because it has been closed for _30 days_ ⏳. This helps our maintainers find and focus on the active issues. 20 | If you have found a problem that seems related to this change, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further. 21 | pr-inactive-days: '30' 22 | -------------------------------------------------------------------------------- /.github/workflows/pr-title.yml: -------------------------------------------------------------------------------- 1 | name: 'Validate PR title' 2 | 3 | on: 4 | pull_request_target: 5 | types: 6 | - opened 7 | - edited 8 | - synchronize 9 | 10 | jobs: 11 | main: 12 | name: Validate PR title 13 | runs-on: ubuntu-latest 14 | steps: 15 | # Please look up the latest version from 16 | # https://github.com/amannn/action-semantic-pull-request/releases 17 | - uses: amannn/action-semantic-pull-request@v5.5.3 18 | env: 19 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 20 | with: 21 | # Configure which types are allowed. 22 | # Default: https://github.com/commitizen/conventional-commit-types 23 | types: | 24 | fix 25 | feat 26 | docs 27 | ci 28 | chore 29 | # Configure that a scope must always be provided. 30 | requireScope: false 31 | # Configure additional validation for the subject based on a regex. 32 | # This example ensures the subject starts with an uppercase character. 33 | subjectPattern: ^[A-Z].+$ 34 | # If `subjectPattern` is configured, you can use this property to override 35 | # the default error message that is shown when the pattern doesn't match. 36 | # The variables `subject` and `title` can be used within the message. 37 | subjectPatternError: | 38 | The subject "{subject}" found in the pull request title "{title}" 39 | didn't match the configured pattern. Please ensure that the subject 40 | starts with an uppercase character. 41 | # For work-in-progress PRs you can typically use draft pull requests 42 | # from Github. However, private repositories on the free plan don't have 43 | # this option and therefore this action allows you to opt-in to using the 44 | # special "[WIP]" prefix to indicate this state. This will avoid the 45 | # validation of the PR title and the pull request checks remain pending. 46 | # Note that a second check will be reported if this is enabled. 47 | wip: true 48 | # When using "Squash and merge" on a PR with only one commit, GitHub 49 | # will suggest using that commit message instead of the PR title for the 50 | # merge commit, and it's easy to commit this by mistake. Enable this option 51 | # to also validate the commit message for one commit PRs. 52 | validateSingleCommit: false 53 | -------------------------------------------------------------------------------- /.github/workflows/pre-commit.yml: -------------------------------------------------------------------------------- 1 | name: Pre-Commit 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | - master 8 | 9 | env: 10 | TERRAFORM_DOCS_VERSION: v0.19.0 11 | TFLINT_VERSION: v0.53.0 12 | 13 | jobs: 14 | collectInputs: 15 | name: Collect workflow inputs 16 | runs-on: ubuntu-latest 17 | outputs: 18 | directories: ${{ steps.dirs.outputs.directories }} 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@v4 22 | 23 | - name: Get root directories 24 | id: dirs 25 | uses: clowdhaus/terraform-composite-actions/directories@v1.9.0 26 | 27 | preCommitMinVersions: 28 | name: Min TF pre-commit 29 | needs: collectInputs 30 | runs-on: ubuntu-latest 31 | strategy: 32 | matrix: 33 | directory: ${{ fromJson(needs.collectInputs.outputs.directories) }} 34 | steps: 35 | # https://github.com/orgs/community/discussions/25678#discussioncomment-5242449 36 | - name: Delete huge unnecessary tools folder 37 | run: | 38 | rm -rf /opt/hostedtoolcache/CodeQL 39 | rm -rf /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk 40 | rm -rf /opt/hostedtoolcache/Ruby 41 | rm -rf /opt/hostedtoolcache/go 42 | 43 | - name: Checkout 44 | uses: actions/checkout@v4 45 | 46 | - name: Terraform min/max versions 47 | id: minMax 48 | uses: clowdhaus/terraform-min-max@v1.3.1 49 | with: 50 | directory: ${{ matrix.directory }} 51 | 52 | - name: Pre-commit Terraform ${{ steps.minMax.outputs.minVersion }} 53 | # Run only validate pre-commit check on min version supported 54 | if: ${{ matrix.directory != '.' }} 55 | uses: clowdhaus/terraform-composite-actions/pre-commit@v1.11.1 56 | with: 57 | terraform-version: ${{ steps.minMax.outputs.minVersion }} 58 | tflint-version: ${{ env.TFLINT_VERSION }} 59 | args: 'terraform_validate --color=always --show-diff-on-failure --files ${{ matrix.directory }}/*' 60 | 61 | - name: Pre-commit Terraform ${{ steps.minMax.outputs.minVersion }} 62 | # Run only validate pre-commit check on min version supported 63 | if: ${{ matrix.directory == '.' }} 64 | uses: clowdhaus/terraform-composite-actions/pre-commit@v1.11.1 65 | with: 66 | terraform-version: ${{ steps.minMax.outputs.minVersion }} 67 | tflint-version: ${{ env.TFLINT_VERSION }} 68 | args: 'terraform_validate --color=always --show-diff-on-failure --files $(ls *.tf)' 69 | 70 | preCommitMaxVersion: 71 | name: Max TF pre-commit 72 | runs-on: ubuntu-latest 73 | needs: collectInputs 74 | steps: 75 | # https://github.com/orgs/community/discussions/25678#discussioncomment-5242449 76 | - name: Delete huge unnecessary tools folder 77 | run: | 78 | rm -rf /opt/hostedtoolcache/CodeQL 79 | rm -rf /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk 80 | rm -rf /opt/hostedtoolcache/Ruby 81 | rm -rf /opt/hostedtoolcache/go 82 | 83 | - name: Checkout 84 | uses: actions/checkout@v4 85 | with: 86 | ref: ${{ github.event.pull_request.head.ref }} 87 | repository: ${{github.event.pull_request.head.repo.full_name}} 88 | 89 | - name: Terraform min/max versions 90 | id: minMax 91 | uses: clowdhaus/terraform-min-max@v1.3.1 92 | 93 | - name: Pre-commit Terraform ${{ steps.minMax.outputs.maxVersion }} 94 | uses: clowdhaus/terraform-composite-actions/pre-commit@v1.11.1 95 | with: 96 | terraform-version: ${{ steps.minMax.outputs.maxVersion }} 97 | tflint-version: ${{ env.TFLINT_VERSION }} 98 | terraform-docs-version: ${{ env.TERRAFORM_DOCS_VERSION }} 99 | install-hcledit: true 100 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - main 8 | - master 9 | paths: 10 | - '**/*.tpl' 11 | - '**/*.py' 12 | - '**/*.tf' 13 | - '.github/workflows/release.yml' 14 | 15 | jobs: 16 | release: 17 | name: Release 18 | runs-on: ubuntu-latest 19 | # Skip running release workflow on forks 20 | if: github.repository_owner == 'terraform-aws-modules' 21 | steps: 22 | - name: Checkout 23 | uses: actions/checkout@v4 24 | with: 25 | persist-credentials: false 26 | fetch-depth: 0 27 | 28 | - name: Release 29 | uses: cycjimmy/semantic-release-action@v4 30 | with: 31 | semantic_version: 23.0.2 32 | extra_plugins: | 33 | @semantic-release/changelog@6.0.3 34 | @semantic-release/git@10.0.1 35 | conventional-changelog-conventionalcommits@7.0.2 36 | env: 37 | GITHUB_TOKEN: ${{ secrets.SEMANTIC_RELEASE_TOKEN }} 38 | -------------------------------------------------------------------------------- /.github/workflows/stale-actions.yaml: -------------------------------------------------------------------------------- 1 | name: 'Mark or close stale issues and PRs' 2 | on: 3 | schedule: 4 | - cron: '0 0 * * *' 5 | 6 | jobs: 7 | stale: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/stale@v9 11 | with: 12 | repo-token: ${{ secrets.GITHUB_TOKEN }} 13 | # Staling issues and PR's 14 | days-before-stale: 30 15 | stale-issue-label: stale 16 | stale-pr-label: stale 17 | stale-issue-message: | 18 | This issue has been automatically marked as stale because it has been open 30 days 19 | with no activity. Remove stale label or comment or this issue will be closed in 10 days 20 | stale-pr-message: | 21 | This PR has been automatically marked as stale because it has been open 30 days 22 | with no activity. Remove stale label or comment or this PR will be closed in 10 days 23 | # Not stale if have this labels or part of milestone 24 | exempt-issue-labels: bug,wip,on-hold 25 | exempt-pr-labels: bug,wip,on-hold 26 | exempt-all-milestones: true 27 | # Close issue operations 28 | # Label will be automatically removed if the issues are no longer closed nor locked. 29 | days-before-close: 10 30 | delete-branch: true 31 | close-issue-message: This issue was automatically closed because of stale in 10 days 32 | close-pr-message: This PR was automatically closed because of stale in 10 days 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Local .terraform directories 2 | **/.terraform/* 3 | 4 | # Terraform lockfile 5 | .terraform.lock.hcl 6 | 7 | # .tfstate files 8 | *.tfstate 9 | *.tfstate.* 10 | 11 | # Crash log files 12 | crash.log 13 | 14 | # Exclude all .tfvars files, which are likely to contain sentitive data, such as 15 | # password, private keys, and other secrets. These should not be part of version 16 | # control as they are data points which are potentially sensitive and subject 17 | # to change depending on the environment. 18 | *.tfvars 19 | 20 | # Ignore override files as they are usually used to override resources locally and so 21 | # are not checked in 22 | override.tf 23 | override.tf.json 24 | *_override.tf 25 | *_override.tf.json 26 | 27 | # Ignore CLI configuration files 28 | .terraformrc 29 | terraform.rc 30 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/antonbabenko/pre-commit-terraform 3 | rev: v1.98.0 4 | hooks: 5 | - id: terraform_fmt 6 | - id: terraform_wrapper_module_for_each 7 | - id: terraform_docs 8 | args: 9 | - '--args=--lockfile=false' 10 | - id: terraform_tflint 11 | args: 12 | - '--args=--only=terraform_deprecated_interpolation' 13 | - '--args=--only=terraform_deprecated_index' 14 | - '--args=--only=terraform_unused_declarations' 15 | - '--args=--only=terraform_comment_syntax' 16 | - '--args=--only=terraform_documented_outputs' 17 | - '--args=--only=terraform_documented_variables' 18 | - '--args=--only=terraform_typed_variables' 19 | - '--args=--only=terraform_module_pinned_source' 20 | - '--args=--only=terraform_naming_convention' 21 | - '--args=--only=terraform_required_version' 22 | - '--args=--only=terraform_required_providers' 23 | - '--args=--only=terraform_standard_module_structure' 24 | - '--args=--only=terraform_workspace_remote' 25 | - id: terraform_validate 26 | - repo: https://github.com/pre-commit/pre-commit-hooks 27 | rev: v5.0.0 28 | hooks: 29 | - id: check-merge-conflict 30 | - id: end-of-file-fixer 31 | - id: trailing-whitespace 32 | -------------------------------------------------------------------------------- /.releaserc.json: -------------------------------------------------------------------------------- 1 | { 2 | "branches": [ 3 | "main", 4 | "master" 5 | ], 6 | "ci": false, 7 | "plugins": [ 8 | [ 9 | "@semantic-release/commit-analyzer", 10 | { 11 | "preset": "conventionalcommits" 12 | } 13 | ], 14 | [ 15 | "@semantic-release/release-notes-generator", 16 | { 17 | "preset": "conventionalcommits" 18 | } 19 | ], 20 | [ 21 | "@semantic-release/github", 22 | { 23 | "successComment": "This ${issue.pull_request ? 'PR is included' : 'issue has been resolved'} in version ${nextRelease.version} :tada:", 24 | "labels": false, 25 | "releasedLabels": false 26 | } 27 | ], 28 | [ 29 | "@semantic-release/changelog", 30 | { 31 | "changelogFile": "CHANGELOG.md", 32 | "changelogTitle": "# Changelog\n\nAll notable changes to this project will be documented in this file." 33 | } 34 | ], 35 | [ 36 | "@semantic-release/git", 37 | { 38 | "assets": [ 39 | "CHANGELOG.md" 40 | ], 41 | "message": "chore(release): version ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" 42 | } 43 | ] 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | ## [5.8.0](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v5.7.1...v5.8.0) (2025-03-30) 6 | 7 | 8 | ### Features 9 | 10 | * Disable IMDSv1 per AWS default behavior change ([#424](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/424)) ([ce8ae23](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/commit/ce8ae23a15a2a58b491161f56fb20635cc2f2733)) 11 | 12 | ## [5.7.1](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v5.7.0...v5.7.1) (2024-10-11) 13 | 14 | 15 | ### Bug Fixes 16 | 17 | * Update CI workflow versions to latest ([#409](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/409)) ([e48d67f](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/commit/e48d67f339c72bb44a544729fa685e347ea6256e)) 18 | 19 | ## [5.7.0](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v5.6.1...v5.7.0) (2024-08-26) 20 | 21 | 22 | ### Features 23 | 24 | * Added parameter to attach aws_eip ([#391](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/391)) ([57cdd5d](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/commit/57cdd5d376939ec8a177c4622d3fe8c6f12c68c7)) 25 | 26 | ## [5.6.1](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v5.6.0...v5.6.1) (2024-03-07) 27 | 28 | 29 | ### Bug Fixes 30 | 31 | * Update CI workflow versions to remove deprecated runtime warnings ([#379](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/379)) ([2c9e615](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/commit/2c9e6156d375cf6adcfef95198318556f19f08f7)) 32 | 33 | ## [5.6.0](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v5.5.0...v5.6.0) (2023-12-25) 34 | 35 | 36 | ### Features 37 | 38 | * Support Private DNS name options ([#370](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/370)) ([d3520fd](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/commit/d3520fd9afc35a2598604e4219ade15021960ba9)) 39 | 40 | ## [5.5.0](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v5.4.0...v5.5.0) (2023-08-30) 41 | 42 | 43 | ### Features 44 | 45 | * Add example for connecting via Session Manager without Internet access ([#336](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/336)) ([68edef8](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/commit/68edef8e2a83f6492db63b684cf5ad7065b89d6f)) 46 | 47 | ## [5.4.0](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v5.3.1...v5.4.0) (2023-08-30) 48 | 49 | 50 | ### Features 51 | 52 | * Add `availability_zone` output ([#347](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/347)) ([1b2cdeb](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/commit/1b2cdeba14ee0aba4f687996fde8ab6eb2ad27c6)) 53 | 54 | ### [5.3.1](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v5.3.0...v5.3.1) (2023-08-17) 55 | 56 | 57 | ### Bug Fixes 58 | 59 | * Fixed ami variable when using without ssm ([#354](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/354)) ([a1691a0](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/commit/a1691a050d92e800b584a5624f3d8f2114e000c6)) 60 | 61 | ## [5.3.0](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v5.2.1...v5.3.0) (2023-08-16) 62 | 63 | 64 | ### Features 65 | 66 | * Remove call data ssm parameter when ami id is specified ([#351](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/351)) ([7ffc3dd](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/commit/7ffc3dd843efecd543fecb0a1b556004d7db2bb7)) 67 | 68 | ### [5.2.1](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v5.2.0...v5.2.1) (2023-07-06) 69 | 70 | 71 | ### Bug Fixes 72 | 73 | * Fixed outputs for Block Devices ([#344](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/344)) ([80381d2](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/commit/80381d2c94e6aec7aa308f4a6cf24732a87c8237)) 74 | 75 | ## [5.2.0](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v5.1.0...v5.2.0) (2023-06-28) 76 | 77 | 78 | ### Features 79 | 80 | * Add input variable 'instance_tags' ([#343](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/343)) ([025d3b4](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/commit/025d3b4beca9835a5e997e41677a4c6441a733f4)) 81 | 82 | ## [5.1.0](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v5.0.0...v5.1.0) (2023-05-30) 83 | 84 | 85 | ### Features 86 | 87 | * Implementation of the cpu_options block and addition of support for AMD SEV-SNP ([#334](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/334)) ([6a123ad](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/commit/6a123adb10393759fcdd18795fbf1484c5f44dde)) 88 | 89 | ## [5.0.0](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v4.5.0...v5.0.0) (2023-04-28) 90 | 91 | 92 | ### ⚠ BREAKING CHANGES 93 | 94 | * Raise minimum required Terraform version to 1.0+ (#331) 95 | 96 | ### Features 97 | 98 | * Raise minimum required Terraform version to 1.0+ ([#331](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/331)) ([9d4e0ca](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/commit/9d4e0ca389535522808ddf988e3a6510bb143161)) 99 | 100 | ## [4.5.0](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v4.4.0...v4.5.0) (2023-04-21) 101 | 102 | 103 | ### Features 104 | 105 | * Add unique tags to EBS block devices ([#327](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/327)) ([55ed759](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/commit/55ed759b9fbc475629da2d5068a593a2ce08d8dc)) 106 | 107 | ## [4.4.0](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v4.3.1...v4.4.0) (2023-04-21) 108 | 109 | 110 | ### Features 111 | 112 | * Addition of block device information in outputs ([#319](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/319)) ([884e244](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/commit/884e24466e19144e6b5a1085ab81b377174c6e0c)) 113 | 114 | ### [4.3.1](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v4.3.0...v4.3.1) (2023-04-21) 115 | 116 | 117 | ### Bug Fixes 118 | 119 | * Marked AMI id as nonsensitive ([#321](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/321)) ([1ae1d5c](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/commit/1ae1d5ce73d6bef0e42821406f82ff16fe718177)) 120 | 121 | ## [4.3.0](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v4.2.1...v4.3.0) (2023-01-01) 122 | 123 | 124 | ### Features 125 | 126 | * Add support for `maintenance_options` ([#312](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/312)) ([2aaa990](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/commit/2aaa99011a5ae0224da13691e9d288a5ef7cbd0d)) 127 | 128 | ### [4.2.1](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v4.2.0...v4.2.1) (2022-11-07) 129 | 130 | 131 | ### Bug Fixes 132 | 133 | * Update CI configuration files to use latest version ([#303](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/303)) ([2151031](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/commit/21510318bffcfa84a13c5ec8cbb93dff9871a4f9)) 134 | 135 | ## [4.2.0](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v4.1.4...v4.2.0) (2022-11-04) 136 | 137 | 138 | ### Features 139 | 140 | * Add support for creating IAM role/instance profile with policies ([#302](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/302)) ([787132e](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/commit/787132e5dbe7b58e4b9a62e1a69a682bcbb9bd58)) 141 | 142 | ### [4.1.4](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v4.1.3...v4.1.4) (2022-08-13) 143 | 144 | 145 | ### Bug Fixes 146 | 147 | * Correct capacity reservation target ([#288](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/288)) ([135145e](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/commit/135145e252c69814c019da49c638973f93523f6a)) 148 | 149 | ### [4.1.3](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v4.1.2...v4.1.3) (2022-08-12) 150 | 151 | 152 | ### Bug Fixes 153 | 154 | * The capacity_reservation_specification default value is updated from null to {} ([#285](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/285)) ([9af6601](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/commit/9af6601abbcfe06fc907ea1eb3abffe30d26daf2)) 155 | 156 | ### [4.1.2](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v4.1.1...v4.1.2) (2022-08-10) 157 | 158 | 159 | ### Bug Fixes 160 | 161 | * Assignment of the Capacity Reservation id to an instance ([#282](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/282)) ([7f0a0ae](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/commit/7f0a0ae66cbe50d0ea1c09191de4e82cfa8c4ca2)) 162 | 163 | ### [4.1.1](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v4.1.0...v4.1.1) (2022-07-21) 164 | 165 | 166 | ### Bug Fixes 167 | 168 | * Creation of an Instance with a Capacity Reservation ID ([#278](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/278)) ([f12ac95](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/commit/f12ac95aa309fdbf532ba1d5a9841690ca7fdb8e)) 169 | 170 | ## [4.1.0](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v4.0.0...v4.1.0) (2022-07-19) 171 | 172 | 173 | ### Features 174 | 175 | * Add support for `disable_api_stop` attribute ([#275](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/275)) ([cb367ec](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/commit/cb367ec54e4386512e37b8ef0b8d01c78f589fb1)) 176 | 177 | ## [4.0.0](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v3.6.0...v4.0.0) (2022-05-09) 178 | 179 | 180 | ### ⚠ BREAKING CHANGES 181 | 182 | * Add support for user_data_replace_on_change, and updated AWS provider to v4.7+ (#272) 183 | 184 | ### Features 185 | 186 | * Add support for user_data_replace_on_change, and updated AWS provider to v4.7+ ([#272](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/272)) ([4d7f3d8](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/commit/4d7f3d873b0d2be7361d439e62b872a895073342)) 187 | 188 | ## [3.6.0](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v3.5.0...v3.6.0) (2022-05-06) 189 | 190 | 191 | ### Features 192 | 193 | * Added wrappers automatically generated via pre-commit hook ([#271](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/271)) ([6e8c541](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/commit/6e8c541b2d9b3fe54c9acc7f4d271648c5844c9b)) 194 | 195 | ## [3.5.0](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v3.4.0...v3.5.0) (2022-03-12) 196 | 197 | 198 | ### Features 199 | 200 | * Made it clear that we stand with Ukraine ([6867788](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/commit/6867788411a202b61187f9935e9eaa72a18f0bbe)) 201 | 202 | ## [3.4.0](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v3.3.0...v3.4.0) (2022-01-14) 203 | 204 | 205 | ### Features 206 | 207 | * Add `instance_metadata_tags` attribute and bump AWS provider to support ([#254](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/254)) ([b2fb960](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/commit/b2fb9604b32aa23d14a8a6e3cff761d6c69661b7)) 208 | 209 | # [3.3.0](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v3.2.1...v3.3.0) (2021-11-22) 210 | 211 | 212 | ### Features 213 | 214 | * Add instance IPv6 addresses to the outputs ([#249](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/249)) ([08bdf6a](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/commit/08bdf6af910f665149d8d64a19175b89a8fac447)) 215 | 216 | ## [3.2.1](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v3.2.0...v3.2.1) (2021-11-22) 217 | 218 | 219 | ### Bug Fixes 220 | 221 | * update CI/CD process to enable auto-release workflow ([#250](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/250)) ([1508c9e](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/commit/1508c9ec45ba954828c734326366143a17434a0f)) 222 | 223 | 224 | ## [v3.2.0] - 2021-10-07 225 | 226 | - feat: Add instance private IP to the outputs ([#241](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/241)) 227 | 228 | 229 | 230 | ## [v3.1.0] - 2021-08-27 231 | 232 | - feat: add support for spot instances via spot instance requests ([#236](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/236)) 233 | - chore: update `README.md` example for making an encrypted AMI ([#235](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/235)) 234 | 235 | 236 | 237 | ## [v3.0.0] - 2021-08-26 238 | 239 | - BREAKING CHANGE: update module to include latest features and remove use of `count` for module `count`/`for_each` ([#234](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/234)) 240 | 241 | 242 | 243 | ## [v2.21.0] - 2021-08-26 244 | 245 | - feat: Add support for EBS GP3 throughput ([#233](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/233)) 246 | 247 | 248 | 249 | ## [v2.20.0] - 2021-08-25 250 | 251 | - feat: Add cpu optimization options ([#181](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/181)) 252 | 253 | 254 | 255 | ## [v2.19.0] - 2021-05-12 256 | 257 | - fix: root_block_device tags conflicts ([#220](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/220)) 258 | 259 | 260 | 261 | ## [v2.18.0] - 2021-05-11 262 | 263 | - feat: add tags support to root block device ([#218](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/218)) 264 | - chore: update CI/CD to use stable `terraform-docs` release artifact and discoverable Apache2.0 license ([#217](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/217)) 265 | - chore: Updated versions&comments in examples 266 | - chore: update documentation and pin `terraform_docs` version to avoid future changes ([#212](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/212)) 267 | - chore: align ci-cd static checks to use individual minimum Terraform versions ([#207](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/207)) 268 | - chore: add ci-cd workflow for pre-commit checks ([#201](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/201)) 269 | 270 | 271 | 272 | ## [v2.17.0] - 2021-02-20 273 | 274 | - chore: update documentation based on latest `terraform-docs` which includes module and resource sections ([#200](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/200)) 275 | 276 | 277 | 278 | ## [v2.16.0] - 2020-12-10 279 | 280 | - feat: Add support for metadata_options argument ([#193](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/193)) 281 | 282 | 283 | 284 | ## [v2.15.0] - 2020-06-10 285 | 286 | - feat: Add "num_suffix_format" variable for instance naming ([#147](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/147)) 287 | 288 | 289 | 290 | ## [v2.14.0] - 2020-06-10 291 | 292 | - Updated README 293 | - Updated t instance type check to include t3a type ([#145](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/145)) 294 | - Updated README 295 | - Instance count as output ([#121](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/121)) 296 | - Added user_data_base64 (fixed [#117](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/117)) ([#137](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/137)) 297 | - Added support for network_interface and arn ([#136](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/136)) 298 | - Update outputs to remove unneeded function wrappers ([#135](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/135)) 299 | - Track all changes (remove ignore_changes lifecycle) ([#125](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/125)) 300 | - Add encrypted and kms_key_id arguments to the ebs_* and root_* block ([#124](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/124)) 301 | - Remove T2 specifics to unify Terraform object names inside TF State ([#111](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/111)) 302 | - Fixed output of placement_group (fixed [#104](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/104)) ([#110](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/110)) 303 | - Add get_password_data ([#105](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/105)) 304 | - Fixed when private_ips is empty (fixed [#103](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/103)) 305 | - Added support for the list of private_ips (fixes [#102](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/102)) ([#103](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/103)) 306 | - Added support for placement group and volume tags ([#96](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/96)) 307 | - Terraform 0.12 update ([#93](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/93)) 308 | 309 | 310 | 311 | ## [v1.25.0] - 2020-03-05 312 | 313 | - Updated t instance type check to include t3a type ([#146](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/146)) 314 | - Added placement groups ([#94](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/94)) 315 | - Revert example 316 | - Added placement groups 317 | - Add volume tags naming and output ([#82](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/82)) 318 | 319 | 320 | 321 | ## [v2.13.0] - 2020-03-05 322 | 323 | - Updated t instance type check to include t3a type ([#145](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/145)) 324 | 325 | 326 | 327 | ## [v2.12.0] - 2019-11-19 328 | 329 | - Updated README 330 | - Instance count as output ([#121](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/121)) 331 | 332 | 333 | 334 | ## [v2.11.0] - 2019-11-19 335 | 336 | - Added user_data_base64 (fixed [#117](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/117)) ([#137](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/137)) 337 | 338 | 339 | 340 | ## [v2.10.0] - 2019-11-19 341 | 342 | - Added support for network_interface and arn ([#136](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/136)) 343 | 344 | 345 | 346 | ## [v2.9.0] - 2019-11-19 347 | 348 | - Update outputs to remove unneeded function wrappers ([#135](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/135)) 349 | 350 | 351 | 352 | ## [v2.8.0] - 2019-08-27 353 | 354 | - Track all changes (remove ignore_changes lifecycle) ([#125](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/125)) 355 | 356 | 357 | 358 | ## [v2.7.0] - 2019-08-27 359 | 360 | - Add encrypted and kms_key_id arguments to the ebs_* and root_* block ([#124](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/124)) 361 | 362 | 363 | 364 | ## [v2.6.0] - 2019-07-21 365 | 366 | - Remove T2 specifics to unify Terraform object names inside TF State ([#111](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/111)) 367 | 368 | 369 | 370 | ## [v2.5.0] - 2019-07-08 371 | 372 | - Fixed output of placement_group (fixed [#104](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/104)) ([#110](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/110)) 373 | 374 | 375 | 376 | ## [v2.4.0] - 2019-06-24 377 | 378 | - Add get_password_data ([#105](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/105)) 379 | 380 | 381 | 382 | ## [v2.3.0] - 2019-06-15 383 | 384 | - Fixed when private_ips is empty (fixed [#103](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/103)) 385 | 386 | 387 | 388 | ## [v2.2.0] - 2019-06-14 389 | 390 | - Added support for the list of private_ips (fixes [#102](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/102)) ([#103](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/103)) 391 | 392 | 393 | 394 | ## [v2.1.0] - 2019-06-08 395 | 396 | - Added support for placement group and volume tags ([#96](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/96)) 397 | - Terraform 0.12 update ([#93](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/93)) 398 | 399 | 400 | 401 | ## [v1.24.0] - 2019-06-06 402 | 403 | - Added placement groups ([#94](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/94)) 404 | - Revert example 405 | - Added placement groups 406 | 407 | 408 | 409 | ## [v1.23.0] - 2019-06-06 410 | 411 | - Add volume tags naming and output ([#82](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/82)) 412 | 413 | 414 | 415 | ## [v2.0.0] - 2019-06-06 416 | 417 | - Terraform 0.12 update ([#93](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/93)) 418 | 419 | 420 | 421 | ## [v1.22.0] - 2019-06-06 422 | 423 | - Update module to the current version ([#88](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/88)) 424 | 425 | 426 | 427 | ## [v1.21.0] - 2019-03-22 428 | 429 | - Fix formatting 430 | - examples/basic/main.tf: Add usage of "root_block_device" ([#18](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/18)) ([#65](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/65)) 431 | 432 | 433 | 434 | ## [v1.20.0] - 2019-03-22 435 | 436 | - Fix formatting 437 | - main.tf: Make number of instances created configurable, defaulting to 1 ([#64](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/64)) 438 | - Add missing required field ([#81](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/81)) 439 | 440 | 441 | 442 | ## [v1.19.0] - 2019-03-01 443 | 444 | - Fixed readme after [#76](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/76) 445 | - network_interface_id Attribute Removal ([#76](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/76)) 446 | 447 | 448 | 449 | ## [v1.18.0] - 2019-02-27 450 | 451 | - fix count variables are only valid within resources ([#72](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/72)) 452 | 453 | 454 | 455 | ## [v1.17.0] - 2019-02-25 456 | 457 | - fix call to local.instance_name ([#71](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/71)) 458 | 459 | 460 | 461 | ## [v1.16.0] - 2019-02-25 462 | 463 | - Fixed readme 464 | - Ability to append numerical suffix even to 1 instance ([#70](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/70)) 465 | 466 | 467 | 468 | ## [v1.15.0] - 2019-02-21 469 | 470 | - Allow multiple subnet ids ([#67](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/67)) 471 | 472 | 473 | 474 | ## [v1.14.0] - 2019-01-26 475 | 476 | - Tags should be possible to override (fixed [#53](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/53)) ([#66](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/66)) 477 | - fix typo ([#61](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/61)) 478 | 479 | 480 | 481 | ## [v1.13.0] - 2018-10-31 482 | 483 | - Include the module version and some code formatting ([#52](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/52)) 484 | 485 | 486 | 487 | ## [v1.12.0] - 2018-10-06 488 | 489 | - Fixed [#51](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/51). t2 and t3 instances can be unlimited 490 | 491 | 492 | 493 | ## [v1.11.0] - 2018-09-04 494 | 495 | - Added example of EBS volume attachment (related to [#46](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/46)) ([#47](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/47)) 496 | - Ignore changes in the ebs_block_device ([#46](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/46)) 497 | 498 | 499 | 500 | ## [v1.10.0] - 2018-08-18 501 | 502 | - [master]: Narrow t2 selection criteria. ([#44](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/44)) 503 | 504 | 505 | 506 | ## [v1.9.0] - 2018-06-08 507 | 508 | - Fixed t2-unlimited bug (related issue [#35](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/35)) ([#37](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/37)) 509 | 510 | 511 | 512 | ## [v1.8.0] - 2018-06-04 513 | 514 | - Added support for CPU credits ([#35](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/35)) 515 | 516 | 517 | 518 | ## [v1.7.0] - 2018-06-02 519 | 520 | - Added encrypted AMI info ([#34](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/34)) 521 | 522 | 523 | 524 | ## [v1.6.0] - 2018-05-16 525 | 526 | - Added pre-commit hook to autogenerate terraform-docs ([#33](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/33)) 527 | 528 | 529 | 530 | ## [v1.5.0] - 2018-04-04 531 | 532 | - Minor formatting fix 533 | - Modify tag name management to add -%d suffixe only if instance_count > 1 534 | 535 | 536 | 537 | ## [v1.4.0] - 2018-04-04 538 | 539 | - Stop ignoring changes in vpc_security_group_ids 540 | 541 | 542 | 543 | ## [v1.3.0] - 2018-03-06 544 | 545 | - Renamed count to instance_count (fixes [#23](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/23)) 546 | - Fix: add missing variable to the usage example 547 | 548 | 549 | 550 | ## [v1.2.1] - 2018-03-01 551 | 552 | - Added aws_eip to example and pre-commit hooks 553 | 554 | 555 | 556 | ## [v1.2.0] - 2018-01-19 557 | 558 | - Add tags to output variables 559 | 560 | 561 | 562 | ## [v1.1.0] - 2017-12-08 563 | 564 | - Make module idempotent by requiring subnet_id and ignore changes in several arguments (fixes [#10](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/issues/10)) 565 | 566 | 567 | 568 | ## [v1.0.4] - 2017-11-21 569 | 570 | - Removed placement_group from outputs 571 | 572 | 573 | 574 | ## [v1.0.3] - 2017-11-15 575 | 576 | - Fix incorrect subnet_id output expression 577 | - Updated example with all-icmp security group rule 578 | 579 | 580 | 581 | ## [v1.0.2] - 2017-10-13 582 | 583 | - Added example with security-group module 584 | 585 | 586 | 587 | ## [v1.0.1] - 2017-09-14 588 | 589 | - Updated example and made security group required 590 | 591 | 592 | 593 | ## v1.0.0 - 2017-09-12 594 | 595 | - Updated repo name 596 | - Updated README 597 | - Added complete code with example and READMEs 598 | - Initial commit 599 | 600 | 601 | [Unreleased]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v3.2.0...HEAD 602 | [v3.2.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v3.1.0...v3.2.0 603 | [v3.1.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v3.0.0...v3.1.0 604 | [v3.0.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v2.21.0...v3.0.0 605 | [v2.21.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v2.20.0...v2.21.0 606 | [v2.20.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v2.19.0...v2.20.0 607 | [v2.19.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v2.18.0...v2.19.0 608 | [v2.18.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v2.17.0...v2.18.0 609 | [v2.17.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v2.16.0...v2.17.0 610 | [v2.16.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v2.15.0...v2.16.0 611 | [v2.15.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v2.14.0...v2.15.0 612 | [v2.14.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v1.25.0...v2.14.0 613 | [v1.25.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v2.13.0...v1.25.0 614 | [v2.13.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v2.12.0...v2.13.0 615 | [v2.12.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v2.11.0...v2.12.0 616 | [v2.11.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v2.10.0...v2.11.0 617 | [v2.10.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v2.9.0...v2.10.0 618 | [v2.9.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v2.8.0...v2.9.0 619 | [v2.8.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v2.7.0...v2.8.0 620 | [v2.7.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v2.6.0...v2.7.0 621 | [v2.6.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v2.5.0...v2.6.0 622 | [v2.5.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v2.4.0...v2.5.0 623 | [v2.4.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v2.3.0...v2.4.0 624 | [v2.3.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v2.2.0...v2.3.0 625 | [v2.2.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v2.1.0...v2.2.0 626 | [v2.1.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v1.24.0...v2.1.0 627 | [v1.24.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v1.23.0...v1.24.0 628 | [v1.23.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v2.0.0...v1.23.0 629 | [v2.0.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v1.22.0...v2.0.0 630 | [v1.22.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v1.21.0...v1.22.0 631 | [v1.21.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v1.20.0...v1.21.0 632 | [v1.20.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v1.19.0...v1.20.0 633 | [v1.19.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v1.18.0...v1.19.0 634 | [v1.18.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v1.17.0...v1.18.0 635 | [v1.17.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v1.16.0...v1.17.0 636 | [v1.16.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v1.15.0...v1.16.0 637 | [v1.15.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v1.14.0...v1.15.0 638 | [v1.14.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v1.13.0...v1.14.0 639 | [v1.13.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v1.12.0...v1.13.0 640 | [v1.12.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v1.11.0...v1.12.0 641 | [v1.11.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v1.10.0...v1.11.0 642 | [v1.10.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v1.9.0...v1.10.0 643 | [v1.9.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v1.8.0...v1.9.0 644 | [v1.8.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v1.7.0...v1.8.0 645 | [v1.7.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v1.6.0...v1.7.0 646 | [v1.6.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v1.5.0...v1.6.0 647 | [v1.5.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v1.4.0...v1.5.0 648 | [v1.4.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v1.3.0...v1.4.0 649 | [v1.3.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v1.2.1...v1.3.0 650 | [v1.2.1]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v1.2.0...v1.2.1 651 | [v1.2.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v1.1.0...v1.2.0 652 | [v1.1.0]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v1.0.4...v1.1.0 653 | [v1.0.4]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v1.0.3...v1.0.4 654 | [v1.0.3]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v1.0.2...v1.0.3 655 | [v1.0.2]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v1.0.1...v1.0.2 656 | [v1.0.1]: https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/compare/v1.0.0...v1.0.1 657 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AWS EC2 Instance Terraform module 2 | 3 | Terraform module which creates an EC2 instance on AWS. 4 | 5 | [![SWUbanner](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner2-direct.svg)](https://github.com/vshymanskyy/StandWithUkraine/blob/main/docs/README.md) 6 | 7 | ## Usage 8 | 9 | ### Single EC2 Instance 10 | 11 | ```hcl 12 | module "ec2_instance" { 13 | source = "terraform-aws-modules/ec2-instance/aws" 14 | 15 | name = "single-instance" 16 | 17 | instance_type = "t2.micro" 18 | key_name = "user1" 19 | monitoring = true 20 | vpc_security_group_ids = ["sg-12345678"] 21 | subnet_id = "subnet-eddcdzz4" 22 | 23 | tags = { 24 | Terraform = "true" 25 | Environment = "dev" 26 | } 27 | } 28 | ``` 29 | 30 | ### Multiple EC2 Instance 31 | 32 | ```hcl 33 | module "ec2_instance" { 34 | source = "terraform-aws-modules/ec2-instance/aws" 35 | 36 | for_each = toset(["one", "two", "three"]) 37 | 38 | name = "instance-${each.key}" 39 | 40 | instance_type = "t2.micro" 41 | key_name = "user1" 42 | monitoring = true 43 | vpc_security_group_ids = ["sg-12345678"] 44 | subnet_id = "subnet-eddcdzz4" 45 | 46 | tags = { 47 | Terraform = "true" 48 | Environment = "dev" 49 | } 50 | } 51 | ``` 52 | 53 | ### Spot EC2 Instance 54 | 55 | ```hcl 56 | module "ec2_instance" { 57 | source = "terraform-aws-modules/ec2-instance/aws" 58 | 59 | name = "spot-instance" 60 | 61 | create_spot_instance = true 62 | spot_price = "0.60" 63 | spot_type = "persistent" 64 | 65 | instance_type = "t2.micro" 66 | key_name = "user1" 67 | monitoring = true 68 | vpc_security_group_ids = ["sg-12345678"] 69 | subnet_id = "subnet-eddcdzz4" 70 | 71 | tags = { 72 | Terraform = "true" 73 | Environment = "dev" 74 | } 75 | } 76 | ``` 77 | 78 | ## Module wrappers 79 | 80 | Users of this Terraform module can create multiple similar resources by using [`for_each` meta-argument within `module` block](https://www.terraform.io/language/meta-arguments/for_each) which became available in Terraform 0.13. 81 | 82 | Users of Terragrunt can achieve similar results by using modules provided in the [wrappers](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/tree/master/wrappers) directory, if they prefer to reduce amount of configuration files. 83 | 84 | ## Examples 85 | 86 | - [Complete EC2 instance](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/tree/master/examples/complete) 87 | - [EC2 instance w/ private network access via Session Manager](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/tree/master/examples/session-manager) 88 | - [EC2 instance with EBS volume attachment](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/tree/master/examples/volume-attachment) 89 | 90 | ## Make an encrypted AMI for use 91 | 92 | This module does not support encrypted AMI's out of the box however it is easy enough for you to generate one for use 93 | 94 | This example creates an encrypted image from the latest ubuntu 16.04 base image. 95 | 96 | ```hcl 97 | provider "aws" { 98 | region = "us-west-2" 99 | } 100 | 101 | data "aws_ami" "ubuntu" { 102 | most_recent = true 103 | owners = ["679593333241"] 104 | 105 | filter { 106 | name = "name" 107 | values = ["ubuntu-minimal/images/hvm-ssd/ubuntu-focal-20.04-*"] 108 | } 109 | 110 | filter { 111 | name = "virtualization-type" 112 | values = ["hvm"] 113 | } 114 | } 115 | 116 | resource "aws_ami_copy" "ubuntu_encrypted_ami" { 117 | name = "ubuntu-encrypted-ami" 118 | description = "An encrypted root ami based off ${data.aws_ami.ubuntu.id}" 119 | source_ami_id = data.aws_ami.ubuntu.id 120 | source_ami_region = "eu-west-2" 121 | encrypted = true 122 | 123 | tags = { Name = "ubuntu-encrypted-ami" } 124 | } 125 | 126 | data "aws_ami" "encrypted-ami" { 127 | most_recent = true 128 | 129 | filter { 130 | name = "name" 131 | values = [aws_ami_copy.ubuntu_encrypted_ami.id] 132 | } 133 | 134 | owners = ["self"] 135 | } 136 | ``` 137 | 138 | ## Conditional creation 139 | 140 | The following combinations are supported to conditionally create resources: 141 | 142 | - Disable resource creation (no resources created): 143 | 144 | ```hcl 145 | create = false 146 | ``` 147 | 148 | - Create spot instance: 149 | 150 | ```hcl 151 | create_spot_instance = true 152 | ``` 153 | 154 | ## Notes 155 | 156 | - `network_interface` can't be specified together with `vpc_security_group_ids`, `associate_public_ip_address`, `subnet_id`. See [complete example](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/tree/master/examples/complete) for details. 157 | - Changes in `ebs_block_device` argument will be ignored. Use [aws_volume_attachment](https://www.terraform.io/docs/providers/aws/r/volume_attachment.html) resource to attach and detach volumes from AWS EC2 instances. See [this example](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/tree/master/examples/volume-attachment). 158 | - In regards to spot instances, you must grant the `AWSServiceRoleForEC2Spot` service-linked role access to any custom KMS keys, otherwise your spot request and instances will fail with `bad parameters`. You can see more details about why the request failed by using the awscli and `aws ec2 describe-spot-instance-requests` 159 | 160 | 161 | ## Requirements 162 | 163 | | Name | Version | 164 | |------|---------| 165 | | [terraform](#requirement\_terraform) | >= 1.0 | 166 | | [aws](#requirement\_aws) | >= 4.66 | 167 | 168 | ## Providers 169 | 170 | | Name | Version | 171 | |------|---------| 172 | | [aws](#provider\_aws) | >= 4.66 | 173 | 174 | ## Modules 175 | 176 | No modules. 177 | 178 | ## Resources 179 | 180 | | Name | Type | 181 | |------|------| 182 | | [aws_eip.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eip) | resource | 183 | | [aws_iam_instance_profile.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_instance_profile) | resource | 184 | | [aws_iam_role.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | 185 | | [aws_iam_role_policy_attachment.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | 186 | | [aws_instance.ignore_ami](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance) | resource | 187 | | [aws_instance.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance) | resource | 188 | | [aws_spot_instance_request.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/spot_instance_request) | resource | 189 | | [aws_iam_policy_document.assume_role_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | 190 | | [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | 191 | | [aws_ssm_parameter.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ssm_parameter) | data source | 192 | 193 | ## Inputs 194 | 195 | | Name | Description | Type | Default | Required | 196 | |------|-------------|------|---------|:--------:| 197 | | [ami](#input\_ami) | ID of AMI to use for the instance | `string` | `null` | no | 198 | | [ami\_ssm\_parameter](#input\_ami\_ssm\_parameter) | SSM parameter name for the AMI ID. For Amazon Linux AMI SSM parameters see [reference](https://docs.aws.amazon.com/systems-manager/latest/userguide/parameter-store-public-parameters-ami.html) | `string` | `"/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2"` | no | 199 | | [associate\_public\_ip\_address](#input\_associate\_public\_ip\_address) | Whether to associate a public IP address with an instance in a VPC | `bool` | `null` | no | 200 | | [availability\_zone](#input\_availability\_zone) | AZ to start the instance in | `string` | `null` | no | 201 | | [capacity\_reservation\_specification](#input\_capacity\_reservation\_specification) | Describes an instance's Capacity Reservation targeting option | `any` | `{}` | no | 202 | | [cpu\_core\_count](#input\_cpu\_core\_count) | Sets the number of CPU cores for an instance | `number` | `null` | no | 203 | | [cpu\_credits](#input\_cpu\_credits) | The credit option for CPU usage (unlimited or standard) | `string` | `null` | no | 204 | | [cpu\_options](#input\_cpu\_options) | Defines CPU options to apply to the instance at launch time. | `any` | `{}` | no | 205 | | [cpu\_threads\_per\_core](#input\_cpu\_threads\_per\_core) | Sets the number of CPU threads per core for an instance (has no effect unless cpu\_core\_count is also set) | `number` | `null` | no | 206 | | [create](#input\_create) | Whether to create an instance | `bool` | `true` | no | 207 | | [create\_eip](#input\_create\_eip) | Determines whether a public EIP will be created and associated with the instance. | `bool` | `false` | no | 208 | | [create\_iam\_instance\_profile](#input\_create\_iam\_instance\_profile) | Determines whether an IAM instance profile is created or to use an existing IAM instance profile | `bool` | `false` | no | 209 | | [create\_spot\_instance](#input\_create\_spot\_instance) | Depicts if the instance is a spot instance | `bool` | `false` | no | 210 | | [disable\_api\_stop](#input\_disable\_api\_stop) | If true, enables EC2 Instance Stop Protection | `bool` | `null` | no | 211 | | [disable\_api\_termination](#input\_disable\_api\_termination) | If true, enables EC2 Instance Termination Protection | `bool` | `null` | no | 212 | | [ebs\_block\_device](#input\_ebs\_block\_device) | Additional EBS block devices to attach to the instance | `list(any)` | `[]` | no | 213 | | [ebs\_optimized](#input\_ebs\_optimized) | If true, the launched EC2 instance will be EBS-optimized | `bool` | `null` | no | 214 | | [eip\_domain](#input\_eip\_domain) | Indicates if this EIP is for use in VPC | `string` | `"vpc"` | no | 215 | | [eip\_tags](#input\_eip\_tags) | A map of additional tags to add to the eip | `map(string)` | `{}` | no | 216 | | [enable\_volume\_tags](#input\_enable\_volume\_tags) | Whether to enable volume tags (if enabled it conflicts with root\_block\_device tags) | `bool` | `true` | no | 217 | | [enclave\_options\_enabled](#input\_enclave\_options\_enabled) | Whether Nitro Enclaves will be enabled on the instance. Defaults to `false` | `bool` | `null` | no | 218 | | [ephemeral\_block\_device](#input\_ephemeral\_block\_device) | Customize Ephemeral (also known as Instance Store) volumes on the instance | `list(map(string))` | `[]` | no | 219 | | [get\_password\_data](#input\_get\_password\_data) | If true, wait for password data to become available and retrieve it | `bool` | `null` | no | 220 | | [hibernation](#input\_hibernation) | If true, the launched EC2 instance will support hibernation | `bool` | `null` | no | 221 | | [host\_id](#input\_host\_id) | ID of a dedicated host that the instance will be assigned to. Use when an instance is to be launched on a specific dedicated host | `string` | `null` | no | 222 | | [iam\_instance\_profile](#input\_iam\_instance\_profile) | IAM Instance Profile to launch the instance with. Specified as the name of the Instance Profile | `string` | `null` | no | 223 | | [iam\_role\_description](#input\_iam\_role\_description) | Description of the role | `string` | `null` | no | 224 | | [iam\_role\_name](#input\_iam\_role\_name) | Name to use on IAM role created | `string` | `null` | no | 225 | | [iam\_role\_path](#input\_iam\_role\_path) | IAM role path | `string` | `null` | no | 226 | | [iam\_role\_permissions\_boundary](#input\_iam\_role\_permissions\_boundary) | ARN of the policy that is used to set the permissions boundary for the IAM role | `string` | `null` | no | 227 | | [iam\_role\_policies](#input\_iam\_role\_policies) | Policies attached to the IAM role | `map(string)` | `{}` | no | 228 | | [iam\_role\_tags](#input\_iam\_role\_tags) | A map of additional tags to add to the IAM role/profile created | `map(string)` | `{}` | no | 229 | | [iam\_role\_use\_name\_prefix](#input\_iam\_role\_use\_name\_prefix) | Determines whether the IAM role name (`iam_role_name` or `name`) is used as a prefix | `bool` | `true` | no | 230 | | [ignore\_ami\_changes](#input\_ignore\_ami\_changes) | Whether changes to the AMI ID changes should be ignored by Terraform. Note - changing this value will result in the replacement of the instance | `bool` | `false` | no | 231 | | [instance\_initiated\_shutdown\_behavior](#input\_instance\_initiated\_shutdown\_behavior) | Shutdown behavior for the instance. Amazon defaults this to stop for EBS-backed instances and terminate for instance-store instances. Cannot be set on instance-store instance | `string` | `null` | no | 232 | | [instance\_tags](#input\_instance\_tags) | Additional tags for the instance | `map(string)` | `{}` | no | 233 | | [instance\_type](#input\_instance\_type) | The type of instance to start | `string` | `"t3.micro"` | no | 234 | | [ipv6\_address\_count](#input\_ipv6\_address\_count) | A number of IPv6 addresses to associate with the primary network interface. Amazon EC2 chooses the IPv6 addresses from the range of your subnet | `number` | `null` | no | 235 | | [ipv6\_addresses](#input\_ipv6\_addresses) | Specify one or more IPv6 addresses from the range of the subnet to associate with the primary network interface | `list(string)` | `null` | no | 236 | | [key\_name](#input\_key\_name) | Key name of the Key Pair to use for the instance; which can be managed using the `aws_key_pair` resource | `string` | `null` | no | 237 | | [launch\_template](#input\_launch\_template) | Specifies a Launch Template to configure the instance. Parameters configured on this resource will override the corresponding parameters in the Launch Template | `map(string)` | `{}` | no | 238 | | [maintenance\_options](#input\_maintenance\_options) | The maintenance options for the instance | `any` | `{}` | no | 239 | | [metadata\_options](#input\_metadata\_options) | Customize the metadata options of the instance | `map(string)` |
{
"http_endpoint": "enabled",
"http_put_response_hop_limit": 1,
"http_tokens": "required"
}
| no | 240 | | [monitoring](#input\_monitoring) | If true, the launched EC2 instance will have detailed monitoring enabled | `bool` | `null` | no | 241 | | [name](#input\_name) | Name to be used on EC2 instance created | `string` | `""` | no | 242 | | [network\_interface](#input\_network\_interface) | Customize network interfaces to be attached at instance boot time | `list(map(string))` | `[]` | no | 243 | | [placement\_group](#input\_placement\_group) | The Placement Group to start the instance in | `string` | `null` | no | 244 | | [private\_dns\_name\_options](#input\_private\_dns\_name\_options) | Customize the private DNS name options of the instance | `map(string)` | `{}` | no | 245 | | [private\_ip](#input\_private\_ip) | Private IP address to associate with the instance in a VPC | `string` | `null` | no | 246 | | [putin\_khuylo](#input\_putin\_khuylo) | Do you agree that Putin doesn't respect Ukrainian sovereignty and territorial integrity? More info: https://en.wikipedia.org/wiki/Putin_khuylo! | `bool` | `true` | no | 247 | | [root\_block\_device](#input\_root\_block\_device) | Customize details about the root block device of the instance. See Block Devices below for details | `list(any)` | `[]` | no | 248 | | [secondary\_private\_ips](#input\_secondary\_private\_ips) | A list of secondary private IPv4 addresses to assign to the instance's primary network interface (eth0) in a VPC. Can only be assigned to the primary network interface (eth0) attached at instance creation, not a pre-existing network interface i.e. referenced in a `network_interface block` | `list(string)` | `null` | no | 249 | | [source\_dest\_check](#input\_source\_dest\_check) | Controls if traffic is routed to the instance when the destination address does not match the instance. Used for NAT or VPNs | `bool` | `null` | no | 250 | | [spot\_block\_duration\_minutes](#input\_spot\_block\_duration\_minutes) | The required duration for the Spot instances, in minutes. This value must be a multiple of 60 (60, 120, 180, 240, 300, or 360) | `number` | `null` | no | 251 | | [spot\_instance\_interruption\_behavior](#input\_spot\_instance\_interruption\_behavior) | Indicates Spot instance behavior when it is interrupted. Valid values are `terminate`, `stop`, or `hibernate` | `string` | `null` | no | 252 | | [spot\_launch\_group](#input\_spot\_launch\_group) | A launch group is a group of spot instances that launch together and terminate together. If left empty instances are launched and terminated individually | `string` | `null` | no | 253 | | [spot\_price](#input\_spot\_price) | The maximum price to request on the spot market. Defaults to on-demand price | `string` | `null` | no | 254 | | [spot\_type](#input\_spot\_type) | If set to one-time, after the instance is terminated, the spot request will be closed. Default `persistent` | `string` | `null` | no | 255 | | [spot\_valid\_from](#input\_spot\_valid\_from) | The start date and time of the request, in UTC RFC3339 format(for example, YYYY-MM-DDTHH:MM:SSZ) | `string` | `null` | no | 256 | | [spot\_valid\_until](#input\_spot\_valid\_until) | The end date and time of the request, in UTC RFC3339 format(for example, YYYY-MM-DDTHH:MM:SSZ) | `string` | `null` | no | 257 | | [spot\_wait\_for\_fulfillment](#input\_spot\_wait\_for\_fulfillment) | If set, Terraform will wait for the Spot Request to be fulfilled, and will throw an error if the timeout of 10m is reached | `bool` | `null` | no | 258 | | [subnet\_id](#input\_subnet\_id) | The VPC Subnet ID to launch in | `string` | `null` | no | 259 | | [tags](#input\_tags) | A mapping of tags to assign to the resource | `map(string)` | `{}` | no | 260 | | [tenancy](#input\_tenancy) | The tenancy of the instance (if the instance is running in a VPC). Available values: default, dedicated, host | `string` | `null` | no | 261 | | [timeouts](#input\_timeouts) | Define maximum timeout for creating, updating, and deleting EC2 instance resources | `map(string)` | `{}` | no | 262 | | [user\_data](#input\_user\_data) | The user data to provide when launching the instance. Do not pass gzip-compressed data via this argument; see user\_data\_base64 instead | `string` | `null` | no | 263 | | [user\_data\_base64](#input\_user\_data\_base64) | Can be used instead of user\_data to pass base64-encoded binary data directly. Use this instead of user\_data whenever the value is not a valid UTF-8 string. For example, gzip-encoded user data must be base64-encoded and passed via this argument to avoid corruption | `string` | `null` | no | 264 | | [user\_data\_replace\_on\_change](#input\_user\_data\_replace\_on\_change) | When used in combination with user\_data or user\_data\_base64 will trigger a destroy and recreate when set to true. Defaults to false if not set | `bool` | `null` | no | 265 | | [volume\_tags](#input\_volume\_tags) | A mapping of tags to assign to the devices created by the instance at launch time | `map(string)` | `{}` | no | 266 | | [vpc\_security\_group\_ids](#input\_vpc\_security\_group\_ids) | A list of security group IDs to associate with | `list(string)` | `null` | no | 267 | 268 | ## Outputs 269 | 270 | | Name | Description | 271 | |------|-------------| 272 | | [ami](#output\_ami) | AMI ID that was used to create the instance | 273 | | [arn](#output\_arn) | The ARN of the instance | 274 | | [availability\_zone](#output\_availability\_zone) | The availability zone of the created instance | 275 | | [capacity\_reservation\_specification](#output\_capacity\_reservation\_specification) | Capacity reservation specification of the instance | 276 | | [ebs\_block\_device](#output\_ebs\_block\_device) | EBS block device information | 277 | | [ephemeral\_block\_device](#output\_ephemeral\_block\_device) | Ephemeral block device information | 278 | | [iam\_instance\_profile\_arn](#output\_iam\_instance\_profile\_arn) | ARN assigned by AWS to the instance profile | 279 | | [iam\_instance\_profile\_id](#output\_iam\_instance\_profile\_id) | Instance profile's ID | 280 | | [iam\_instance\_profile\_unique](#output\_iam\_instance\_profile\_unique) | Stable and unique string identifying the IAM instance profile | 281 | | [iam\_role\_arn](#output\_iam\_role\_arn) | The Amazon Resource Name (ARN) specifying the IAM role | 282 | | [iam\_role\_name](#output\_iam\_role\_name) | The name of the IAM role | 283 | | [iam\_role\_unique\_id](#output\_iam\_role\_unique\_id) | Stable and unique string identifying the IAM role | 284 | | [id](#output\_id) | The ID of the instance | 285 | | [instance\_state](#output\_instance\_state) | The state of the instance | 286 | | [ipv6\_addresses](#output\_ipv6\_addresses) | The IPv6 address assigned to the instance, if applicable | 287 | | [outpost\_arn](#output\_outpost\_arn) | The ARN of the Outpost the instance is assigned to | 288 | | [password\_data](#output\_password\_data) | Base-64 encoded encrypted password data for the instance. Useful for getting the administrator password for instances running Microsoft Windows. This attribute is only exported if `get_password_data` is true | 289 | | [primary\_network\_interface\_id](#output\_primary\_network\_interface\_id) | The ID of the instance's primary network interface | 290 | | [private\_dns](#output\_private\_dns) | The private DNS name assigned to the instance. Can only be used inside the Amazon EC2, and only available if you've enabled DNS hostnames for your VPC | 291 | | [private\_ip](#output\_private\_ip) | The private IP address assigned to the instance | 292 | | [public\_dns](#output\_public\_dns) | The public DNS name assigned to the instance. For EC2-VPC, this is only available if you've enabled DNS hostnames for your VPC | 293 | | [public\_ip](#output\_public\_ip) | The public IP address assigned to the instance, if applicable. | 294 | | [root\_block\_device](#output\_root\_block\_device) | Root block device information | 295 | | [spot\_bid\_status](#output\_spot\_bid\_status) | The current bid status of the Spot Instance Request | 296 | | [spot\_instance\_id](#output\_spot\_instance\_id) | The Instance ID (if any) that is currently fulfilling the Spot Instance request | 297 | | [spot\_request\_state](#output\_spot\_request\_state) | The current request state of the Spot Instance Request | 298 | | [tags\_all](#output\_tags\_all) | A map of tags assigned to the resource, including those inherited from the provider default\_tags configuration block | 299 | 300 | 301 | ## Authors 302 | 303 | Module is maintained by [Anton Babenko](https://github.com/antonbabenko) with help from [these awesome contributors](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/graphs/contributors). 304 | 305 | ## License 306 | 307 | Apache 2 Licensed. See [LICENSE](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/tree/master/LICENSE) for full details. 308 | 309 | ## Additional information for users from Russia and Belarus 310 | 311 | * Russia has [illegally annexed Crimea in 2014](https://en.wikipedia.org/wiki/Annexation_of_Crimea_by_the_Russian_Federation) and [brought the war in Donbas](https://en.wikipedia.org/wiki/War_in_Donbas) followed by [full-scale invasion of Ukraine in 2022](https://en.wikipedia.org/wiki/2022_Russian_invasion_of_Ukraine). 312 | * Russia has brought sorrow and devastations to millions of Ukrainians, killed hundreds of innocent people, damaged thousands of buildings, and forced several million people to flee. 313 | * [Putin khuylo!](https://en.wikipedia.org/wiki/Putin_khuylo!) 314 | -------------------------------------------------------------------------------- /UPGRADE-3.0.md: -------------------------------------------------------------------------------- 1 | # Upgrade from v2.x to v3.x 2 | 3 | If you have any questions regarding this upgrade process, please consult the `examples` directory: 4 | 5 | - [Complete](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/tree/master/examples/complete) 6 | - [Volume Attachment](https://github.com/terraform-aws-modules/terraform-aws-ec2-instance/tree/master/examples/volume-attachment) 7 | 8 | If you find a bug, please open an issue with supporting configuration to reproduce. 9 | 10 | ## List of backwards incompatible changes 11 | 12 | - Terraform v0.13.1 is now minimum supported version to take advantage of `count` and `for_each` arguments at module level 13 | 14 | ### Variable and output changes 15 | 16 | 1. Removed variables: 17 | 18 | - `instance_count` 19 | - `subnet_ids` (only need to use `subnet_id` now) 20 | - `private_ips` (only need to use `private_ip` now) 21 | - `use_num_suffix` 22 | - `num_suffix_format` 23 | 24 | 2. Renamed variables: 25 | 26 | - `tags` -> `tags_all` 27 | 28 | 3. Removed outputs: 29 | 30 | - `availability_zone` 31 | - `placement_group` 32 | - `key_name` 33 | - `ipv6_addresses` 34 | - `private_ip` 35 | - `security_groups` 36 | - `vpc_security_group_ids` 37 | - `subnet_id` 38 | - `credit_specification` 39 | - `metadata_options` 40 | - `root_block_device_volume_ids` 41 | - `ebs_block_device_volume_ids` 42 | - `volume_tags` 43 | - `instance_count` 44 | 45 | 4. Renamed outputs: 46 | 47 | :info: All outputs used to be lists, and are now singular outputs due to the removal of `count` 48 | 49 | ## Upgrade State Migrations 50 | 51 | ### Before 2.x Example 52 | 53 | ```hcl 54 | module "ec2_upgrade" { 55 | source = "terraform-aws-modules/ec2-instance/aws" 56 | version = "2.21.0" 57 | 58 | instance_count = 3 59 | 60 | name = local.name 61 | ami = data.aws_ami.amazon_linux.id 62 | instance_type = "c5.large" 63 | subnet_ids = module.vpc.private_subnets 64 | vpc_security_group_ids = [module.security_group.security_group_id] 65 | associate_public_ip_address = true 66 | 67 | tags = local.tags 68 | } 69 | ``` 70 | 71 | ### After 3.x Example 72 | 73 | ```hcl 74 | locals { 75 | num_suffix_format = "-%d" 76 | multiple_instances = { 77 | 0 = { 78 | num_suffix = 1 79 | instance_type = "c5.large" 80 | subnet_id = element(module.vpc.private_subnets, 0) 81 | } 82 | 1 = { 83 | num_suffix = 2 84 | instance_type = "c5.large" 85 | subnet_id = element(module.vpc.private_subnets, 1) 86 | } 87 | 2 = { 88 | num_suffix = 3 89 | instance_type = "c5.large" 90 | subnet_id = element(module.vpc.private_subnets, 2) 91 | } 92 | } 93 | } 94 | 95 | module "ec2_upgrade" { 96 | source = "../../" 97 | 98 | for_each = local.multiple_instances 99 | 100 | name = format("%s${local.num_suffix_format}", local.name, each.value.num_suffix) 101 | 102 | ami = data.aws_ami.amazon_linux.id 103 | instance_type = each.value.instance_type 104 | subnet_id = each.value.subnet_id 105 | vpc_security_group_ids = [module.security_group.security_group_id] 106 | associate_public_ip_address = true 107 | 108 | tags = local.tags 109 | } 110 | ``` 111 | 112 | To migrate from the `v2.x` version to `v3.x` version example shown above, the following state move commands can be performed to maintain the current resources without modification: 113 | 114 | ```bash 115 | terraform state mv 'module.ec2_upgrade.aws_instance.this[0]' 'module.ec2_upgrade["0"].aws_instance.this[0]' 116 | terraform state mv 'module.ec2_upgrade.aws_instance.this[1]' 'module.ec2_upgrade["1"].aws_instance.this[0]' 117 | terraform state mv 'module.ec2_upgrade.aws_instance.this[2]' 'module.ec2_upgrade["2"].aws_instance.this[0]' 118 | ``` 119 | 120 | :info: Notes 121 | 122 | - In the `v2.x` example we use `subnet_ids` which is an array of subnets. These are mapped to the respective instance based on their index location; therefore in the `v3.x` example we are doing a similar index lookup to map back to the existing subnet used for that instance. This would also be the case for `private_ips` 123 | - In the `v3.x` example we have shown how users can continue to use the same naming scheme that is currently in use by the `v2.x` module. By moving the `num_suffix_format` into the module name itself inside a format function, users can continue to customize the names generated in a similar manner as that of the `v2.x` module. 124 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | Please note - the examples provided serve two primary means: 4 | 5 | 1. Show users working examples of the various ways in which the module can be configured and features supported 6 | 2. A means of testing/validating module changes 7 | 8 | Please do not mistake the examples provided as "best practices". It is up to users to consult the AWS service documentation for best practices, usage recommendations, etc. 9 | -------------------------------------------------------------------------------- /examples/complete/README.md: -------------------------------------------------------------------------------- 1 | # Complete EC2 instance 2 | 3 | Configuration in this directory creates EC2 instances with different sets of arguments (with Elastic IP, with network interface attached, with credit specifications). 4 | 5 | ## Usage 6 | 7 | To run this example you need to execute: 8 | 9 | ```bash 10 | $ terraform init 11 | $ terraform plan 12 | $ terraform apply 13 | ``` 14 | 15 | Note that this example may create resources which can cost money. Run `terraform destroy` when you don't need these resources. 16 | 17 | 18 | ## Requirements 19 | 20 | | Name | Version | 21 | |------|---------| 22 | | [terraform](#requirement\_terraform) | >= 1.0 | 23 | | [aws](#requirement\_aws) | >= 4.66 | 24 | 25 | ## Providers 26 | 27 | | Name | Version | 28 | |------|---------| 29 | | [aws](#provider\_aws) | >= 4.66 | 30 | 31 | ## Modules 32 | 33 | | Name | Source | Version | 34 | |------|--------|---------| 35 | | [ec2\_complete](#module\_ec2\_complete) | ../../ | n/a | 36 | | [ec2\_cpu\_options](#module\_ec2\_cpu\_options) | ../../ | n/a | 37 | | [ec2\_disabled](#module\_ec2\_disabled) | ../../ | n/a | 38 | | [ec2\_ignore\_ami\_changes](#module\_ec2\_ignore\_ami\_changes) | ../../ | n/a | 39 | | [ec2\_metadata\_options](#module\_ec2\_metadata\_options) | ../../ | n/a | 40 | | [ec2\_multiple](#module\_ec2\_multiple) | ../../ | n/a | 41 | | [ec2\_network\_interface](#module\_ec2\_network\_interface) | ../../ | n/a | 42 | | [ec2\_open\_capacity\_reservation](#module\_ec2\_open\_capacity\_reservation) | ../../ | n/a | 43 | | [ec2\_spot\_instance](#module\_ec2\_spot\_instance) | ../../ | n/a | 44 | | [ec2\_t2\_unlimited](#module\_ec2\_t2\_unlimited) | ../../ | n/a | 45 | | [ec2\_t3\_unlimited](#module\_ec2\_t3\_unlimited) | ../../ | n/a | 46 | | [ec2\_targeted\_capacity\_reservation](#module\_ec2\_targeted\_capacity\_reservation) | ../../ | n/a | 47 | | [security\_group](#module\_security\_group) | terraform-aws-modules/security-group/aws | ~> 4.0 | 48 | | [vpc](#module\_vpc) | terraform-aws-modules/vpc/aws | ~> 5.0 | 49 | 50 | ## Resources 51 | 52 | | Name | Type | 53 | |------|------| 54 | | [aws_ec2_capacity_reservation.open](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_capacity_reservation) | resource | 55 | | [aws_ec2_capacity_reservation.targeted](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_capacity_reservation) | resource | 56 | | [aws_kms_key.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key) | resource | 57 | | [aws_network_interface.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_interface) | resource | 58 | | [aws_placement_group.web](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/placement_group) | resource | 59 | | [aws_ami.amazon_linux](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami) | data source | 60 | | [aws_ami.amazon_linux_23](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami) | data source | 61 | | [aws_availability_zones.available](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/availability_zones) | data source | 62 | 63 | ## Inputs 64 | 65 | No inputs. 66 | 67 | ## Outputs 68 | 69 | | Name | Description | 70 | |------|-------------| 71 | | [ec2\_complete\_arn](#output\_ec2\_complete\_arn) | The ARN of the instance | 72 | | [ec2\_complete\_availability\_zone](#output\_ec2\_complete\_availability\_zone) | The availability zone of the created instance | 73 | | [ec2\_complete\_capacity\_reservation\_specification](#output\_ec2\_complete\_capacity\_reservation\_specification) | Capacity reservation specification of the instance | 74 | | [ec2\_complete\_ebs\_block\_device](#output\_ec2\_complete\_ebs\_block\_device) | EBS block device information | 75 | | [ec2\_complete\_ephemeral\_block\_device](#output\_ec2\_complete\_ephemeral\_block\_device) | Ephemeral block device information | 76 | | [ec2\_complete\_iam\_instance\_profile\_arn](#output\_ec2\_complete\_iam\_instance\_profile\_arn) | ARN assigned by AWS to the instance profile | 77 | | [ec2\_complete\_iam\_instance\_profile\_id](#output\_ec2\_complete\_iam\_instance\_profile\_id) | Instance profile's ID | 78 | | [ec2\_complete\_iam\_instance\_profile\_unique](#output\_ec2\_complete\_iam\_instance\_profile\_unique) | Stable and unique string identifying the IAM instance profile | 79 | | [ec2\_complete\_iam\_role\_arn](#output\_ec2\_complete\_iam\_role\_arn) | The Amazon Resource Name (ARN) specifying the IAM role | 80 | | [ec2\_complete\_iam\_role\_name](#output\_ec2\_complete\_iam\_role\_name) | The name of the IAM role | 81 | | [ec2\_complete\_iam\_role\_unique\_id](#output\_ec2\_complete\_iam\_role\_unique\_id) | Stable and unique string identifying the IAM role | 82 | | [ec2\_complete\_id](#output\_ec2\_complete\_id) | The ID of the instance | 83 | | [ec2\_complete\_instance\_state](#output\_ec2\_complete\_instance\_state) | The state of the instance. One of: `pending`, `running`, `shutting-down`, `terminated`, `stopping`, `stopped` | 84 | | [ec2\_complete\_primary\_network\_interface\_id](#output\_ec2\_complete\_primary\_network\_interface\_id) | The ID of the instance's primary network interface | 85 | | [ec2\_complete\_private\_dns](#output\_ec2\_complete\_private\_dns) | The private DNS name assigned to the instance. Can only be used inside the Amazon EC2, and only available if you've enabled DNS hostnames for your VPC | 86 | | [ec2\_complete\_public\_dns](#output\_ec2\_complete\_public\_dns) | The public DNS name assigned to the instance. For EC2-VPC, this is only available if you've enabled DNS hostnames for your VPC | 87 | | [ec2\_complete\_public\_ip](#output\_ec2\_complete\_public\_ip) | The public IP address assigned to the instance, if applicable. NOTE: If you are using an aws\_eip with your instance, you should refer to the EIP's address directly and not use `public_ip` as this field will change after the EIP is attached | 88 | | [ec2\_complete\_root\_block\_device](#output\_ec2\_complete\_root\_block\_device) | Root block device information | 89 | | [ec2\_complete\_tags\_all](#output\_ec2\_complete\_tags\_all) | A map of tags assigned to the resource, including those inherited from the provider default\_tags configuration block | 90 | | [ec2\_ignore\_ami\_changes\_ami](#output\_ec2\_ignore\_ami\_changes\_ami) | The AMI of the instance (ignore\_ami\_changes = true) | 91 | | [ec2\_multiple](#output\_ec2\_multiple) | The full output of the `ec2_module` module | 92 | | [ec2\_spot\_instance\_arn](#output\_ec2\_spot\_instance\_arn) | The ARN of the instance | 93 | | [ec2\_spot\_instance\_capacity\_reservation\_specification](#output\_ec2\_spot\_instance\_capacity\_reservation\_specification) | Capacity reservation specification of the instance | 94 | | [ec2\_spot\_instance\_id](#output\_ec2\_spot\_instance\_id) | The ID of the instance | 95 | | [ec2\_spot\_instance\_instance\_state](#output\_ec2\_spot\_instance\_instance\_state) | The state of the instance. One of: `pending`, `running`, `shutting-down`, `terminated`, `stopping`, `stopped` | 96 | | [ec2\_spot\_instance\_primary\_network\_interface\_id](#output\_ec2\_spot\_instance\_primary\_network\_interface\_id) | The ID of the instance's primary network interface | 97 | | [ec2\_spot\_instance\_private\_dns](#output\_ec2\_spot\_instance\_private\_dns) | The private DNS name assigned to the instance. Can only be used inside the Amazon EC2, and only available if you've enabled DNS hostnames for your VPC | 98 | | [ec2\_spot\_instance\_public\_dns](#output\_ec2\_spot\_instance\_public\_dns) | The public DNS name assigned to the instance. For EC2-VPC, this is only available if you've enabled DNS hostnames for your VPC | 99 | | [ec2\_spot\_instance\_public\_ip](#output\_ec2\_spot\_instance\_public\_ip) | The public IP address assigned to the instance, if applicable. NOTE: If you are using an aws\_eip with your instance, you should refer to the EIP's address directly and not use `public_ip` as this field will change after the EIP is attached | 100 | | [ec2\_spot\_instance\_tags\_all](#output\_ec2\_spot\_instance\_tags\_all) | A map of tags assigned to the resource, including those inherited from the provider default\_tags configuration block | 101 | | [ec2\_t2\_unlimited\_arn](#output\_ec2\_t2\_unlimited\_arn) | The ARN of the instance | 102 | | [ec2\_t2\_unlimited\_availability\_zone](#output\_ec2\_t2\_unlimited\_availability\_zone) | The availability zone of the created instance | 103 | | [ec2\_t2\_unlimited\_capacity\_reservation\_specification](#output\_ec2\_t2\_unlimited\_capacity\_reservation\_specification) | Capacity reservation specification of the instance | 104 | | [ec2\_t2\_unlimited\_id](#output\_ec2\_t2\_unlimited\_id) | The ID of the instance | 105 | | [ec2\_t2\_unlimited\_instance\_state](#output\_ec2\_t2\_unlimited\_instance\_state) | The state of the instance. One of: `pending`, `running`, `shutting-down`, `terminated`, `stopping`, `stopped` | 106 | | [ec2\_t2\_unlimited\_primary\_network\_interface\_id](#output\_ec2\_t2\_unlimited\_primary\_network\_interface\_id) | The ID of the instance's primary network interface | 107 | | [ec2\_t2\_unlimited\_private\_dns](#output\_ec2\_t2\_unlimited\_private\_dns) | The private DNS name assigned to the instance. Can only be used inside the Amazon EC2, and only available if you've enabled DNS hostnames for your VPC | 108 | | [ec2\_t2\_unlimited\_public\_dns](#output\_ec2\_t2\_unlimited\_public\_dns) | The public DNS name assigned to the instance. For EC2-VPC, this is only available if you've enabled DNS hostnames for your VPC | 109 | | [ec2\_t2\_unlimited\_public\_ip](#output\_ec2\_t2\_unlimited\_public\_ip) | The public IP address assigned to the instance, if applicable. NOTE: If you are using an aws\_eip with your instance, you should refer to the EIP's address directly and not use `public_ip` as this field will change after the EIP is attached | 110 | | [ec2\_t2\_unlimited\_tags\_all](#output\_ec2\_t2\_unlimited\_tags\_all) | A map of tags assigned to the resource, including those inherited from the provider default\_tags configuration block | 111 | | [ec2\_t3\_unlimited\_arn](#output\_ec2\_t3\_unlimited\_arn) | The ARN of the instance | 112 | | [ec2\_t3\_unlimited\_availability\_zone](#output\_ec2\_t3\_unlimited\_availability\_zone) | The availability zone of the created instance | 113 | | [ec2\_t3\_unlimited\_capacity\_reservation\_specification](#output\_ec2\_t3\_unlimited\_capacity\_reservation\_specification) | Capacity reservation specification of the instance | 114 | | [ec2\_t3\_unlimited\_id](#output\_ec2\_t3\_unlimited\_id) | The ID of the instance | 115 | | [ec2\_t3\_unlimited\_instance\_state](#output\_ec2\_t3\_unlimited\_instance\_state) | The state of the instance. One of: `pending`, `running`, `shutting-down`, `terminated`, `stopping`, `stopped` | 116 | | [ec2\_t3\_unlimited\_primary\_network\_interface\_id](#output\_ec2\_t3\_unlimited\_primary\_network\_interface\_id) | The ID of the instance's primary network interface | 117 | | [ec2\_t3\_unlimited\_private\_dns](#output\_ec2\_t3\_unlimited\_private\_dns) | The private DNS name assigned to the instance. Can only be used inside the Amazon EC2, and only available if you've enabled DNS hostnames for your VPC | 118 | | [ec2\_t3\_unlimited\_public\_dns](#output\_ec2\_t3\_unlimited\_public\_dns) | The public DNS name assigned to the instance. For EC2-VPC, this is only available if you've enabled DNS hostnames for your VPC | 119 | | [ec2\_t3\_unlimited\_public\_ip](#output\_ec2\_t3\_unlimited\_public\_ip) | The public IP address assigned to the instance, if applicable. NOTE: If you are using an aws\_eip with your instance, you should refer to the EIP's address directly and not use `public_ip` as this field will change after the EIP is attached | 120 | | [ec2\_t3\_unlimited\_tags\_all](#output\_ec2\_t3\_unlimited\_tags\_all) | A map of tags assigned to the resource, including those inherited from the provider default\_tags configuration block | 121 | | [spot\_bid\_status](#output\_spot\_bid\_status) | The current bid status of the Spot Instance Request | 122 | | [spot\_instance\_availability\_zone](#output\_spot\_instance\_availability\_zone) | The availability zone of the created spot instance | 123 | | [spot\_instance\_id](#output\_spot\_instance\_id) | The Instance ID (if any) that is currently fulfilling the Spot Instance request | 124 | | [spot\_request\_state](#output\_spot\_request\_state) | The current request state of the Spot Instance Request | 125 | 126 | -------------------------------------------------------------------------------- /examples/complete/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = local.region 3 | } 4 | 5 | data "aws_availability_zones" "available" {} 6 | 7 | locals { 8 | name = "ex-${basename(path.cwd)}" 9 | region = "eu-west-1" 10 | 11 | vpc_cidr = "10.0.0.0/16" 12 | azs = slice(data.aws_availability_zones.available.names, 0, 3) 13 | 14 | user_data = <<-EOT 15 | #!/bin/bash 16 | echo "Hello Terraform!" 17 | EOT 18 | 19 | tags = { 20 | Name = local.name 21 | Example = local.name 22 | Repository = "https://github.com/terraform-aws-modules/terraform-aws-ec2-instance" 23 | } 24 | } 25 | 26 | ################################################################################ 27 | # EC2 Module 28 | ################################################################################ 29 | 30 | module "ec2_complete" { 31 | source = "../../" 32 | 33 | name = local.name 34 | 35 | ami = data.aws_ami.amazon_linux.id 36 | instance_type = "c5.xlarge" # used to set core count below 37 | availability_zone = element(module.vpc.azs, 0) 38 | subnet_id = element(module.vpc.private_subnets, 0) 39 | vpc_security_group_ids = [module.security_group.security_group_id] 40 | placement_group = aws_placement_group.web.id 41 | create_eip = true 42 | disable_api_stop = false 43 | 44 | create_iam_instance_profile = true 45 | iam_role_description = "IAM role for EC2 instance" 46 | iam_role_policies = { 47 | AdministratorAccess = "arn:aws:iam::aws:policy/AdministratorAccess" 48 | } 49 | 50 | # only one of these can be enabled at a time 51 | hibernation = true 52 | # enclave_options_enabled = true 53 | 54 | user_data_base64 = base64encode(local.user_data) 55 | user_data_replace_on_change = true 56 | 57 | cpu_options = { 58 | core_count = 2 59 | threads_per_core = 1 60 | } 61 | enable_volume_tags = false 62 | root_block_device = [ 63 | { 64 | encrypted = true 65 | volume_type = "gp3" 66 | throughput = 200 67 | volume_size = 50 68 | tags = { 69 | Name = "my-root-block" 70 | } 71 | }, 72 | ] 73 | 74 | ebs_block_device = [ 75 | { 76 | device_name = "/dev/sdf" 77 | volume_type = "gp3" 78 | volume_size = 5 79 | throughput = 200 80 | encrypted = true 81 | kms_key_id = aws_kms_key.this.arn 82 | tags = { 83 | MountPoint = "/mnt/data" 84 | } 85 | } 86 | ] 87 | 88 | tags = local.tags 89 | } 90 | 91 | module "ec2_network_interface" { 92 | source = "../../" 93 | 94 | name = "${local.name}-network-interface" 95 | 96 | network_interface = [ 97 | { 98 | device_index = 0 99 | network_interface_id = aws_network_interface.this.id 100 | delete_on_termination = false 101 | } 102 | ] 103 | 104 | tags = local.tags 105 | } 106 | 107 | module "ec2_metadata_options" { 108 | source = "../../" 109 | 110 | name = "${local.name}-metadata-options" 111 | 112 | subnet_id = element(module.vpc.private_subnets, 0) 113 | vpc_security_group_ids = [module.security_group.security_group_id] 114 | 115 | metadata_options = { 116 | http_endpoint = "enabled" 117 | http_tokens = "required" 118 | http_put_response_hop_limit = 8 119 | instance_metadata_tags = "enabled" 120 | } 121 | 122 | tags = local.tags 123 | } 124 | 125 | module "ec2_t2_unlimited" { 126 | source = "../../" 127 | 128 | name = "${local.name}-t2-unlimited" 129 | 130 | instance_type = "t2.micro" 131 | cpu_credits = "unlimited" 132 | subnet_id = element(module.vpc.private_subnets, 0) 133 | vpc_security_group_ids = [module.security_group.security_group_id] 134 | associate_public_ip_address = true 135 | 136 | maintenance_options = { 137 | auto_recovery = "default" 138 | } 139 | 140 | tags = local.tags 141 | } 142 | 143 | module "ec2_t3_unlimited" { 144 | source = "../../" 145 | 146 | name = "${local.name}-t3-unlimited" 147 | 148 | instance_type = "t3.micro" 149 | cpu_credits = "unlimited" 150 | subnet_id = element(module.vpc.private_subnets, 0) 151 | vpc_security_group_ids = [module.security_group.security_group_id] 152 | associate_public_ip_address = true 153 | 154 | tags = local.tags 155 | } 156 | 157 | module "ec2_disabled" { 158 | source = "../../" 159 | 160 | create = false 161 | } 162 | 163 | ################################################################################ 164 | # EC2 Module - with ignore AMI changes 165 | ################################################################################ 166 | 167 | module "ec2_ignore_ami_changes" { 168 | source = "../../" 169 | 170 | name = local.name 171 | 172 | ignore_ami_changes = true 173 | 174 | ami = data.aws_ami.amazon_linux.id 175 | instance_type = "t2.micro" 176 | availability_zone = element(module.vpc.azs, 0) 177 | subnet_id = element(module.vpc.private_subnets, 0) 178 | vpc_security_group_ids = [module.security_group.security_group_id] 179 | 180 | tags = local.tags 181 | } 182 | 183 | ################################################################################ 184 | # EC2 Module - multiple instances with `for_each` 185 | ################################################################################ 186 | 187 | locals { 188 | multiple_instances = { 189 | one = { 190 | instance_type = "t3.micro" 191 | availability_zone = element(module.vpc.azs, 0) 192 | subnet_id = element(module.vpc.private_subnets, 0) 193 | root_block_device = [ 194 | { 195 | encrypted = true 196 | volume_type = "gp3" 197 | throughput = 200 198 | volume_size = 50 199 | tags = { 200 | Name = "my-root-block" 201 | } 202 | } 203 | ] 204 | } 205 | two = { 206 | instance_type = "t3.small" 207 | availability_zone = element(module.vpc.azs, 1) 208 | subnet_id = element(module.vpc.private_subnets, 1) 209 | root_block_device = [ 210 | { 211 | encrypted = true 212 | volume_type = "gp2" 213 | volume_size = 50 214 | } 215 | ] 216 | } 217 | three = { 218 | instance_type = "t3.medium" 219 | availability_zone = element(module.vpc.azs, 2) 220 | subnet_id = element(module.vpc.private_subnets, 2) 221 | } 222 | } 223 | } 224 | 225 | module "ec2_multiple" { 226 | source = "../../" 227 | 228 | for_each = local.multiple_instances 229 | 230 | name = "${local.name}-multi-${each.key}" 231 | 232 | instance_type = each.value.instance_type 233 | availability_zone = each.value.availability_zone 234 | subnet_id = each.value.subnet_id 235 | vpc_security_group_ids = [module.security_group.security_group_id] 236 | 237 | enable_volume_tags = false 238 | root_block_device = lookup(each.value, "root_block_device", []) 239 | 240 | tags = local.tags 241 | } 242 | 243 | ################################################################################ 244 | # EC2 Module - spot instance request 245 | ################################################################################ 246 | 247 | module "ec2_spot_instance" { 248 | source = "../../" 249 | 250 | name = "${local.name}-spot-instance" 251 | create_spot_instance = true 252 | 253 | availability_zone = element(module.vpc.azs, 0) 254 | subnet_id = element(module.vpc.private_subnets, 0) 255 | vpc_security_group_ids = [module.security_group.security_group_id] 256 | associate_public_ip_address = true 257 | 258 | # Spot request specific attributes 259 | spot_price = "0.1" 260 | spot_wait_for_fulfillment = true 261 | spot_type = "persistent" 262 | spot_instance_interruption_behavior = "terminate" 263 | # End spot request specific attributes 264 | 265 | user_data_base64 = base64encode(local.user_data) 266 | 267 | cpu_options = { 268 | core_count = 2 269 | threads_per_core = 1 270 | } 271 | 272 | enable_volume_tags = false 273 | root_block_device = [ 274 | { 275 | encrypted = true 276 | volume_type = "gp3" 277 | throughput = 200 278 | volume_size = 50 279 | tags = { 280 | Name = "my-root-block" 281 | } 282 | }, 283 | ] 284 | 285 | ebs_block_device = [ 286 | { 287 | device_name = "/dev/sdf" 288 | volume_type = "gp3" 289 | volume_size = 5 290 | throughput = 200 291 | encrypted = true 292 | # kms_key_id = aws_kms_key.this.arn # you must grant the AWSServiceRoleForEC2Spot service-linked role access to any custom KMS keys 293 | } 294 | ] 295 | 296 | tags = local.tags 297 | } 298 | 299 | ################################################################################ 300 | # EC2 Module - Capacity Reservation 301 | ################################################################################ 302 | 303 | module "ec2_open_capacity_reservation" { 304 | source = "../../" 305 | 306 | name = "${local.name}-open-capacity-reservation" 307 | 308 | ami = data.aws_ami.amazon_linux.id 309 | instance_type = "t3.micro" 310 | subnet_id = element(module.vpc.private_subnets, 0) 311 | vpc_security_group_ids = [module.security_group.security_group_id] 312 | associate_public_ip_address = false 313 | 314 | capacity_reservation_specification = { 315 | capacity_reservation_target = { 316 | capacity_reservation_id = aws_ec2_capacity_reservation.open.id 317 | } 318 | } 319 | 320 | tags = local.tags 321 | } 322 | 323 | module "ec2_targeted_capacity_reservation" { 324 | source = "../../" 325 | 326 | name = "${local.name}-targeted-capacity-reservation" 327 | 328 | ami = data.aws_ami.amazon_linux.id 329 | instance_type = "t3.micro" 330 | subnet_id = element(module.vpc.private_subnets, 0) 331 | vpc_security_group_ids = [module.security_group.security_group_id] 332 | associate_public_ip_address = false 333 | 334 | capacity_reservation_specification = { 335 | capacity_reservation_target = { 336 | capacity_reservation_id = aws_ec2_capacity_reservation.targeted.id 337 | } 338 | } 339 | 340 | tags = local.tags 341 | } 342 | 343 | resource "aws_ec2_capacity_reservation" "open" { 344 | instance_type = "t3.micro" 345 | instance_platform = "Linux/UNIX" 346 | availability_zone = "${local.region}a" 347 | instance_count = 1 348 | instance_match_criteria = "open" 349 | } 350 | 351 | resource "aws_ec2_capacity_reservation" "targeted" { 352 | instance_type = "t3.micro" 353 | instance_platform = "Linux/UNIX" 354 | availability_zone = "${local.region}a" 355 | instance_count = 1 356 | instance_match_criteria = "targeted" 357 | } 358 | 359 | ################################################################################ 360 | # EC2 Module - CPU Options 361 | ################################################################################ 362 | 363 | module "ec2_cpu_options" { 364 | source = "../../" 365 | 366 | name = "${local.name}-cpu-options" 367 | 368 | ami = data.aws_ami.amazon_linux_23.id 369 | instance_type = "c6a.xlarge" # used to set core count below and test amd_sev_snp attribute 370 | availability_zone = element(module.vpc.azs, 0) 371 | subnet_id = element(module.vpc.private_subnets, 0) 372 | vpc_security_group_ids = [module.security_group.security_group_id] 373 | placement_group = aws_placement_group.web.id 374 | associate_public_ip_address = true 375 | disable_api_stop = false 376 | 377 | create_iam_instance_profile = true 378 | iam_role_description = "IAM role for EC2 instance" 379 | iam_role_policies = { 380 | AdministratorAccess = "arn:aws:iam::aws:policy/AdministratorAccess" 381 | } 382 | 383 | user_data_base64 = base64encode(local.user_data) 384 | user_data_replace_on_change = true 385 | 386 | cpu_options = { 387 | core_count = 2 388 | threads_per_core = 1 389 | amd_sev_snp = "enabled" 390 | } 391 | enable_volume_tags = false 392 | root_block_device = [ 393 | { 394 | encrypted = true 395 | volume_type = "gp3" 396 | throughput = 200 397 | volume_size = 50 398 | tags = { 399 | Name = "my-root-block" 400 | } 401 | }, 402 | ] 403 | 404 | ebs_block_device = [ 405 | { 406 | device_name = "/dev/sdf" 407 | volume_type = "gp3" 408 | volume_size = 5 409 | throughput = 200 410 | encrypted = true 411 | kms_key_id = aws_kms_key.this.arn 412 | tags = { 413 | MountPoint = "/mnt/data" 414 | } 415 | } 416 | ] 417 | 418 | instance_tags = { Persistence = "09:00-18:00" } 419 | 420 | tags = local.tags 421 | } 422 | 423 | ################################################################################ 424 | # Supporting Resources 425 | ################################################################################ 426 | 427 | module "vpc" { 428 | source = "terraform-aws-modules/vpc/aws" 429 | version = "~> 5.0" 430 | 431 | name = local.name 432 | cidr = local.vpc_cidr 433 | 434 | azs = local.azs 435 | private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 4, k)] 436 | public_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 48)] 437 | 438 | tags = local.tags 439 | } 440 | 441 | data "aws_ami" "amazon_linux" { 442 | most_recent = true 443 | owners = ["amazon"] 444 | 445 | filter { 446 | name = "name" 447 | values = ["amzn-ami-hvm-*-x86_64-gp2"] 448 | } 449 | } 450 | 451 | data "aws_ami" "amazon_linux_23" { 452 | most_recent = true 453 | owners = ["amazon"] 454 | 455 | filter { 456 | name = "name" 457 | values = ["al2023-ami-2023*-x86_64"] 458 | } 459 | } 460 | 461 | module "security_group" { 462 | source = "terraform-aws-modules/security-group/aws" 463 | version = "~> 4.0" 464 | 465 | name = local.name 466 | description = "Security group for example usage with EC2 instance" 467 | vpc_id = module.vpc.vpc_id 468 | 469 | ingress_cidr_blocks = ["0.0.0.0/0"] 470 | ingress_rules = ["http-80-tcp", "all-icmp"] 471 | egress_rules = ["all-all"] 472 | 473 | tags = local.tags 474 | } 475 | 476 | resource "aws_placement_group" "web" { 477 | name = local.name 478 | strategy = "cluster" 479 | } 480 | 481 | resource "aws_kms_key" "this" { 482 | } 483 | 484 | resource "aws_network_interface" "this" { 485 | subnet_id = element(module.vpc.private_subnets, 0) 486 | } 487 | -------------------------------------------------------------------------------- /examples/complete/outputs.tf: -------------------------------------------------------------------------------- 1 | # EC2 Complete 2 | output "ec2_complete_id" { 3 | description = "The ID of the instance" 4 | value = module.ec2_complete.id 5 | } 6 | 7 | output "ec2_complete_arn" { 8 | description = "The ARN of the instance" 9 | value = module.ec2_complete.arn 10 | } 11 | 12 | output "ec2_complete_capacity_reservation_specification" { 13 | description = "Capacity reservation specification of the instance" 14 | value = module.ec2_complete.capacity_reservation_specification 15 | } 16 | 17 | output "ec2_complete_instance_state" { 18 | description = "The state of the instance. One of: `pending`, `running`, `shutting-down`, `terminated`, `stopping`, `stopped`" 19 | value = module.ec2_complete.instance_state 20 | } 21 | 22 | output "ec2_complete_primary_network_interface_id" { 23 | description = "The ID of the instance's primary network interface" 24 | value = module.ec2_complete.primary_network_interface_id 25 | } 26 | 27 | output "ec2_complete_private_dns" { 28 | description = "The private DNS name assigned to the instance. Can only be used inside the Amazon EC2, and only available if you've enabled DNS hostnames for your VPC" 29 | value = module.ec2_complete.private_dns 30 | } 31 | 32 | output "ec2_complete_public_dns" { 33 | description = "The public DNS name assigned to the instance. For EC2-VPC, this is only available if you've enabled DNS hostnames for your VPC" 34 | value = module.ec2_complete.public_dns 35 | } 36 | 37 | output "ec2_complete_public_ip" { 38 | description = "The public IP address assigned to the instance, if applicable. NOTE: If you are using an aws_eip with your instance, you should refer to the EIP's address directly and not use `public_ip` as this field will change after the EIP is attached" 39 | value = module.ec2_complete.public_ip 40 | } 41 | 42 | output "ec2_complete_tags_all" { 43 | description = "A map of tags assigned to the resource, including those inherited from the provider default_tags configuration block" 44 | value = module.ec2_complete.tags_all 45 | } 46 | 47 | output "ec2_complete_iam_role_name" { 48 | description = "The name of the IAM role" 49 | value = module.ec2_complete.iam_role_name 50 | } 51 | 52 | output "ec2_complete_iam_role_arn" { 53 | description = "The Amazon Resource Name (ARN) specifying the IAM role" 54 | value = module.ec2_complete.iam_role_arn 55 | } 56 | 57 | output "ec2_complete_iam_role_unique_id" { 58 | description = "Stable and unique string identifying the IAM role" 59 | value = module.ec2_complete.iam_role_unique_id 60 | } 61 | 62 | output "ec2_complete_iam_instance_profile_arn" { 63 | description = "ARN assigned by AWS to the instance profile" 64 | value = module.ec2_complete.iam_instance_profile_arn 65 | } 66 | 67 | output "ec2_complete_iam_instance_profile_id" { 68 | description = "Instance profile's ID" 69 | value = module.ec2_complete.iam_instance_profile_id 70 | } 71 | 72 | output "ec2_complete_iam_instance_profile_unique" { 73 | description = "Stable and unique string identifying the IAM instance profile" 74 | value = module.ec2_complete.iam_instance_profile_unique 75 | } 76 | 77 | output "ec2_complete_root_block_device" { 78 | description = "Root block device information" 79 | value = module.ec2_complete.root_block_device 80 | } 81 | 82 | output "ec2_complete_ebs_block_device" { 83 | description = "EBS block device information" 84 | value = module.ec2_complete.ebs_block_device 85 | } 86 | 87 | output "ec2_complete_ephemeral_block_device" { 88 | description = "Ephemeral block device information" 89 | value = module.ec2_complete.ephemeral_block_device 90 | } 91 | 92 | output "ec2_complete_availability_zone" { 93 | description = "The availability zone of the created instance" 94 | value = module.ec2_complete.availability_zone 95 | } 96 | 97 | # EC2 T2 Unlimited 98 | output "ec2_t2_unlimited_id" { 99 | description = "The ID of the instance" 100 | value = module.ec2_t2_unlimited.id 101 | } 102 | 103 | output "ec2_t2_unlimited_arn" { 104 | description = "The ARN of the instance" 105 | value = module.ec2_t2_unlimited.arn 106 | } 107 | 108 | output "ec2_t2_unlimited_capacity_reservation_specification" { 109 | description = "Capacity reservation specification of the instance" 110 | value = module.ec2_t2_unlimited.capacity_reservation_specification 111 | } 112 | 113 | output "ec2_t2_unlimited_instance_state" { 114 | description = "The state of the instance. One of: `pending`, `running`, `shutting-down`, `terminated`, `stopping`, `stopped`" 115 | value = module.ec2_t2_unlimited.instance_state 116 | } 117 | 118 | output "ec2_t2_unlimited_primary_network_interface_id" { 119 | description = "The ID of the instance's primary network interface" 120 | value = module.ec2_t2_unlimited.primary_network_interface_id 121 | } 122 | 123 | output "ec2_t2_unlimited_private_dns" { 124 | description = "The private DNS name assigned to the instance. Can only be used inside the Amazon EC2, and only available if you've enabled DNS hostnames for your VPC" 125 | value = module.ec2_t2_unlimited.private_dns 126 | } 127 | 128 | output "ec2_t2_unlimited_public_dns" { 129 | description = "The public DNS name assigned to the instance. For EC2-VPC, this is only available if you've enabled DNS hostnames for your VPC" 130 | value = module.ec2_t2_unlimited.public_dns 131 | } 132 | 133 | output "ec2_t2_unlimited_public_ip" { 134 | description = "The public IP address assigned to the instance, if applicable. NOTE: If you are using an aws_eip with your instance, you should refer to the EIP's address directly and not use `public_ip` as this field will change after the EIP is attached" 135 | value = module.ec2_t2_unlimited.public_ip 136 | } 137 | 138 | output "ec2_t2_unlimited_tags_all" { 139 | description = "A map of tags assigned to the resource, including those inherited from the provider default_tags configuration block" 140 | value = module.ec2_t2_unlimited.tags_all 141 | } 142 | 143 | output "ec2_t2_unlimited_availability_zone" { 144 | description = "The availability zone of the created instance" 145 | value = module.ec2_t2_unlimited.availability_zone 146 | } 147 | 148 | # EC2 T3 Unlimited 149 | output "ec2_t3_unlimited_id" { 150 | description = "The ID of the instance" 151 | value = module.ec2_t3_unlimited.id 152 | } 153 | 154 | output "ec2_t3_unlimited_arn" { 155 | description = "The ARN of the instance" 156 | value = module.ec2_t3_unlimited.arn 157 | } 158 | 159 | output "ec2_t3_unlimited_capacity_reservation_specification" { 160 | description = "Capacity reservation specification of the instance" 161 | value = module.ec2_t3_unlimited.capacity_reservation_specification 162 | } 163 | 164 | output "ec2_t3_unlimited_instance_state" { 165 | description = "The state of the instance. One of: `pending`, `running`, `shutting-down`, `terminated`, `stopping`, `stopped`" 166 | value = module.ec2_t3_unlimited.instance_state 167 | } 168 | 169 | output "ec2_t3_unlimited_primary_network_interface_id" { 170 | description = "The ID of the instance's primary network interface" 171 | value = module.ec2_t3_unlimited.primary_network_interface_id 172 | } 173 | 174 | output "ec2_t3_unlimited_private_dns" { 175 | description = "The private DNS name assigned to the instance. Can only be used inside the Amazon EC2, and only available if you've enabled DNS hostnames for your VPC" 176 | value = module.ec2_t3_unlimited.private_dns 177 | } 178 | 179 | output "ec2_t3_unlimited_public_dns" { 180 | description = "The public DNS name assigned to the instance. For EC2-VPC, this is only available if you've enabled DNS hostnames for your VPC" 181 | value = module.ec2_t3_unlimited.public_dns 182 | } 183 | 184 | output "ec2_t3_unlimited_public_ip" { 185 | description = "The public IP address assigned to the instance, if applicable. NOTE: If you are using an aws_eip with your instance, you should refer to the EIP's address directly and not use `public_ip` as this field will change after the EIP is attached" 186 | value = module.ec2_t3_unlimited.public_ip 187 | } 188 | 189 | output "ec2_t3_unlimited_tags_all" { 190 | description = "A map of tags assigned to the resource, including those inherited from the provider default_tags configuration block" 191 | value = module.ec2_t3_unlimited.tags_all 192 | } 193 | 194 | output "ec2_t3_unlimited_availability_zone" { 195 | description = "The availability zone of the created instance" 196 | value = module.ec2_t3_unlimited.availability_zone 197 | } 198 | 199 | # EC2 with ignore AMI changes 200 | output "ec2_ignore_ami_changes_ami" { 201 | description = "The AMI of the instance (ignore_ami_changes = true)" 202 | value = module.ec2_ignore_ami_changes.ami 203 | } 204 | 205 | # EC2 Multiple 206 | output "ec2_multiple" { 207 | description = "The full output of the `ec2_module` module" 208 | value = module.ec2_multiple 209 | } 210 | 211 | # EC2 Spot Instance 212 | output "ec2_spot_instance_id" { 213 | description = "The ID of the instance" 214 | value = module.ec2_spot_instance.id 215 | } 216 | 217 | output "ec2_spot_instance_arn" { 218 | description = "The ARN of the instance" 219 | value = module.ec2_spot_instance.arn 220 | } 221 | 222 | output "ec2_spot_instance_capacity_reservation_specification" { 223 | description = "Capacity reservation specification of the instance" 224 | value = module.ec2_spot_instance.capacity_reservation_specification 225 | } 226 | 227 | output "ec2_spot_instance_instance_state" { 228 | description = "The state of the instance. One of: `pending`, `running`, `shutting-down`, `terminated`, `stopping`, `stopped`" 229 | value = module.ec2_spot_instance.instance_state 230 | } 231 | 232 | output "ec2_spot_instance_primary_network_interface_id" { 233 | description = "The ID of the instance's primary network interface" 234 | value = module.ec2_spot_instance.primary_network_interface_id 235 | } 236 | 237 | output "ec2_spot_instance_private_dns" { 238 | description = "The private DNS name assigned to the instance. Can only be used inside the Amazon EC2, and only available if you've enabled DNS hostnames for your VPC" 239 | value = module.ec2_spot_instance.private_dns 240 | } 241 | 242 | output "ec2_spot_instance_public_dns" { 243 | description = "The public DNS name assigned to the instance. For EC2-VPC, this is only available if you've enabled DNS hostnames for your VPC" 244 | value = module.ec2_spot_instance.public_dns 245 | } 246 | 247 | output "ec2_spot_instance_public_ip" { 248 | description = "The public IP address assigned to the instance, if applicable. NOTE: If you are using an aws_eip with your instance, you should refer to the EIP's address directly and not use `public_ip` as this field will change after the EIP is attached" 249 | value = module.ec2_spot_instance.public_ip 250 | } 251 | 252 | output "ec2_spot_instance_tags_all" { 253 | description = "A map of tags assigned to the resource, including those inherited from the provider default_tags configuration block" 254 | value = module.ec2_spot_instance.tags_all 255 | } 256 | 257 | output "spot_bid_status" { 258 | description = "The current bid status of the Spot Instance Request" 259 | value = module.ec2_spot_instance.spot_bid_status 260 | } 261 | 262 | output "spot_request_state" { 263 | description = "The current request state of the Spot Instance Request" 264 | value = module.ec2_spot_instance.spot_request_state 265 | } 266 | 267 | output "spot_instance_id" { 268 | description = "The Instance ID (if any) that is currently fulfilling the Spot Instance request" 269 | value = module.ec2_spot_instance.spot_instance_id 270 | } 271 | 272 | output "spot_instance_availability_zone" { 273 | description = "The availability zone of the created spot instance" 274 | value = module.ec2_spot_instance.availability_zone 275 | } 276 | -------------------------------------------------------------------------------- /examples/complete/variables.tf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terraform-aws-modules/terraform-aws-ec2-instance/5b17f94c354eb3fa2b3bc435c861b916c9668e05/examples/complete/variables.tf -------------------------------------------------------------------------------- /examples/complete/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.0" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 4.66" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/session-manager/README.md: -------------------------------------------------------------------------------- 1 | # EC2 instance w/ private network access via Session Manager 2 | 3 | The configuration in this directory creates an EC2 instance not connected to the Internet that can be accessed using Session Manager through VPC Endpoints. 4 | 5 | This example outputs instance id, ARN, state, and tags. 6 | 7 | ## Usage 8 | 9 | To run this example you need to execute: 10 | 11 | ```bash 12 | $ terraform init 13 | $ terraform plan 14 | $ terraform apply 15 | ``` 16 | 17 | You can verify that SSM is setup correctly by connecting to the instance. The example output provides the AWS CLI command to connect to the instance under the output `ssm_connect_command` which will look like: 18 | 19 | ```bash 20 | aws ssm start-session --target --region 21 | ``` 22 | 23 | You will need to have the Session Manager plugin for the AWS CLI installed to execute the command. Instructions for installing can be found [here](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html). 24 | 25 | Note that this example may create resources which can cost money. Run `terraform destroy` when you don't need these resources. 26 | 27 | 28 | ## Requirements 29 | 30 | | Name | Version | 31 | |------|---------| 32 | | [terraform](#requirement\_terraform) | >= 1.0 | 33 | | [aws](#requirement\_aws) | >= 4.66 | 34 | 35 | ## Providers 36 | 37 | | Name | Version | 38 | |------|---------| 39 | | [aws](#provider\_aws) | >= 4.66 | 40 | 41 | ## Modules 42 | 43 | | Name | Source | Version | 44 | |------|--------|---------| 45 | | [ec2](#module\_ec2) | ../../ | n/a | 46 | | [security\_group\_instance](#module\_security\_group\_instance) | terraform-aws-modules/security-group/aws | ~> 5.0 | 47 | | [vpc](#module\_vpc) | terraform-aws-modules/vpc/aws | ~> 5.0 | 48 | | [vpc\_endpoints](#module\_vpc\_endpoints) | terraform-aws-modules/vpc/aws//modules/vpc-endpoints | ~> 5.0 | 49 | 50 | ## Resources 51 | 52 | | Name | Type | 53 | |------|------| 54 | | [aws_availability_zones.available](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/availability_zones) | data source | 55 | 56 | ## Inputs 57 | 58 | No inputs. 59 | 60 | ## Outputs 61 | 62 | | Name | Description | 63 | |------|-------------| 64 | | [ec2\_arn](#output\_ec2\_arn) | The ARN of the instance | 65 | | [ec2\_capacity\_reservation\_specification](#output\_ec2\_capacity\_reservation\_specification) | Capacity reservation specification of the instance | 66 | | [ec2\_ebs\_block\_device](#output\_ec2\_ebs\_block\_device) | EBS block device information | 67 | | [ec2\_ephemeral\_block\_device](#output\_ec2\_ephemeral\_block\_device) | Ephemeral block device information | 68 | | [ec2\_iam\_instance\_profile\_arn](#output\_ec2\_iam\_instance\_profile\_arn) | ARN assigned by AWS to the instance profile | 69 | | [ec2\_iam\_instance\_profile\_id](#output\_ec2\_iam\_instance\_profile\_id) | Instance profile's ID | 70 | | [ec2\_iam\_instance\_profile\_unique](#output\_ec2\_iam\_instance\_profile\_unique) | Stable and unique string identifying the IAM instance profile | 71 | | [ec2\_iam\_role\_arn](#output\_ec2\_iam\_role\_arn) | The Amazon Resource Name (ARN) specifying the IAM role | 72 | | [ec2\_iam\_role\_name](#output\_ec2\_iam\_role\_name) | The name of the IAM role | 73 | | [ec2\_iam\_role\_unique\_id](#output\_ec2\_iam\_role\_unique\_id) | Stable and unique string identifying the IAM role | 74 | | [ec2\_id](#output\_ec2\_id) | The ID of the instance | 75 | | [ec2\_instance\_state](#output\_ec2\_instance\_state) | The state of the instance. One of: `pending`, `running`, `shutting-down`, `terminated`, `stopping`, `stopped` | 76 | | [ec2\_primary\_network\_interface\_id](#output\_ec2\_primary\_network\_interface\_id) | The ID of the instance's primary network interface | 77 | | [ec2\_private\_dns](#output\_ec2\_private\_dns) | The private DNS name assigned to the instance. Can only be used inside the Amazon EC2, and only available if you've enabled DNS hostnames for your VPC | 78 | | [ec2\_public\_dns](#output\_ec2\_public\_dns) | The public DNS name assigned to the instance. For EC2-VPC, this is only available if you've enabled DNS hostnames for your VPC | 79 | | [ec2\_public\_ip](#output\_ec2\_public\_ip) | The public IP address assigned to the instance, if applicable. NOTE: If you are using an aws\_eip with your instance, you should refer to the EIP's address directly and not use `public_ip` as this field will change after the EIP is attached | 80 | | [ec2\_root\_block\_device](#output\_ec2\_root\_block\_device) | Root block device information | 81 | | [ec2\_tags\_all](#output\_ec2\_tags\_all) | A map of tags assigned to the resource, including those inherited from the provider default\_tags configuration block | 82 | | [ssm\_connect\_command](#output\_ssm\_connect\_command) | The AWS CLI command to connect to the instance using Session Manager | 83 | 84 | -------------------------------------------------------------------------------- /examples/session-manager/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = local.region 3 | } 4 | 5 | data "aws_availability_zones" "available" {} 6 | 7 | locals { 8 | name = "ex-${basename(path.cwd)}" 9 | region = "eu-west-1" 10 | 11 | vpc_cidr = "10.0.0.0/16" 12 | azs = slice(data.aws_availability_zones.available.names, 0, 3) 13 | 14 | tags = { 15 | Name = local.name 16 | Example = local.name 17 | Repository = "https://github.com/terraform-aws-modules/terraform-aws-ec2-instance" 18 | } 19 | } 20 | 21 | ################################################################################ 22 | # EC2 Module 23 | ################################################################################ 24 | 25 | module "ec2" { 26 | source = "../../" 27 | 28 | name = local.name 29 | 30 | subnet_id = element(module.vpc.intra_subnets, 0) 31 | vpc_security_group_ids = [module.security_group_instance.security_group_id] 32 | 33 | create_iam_instance_profile = true 34 | iam_role_description = "IAM role for EC2 instance" 35 | iam_role_policies = { 36 | AmazonSSMManagedInstanceCore = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" 37 | } 38 | 39 | tags = local.tags 40 | } 41 | 42 | ################################################################################ 43 | # Supporting Resources 44 | ################################################################################ 45 | 46 | module "vpc" { 47 | source = "terraform-aws-modules/vpc/aws" 48 | version = "~> 5.0" 49 | 50 | name = local.name 51 | cidr = local.vpc_cidr 52 | 53 | azs = local.azs 54 | intra_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k)] 55 | 56 | tags = local.tags 57 | } 58 | 59 | module "security_group_instance" { 60 | source = "terraform-aws-modules/security-group/aws" 61 | version = "~> 5.0" 62 | 63 | name = "${local.name}-ec2" 64 | description = "Security Group for EC2 Instance Egress" 65 | 66 | vpc_id = module.vpc.vpc_id 67 | 68 | egress_rules = ["https-443-tcp"] 69 | 70 | tags = local.tags 71 | } 72 | 73 | module "vpc_endpoints" { 74 | source = "terraform-aws-modules/vpc/aws//modules/vpc-endpoints" 75 | version = "~> 5.0" 76 | 77 | vpc_id = module.vpc.vpc_id 78 | 79 | endpoints = { for service in toset(["ssm", "ssmmessages", "ec2messages"]) : 80 | replace(service, ".", "_") => 81 | { 82 | service = service 83 | subnet_ids = module.vpc.intra_subnets 84 | private_dns_enabled = true 85 | tags = { Name = "${local.name}-${service}" } 86 | } 87 | } 88 | 89 | create_security_group = true 90 | security_group_name_prefix = "${local.name}-vpc-endpoints-" 91 | security_group_description = "VPC endpoint security group" 92 | security_group_rules = { 93 | ingress_https = { 94 | description = "HTTPS from subnets" 95 | cidr_blocks = module.vpc.intra_subnets_cidr_blocks 96 | } 97 | } 98 | 99 | tags = local.tags 100 | } 101 | -------------------------------------------------------------------------------- /examples/session-manager/outputs.tf: -------------------------------------------------------------------------------- 1 | output "ec2_id" { 2 | description = "The ID of the instance" 3 | value = module.ec2.id 4 | } 5 | 6 | output "ec2_arn" { 7 | description = "The ARN of the instance" 8 | value = module.ec2.arn 9 | } 10 | 11 | output "ec2_capacity_reservation_specification" { 12 | description = "Capacity reservation specification of the instance" 13 | value = module.ec2.capacity_reservation_specification 14 | } 15 | 16 | output "ec2_instance_state" { 17 | description = "The state of the instance. One of: `pending`, `running`, `shutting-down`, `terminated`, `stopping`, `stopped`" 18 | value = module.ec2.instance_state 19 | } 20 | 21 | output "ec2_primary_network_interface_id" { 22 | description = "The ID of the instance's primary network interface" 23 | value = module.ec2.primary_network_interface_id 24 | } 25 | 26 | output "ec2_private_dns" { 27 | description = "The private DNS name assigned to the instance. Can only be used inside the Amazon EC2, and only available if you've enabled DNS hostnames for your VPC" 28 | value = module.ec2.private_dns 29 | } 30 | 31 | output "ec2_public_dns" { 32 | description = "The public DNS name assigned to the instance. For EC2-VPC, this is only available if you've enabled DNS hostnames for your VPC" 33 | value = module.ec2.public_dns 34 | } 35 | 36 | output "ec2_public_ip" { 37 | description = "The public IP address assigned to the instance, if applicable. NOTE: If you are using an aws_eip with your instance, you should refer to the EIP's address directly and not use `public_ip` as this field will change after the EIP is attached" 38 | value = module.ec2.public_ip 39 | } 40 | 41 | output "ec2_tags_all" { 42 | description = "A map of tags assigned to the resource, including those inherited from the provider default_tags configuration block" 43 | value = module.ec2.tags_all 44 | } 45 | 46 | output "ec2_iam_role_name" { 47 | description = "The name of the IAM role" 48 | value = module.ec2.iam_role_name 49 | } 50 | 51 | output "ec2_iam_role_arn" { 52 | description = "The Amazon Resource Name (ARN) specifying the IAM role" 53 | value = module.ec2.iam_role_arn 54 | } 55 | 56 | output "ec2_iam_role_unique_id" { 57 | description = "Stable and unique string identifying the IAM role" 58 | value = module.ec2.iam_role_unique_id 59 | } 60 | 61 | output "ec2_iam_instance_profile_arn" { 62 | description = "ARN assigned by AWS to the instance profile" 63 | value = module.ec2.iam_instance_profile_arn 64 | } 65 | 66 | output "ec2_iam_instance_profile_id" { 67 | description = "Instance profile's ID" 68 | value = module.ec2.iam_instance_profile_id 69 | } 70 | 71 | output "ec2_iam_instance_profile_unique" { 72 | description = "Stable and unique string identifying the IAM instance profile" 73 | value = module.ec2.iam_instance_profile_unique 74 | } 75 | 76 | output "ec2_root_block_device" { 77 | description = "Root block device information" 78 | value = module.ec2.root_block_device 79 | } 80 | 81 | output "ec2_ebs_block_device" { 82 | description = "EBS block device information" 83 | value = module.ec2.ebs_block_device 84 | } 85 | 86 | output "ec2_ephemeral_block_device" { 87 | description = "Ephemeral block device information" 88 | value = module.ec2.ephemeral_block_device 89 | } 90 | 91 | output "ssm_connect_command" { 92 | description = "The AWS CLI command to connect to the instance using Session Manager" 93 | value = "aws ssm start-session --target ${module.ec2.id} --region ${local.region}" 94 | } 95 | -------------------------------------------------------------------------------- /examples/session-manager/variables.tf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terraform-aws-modules/terraform-aws-ec2-instance/5b17f94c354eb3fa2b3bc435c861b916c9668e05/examples/session-manager/variables.tf -------------------------------------------------------------------------------- /examples/session-manager/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.0" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 4.66" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/volume-attachment/README.md: -------------------------------------------------------------------------------- 1 | # EC2 instance with EBS volume attachment 2 | 3 | Configuration in this directory creates EC2 instances, EBS volume and attach it together. 4 | 5 | This example outputs instance id and EBS volume id. 6 | 7 | ## Usage 8 | 9 | To run this example you need to execute: 10 | 11 | ```bash 12 | $ terraform init 13 | $ terraform plan 14 | $ terraform apply 15 | ``` 16 | 17 | Note that this example may create resources which can cost money. Run `terraform destroy` when you don't need these resources. 18 | 19 | 20 | ## Requirements 21 | 22 | | Name | Version | 23 | |------|---------| 24 | | [terraform](#requirement\_terraform) | >= 1.0 | 25 | | [aws](#requirement\_aws) | >= 4.66 | 26 | 27 | ## Providers 28 | 29 | | Name | Version | 30 | |------|---------| 31 | | [aws](#provider\_aws) | >= 4.66 | 32 | 33 | ## Modules 34 | 35 | | Name | Source | Version | 36 | |------|--------|---------| 37 | | [ec2](#module\_ec2) | ../../ | n/a | 38 | | [security\_group](#module\_security\_group) | terraform-aws-modules/security-group/aws | ~> 4.0 | 39 | | [vpc](#module\_vpc) | terraform-aws-modules/vpc/aws | ~> 4.0 | 40 | 41 | ## Resources 42 | 43 | | Name | Type | 44 | |------|------| 45 | | [aws_ebs_volume.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ebs_volume) | resource | 46 | | [aws_volume_attachment.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/volume_attachment) | resource | 47 | | [aws_ami.amazon_linux](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami) | data source | 48 | | [aws_availability_zones.available](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/availability_zones) | data source | 49 | 50 | ## Inputs 51 | 52 | No inputs. 53 | 54 | ## Outputs 55 | 56 | | Name | Description | 57 | |------|-------------| 58 | | [ec2\_arn](#output\_ec2\_arn) | The ARN of the instance | 59 | | [ec2\_availability\_zone](#output\_ec2\_availability\_zone) | The availability zone of the created spot instance | 60 | | [ec2\_capacity\_reservation\_specification](#output\_ec2\_capacity\_reservation\_specification) | Capacity reservation specification of the instance | 61 | | [ec2\_id](#output\_ec2\_id) | The ID of the instance | 62 | | [ec2\_instance\_state](#output\_ec2\_instance\_state) | The state of the instance. One of: `pending`, `running`, `shutting-down`, `terminated`, `stopping`, `stopped` | 63 | | [ec2\_primary\_network\_interface\_id](#output\_ec2\_primary\_network\_interface\_id) | The ID of the instance's primary network interface | 64 | | [ec2\_private\_dns](#output\_ec2\_private\_dns) | The private DNS name assigned to the instance. Can only be used inside the Amazon EC2, and only available if you've enabled DNS hostnames for your VPC | 65 | | [ec2\_public\_dns](#output\_ec2\_public\_dns) | The public DNS name assigned to the instance. For EC2-VPC, this is only available if you've enabled DNS hostnames for your VPC | 66 | | [ec2\_public\_ip](#output\_ec2\_public\_ip) | The public IP address assigned to the instance, if applicable. NOTE: If you are using an aws\_eip with your instance, you should refer to the EIP's address directly and not use `public_ip` as this field will change after the EIP is attached | 67 | | [ec2\_tags\_all](#output\_ec2\_tags\_all) | A map of tags assigned to the resource, including those inherited from the provider default\_tags configuration block | 68 | 69 | -------------------------------------------------------------------------------- /examples/volume-attachment/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = local.region 3 | } 4 | 5 | data "aws_availability_zones" "available" {} 6 | 7 | locals { 8 | name = "ex-${basename(path.cwd)}" 9 | region = "eu-west-1" 10 | 11 | vpc_cidr = "10.0.0.0/16" 12 | azs = slice(data.aws_availability_zones.available.names, 0, 3) 13 | 14 | tags = { 15 | Name = local.name 16 | Example = local.name 17 | Repository = "https://github.com/terraform-aws-modules/terraform-aws-ec2-instance" 18 | } 19 | } 20 | 21 | ################################################################################ 22 | # EC2 Module 23 | ################################################################################ 24 | 25 | module "ec2" { 26 | source = "../../" 27 | 28 | name = local.name 29 | 30 | ami = data.aws_ami.amazon_linux.id 31 | instance_type = "c5.large" 32 | availability_zone = element(local.azs, 0) 33 | subnet_id = element(module.vpc.private_subnets, 0) 34 | vpc_security_group_ids = [module.security_group.security_group_id] 35 | associate_public_ip_address = true 36 | 37 | tags = local.tags 38 | } 39 | 40 | resource "aws_volume_attachment" "this" { 41 | device_name = "/dev/sdh" 42 | volume_id = aws_ebs_volume.this.id 43 | instance_id = module.ec2.id 44 | } 45 | 46 | resource "aws_ebs_volume" "this" { 47 | availability_zone = module.ec2.availability_zone 48 | size = 1 49 | 50 | tags = local.tags 51 | } 52 | 53 | ################################################################################ 54 | # Supporting Resources 55 | ################################################################################ 56 | 57 | module "vpc" { 58 | source = "terraform-aws-modules/vpc/aws" 59 | version = "~> 4.0" 60 | 61 | name = local.name 62 | cidr = local.vpc_cidr 63 | 64 | azs = local.azs 65 | private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 4, k)] 66 | public_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 48)] 67 | 68 | tags = local.tags 69 | } 70 | 71 | data "aws_ami" "amazon_linux" { 72 | most_recent = true 73 | owners = ["amazon"] 74 | 75 | filter { 76 | name = "name" 77 | values = ["amzn-ami-hvm-*-x86_64-gp2"] 78 | } 79 | } 80 | 81 | module "security_group" { 82 | source = "terraform-aws-modules/security-group/aws" 83 | version = "~> 4.0" 84 | 85 | name = local.name 86 | description = "Security group for example usage with EC2 instance" 87 | vpc_id = module.vpc.vpc_id 88 | 89 | ingress_cidr_blocks = ["0.0.0.0/0"] 90 | ingress_rules = ["http-80-tcp", "all-icmp"] 91 | egress_rules = ["all-all"] 92 | 93 | tags = local.tags 94 | } 95 | -------------------------------------------------------------------------------- /examples/volume-attachment/outputs.tf: -------------------------------------------------------------------------------- 1 | # EC2 2 | output "ec2_id" { 3 | description = "The ID of the instance" 4 | value = module.ec2.id 5 | } 6 | 7 | output "ec2_arn" { 8 | description = "The ARN of the instance" 9 | value = module.ec2.arn 10 | } 11 | 12 | output "ec2_capacity_reservation_specification" { 13 | description = "Capacity reservation specification of the instance" 14 | value = module.ec2.capacity_reservation_specification 15 | } 16 | 17 | output "ec2_instance_state" { 18 | description = "The state of the instance. One of: `pending`, `running`, `shutting-down`, `terminated`, `stopping`, `stopped`" 19 | value = module.ec2.instance_state 20 | } 21 | 22 | output "ec2_primary_network_interface_id" { 23 | description = "The ID of the instance's primary network interface" 24 | value = module.ec2.primary_network_interface_id 25 | } 26 | 27 | output "ec2_private_dns" { 28 | description = "The private DNS name assigned to the instance. Can only be used inside the Amazon EC2, and only available if you've enabled DNS hostnames for your VPC" 29 | value = module.ec2.private_dns 30 | } 31 | 32 | output "ec2_public_dns" { 33 | description = "The public DNS name assigned to the instance. For EC2-VPC, this is only available if you've enabled DNS hostnames for your VPC" 34 | value = module.ec2.public_dns 35 | } 36 | 37 | output "ec2_public_ip" { 38 | description = "The public IP address assigned to the instance, if applicable. NOTE: If you are using an aws_eip with your instance, you should refer to the EIP's address directly and not use `public_ip` as this field will change after the EIP is attached" 39 | value = module.ec2.public_ip 40 | } 41 | 42 | output "ec2_tags_all" { 43 | description = "A map of tags assigned to the resource, including those inherited from the provider default_tags configuration block" 44 | value = module.ec2.tags_all 45 | } 46 | 47 | output "ec2_availability_zone" { 48 | description = "The availability zone of the created spot instance" 49 | value = module.ec2.availability_zone 50 | } 51 | -------------------------------------------------------------------------------- /examples/volume-attachment/variables.tf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terraform-aws-modules/terraform-aws-ec2-instance/5b17f94c354eb3fa2b3bc435c861b916c9668e05/examples/volume-attachment/variables.tf -------------------------------------------------------------------------------- /examples/volume-attachment/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.0" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 4.66" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /main.tf: -------------------------------------------------------------------------------- 1 | data "aws_partition" "current" {} 2 | 3 | locals { 4 | create = var.create && var.putin_khuylo 5 | 6 | is_t_instance_type = replace(var.instance_type, "/^t(2|3|3a|4g){1}\\..*$/", "1") == "1" ? true : false 7 | 8 | ami = try(coalesce(var.ami, try(nonsensitive(data.aws_ssm_parameter.this[0].value), null)), null) 9 | } 10 | 11 | data "aws_ssm_parameter" "this" { 12 | count = local.create && var.ami == null ? 1 : 0 13 | 14 | name = var.ami_ssm_parameter 15 | } 16 | 17 | ################################################################################ 18 | # Instance 19 | ################################################################################ 20 | 21 | resource "aws_instance" "this" { 22 | count = local.create && !var.ignore_ami_changes && !var.create_spot_instance ? 1 : 0 23 | 24 | ami = local.ami 25 | instance_type = var.instance_type 26 | cpu_core_count = var.cpu_core_count 27 | cpu_threads_per_core = var.cpu_threads_per_core 28 | hibernation = var.hibernation 29 | 30 | user_data = var.user_data 31 | user_data_base64 = var.user_data_base64 32 | user_data_replace_on_change = var.user_data_replace_on_change 33 | 34 | availability_zone = var.availability_zone 35 | subnet_id = var.subnet_id 36 | vpc_security_group_ids = var.vpc_security_group_ids 37 | 38 | key_name = var.key_name 39 | monitoring = var.monitoring 40 | get_password_data = var.get_password_data 41 | iam_instance_profile = var.create_iam_instance_profile ? aws_iam_instance_profile.this[0].name : var.iam_instance_profile 42 | 43 | associate_public_ip_address = var.associate_public_ip_address 44 | private_ip = var.private_ip 45 | secondary_private_ips = var.secondary_private_ips 46 | ipv6_address_count = var.ipv6_address_count 47 | ipv6_addresses = var.ipv6_addresses 48 | 49 | ebs_optimized = var.ebs_optimized 50 | 51 | dynamic "cpu_options" { 52 | for_each = length(var.cpu_options) > 0 ? [var.cpu_options] : [] 53 | 54 | content { 55 | core_count = try(cpu_options.value.core_count, null) 56 | threads_per_core = try(cpu_options.value.threads_per_core, null) 57 | amd_sev_snp = try(cpu_options.value.amd_sev_snp, null) 58 | } 59 | } 60 | 61 | dynamic "capacity_reservation_specification" { 62 | for_each = length(var.capacity_reservation_specification) > 0 ? [var.capacity_reservation_specification] : [] 63 | 64 | content { 65 | capacity_reservation_preference = try(capacity_reservation_specification.value.capacity_reservation_preference, null) 66 | 67 | dynamic "capacity_reservation_target" { 68 | for_each = try([capacity_reservation_specification.value.capacity_reservation_target], []) 69 | 70 | content { 71 | capacity_reservation_id = try(capacity_reservation_target.value.capacity_reservation_id, null) 72 | capacity_reservation_resource_group_arn = try(capacity_reservation_target.value.capacity_reservation_resource_group_arn, null) 73 | } 74 | } 75 | } 76 | } 77 | 78 | dynamic "root_block_device" { 79 | for_each = var.root_block_device 80 | 81 | content { 82 | delete_on_termination = try(root_block_device.value.delete_on_termination, null) 83 | encrypted = try(root_block_device.value.encrypted, null) 84 | iops = try(root_block_device.value.iops, null) 85 | kms_key_id = lookup(root_block_device.value, "kms_key_id", null) 86 | volume_size = try(root_block_device.value.volume_size, null) 87 | volume_type = try(root_block_device.value.volume_type, null) 88 | throughput = try(root_block_device.value.throughput, null) 89 | tags = try(root_block_device.value.tags, null) 90 | } 91 | } 92 | 93 | dynamic "ebs_block_device" { 94 | for_each = var.ebs_block_device 95 | 96 | content { 97 | delete_on_termination = try(ebs_block_device.value.delete_on_termination, null) 98 | device_name = ebs_block_device.value.device_name 99 | encrypted = try(ebs_block_device.value.encrypted, null) 100 | iops = try(ebs_block_device.value.iops, null) 101 | kms_key_id = lookup(ebs_block_device.value, "kms_key_id", null) 102 | snapshot_id = lookup(ebs_block_device.value, "snapshot_id", null) 103 | volume_size = try(ebs_block_device.value.volume_size, null) 104 | volume_type = try(ebs_block_device.value.volume_type, null) 105 | throughput = try(ebs_block_device.value.throughput, null) 106 | tags = try(ebs_block_device.value.tags, null) 107 | } 108 | } 109 | 110 | dynamic "ephemeral_block_device" { 111 | for_each = var.ephemeral_block_device 112 | 113 | content { 114 | device_name = ephemeral_block_device.value.device_name 115 | no_device = try(ephemeral_block_device.value.no_device, null) 116 | virtual_name = try(ephemeral_block_device.value.virtual_name, null) 117 | } 118 | } 119 | 120 | dynamic "metadata_options" { 121 | for_each = length(var.metadata_options) > 0 ? [var.metadata_options] : [] 122 | 123 | content { 124 | http_endpoint = try(metadata_options.value.http_endpoint, "enabled") 125 | http_tokens = try(metadata_options.value.http_tokens, "required") 126 | http_put_response_hop_limit = try(metadata_options.value.http_put_response_hop_limit, 1) 127 | instance_metadata_tags = try(metadata_options.value.instance_metadata_tags, null) 128 | } 129 | } 130 | 131 | dynamic "network_interface" { 132 | for_each = var.network_interface 133 | 134 | content { 135 | device_index = network_interface.value.device_index 136 | network_interface_id = lookup(network_interface.value, "network_interface_id", null) 137 | delete_on_termination = try(network_interface.value.delete_on_termination, false) 138 | } 139 | } 140 | 141 | dynamic "private_dns_name_options" { 142 | for_each = length(var.private_dns_name_options) > 0 ? [var.private_dns_name_options] : [] 143 | 144 | content { 145 | hostname_type = try(private_dns_name_options.value.hostname_type, null) 146 | enable_resource_name_dns_a_record = try(private_dns_name_options.value.enable_resource_name_dns_a_record, null) 147 | enable_resource_name_dns_aaaa_record = try(private_dns_name_options.value.enable_resource_name_dns_aaaa_record, null) 148 | } 149 | } 150 | 151 | dynamic "launch_template" { 152 | for_each = length(var.launch_template) > 0 ? [var.launch_template] : [] 153 | 154 | content { 155 | id = lookup(var.launch_template, "id", null) 156 | name = lookup(var.launch_template, "name", null) 157 | version = lookup(var.launch_template, "version", null) 158 | } 159 | } 160 | 161 | dynamic "maintenance_options" { 162 | for_each = length(var.maintenance_options) > 0 ? [var.maintenance_options] : [] 163 | 164 | content { 165 | auto_recovery = try(maintenance_options.value.auto_recovery, null) 166 | } 167 | } 168 | 169 | enclave_options { 170 | enabled = var.enclave_options_enabled 171 | } 172 | 173 | source_dest_check = length(var.network_interface) > 0 ? null : var.source_dest_check 174 | disable_api_termination = var.disable_api_termination 175 | disable_api_stop = var.disable_api_stop 176 | instance_initiated_shutdown_behavior = var.instance_initiated_shutdown_behavior 177 | placement_group = var.placement_group 178 | tenancy = var.tenancy 179 | host_id = var.host_id 180 | 181 | credit_specification { 182 | cpu_credits = local.is_t_instance_type ? var.cpu_credits : null 183 | } 184 | 185 | timeouts { 186 | create = try(var.timeouts.create, null) 187 | update = try(var.timeouts.update, null) 188 | delete = try(var.timeouts.delete, null) 189 | } 190 | 191 | tags = merge({ "Name" = var.name }, var.instance_tags, var.tags) 192 | volume_tags = var.enable_volume_tags ? merge({ "Name" = var.name }, var.volume_tags) : null 193 | } 194 | 195 | ################################################################################ 196 | # Instance - Ignore AMI Changes 197 | ################################################################################ 198 | 199 | resource "aws_instance" "ignore_ami" { 200 | count = local.create && var.ignore_ami_changes && !var.create_spot_instance ? 1 : 0 201 | 202 | ami = local.ami 203 | instance_type = var.instance_type 204 | cpu_core_count = var.cpu_core_count 205 | cpu_threads_per_core = var.cpu_threads_per_core 206 | hibernation = var.hibernation 207 | 208 | user_data = var.user_data 209 | user_data_base64 = var.user_data_base64 210 | user_data_replace_on_change = var.user_data_replace_on_change 211 | 212 | availability_zone = var.availability_zone 213 | subnet_id = var.subnet_id 214 | vpc_security_group_ids = var.vpc_security_group_ids 215 | 216 | key_name = var.key_name 217 | monitoring = var.monitoring 218 | get_password_data = var.get_password_data 219 | iam_instance_profile = var.create_iam_instance_profile ? aws_iam_instance_profile.this[0].name : var.iam_instance_profile 220 | 221 | associate_public_ip_address = var.associate_public_ip_address 222 | private_ip = var.private_ip 223 | secondary_private_ips = var.secondary_private_ips 224 | ipv6_address_count = var.ipv6_address_count 225 | ipv6_addresses = var.ipv6_addresses 226 | 227 | ebs_optimized = var.ebs_optimized 228 | 229 | dynamic "cpu_options" { 230 | for_each = length(var.cpu_options) > 0 ? [var.cpu_options] : [] 231 | 232 | content { 233 | core_count = try(cpu_options.value.core_count, null) 234 | threads_per_core = try(cpu_options.value.threads_per_core, null) 235 | amd_sev_snp = try(cpu_options.value.amd_sev_snp, null) 236 | } 237 | } 238 | 239 | dynamic "capacity_reservation_specification" { 240 | for_each = length(var.capacity_reservation_specification) > 0 ? [var.capacity_reservation_specification] : [] 241 | 242 | content { 243 | capacity_reservation_preference = try(capacity_reservation_specification.value.capacity_reservation_preference, null) 244 | 245 | dynamic "capacity_reservation_target" { 246 | for_each = try([capacity_reservation_specification.value.capacity_reservation_target], []) 247 | 248 | content { 249 | capacity_reservation_id = try(capacity_reservation_target.value.capacity_reservation_id, null) 250 | capacity_reservation_resource_group_arn = try(capacity_reservation_target.value.capacity_reservation_resource_group_arn, null) 251 | } 252 | } 253 | } 254 | } 255 | 256 | dynamic "root_block_device" { 257 | for_each = var.root_block_device 258 | 259 | content { 260 | delete_on_termination = try(root_block_device.value.delete_on_termination, null) 261 | encrypted = try(root_block_device.value.encrypted, null) 262 | iops = try(root_block_device.value.iops, null) 263 | kms_key_id = lookup(root_block_device.value, "kms_key_id", null) 264 | volume_size = try(root_block_device.value.volume_size, null) 265 | volume_type = try(root_block_device.value.volume_type, null) 266 | throughput = try(root_block_device.value.throughput, null) 267 | tags = try(root_block_device.value.tags, null) 268 | } 269 | } 270 | 271 | dynamic "ebs_block_device" { 272 | for_each = var.ebs_block_device 273 | 274 | content { 275 | delete_on_termination = try(ebs_block_device.value.delete_on_termination, null) 276 | device_name = ebs_block_device.value.device_name 277 | encrypted = try(ebs_block_device.value.encrypted, null) 278 | iops = try(ebs_block_device.value.iops, null) 279 | kms_key_id = lookup(ebs_block_device.value, "kms_key_id", null) 280 | snapshot_id = lookup(ebs_block_device.value, "snapshot_id", null) 281 | volume_size = try(ebs_block_device.value.volume_size, null) 282 | volume_type = try(ebs_block_device.value.volume_type, null) 283 | throughput = try(ebs_block_device.value.throughput, null) 284 | tags = try(ebs_block_device.value.tags, null) 285 | } 286 | } 287 | 288 | dynamic "ephemeral_block_device" { 289 | for_each = var.ephemeral_block_device 290 | 291 | content { 292 | device_name = ephemeral_block_device.value.device_name 293 | no_device = try(ephemeral_block_device.value.no_device, null) 294 | virtual_name = try(ephemeral_block_device.value.virtual_name, null) 295 | } 296 | } 297 | 298 | dynamic "metadata_options" { 299 | for_each = length(var.metadata_options) > 0 ? [var.metadata_options] : [] 300 | 301 | content { 302 | http_endpoint = try(metadata_options.value.http_endpoint, "enabled") 303 | http_tokens = try(metadata_options.value.http_tokens, "required") 304 | http_put_response_hop_limit = try(metadata_options.value.http_put_response_hop_limit, 1) 305 | instance_metadata_tags = try(metadata_options.value.instance_metadata_tags, null) 306 | } 307 | } 308 | 309 | dynamic "network_interface" { 310 | for_each = var.network_interface 311 | 312 | content { 313 | device_index = network_interface.value.device_index 314 | network_interface_id = lookup(network_interface.value, "network_interface_id", null) 315 | delete_on_termination = try(network_interface.value.delete_on_termination, false) 316 | } 317 | } 318 | 319 | dynamic "private_dns_name_options" { 320 | for_each = length(var.private_dns_name_options) > 0 ? [var.private_dns_name_options] : [] 321 | 322 | content { 323 | hostname_type = try(private_dns_name_options.value.hostname_type, null) 324 | enable_resource_name_dns_a_record = try(private_dns_name_options.value.enable_resource_name_dns_a_record, null) 325 | enable_resource_name_dns_aaaa_record = try(private_dns_name_options.value.enable_resource_name_dns_aaaa_record, null) 326 | } 327 | } 328 | 329 | dynamic "launch_template" { 330 | for_each = length(var.launch_template) > 0 ? [var.launch_template] : [] 331 | 332 | content { 333 | id = lookup(var.launch_template, "id", null) 334 | name = lookup(var.launch_template, "name", null) 335 | version = lookup(var.launch_template, "version", null) 336 | } 337 | } 338 | 339 | dynamic "maintenance_options" { 340 | for_each = length(var.maintenance_options) > 0 ? [var.maintenance_options] : [] 341 | 342 | content { 343 | auto_recovery = try(maintenance_options.value.auto_recovery, null) 344 | } 345 | } 346 | 347 | enclave_options { 348 | enabled = var.enclave_options_enabled 349 | } 350 | 351 | source_dest_check = length(var.network_interface) > 0 ? null : var.source_dest_check 352 | disable_api_termination = var.disable_api_termination 353 | disable_api_stop = var.disable_api_stop 354 | instance_initiated_shutdown_behavior = var.instance_initiated_shutdown_behavior 355 | placement_group = var.placement_group 356 | tenancy = var.tenancy 357 | host_id = var.host_id 358 | 359 | credit_specification { 360 | cpu_credits = local.is_t_instance_type ? var.cpu_credits : null 361 | } 362 | 363 | timeouts { 364 | create = try(var.timeouts.create, null) 365 | update = try(var.timeouts.update, null) 366 | delete = try(var.timeouts.delete, null) 367 | } 368 | 369 | tags = merge({ "Name" = var.name }, var.instance_tags, var.tags) 370 | volume_tags = var.enable_volume_tags ? merge({ "Name" = var.name }, var.volume_tags) : null 371 | 372 | lifecycle { 373 | ignore_changes = [ 374 | ami 375 | ] 376 | } 377 | } 378 | 379 | ################################################################################ 380 | # Spot Instance 381 | ################################################################################ 382 | 383 | resource "aws_spot_instance_request" "this" { 384 | count = local.create && var.create_spot_instance ? 1 : 0 385 | 386 | ami = local.ami 387 | instance_type = var.instance_type 388 | cpu_core_count = var.cpu_core_count 389 | cpu_threads_per_core = var.cpu_threads_per_core 390 | hibernation = var.hibernation 391 | 392 | user_data = var.user_data 393 | user_data_base64 = var.user_data_base64 394 | user_data_replace_on_change = var.user_data_replace_on_change 395 | 396 | availability_zone = var.availability_zone 397 | subnet_id = var.subnet_id 398 | vpc_security_group_ids = var.vpc_security_group_ids 399 | 400 | key_name = var.key_name 401 | monitoring = var.monitoring 402 | get_password_data = var.get_password_data 403 | iam_instance_profile = var.create_iam_instance_profile ? aws_iam_instance_profile.this[0].name : var.iam_instance_profile 404 | 405 | associate_public_ip_address = var.associate_public_ip_address 406 | private_ip = var.private_ip 407 | secondary_private_ips = var.secondary_private_ips 408 | ipv6_address_count = var.ipv6_address_count 409 | ipv6_addresses = var.ipv6_addresses 410 | 411 | ebs_optimized = var.ebs_optimized 412 | 413 | # Spot request specific attributes 414 | spot_price = var.spot_price 415 | wait_for_fulfillment = var.spot_wait_for_fulfillment 416 | spot_type = var.spot_type 417 | launch_group = var.spot_launch_group 418 | block_duration_minutes = var.spot_block_duration_minutes 419 | instance_interruption_behavior = var.spot_instance_interruption_behavior 420 | valid_until = var.spot_valid_until 421 | valid_from = var.spot_valid_from 422 | # End spot request specific attributes 423 | 424 | dynamic "cpu_options" { 425 | for_each = length(var.cpu_options) > 0 ? [var.cpu_options] : [] 426 | 427 | content { 428 | core_count = try(cpu_options.value.core_count, null) 429 | threads_per_core = try(cpu_options.value.threads_per_core, null) 430 | amd_sev_snp = try(cpu_options.value.amd_sev_snp, null) 431 | } 432 | } 433 | 434 | dynamic "capacity_reservation_specification" { 435 | for_each = length(var.capacity_reservation_specification) > 0 ? [var.capacity_reservation_specification] : [] 436 | 437 | content { 438 | capacity_reservation_preference = try(capacity_reservation_specification.value.capacity_reservation_preference, null) 439 | 440 | dynamic "capacity_reservation_target" { 441 | for_each = try([capacity_reservation_specification.value.capacity_reservation_target], []) 442 | content { 443 | capacity_reservation_id = try(capacity_reservation_target.value.capacity_reservation_id, null) 444 | capacity_reservation_resource_group_arn = try(capacity_reservation_target.value.capacity_reservation_resource_group_arn, null) 445 | } 446 | } 447 | } 448 | } 449 | 450 | dynamic "root_block_device" { 451 | for_each = var.root_block_device 452 | 453 | content { 454 | delete_on_termination = try(root_block_device.value.delete_on_termination, null) 455 | encrypted = try(root_block_device.value.encrypted, null) 456 | iops = try(root_block_device.value.iops, null) 457 | kms_key_id = lookup(root_block_device.value, "kms_key_id", null) 458 | volume_size = try(root_block_device.value.volume_size, null) 459 | volume_type = try(root_block_device.value.volume_type, null) 460 | throughput = try(root_block_device.value.throughput, null) 461 | tags = try(root_block_device.value.tags, null) 462 | } 463 | } 464 | 465 | dynamic "ebs_block_device" { 466 | for_each = var.ebs_block_device 467 | 468 | content { 469 | delete_on_termination = try(ebs_block_device.value.delete_on_termination, null) 470 | device_name = ebs_block_device.value.device_name 471 | encrypted = try(ebs_block_device.value.encrypted, null) 472 | iops = try(ebs_block_device.value.iops, null) 473 | kms_key_id = lookup(ebs_block_device.value, "kms_key_id", null) 474 | snapshot_id = lookup(ebs_block_device.value, "snapshot_id", null) 475 | volume_size = try(ebs_block_device.value.volume_size, null) 476 | volume_type = try(ebs_block_device.value.volume_type, null) 477 | throughput = try(ebs_block_device.value.throughput, null) 478 | tags = try(ebs_block_device.value.tags, null) 479 | } 480 | } 481 | 482 | dynamic "ephemeral_block_device" { 483 | for_each = var.ephemeral_block_device 484 | 485 | content { 486 | device_name = ephemeral_block_device.value.device_name 487 | no_device = try(ephemeral_block_device.value.no_device, null) 488 | virtual_name = try(ephemeral_block_device.value.virtual_name, null) 489 | } 490 | } 491 | 492 | dynamic "metadata_options" { 493 | for_each = length(var.metadata_options) > 0 ? [var.metadata_options] : [] 494 | 495 | content { 496 | http_endpoint = try(metadata_options.value.http_endpoint, "enabled") 497 | http_tokens = try(metadata_options.value.http_tokens, "required") 498 | http_put_response_hop_limit = try(metadata_options.value.http_put_response_hop_limit, 1) 499 | instance_metadata_tags = try(metadata_options.value.instance_metadata_tags, null) 500 | } 501 | } 502 | 503 | dynamic "network_interface" { 504 | for_each = var.network_interface 505 | 506 | content { 507 | device_index = network_interface.value.device_index 508 | network_interface_id = lookup(network_interface.value, "network_interface_id", null) 509 | delete_on_termination = try(network_interface.value.delete_on_termination, false) 510 | } 511 | } 512 | 513 | dynamic "launch_template" { 514 | for_each = length(var.launch_template) > 0 ? [var.launch_template] : [] 515 | 516 | content { 517 | id = lookup(var.launch_template, "id", null) 518 | name = lookup(var.launch_template, "name", null) 519 | version = lookup(var.launch_template, "version", null) 520 | } 521 | } 522 | 523 | enclave_options { 524 | enabled = var.enclave_options_enabled 525 | } 526 | 527 | source_dest_check = length(var.network_interface) > 0 ? null : var.source_dest_check 528 | disable_api_termination = var.disable_api_termination 529 | instance_initiated_shutdown_behavior = var.instance_initiated_shutdown_behavior 530 | placement_group = var.placement_group 531 | tenancy = var.tenancy 532 | host_id = var.host_id 533 | 534 | credit_specification { 535 | cpu_credits = local.is_t_instance_type ? var.cpu_credits : null 536 | } 537 | 538 | timeouts { 539 | create = try(var.timeouts.create, null) 540 | delete = try(var.timeouts.delete, null) 541 | } 542 | 543 | tags = merge({ "Name" = var.name }, var.instance_tags, var.tags) 544 | volume_tags = var.enable_volume_tags ? merge({ "Name" = var.name }, var.volume_tags) : null 545 | } 546 | 547 | ################################################################################ 548 | # IAM Role / Instance Profile 549 | ################################################################################ 550 | 551 | locals { 552 | iam_role_name = try(coalesce(var.iam_role_name, var.name), "") 553 | } 554 | 555 | data "aws_iam_policy_document" "assume_role_policy" { 556 | count = var.create && var.create_iam_instance_profile ? 1 : 0 557 | 558 | statement { 559 | sid = "EC2AssumeRole" 560 | actions = ["sts:AssumeRole"] 561 | 562 | principals { 563 | type = "Service" 564 | identifiers = ["ec2.${data.aws_partition.current.dns_suffix}"] 565 | } 566 | } 567 | } 568 | 569 | resource "aws_iam_role" "this" { 570 | count = var.create && var.create_iam_instance_profile ? 1 : 0 571 | 572 | name = var.iam_role_use_name_prefix ? null : local.iam_role_name 573 | name_prefix = var.iam_role_use_name_prefix ? "${local.iam_role_name}-" : null 574 | path = var.iam_role_path 575 | description = var.iam_role_description 576 | 577 | assume_role_policy = data.aws_iam_policy_document.assume_role_policy[0].json 578 | permissions_boundary = var.iam_role_permissions_boundary 579 | force_detach_policies = true 580 | 581 | tags = merge(var.tags, var.iam_role_tags) 582 | } 583 | 584 | resource "aws_iam_role_policy_attachment" "this" { 585 | for_each = { for k, v in var.iam_role_policies : k => v if var.create && var.create_iam_instance_profile } 586 | 587 | policy_arn = each.value 588 | role = aws_iam_role.this[0].name 589 | } 590 | 591 | resource "aws_iam_instance_profile" "this" { 592 | count = var.create && var.create_iam_instance_profile ? 1 : 0 593 | 594 | role = aws_iam_role.this[0].name 595 | 596 | name = var.iam_role_use_name_prefix ? null : local.iam_role_name 597 | name_prefix = var.iam_role_use_name_prefix ? "${local.iam_role_name}-" : null 598 | path = var.iam_role_path 599 | 600 | tags = merge(var.tags, var.iam_role_tags) 601 | 602 | lifecycle { 603 | create_before_destroy = true 604 | } 605 | } 606 | 607 | ################################################################################ 608 | # Elastic IP 609 | ################################################################################ 610 | 611 | resource "aws_eip" "this" { 612 | count = local.create && var.create_eip && !var.create_spot_instance ? 1 : 0 613 | 614 | instance = try( 615 | aws_instance.this[0].id, 616 | aws_instance.ignore_ami[0].id, 617 | ) 618 | 619 | domain = var.eip_domain 620 | 621 | tags = merge(var.tags, var.eip_tags) 622 | } 623 | -------------------------------------------------------------------------------- /outputs.tf: -------------------------------------------------------------------------------- 1 | output "id" { 2 | description = "The ID of the instance" 3 | value = try( 4 | aws_instance.this[0].id, 5 | aws_instance.ignore_ami[0].id, 6 | aws_spot_instance_request.this[0].id, 7 | null, 8 | ) 9 | } 10 | 11 | output "arn" { 12 | description = "The ARN of the instance" 13 | value = try( 14 | aws_instance.this[0].arn, 15 | aws_instance.ignore_ami[0].arn, 16 | aws_spot_instance_request.this[0].arn, 17 | null, 18 | ) 19 | } 20 | 21 | output "capacity_reservation_specification" { 22 | description = "Capacity reservation specification of the instance" 23 | value = try( 24 | aws_instance.this[0].capacity_reservation_specification, 25 | aws_instance.ignore_ami[0].capacity_reservation_specification, 26 | aws_spot_instance_request.this[0].capacity_reservation_specification, 27 | null, 28 | ) 29 | } 30 | 31 | output "instance_state" { 32 | description = "The state of the instance" 33 | value = try( 34 | aws_instance.this[0].instance_state, 35 | aws_instance.ignore_ami[0].instance_state, 36 | aws_spot_instance_request.this[0].instance_state, 37 | null, 38 | ) 39 | } 40 | 41 | output "outpost_arn" { 42 | description = "The ARN of the Outpost the instance is assigned to" 43 | value = try( 44 | aws_instance.this[0].outpost_arn, 45 | aws_instance.ignore_ami[0].outpost_arn, 46 | aws_spot_instance_request.this[0].outpost_arn, 47 | null, 48 | ) 49 | } 50 | 51 | output "password_data" { 52 | description = "Base-64 encoded encrypted password data for the instance. Useful for getting the administrator password for instances running Microsoft Windows. This attribute is only exported if `get_password_data` is true" 53 | value = try( 54 | aws_instance.this[0].password_data, 55 | aws_instance.ignore_ami[0].password_data, 56 | aws_spot_instance_request.this[0].password_data, 57 | null, 58 | ) 59 | } 60 | 61 | output "primary_network_interface_id" { 62 | description = "The ID of the instance's primary network interface" 63 | value = try( 64 | aws_instance.this[0].primary_network_interface_id, 65 | aws_instance.ignore_ami[0].primary_network_interface_id, 66 | aws_spot_instance_request.this[0].primary_network_interface_id, 67 | null, 68 | ) 69 | } 70 | 71 | output "private_dns" { 72 | description = "The private DNS name assigned to the instance. Can only be used inside the Amazon EC2, and only available if you've enabled DNS hostnames for your VPC" 73 | value = try( 74 | aws_instance.this[0].private_dns, 75 | aws_instance.ignore_ami[0].private_dns, 76 | aws_spot_instance_request.this[0].private_dns, 77 | null, 78 | ) 79 | } 80 | 81 | output "public_dns" { 82 | description = "The public DNS name assigned to the instance. For EC2-VPC, this is only available if you've enabled DNS hostnames for your VPC" 83 | value = try( 84 | aws_instance.this[0].public_dns, 85 | aws_instance.ignore_ami[0].public_dns, 86 | aws_spot_instance_request.this[0].public_dns, 87 | null, 88 | ) 89 | } 90 | 91 | output "public_ip" { 92 | description = "The public IP address assigned to the instance, if applicable." 93 | value = try( 94 | aws_eip.this[0].public_ip, 95 | aws_instance.this[0].public_ip, 96 | aws_instance.ignore_ami[0].public_ip, 97 | aws_spot_instance_request.this[0].public_ip, 98 | null, 99 | ) 100 | } 101 | 102 | output "private_ip" { 103 | description = "The private IP address assigned to the instance" 104 | value = try( 105 | aws_instance.this[0].private_ip, 106 | aws_instance.ignore_ami[0].private_ip, 107 | aws_spot_instance_request.this[0].private_ip, 108 | null, 109 | ) 110 | } 111 | 112 | output "ipv6_addresses" { 113 | description = "The IPv6 address assigned to the instance, if applicable" 114 | value = try( 115 | aws_instance.this[0].ipv6_addresses, 116 | aws_instance.ignore_ami[0].ipv6_addresses, 117 | aws_spot_instance_request.this[0].ipv6_addresses, 118 | [], 119 | ) 120 | } 121 | 122 | output "tags_all" { 123 | description = "A map of tags assigned to the resource, including those inherited from the provider default_tags configuration block" 124 | value = try( 125 | aws_instance.this[0].tags_all, 126 | aws_instance.ignore_ami[0].tags_all, 127 | aws_spot_instance_request.this[0].tags_all, 128 | {}, 129 | ) 130 | } 131 | 132 | output "spot_bid_status" { 133 | description = "The current bid status of the Spot Instance Request" 134 | value = try(aws_spot_instance_request.this[0].spot_bid_status, null) 135 | } 136 | 137 | output "spot_request_state" { 138 | description = "The current request state of the Spot Instance Request" 139 | value = try(aws_spot_instance_request.this[0].spot_request_state, null) 140 | } 141 | 142 | output "spot_instance_id" { 143 | description = "The Instance ID (if any) that is currently fulfilling the Spot Instance request" 144 | value = try(aws_spot_instance_request.this[0].spot_instance_id, null) 145 | } 146 | 147 | output "ami" { 148 | description = "AMI ID that was used to create the instance" 149 | value = try( 150 | aws_instance.this[0].ami, 151 | aws_instance.ignore_ami[0].ami, 152 | aws_spot_instance_request.this[0].ami, 153 | null, 154 | ) 155 | } 156 | 157 | output "availability_zone" { 158 | description = "The availability zone of the created instance" 159 | value = try( 160 | aws_instance.this[0].availability_zone, 161 | aws_instance.ignore_ami[0].availability_zone, 162 | aws_spot_instance_request.this[0].availability_zone, 163 | null, 164 | ) 165 | } 166 | 167 | ################################################################################ 168 | # IAM Role / Instance Profile 169 | ################################################################################ 170 | 171 | output "iam_role_name" { 172 | description = "The name of the IAM role" 173 | value = try(aws_iam_role.this[0].name, null) 174 | } 175 | 176 | output "iam_role_arn" { 177 | description = "The Amazon Resource Name (ARN) specifying the IAM role" 178 | value = try(aws_iam_role.this[0].arn, null) 179 | } 180 | 181 | output "iam_role_unique_id" { 182 | description = "Stable and unique string identifying the IAM role" 183 | value = try(aws_iam_role.this[0].unique_id, null) 184 | } 185 | 186 | output "iam_instance_profile_arn" { 187 | description = "ARN assigned by AWS to the instance profile" 188 | value = try(aws_iam_instance_profile.this[0].arn, null) 189 | } 190 | 191 | output "iam_instance_profile_id" { 192 | description = "Instance profile's ID" 193 | value = try(aws_iam_instance_profile.this[0].id, null) 194 | } 195 | 196 | output "iam_instance_profile_unique" { 197 | description = "Stable and unique string identifying the IAM instance profile" 198 | value = try(aws_iam_instance_profile.this[0].unique_id, null) 199 | } 200 | 201 | ################################################################################ 202 | # Block Devices 203 | ################################################################################ 204 | output "root_block_device" { 205 | description = "Root block device information" 206 | value = try( 207 | aws_instance.this[0].root_block_device, 208 | aws_instance.ignore_ami[0].root_block_device, 209 | aws_spot_instance_request.this[0].root_block_device, 210 | null 211 | ) 212 | } 213 | 214 | output "ebs_block_device" { 215 | description = "EBS block device information" 216 | value = try( 217 | aws_instance.this[0].ebs_block_device, 218 | aws_instance.ignore_ami[0].ebs_block_device, 219 | aws_spot_instance_request.this[0].ebs_block_device, 220 | null 221 | ) 222 | } 223 | 224 | output "ephemeral_block_device" { 225 | description = "Ephemeral block device information" 226 | value = try( 227 | aws_instance.this[0].ephemeral_block_device, 228 | aws_instance.ignore_ami[0].ephemeral_block_device, 229 | aws_spot_instance_request.this[0].ephemeral_block_device, 230 | null 231 | ) 232 | } 233 | -------------------------------------------------------------------------------- /variables.tf: -------------------------------------------------------------------------------- 1 | variable "create" { 2 | description = "Whether to create an instance" 3 | type = bool 4 | default = true 5 | } 6 | 7 | variable "name" { 8 | description = "Name to be used on EC2 instance created" 9 | type = string 10 | default = "" 11 | } 12 | 13 | variable "ami_ssm_parameter" { 14 | description = "SSM parameter name for the AMI ID. For Amazon Linux AMI SSM parameters see [reference](https://docs.aws.amazon.com/systems-manager/latest/userguide/parameter-store-public-parameters-ami.html)" 15 | type = string 16 | default = "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2" 17 | } 18 | 19 | variable "ami" { 20 | description = "ID of AMI to use for the instance" 21 | type = string 22 | default = null 23 | } 24 | 25 | variable "ignore_ami_changes" { 26 | description = "Whether changes to the AMI ID changes should be ignored by Terraform. Note - changing this value will result in the replacement of the instance" 27 | type = bool 28 | default = false 29 | } 30 | 31 | variable "associate_public_ip_address" { 32 | description = "Whether to associate a public IP address with an instance in a VPC" 33 | type = bool 34 | default = null 35 | } 36 | 37 | variable "maintenance_options" { 38 | description = "The maintenance options for the instance" 39 | type = any 40 | default = {} 41 | } 42 | 43 | variable "availability_zone" { 44 | description = "AZ to start the instance in" 45 | type = string 46 | default = null 47 | } 48 | 49 | variable "capacity_reservation_specification" { 50 | description = "Describes an instance's Capacity Reservation targeting option" 51 | type = any 52 | default = {} 53 | } 54 | 55 | variable "cpu_credits" { 56 | description = "The credit option for CPU usage (unlimited or standard)" 57 | type = string 58 | default = null 59 | } 60 | 61 | variable "disable_api_termination" { 62 | description = "If true, enables EC2 Instance Termination Protection" 63 | type = bool 64 | default = null 65 | } 66 | 67 | variable "ebs_block_device" { 68 | description = "Additional EBS block devices to attach to the instance" 69 | type = list(any) 70 | default = [] 71 | } 72 | 73 | variable "ebs_optimized" { 74 | description = "If true, the launched EC2 instance will be EBS-optimized" 75 | type = bool 76 | default = null 77 | } 78 | 79 | variable "enclave_options_enabled" { 80 | description = "Whether Nitro Enclaves will be enabled on the instance. Defaults to `false`" 81 | type = bool 82 | default = null 83 | } 84 | 85 | variable "ephemeral_block_device" { 86 | description = "Customize Ephemeral (also known as Instance Store) volumes on the instance" 87 | type = list(map(string)) 88 | default = [] 89 | } 90 | 91 | variable "get_password_data" { 92 | description = "If true, wait for password data to become available and retrieve it" 93 | type = bool 94 | default = null 95 | } 96 | 97 | variable "hibernation" { 98 | description = "If true, the launched EC2 instance will support hibernation" 99 | type = bool 100 | default = null 101 | } 102 | 103 | variable "host_id" { 104 | description = "ID of a dedicated host that the instance will be assigned to. Use when an instance is to be launched on a specific dedicated host" 105 | type = string 106 | default = null 107 | } 108 | 109 | variable "iam_instance_profile" { 110 | description = "IAM Instance Profile to launch the instance with. Specified as the name of the Instance Profile" 111 | type = string 112 | default = null 113 | } 114 | 115 | variable "instance_initiated_shutdown_behavior" { 116 | description = "Shutdown behavior for the instance. Amazon defaults this to stop for EBS-backed instances and terminate for instance-store instances. Cannot be set on instance-store instance" # https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/terminating-instances.html#Using_ChangingInstanceInitiatedShutdownBehavior 117 | type = string 118 | default = null 119 | } 120 | 121 | variable "instance_type" { 122 | description = "The type of instance to start" 123 | type = string 124 | default = "t3.micro" 125 | } 126 | 127 | variable "instance_tags" { 128 | description = "Additional tags for the instance" 129 | type = map(string) 130 | default = {} 131 | } 132 | 133 | variable "ipv6_address_count" { 134 | description = "A number of IPv6 addresses to associate with the primary network interface. Amazon EC2 chooses the IPv6 addresses from the range of your subnet" 135 | type = number 136 | default = null 137 | } 138 | 139 | variable "ipv6_addresses" { 140 | description = "Specify one or more IPv6 addresses from the range of the subnet to associate with the primary network interface" 141 | type = list(string) 142 | default = null 143 | } 144 | 145 | variable "key_name" { 146 | description = "Key name of the Key Pair to use for the instance; which can be managed using the `aws_key_pair` resource" 147 | type = string 148 | default = null 149 | } 150 | 151 | variable "launch_template" { 152 | description = "Specifies a Launch Template to configure the instance. Parameters configured on this resource will override the corresponding parameters in the Launch Template" 153 | type = map(string) 154 | default = {} 155 | } 156 | 157 | variable "metadata_options" { 158 | description = "Customize the metadata options of the instance" 159 | type = map(string) 160 | default = { 161 | "http_endpoint" = "enabled" 162 | "http_put_response_hop_limit" = 1 163 | "http_tokens" = "required" 164 | } 165 | } 166 | 167 | variable "monitoring" { 168 | description = "If true, the launched EC2 instance will have detailed monitoring enabled" 169 | type = bool 170 | default = null 171 | } 172 | 173 | variable "network_interface" { 174 | description = "Customize network interfaces to be attached at instance boot time" 175 | type = list(map(string)) 176 | default = [] 177 | } 178 | 179 | variable "private_dns_name_options" { 180 | description = "Customize the private DNS name options of the instance" 181 | type = map(string) 182 | default = {} 183 | } 184 | 185 | variable "placement_group" { 186 | description = "The Placement Group to start the instance in" 187 | type = string 188 | default = null 189 | } 190 | 191 | variable "private_ip" { 192 | description = "Private IP address to associate with the instance in a VPC" 193 | type = string 194 | default = null 195 | } 196 | 197 | variable "root_block_device" { 198 | description = "Customize details about the root block device of the instance. See Block Devices below for details" 199 | type = list(any) 200 | default = [] 201 | } 202 | 203 | variable "secondary_private_ips" { 204 | description = "A list of secondary private IPv4 addresses to assign to the instance's primary network interface (eth0) in a VPC. Can only be assigned to the primary network interface (eth0) attached at instance creation, not a pre-existing network interface i.e. referenced in a `network_interface block`" 205 | type = list(string) 206 | default = null 207 | } 208 | 209 | variable "source_dest_check" { 210 | description = "Controls if traffic is routed to the instance when the destination address does not match the instance. Used for NAT or VPNs" 211 | type = bool 212 | default = null 213 | } 214 | 215 | variable "subnet_id" { 216 | description = "The VPC Subnet ID to launch in" 217 | type = string 218 | default = null 219 | } 220 | 221 | variable "tags" { 222 | description = "A mapping of tags to assign to the resource" 223 | type = map(string) 224 | default = {} 225 | } 226 | 227 | variable "tenancy" { 228 | description = "The tenancy of the instance (if the instance is running in a VPC). Available values: default, dedicated, host" 229 | type = string 230 | default = null 231 | } 232 | 233 | variable "user_data" { 234 | description = "The user data to provide when launching the instance. Do not pass gzip-compressed data via this argument; see user_data_base64 instead" 235 | type = string 236 | default = null 237 | } 238 | 239 | variable "user_data_base64" { 240 | description = "Can be used instead of user_data to pass base64-encoded binary data directly. Use this instead of user_data whenever the value is not a valid UTF-8 string. For example, gzip-encoded user data must be base64-encoded and passed via this argument to avoid corruption" 241 | type = string 242 | default = null 243 | } 244 | 245 | variable "user_data_replace_on_change" { 246 | description = "When used in combination with user_data or user_data_base64 will trigger a destroy and recreate when set to true. Defaults to false if not set" 247 | type = bool 248 | default = null 249 | } 250 | 251 | variable "volume_tags" { 252 | description = "A mapping of tags to assign to the devices created by the instance at launch time" 253 | type = map(string) 254 | default = {} 255 | } 256 | 257 | variable "enable_volume_tags" { 258 | description = "Whether to enable volume tags (if enabled it conflicts with root_block_device tags)" 259 | type = bool 260 | default = true 261 | } 262 | 263 | variable "vpc_security_group_ids" { 264 | description = "A list of security group IDs to associate with" 265 | type = list(string) 266 | default = null 267 | } 268 | 269 | variable "timeouts" { 270 | description = "Define maximum timeout for creating, updating, and deleting EC2 instance resources" 271 | type = map(string) 272 | default = {} 273 | } 274 | 275 | variable "cpu_options" { 276 | description = "Defines CPU options to apply to the instance at launch time." 277 | type = any 278 | default = {} 279 | } 280 | 281 | variable "cpu_core_count" { 282 | description = "Sets the number of CPU cores for an instance" # This option is only supported on creation of instance type that support CPU Options https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-optimize-cpu.html#cpu-options-supported-instances-values 283 | type = number 284 | default = null 285 | } 286 | 287 | variable "cpu_threads_per_core" { 288 | description = "Sets the number of CPU threads per core for an instance (has no effect unless cpu_core_count is also set)" 289 | type = number 290 | default = null 291 | } 292 | 293 | # Spot instance request 294 | variable "create_spot_instance" { 295 | description = "Depicts if the instance is a spot instance" 296 | type = bool 297 | default = false 298 | } 299 | 300 | variable "spot_price" { 301 | description = "The maximum price to request on the spot market. Defaults to on-demand price" 302 | type = string 303 | default = null 304 | } 305 | 306 | variable "spot_wait_for_fulfillment" { 307 | description = "If set, Terraform will wait for the Spot Request to be fulfilled, and will throw an error if the timeout of 10m is reached" 308 | type = bool 309 | default = null 310 | } 311 | 312 | variable "spot_type" { 313 | description = "If set to one-time, after the instance is terminated, the spot request will be closed. Default `persistent`" 314 | type = string 315 | default = null 316 | } 317 | 318 | variable "spot_launch_group" { 319 | description = "A launch group is a group of spot instances that launch together and terminate together. If left empty instances are launched and terminated individually" 320 | type = string 321 | default = null 322 | } 323 | 324 | variable "spot_block_duration_minutes" { 325 | description = "The required duration for the Spot instances, in minutes. This value must be a multiple of 60 (60, 120, 180, 240, 300, or 360)" 326 | type = number 327 | default = null 328 | } 329 | 330 | variable "spot_instance_interruption_behavior" { 331 | description = "Indicates Spot instance behavior when it is interrupted. Valid values are `terminate`, `stop`, or `hibernate`" 332 | type = string 333 | default = null 334 | } 335 | 336 | variable "spot_valid_until" { 337 | description = "The end date and time of the request, in UTC RFC3339 format(for example, YYYY-MM-DDTHH:MM:SSZ)" 338 | type = string 339 | default = null 340 | } 341 | 342 | variable "spot_valid_from" { 343 | description = "The start date and time of the request, in UTC RFC3339 format(for example, YYYY-MM-DDTHH:MM:SSZ)" 344 | type = string 345 | default = null 346 | } 347 | 348 | variable "disable_api_stop" { 349 | description = "If true, enables EC2 Instance Stop Protection" 350 | type = bool 351 | default = null 352 | 353 | } 354 | variable "putin_khuylo" { 355 | description = "Do you agree that Putin doesn't respect Ukrainian sovereignty and territorial integrity? More info: https://en.wikipedia.org/wiki/Putin_khuylo!" 356 | type = bool 357 | default = true 358 | } 359 | 360 | ################################################################################ 361 | # IAM Role / Instance Profile 362 | ################################################################################ 363 | 364 | variable "create_iam_instance_profile" { 365 | description = "Determines whether an IAM instance profile is created or to use an existing IAM instance profile" 366 | type = bool 367 | default = false 368 | } 369 | 370 | variable "iam_role_name" { 371 | description = "Name to use on IAM role created" 372 | type = string 373 | default = null 374 | } 375 | 376 | variable "iam_role_use_name_prefix" { 377 | description = "Determines whether the IAM role name (`iam_role_name` or `name`) is used as a prefix" 378 | type = bool 379 | default = true 380 | } 381 | 382 | variable "iam_role_path" { 383 | description = "IAM role path" 384 | type = string 385 | default = null 386 | } 387 | 388 | variable "iam_role_description" { 389 | description = "Description of the role" 390 | type = string 391 | default = null 392 | } 393 | 394 | variable "iam_role_permissions_boundary" { 395 | description = "ARN of the policy that is used to set the permissions boundary for the IAM role" 396 | type = string 397 | default = null 398 | } 399 | 400 | variable "iam_role_policies" { 401 | description = "Policies attached to the IAM role" 402 | type = map(string) 403 | default = {} 404 | } 405 | 406 | variable "iam_role_tags" { 407 | description = "A map of additional tags to add to the IAM role/profile created" 408 | type = map(string) 409 | default = {} 410 | } 411 | 412 | ################################################################################ 413 | # Elastic IP 414 | ################################################################################ 415 | 416 | variable "create_eip" { 417 | description = "Determines whether a public EIP will be created and associated with the instance." 418 | type = bool 419 | default = false 420 | } 421 | 422 | variable "eip_domain" { 423 | description = "Indicates if this EIP is for use in VPC" 424 | type = string 425 | default = "vpc" 426 | } 427 | 428 | variable "eip_tags" { 429 | description = "A map of additional tags to add to the eip" 430 | type = map(string) 431 | default = {} 432 | } 433 | -------------------------------------------------------------------------------- /versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.0" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 4.66" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /wrappers/README.md: -------------------------------------------------------------------------------- 1 | # Wrapper for the root module 2 | 3 | The configuration in this directory contains an implementation of a single module wrapper pattern, which allows managing several copies of a module in places where using the native Terraform 0.13+ `for_each` feature is not feasible (e.g., with Terragrunt). 4 | 5 | You may want to use a single Terragrunt configuration file to manage multiple resources without duplicating `terragrunt.hcl` files for each copy of the same module. 6 | 7 | This wrapper does not implement any extra functionality. 8 | 9 | ## Usage with Terragrunt 10 | 11 | `terragrunt.hcl`: 12 | 13 | ```hcl 14 | terraform { 15 | source = "tfr:///terraform-aws-modules/ec2-instance/aws//wrappers" 16 | # Alternative source: 17 | # source = "git::git@github.com:terraform-aws-modules/terraform-aws-ec2-instance.git//wrappers?ref=master" 18 | } 19 | 20 | inputs = { 21 | defaults = { # Default values 22 | create = true 23 | tags = { 24 | Terraform = "true" 25 | Environment = "dev" 26 | } 27 | } 28 | 29 | items = { 30 | my-item = { 31 | # omitted... can be any argument supported by the module 32 | } 33 | my-second-item = { 34 | # omitted... can be any argument supported by the module 35 | } 36 | # omitted... 37 | } 38 | } 39 | ``` 40 | 41 | ## Usage with Terraform 42 | 43 | ```hcl 44 | module "wrapper" { 45 | source = "terraform-aws-modules/ec2-instance/aws//wrappers" 46 | 47 | defaults = { # Default values 48 | create = true 49 | tags = { 50 | Terraform = "true" 51 | Environment = "dev" 52 | } 53 | } 54 | 55 | items = { 56 | my-item = { 57 | # omitted... can be any argument supported by the module 58 | } 59 | my-second-item = { 60 | # omitted... can be any argument supported by the module 61 | } 62 | # omitted... 63 | } 64 | } 65 | ``` 66 | 67 | ## Example: Manage multiple S3 buckets in one Terragrunt layer 68 | 69 | `eu-west-1/s3-buckets/terragrunt.hcl`: 70 | 71 | ```hcl 72 | terraform { 73 | source = "tfr:///terraform-aws-modules/s3-bucket/aws//wrappers" 74 | # Alternative source: 75 | # source = "git::git@github.com:terraform-aws-modules/terraform-aws-s3-bucket.git//wrappers?ref=master" 76 | } 77 | 78 | inputs = { 79 | defaults = { 80 | force_destroy = true 81 | 82 | attach_elb_log_delivery_policy = true 83 | attach_lb_log_delivery_policy = true 84 | attach_deny_insecure_transport_policy = true 85 | attach_require_latest_tls_policy = true 86 | } 87 | 88 | items = { 89 | bucket1 = { 90 | bucket = "my-random-bucket-1" 91 | } 92 | bucket2 = { 93 | bucket = "my-random-bucket-2" 94 | tags = { 95 | Secure = "probably" 96 | } 97 | } 98 | } 99 | } 100 | ``` 101 | -------------------------------------------------------------------------------- /wrappers/main.tf: -------------------------------------------------------------------------------- 1 | module "wrapper" { 2 | source = "../" 3 | 4 | for_each = var.items 5 | 6 | ami = try(each.value.ami, var.defaults.ami, null) 7 | ami_ssm_parameter = try(each.value.ami_ssm_parameter, var.defaults.ami_ssm_parameter, "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2") 8 | associate_public_ip_address = try(each.value.associate_public_ip_address, var.defaults.associate_public_ip_address, null) 9 | availability_zone = try(each.value.availability_zone, var.defaults.availability_zone, null) 10 | capacity_reservation_specification = try(each.value.capacity_reservation_specification, var.defaults.capacity_reservation_specification, {}) 11 | cpu_core_count = try(each.value.cpu_core_count, var.defaults.cpu_core_count, null) 12 | cpu_credits = try(each.value.cpu_credits, var.defaults.cpu_credits, null) 13 | cpu_options = try(each.value.cpu_options, var.defaults.cpu_options, {}) 14 | cpu_threads_per_core = try(each.value.cpu_threads_per_core, var.defaults.cpu_threads_per_core, null) 15 | create = try(each.value.create, var.defaults.create, true) 16 | create_eip = try(each.value.create_eip, var.defaults.create_eip, false) 17 | create_iam_instance_profile = try(each.value.create_iam_instance_profile, var.defaults.create_iam_instance_profile, false) 18 | create_spot_instance = try(each.value.create_spot_instance, var.defaults.create_spot_instance, false) 19 | disable_api_stop = try(each.value.disable_api_stop, var.defaults.disable_api_stop, null) 20 | disable_api_termination = try(each.value.disable_api_termination, var.defaults.disable_api_termination, null) 21 | ebs_block_device = try(each.value.ebs_block_device, var.defaults.ebs_block_device, []) 22 | ebs_optimized = try(each.value.ebs_optimized, var.defaults.ebs_optimized, null) 23 | eip_domain = try(each.value.eip_domain, var.defaults.eip_domain, "vpc") 24 | eip_tags = try(each.value.eip_tags, var.defaults.eip_tags, {}) 25 | enable_volume_tags = try(each.value.enable_volume_tags, var.defaults.enable_volume_tags, true) 26 | enclave_options_enabled = try(each.value.enclave_options_enabled, var.defaults.enclave_options_enabled, null) 27 | ephemeral_block_device = try(each.value.ephemeral_block_device, var.defaults.ephemeral_block_device, []) 28 | get_password_data = try(each.value.get_password_data, var.defaults.get_password_data, null) 29 | hibernation = try(each.value.hibernation, var.defaults.hibernation, null) 30 | host_id = try(each.value.host_id, var.defaults.host_id, null) 31 | iam_instance_profile = try(each.value.iam_instance_profile, var.defaults.iam_instance_profile, null) 32 | iam_role_description = try(each.value.iam_role_description, var.defaults.iam_role_description, null) 33 | iam_role_name = try(each.value.iam_role_name, var.defaults.iam_role_name, null) 34 | iam_role_path = try(each.value.iam_role_path, var.defaults.iam_role_path, null) 35 | iam_role_permissions_boundary = try(each.value.iam_role_permissions_boundary, var.defaults.iam_role_permissions_boundary, null) 36 | iam_role_policies = try(each.value.iam_role_policies, var.defaults.iam_role_policies, {}) 37 | iam_role_tags = try(each.value.iam_role_tags, var.defaults.iam_role_tags, {}) 38 | iam_role_use_name_prefix = try(each.value.iam_role_use_name_prefix, var.defaults.iam_role_use_name_prefix, true) 39 | ignore_ami_changes = try(each.value.ignore_ami_changes, var.defaults.ignore_ami_changes, false) 40 | instance_initiated_shutdown_behavior = try(each.value.instance_initiated_shutdown_behavior, var.defaults.instance_initiated_shutdown_behavior, null) 41 | instance_tags = try(each.value.instance_tags, var.defaults.instance_tags, {}) 42 | instance_type = try(each.value.instance_type, var.defaults.instance_type, "t3.micro") 43 | ipv6_address_count = try(each.value.ipv6_address_count, var.defaults.ipv6_address_count, null) 44 | ipv6_addresses = try(each.value.ipv6_addresses, var.defaults.ipv6_addresses, null) 45 | key_name = try(each.value.key_name, var.defaults.key_name, null) 46 | launch_template = try(each.value.launch_template, var.defaults.launch_template, {}) 47 | maintenance_options = try(each.value.maintenance_options, var.defaults.maintenance_options, {}) 48 | metadata_options = try(each.value.metadata_options, var.defaults.metadata_options, { 49 | "http_endpoint" = "enabled" 50 | "http_put_response_hop_limit" = 1 51 | "http_tokens" = "required" 52 | }) 53 | monitoring = try(each.value.monitoring, var.defaults.monitoring, null) 54 | name = try(each.value.name, var.defaults.name, "") 55 | network_interface = try(each.value.network_interface, var.defaults.network_interface, []) 56 | placement_group = try(each.value.placement_group, var.defaults.placement_group, null) 57 | private_dns_name_options = try(each.value.private_dns_name_options, var.defaults.private_dns_name_options, {}) 58 | private_ip = try(each.value.private_ip, var.defaults.private_ip, null) 59 | putin_khuylo = try(each.value.putin_khuylo, var.defaults.putin_khuylo, true) 60 | root_block_device = try(each.value.root_block_device, var.defaults.root_block_device, []) 61 | secondary_private_ips = try(each.value.secondary_private_ips, var.defaults.secondary_private_ips, null) 62 | source_dest_check = try(each.value.source_dest_check, var.defaults.source_dest_check, null) 63 | spot_block_duration_minutes = try(each.value.spot_block_duration_minutes, var.defaults.spot_block_duration_minutes, null) 64 | spot_instance_interruption_behavior = try(each.value.spot_instance_interruption_behavior, var.defaults.spot_instance_interruption_behavior, null) 65 | spot_launch_group = try(each.value.spot_launch_group, var.defaults.spot_launch_group, null) 66 | spot_price = try(each.value.spot_price, var.defaults.spot_price, null) 67 | spot_type = try(each.value.spot_type, var.defaults.spot_type, null) 68 | spot_valid_from = try(each.value.spot_valid_from, var.defaults.spot_valid_from, null) 69 | spot_valid_until = try(each.value.spot_valid_until, var.defaults.spot_valid_until, null) 70 | spot_wait_for_fulfillment = try(each.value.spot_wait_for_fulfillment, var.defaults.spot_wait_for_fulfillment, null) 71 | subnet_id = try(each.value.subnet_id, var.defaults.subnet_id, null) 72 | tags = try(each.value.tags, var.defaults.tags, {}) 73 | tenancy = try(each.value.tenancy, var.defaults.tenancy, null) 74 | timeouts = try(each.value.timeouts, var.defaults.timeouts, {}) 75 | user_data = try(each.value.user_data, var.defaults.user_data, null) 76 | user_data_base64 = try(each.value.user_data_base64, var.defaults.user_data_base64, null) 77 | user_data_replace_on_change = try(each.value.user_data_replace_on_change, var.defaults.user_data_replace_on_change, null) 78 | volume_tags = try(each.value.volume_tags, var.defaults.volume_tags, {}) 79 | vpc_security_group_ids = try(each.value.vpc_security_group_ids, var.defaults.vpc_security_group_ids, null) 80 | } 81 | -------------------------------------------------------------------------------- /wrappers/outputs.tf: -------------------------------------------------------------------------------- 1 | output "wrapper" { 2 | description = "Map of outputs of a wrapper." 3 | value = module.wrapper 4 | # sensitive = false # No sensitive module output found 5 | } 6 | -------------------------------------------------------------------------------- /wrappers/variables.tf: -------------------------------------------------------------------------------- 1 | variable "defaults" { 2 | description = "Map of default values which will be used for each item." 3 | type = any 4 | default = {} 5 | } 6 | 7 | variable "items" { 8 | description = "Maps of items to create a wrapper from. Values are passed through to the module." 9 | type = any 10 | default = {} 11 | } 12 | -------------------------------------------------------------------------------- /wrappers/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.0" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 4.66" 8 | } 9 | } 10 | } 11 | --------------------------------------------------------------------------------