diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index d64d5d0d5..000000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,95 +0,0 @@ -version: 2.1 - -executors: - golang: - docker: - - image: docker.mirror.hashicorp.services/cimg/go:1.18 - resource_class: medium+ - -commands: - build-and-persist-plugin-binary: - parameters: - GOOS: - type: string - GOARCH: - default: "amd64" - type: string - steps: - - checkout - - run: GOOS=<< parameters.GOOS >> GOARCH=<> go build -o ./pkg/packer_plugin_amazon_<< parameters.GOOS >>_<< parameters.GOARCH >> . - - run: zip ./pkg/packer_plugin_amazon_<< parameters.GOOS >>_<< parameters.GOARCH >>.zip ./pkg/packer_plugin_amazon_<< parameters.GOOS >>_<< parameters.GOARCH >> - - run: rm ./pkg/packer_plugin_amazon_<< parameters.GOOS >>_<< parameters.GOARCH >> - - persist_to_workspace: - root: . - paths: - - ./pkg/ - -# Golang CircleCI 2.0 configuration file -# -# Check https://circleci.com/docs/2.0/language-go/ for more details -jobs: - build_linux: - executor: golang - steps: - - build-and-persist-plugin-binary: - GOOS: linux - build_windows: - executor: golang - working_directory: ~/go/src/github.com/hashicorp/packer-plugin-amazon - steps: - - build-and-persist-plugin-binary: - GOOS: windows - build_darwin: - executor: golang - working_directory: ~/go/src/github.com/hashicorp/packer-plugin-amazon - steps: - - build-and-persist-plugin-binary: - GOOS: darwin - - build-and-persist-plugin-binary: - GOOS: darwin - GOARCH: arm64 - build_freebsd: - executor: golang - working_directory: ~/go/src/github.com/hashicorp/packer-plugin-amazon - steps: - - build-and-persist-plugin-binary: - GOOS: freebsd - build_solaris: - executor: golang - working_directory: ~/go/src/github.com/hashicorp/packer-plugin-amazon - steps: - - build-and-persist-plugin-binary: - GOOS: solaris - build_openbsd: - executor: golang - working_directory: ~/go/src/github.com/hashicorp/packer-plugin-amazon - steps: - - build-and-persist-plugin-binary: - GOOS: openbsd - store_artifacts: - executor: golang - steps: - - attach_workspace: - at: . - - store_artifacts: - path: ./pkg/ - destination: / - -workflows: - version: 2 - build_plugin_binaries: - jobs: - - build_darwin - - build_freebsd - - build_linux - - build_openbsd - - build_solaris - - build_windows - - store_artifacts: - requires: - - build_darwin - - build_freebsd - - build_linux - - build_openbsd - - build_solaris - - build_windows \ No newline at end of file diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index bb4d7e741..66caae073 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -66,7 +66,7 @@ runtime in order to build packer with the Amazon plugin. 1. This project always releases from the latest version of golang. [Install go](https://golang.org/doc/install#install) To properly build from -source, you need to have golang >= 1.18 +source, you need to have golang >= 1.21 ## Setting up Amazon plugin for dev diff --git a/.github/actions/build-and-persist-plugin-binary/action.yml b/.github/actions/build-and-persist-plugin-binary/action.yml new file mode 100644 index 000000000..81d274bfc --- /dev/null +++ b/.github/actions/build-and-persist-plugin-binary/action.yml @@ -0,0 +1,24 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +name: build-and-persist-plugin-binary +inputs: + GOOS: + required: true + GOARCH: + required: true +runs: + using: composite + steps: + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + - run: "GOOS=${{ inputs.GOOS }} GOARCH=${{ inputs.GOARCH }} go build -o ./pkg/packer_plugin_amazon_${{ inputs.GOOS }}_${{ inputs.GOARCH }} ." + shell: bash + - run: zip ./pkg/packer_plugin_amazon_${{ inputs.GOOS }}_${{ inputs.GOARCH }}.zip ./pkg/packer_plugin_amazon_${{ inputs.GOOS }}_${{ inputs.GOARCH }} + shell: bash + - run: rm ./pkg/packer_plugin_amazon_${{ inputs.GOOS }}_${{ inputs.GOARCH }} + shell: bash + - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 + with: + name: "packer_plugin_amazon_${{ inputs.GOOS }}_${{ inputs.GOARCH }}.zip" + path: "pkg/packer_plugin_amazon_${{ inputs.GOOS }}_${{ inputs.GOARCH }}.zip" + retention-days: 30 diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 1f794d7f1..108edd0d2 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,7 +1,5 @@ -# To get started with Dependabot version updates, you'll need to specify which -# package ecosystems to update and where the package manifests are located. -# Please see the documentation for all configuration options: -# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 version: 2 updates: @@ -11,6 +9,4 @@ updates: interval: "daily" allow: - dependency-name: "github.com/hashicorp/packer-plugin-sdk" - - dependency-name: "github.com/hashicorp/hcl/v2" - - dependency-name: "github.com/zclconf/go-cty" diff --git a/.github/release.yml b/.github/release.yml index 7719b0431..47288604a 100644 --- a/.github/release.yml +++ b/.github/release.yml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + changelog: exclude: labels: diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml new file mode 100644 index 000000000..3d4be6a8d --- /dev/null +++ b/.github/workflows/acceptance-tests.yml @@ -0,0 +1,118 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +name: "AWS Acceptance Tests" + +on: + schedule: + - cron: '0 4 * * SUN' + workflow_dispatch: + inputs: + branch: + description: "A branch or SHA" + default: 'main' + required: false + run_pattern: + description: "The pattern to run tests on" + default: "TestAcc" + required: false + +permissions: + contents: read + +jobs: + get-go-version: + runs-on: ubuntu-latest + outputs: + go-version: ${{ steps.get-go-version.outputs.go-version }} + steps: + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + - name: 'Determine Go version' + id: get-go-version + run: | + echo "Found Go $(cat .go-version)" + echo "go-version=$(cat .go-version)" >> "$GITHUB_OUTPUT" + + ebs-acc-tests: + needs: + - get-go-version + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + name: AWS EBS Acceptance tests + steps: + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + with: + ref: ${{ github.event.inputs.branch }} + - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 + with: + go-version: ${{ needs.get-go-version.outputs.go-version }} + - name: "Compile/install the plugin on the current branch" + run: | + make dev + - uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2 + with: + aws-access-key-id: "${{ secrets.AWS_ACC_TEST_KEY_ID }}" + aws-secret-access-key: "${{ secrets.AWS_ACC_TEST_KEY_SECRET }}" + aws-region: "${{ secrets.AWS_ACC_TEST_REGION }}" + role-to-assume: "${{ secrets.AWS_ACC_TEST_ROLE }}" + role-session-name: "packer-aws-acceptance-tests" + role-duration-seconds: 21600 # 6h + - run: | + echo "Testing with Go ${{ needs.get-go-version.outputs.go-version }}" + PACKER_ACC=1 go test \ + -timeout 5h \ + -count 1 \ + -run "${{ github.event.inputs.run_pattern }}" \ + ./builder/ebs + - run: zip ebs_failure_logs.zip builder/ebs/*txt + if: ${{ failure() }} + - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 + if: ${{ failure() }} + with: + name: "ebs_failure_logs.zip" + path: "ebs_failure_logs.zip" + retention-days: 5 + + ebssurrogate-acc-tests: + needs: + - get-go-version + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + name: AWS EBS Surrogate Acceptance tests + steps: + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + with: + ref: ${{ github.event.inputs.branch }} + - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 + with: + go-version: ${{ needs.get-go-version.outputs.go-version }} + - name: "Compile/install the plugin on the current branch" + run: | + make dev + - uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2 + with: + aws-access-key-id: "${{ secrets.AWS_ACC_TEST_KEY_ID }}" + aws-secret-access-key: "${{ secrets.AWS_ACC_TEST_KEY_SECRET }}" + aws-region: "${{ secrets.AWS_ACC_TEST_REGION }}" + role-to-assume: "${{ secrets.AWS_ACC_TEST_ROLE }}" + role-session-name: "packer-aws-acceptance-tests" + role-duration-seconds: 14400 # 4h + - run: | + echo "Testing with Go ${{ needs.get-go-version.outputs.go-version }}" + PACKER_ACC=1 go test \ + -timeout 1h \ + -count 1 \ + -run "${{ github.event.inputs.run_pattern }}" \ + ./builder/ebssurrogate + - run: zip ebssurrogate_failure_logs.zip builder/ebssurrogate/*txt + if: ${{ failure() }} + - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 + if: ${{ failure() }} + with: + name: "ebssurrogate_failure_logs.zip" + path: "ebssurrogate_failure_logs.zip" + retention-days: 5 diff --git a/.github/workflows/build_plugin_binaries.yml b/.github/workflows/build_plugin_binaries.yml new file mode 100644 index 000000000..36ea7f0eb --- /dev/null +++ b/.github/workflows/build_plugin_binaries.yml @@ -0,0 +1,146 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +name: hashicorp/packer-plugin-amazon/build_plugin_binaries +permissions: + contents: read +on: + push: + branches: + - main +jobs: + build_darwin: + defaults: + run: + working-directory: ~/go/src/github.com/hashicorp/packer-plugin-amazon + runs-on: ubuntu-latest + container: + image: docker.mirror.hashicorp.services/cimg/go:1.21 + steps: + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + - uses: "./.github/actions/build-and-persist-plugin-binary" + with: + GOOS: darwin + GOARCH: amd64 + - uses: "./.github/actions/build-and-persist-plugin-binary" + with: + GOOS: darwin + GOARCH: arm64 + build_freebsd: + defaults: + run: + working-directory: ~/go/src/github.com/hashicorp/packer-plugin-amazon + runs-on: ubuntu-latest + container: + image: docker.mirror.hashicorp.services/cimg/go:1.21 + steps: + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + - uses: "./.github/actions/build-and-persist-plugin-binary" + with: + GOOS: freebsd + GOARCH: 386 + - uses: "./.github/actions/build-and-persist-plugin-binary" + with: + GOOS: freebsd + GOARCH: amd64 + - uses: "./.github/actions/build-and-persist-plugin-binary" + with: + GOOS: freebsd + GOARCH: arm + build_linux: + defaults: + run: + working-directory: ~/go/src/github.com/hashicorp/packer-plugin-amazon + runs-on: ubuntu-latest + container: + image: docker.mirror.hashicorp.services/cimg/go:1.21 + steps: + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + - uses: "./.github/actions/build-and-persist-plugin-binary" + with: + GOOS: linux + GOARCH: 386 + - uses: "./.github/actions/build-and-persist-plugin-binary" + with: + GOOS: linux + GOARCH: amd64 + - uses: "./.github/actions/build-and-persist-plugin-binary" + with: + GOOS: linux + GOARCH: arm + - uses: "./.github/actions/build-and-persist-plugin-binary" + with: + GOOS: linux + GOARCH: arm64 + build_netbsd: + defaults: + run: + working-directory: ~/go/src/github.com/hashicorp/packer-plugin-amazon + runs-on: ubuntu-latest + container: + image: docker.mirror.hashicorp.services/cimg/go:1.21 + steps: + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + - uses: "./.github/actions/build-and-persist-plugin-binary" + with: + GOOS: netbsd + GOARCH: 386 + - uses: "./.github/actions/build-and-persist-plugin-binary" + with: + GOOS: netbsd + GOARCH: amd64 + - uses: "./.github/actions/build-and-persist-plugin-binary" + with: + GOOS: netbsd + GOARCH: arm + build_openbsd: + defaults: + run: + working-directory: ~/go/src/github.com/hashicorp/packer-plugin-amazon + runs-on: ubuntu-latest + container: + image: docker.mirror.hashicorp.services/cimg/go:1.21 + steps: + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + - uses: "./.github/actions/build-and-persist-plugin-binary" + with: + GOOS: openbsd + GOARCH: 386 + - uses: "./.github/actions/build-and-persist-plugin-binary" + with: + GOOS: openbsd + GOARCH: amd64 + - uses: "./.github/actions/build-and-persist-plugin-binary" + with: + GOOS: openbsd + GOARCH: arm + build_solaris: + defaults: + run: + working-directory: ~/go/src/github.com/hashicorp/packer-plugin-amazon + runs-on: ubuntu-latest + container: + image: docker.mirror.hashicorp.services/cimg/go:1.21 + steps: + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + - uses: "./.github/actions/build-and-persist-plugin-binary" + with: + GOOS: solaris + GOARCH: amd64 + build_windows: + defaults: + run: + working-directory: ~/go/src/github.com/hashicorp/packer-plugin-amazon + runs-on: ubuntu-latest + container: + image: docker.mirror.hashicorp.services/cimg/go:1.21 + steps: + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + - uses: "./.github/actions/build-and-persist-plugin-binary" + with: + GOOS: windows + GOARCH: 386 + - uses: "./.github/actions/build-and-persist-plugin-binary" + with: + GOOS: windows + GOARCH: amd64 diff --git a/.github/workflows/go-test-darwin.yml b/.github/workflows/go-test-darwin.yml index 76b2ca3a8..ee4bd0920 100644 --- a/.github/workflows/go-test-darwin.yml +++ b/.github/workflows/go-test-darwin.yml @@ -1,4 +1,7 @@ # +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + # This GitHub action runs Packer go tests across # MacOS runners. # @@ -20,7 +23,7 @@ jobs: outputs: go-version: ${{ steps.get-go-version.outputs.go-version }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: 'Determine Go version' id: get-go-version run: | @@ -32,8 +35,8 @@ jobs: runs-on: macos-latest name: Darwin Go tests steps: - - uses: actions/checkout@v2 - - uses: actions/setup-go@v3 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 with: go-version: ${{ needs.get-go-version.outputs.go-version }} - run: | diff --git a/.github/workflows/go-test-linux.yml b/.github/workflows/go-test-linux.yml index 9b82c395a..623b65196 100644 --- a/.github/workflows/go-test-linux.yml +++ b/.github/workflows/go-test-linux.yml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + # # This GitHub action runs Packer go tests across # Linux runners. @@ -20,7 +23,7 @@ jobs: outputs: go-version: ${{ steps.get-go-version.outputs.go-version }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: 'Determine Go version' id: get-go-version run: | @@ -32,8 +35,8 @@ jobs: runs-on: ubuntu-latest name: Linux Go tests steps: - - uses: actions/checkout@v2 - - uses: actions/setup-go@v3 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 with: go-version: ${{ needs.get-go-version.outputs.go-version }} - run: | diff --git a/.github/workflows/go-test-windows.yml b/.github/workflows/go-test-windows.yml index 35b8f2719..6b6482d26 100644 --- a/.github/workflows/go-test-windows.yml +++ b/.github/workflows/go-test-windows.yml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + # # This GitHub action runs Packer go tests across # Windows runners. @@ -20,7 +23,7 @@ jobs: outputs: go-version: ${{ steps.get-go-version.outputs.go-version }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: 'Determine Go version' id: get-go-version run: | @@ -32,8 +35,8 @@ jobs: runs-on: windows-latest name: Windows Go tests steps: - - uses: actions/checkout@v2 - - uses: actions/setup-go@v3 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 with: go-version: ${{ needs.get-go-version.outputs.go-version }} - run: | diff --git a/.github/workflows/go-validate.yml b/.github/workflows/go-validate.yml index 50ab32bea..7e67a99b2 100644 --- a/.github/workflows/go-validate.yml +++ b/.github/workflows/go-validate.yml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + # # This GitHub action runs basic linting checks for Packer. # @@ -19,7 +22,7 @@ jobs: outputs: go-version: ${{ steps.get-go-version.outputs.go-version }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: 'Determine Go version' id: get-go-version run: | @@ -31,8 +34,8 @@ jobs: runs-on: ubuntu-latest name: Go Mod Tidy steps: - - uses: actions/checkout@v2 - - uses: actions/setup-go@v3 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 with: go-version: ${{ needs.get-go-version.outputs.go-version }} - run: go mod tidy @@ -42,13 +45,13 @@ jobs: runs-on: ubuntu-latest name: Lint check steps: - - uses: actions/checkout@v2 - - uses: actions/setup-go@v3 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 with: go-version: ${{ needs.get-go-version.outputs.go-version }} - - uses: golangci/golangci-lint-action@v3 + - uses: golangci/golangci-lint-action@82d40c283aeb1f2b6595839195e95c2d6a49081b # v5.0.0 with: - version: v1.47.3 + version: v1.54.2 only-new-issues: true check-fmt: needs: @@ -56,8 +59,8 @@ jobs: runs-on: ubuntu-latest name: Gofmt check steps: - - uses: actions/checkout@v2 - - uses: actions/setup-go@v3 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 with: go-version: ${{ needs.get-go-version.outputs.go-version }} - run: | @@ -74,10 +77,20 @@ jobs: runs-on: ubuntu-latest name: Generate check steps: - - uses: actions/checkout@v2 - - uses: actions/setup-go@v3 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 with: go-version: ${{ needs.get-go-version.outputs.go-version }} - run: | export PATH=$PATH:$(go env GOPATH)/bin make generate + uncommitted="$(git status -s)" + if [[ -z "$uncommitted" ]]; then + echo "OK" + else + echo "Docs have been updated, but the compiled docs have not been committed." + echo "Run 'make generate', and commit the result to resolve this error." + echo "Generated but uncommitted files:" + echo "$uncommitted" + exit 1 + fi diff --git a/.github/workflows/jira.yml b/.github/workflows/jira.yml index 45e638130..e0163a9e4 100644 --- a/.github/workflows/jira.yml +++ b/.github/workflows/jira.yml @@ -1,86 +1,80 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +name: JIRA Sync on: issues: types: [labeled] - permissions: contents: read - -name: JIRA Sync - jobs: sync: name: Sync to JIRA permissions: issues: write # for actions-ecosytem/action-create-comment runs-on: ubuntu-latest - steps: + steps: - name: Login - uses: atlassian/gajira-login@v3 + uses: atlassian/gajira-login@45fd029b9f1d6d8926c6f04175aa80c0e42c9026 # v3.0.1 env: JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} - - name: Search if: github.event.action == 'labeled' id: search - uses: tomhjp/gh-action-jira-search@v0.2.1 + uses: tomhjp/gh-action-jira-search@04700b457f317c3e341ce90da5a3ff4ce058f2fa # v0.2.2 with: # cf[10089] is Issue Link (use JIRA API to retrieve) jql: 'project = "HPR" AND cf[10089] = "${{ github.event.issue.html_url }}"' - - - name: Set type id: set-ticket-type run: | # Questions are not tracked in JIRA at this time. if [[ "${{ contains(github.event.issue.labels.*.name, 'question') }}" == "true" ]]; then - echo "::set-output name=type::Invalid" + echo "type=Invalid" >> "$GITHUB_OUTPUT" else # Properly labeled GH issues are assigned the standard "GH Issue" type upon creation. - echo "::set-output name=type::GH Issue" + echo "type=GH Issue" >> "$GITHUB_OUTPUT" fi - - name: Set labels - id: set-ticket-labels + id: set-ticket-labels run: | if [[ "${{ contains(github.event.issue.labels.*.name, 'bug') }}" == "true" ]]; then - echo "::set-output name=labels::[\"bug\"]" + echo "labels=[\"bug\"]" >> "$GITHUB_OUTPUT" elif [[ "${{ contains(github.event.issue.labels.*.name, 'enhancement') }}" == "true" ]]; then - echo "::set-output name=labels::[\"enhancement\"]" + echo "labels=[\"enhancement\"]" >> "$GITHUB_OUTPUT" else - echo "::set-output name=labels::[]" + echo "labels=[]" >> "$GITHUB_OUTPUT" fi - - name: Validate ticket if: steps.set-ticket-type.outputs.type == 'Invalid' run: | echo "Questions are not being synced to JIRA at this time." echo "If the issue is a bug or an enhancement please remove the question label and reapply the 'sync to jira' label." - - name: Create ticket id: create-ticket if: steps.search.outputs.issue == '' && github.event.label.name == 'sync to jira' && steps.set-ticket-type.outputs.type != 'Invalid' - uses: atlassian/gajira-create@v3 + uses: atlassian/gajira-create@59e177c4f6451399df5b4911c2211104f171e669 # v3.0.1 with: project: HPR issuetype: "${{ steps.set-ticket-type.outputs.type }}" summary: "${{ github.event.repository.name }}: ${{ github.event.issue.title }}" description: "${{ github.event.issue.body }}\n\n_Created from GitHub by ${{ github.actor }}._" - # The field customfield_10089 refers to the Issue Link field in JIRA. - fields: '{ "customfield_10089": "${{ github.event.issue.html_url }}", - "components": [{ "name": "OSS" }], + # The field customfield_10089 refers to the Issue Link field in JIRA. + fields: '{ "customfield_10089": "${{ github.event.issue.html_url }}", + "components": [{ "name": "Core" }], "labels": ${{ steps.set-ticket-labels.outputs.labels }} }' - - name: Add tracking comment if: steps.create-ticket.outputs.issue != '' && steps.set-ticket-type.outputs.type != 'Invalid' - uses: actions-ecosystem/action-create-comment@v1.0.0 + uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6.4.1 with: - github_token: ${{ secrets.GITHUB_TOKEN }} - body: | - This issue has been synced to JIRA for planning. - - JIRA ID: [${{ steps.create-ticket.outputs.issue }}](https://hashicorp.atlassian.net/browse/${{steps.create-ticket.outputs.issue}}) - - - + script: | + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: ` + This issue has been synced to JIRA for planning. + JIRA ID: [${{ steps.create-ticket.outputs.issue }}](https://hashicorp.atlassian.net/browse/${{steps.create-ticket.outputs.issue}})` + }) diff --git a/.github/workflows/notify-integration-release-via-manual.yaml b/.github/workflows/notify-integration-release-via-manual.yaml new file mode 100644 index 000000000..3a84c97d0 --- /dev/null +++ b/.github/workflows/notify-integration-release-via-manual.yaml @@ -0,0 +1,62 @@ +name: Notify Integration Release (Manual) +on: + workflow_dispatch: + inputs: + version: + description: "The release version (semver)" + default: 0.0.1 + required: false + branch: + description: "A branch or SHA" + default: 'main' + required: false +jobs: + strip-version: + runs-on: ubuntu-latest + outputs: + packer-version: ${{ steps.strip.outputs.packer-version }} + steps: + - name: Strip leading v from version tag + id: strip + env: + REF: ${{ github.event.inputs.version }} + run: | + echo "packer-version=$(echo "$REF" | sed -E 's/v?([0-9]+\.[0-9]+\.[0-9]+)/\1/')" >> "$GITHUB_OUTPUT" + notify-release: + needs: + - strip-version + runs-on: ubuntu-latest + steps: + - name: Checkout this repo + uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + with: + ref: ${{ github.event.inputs.branch }} + # Ensure that Docs are Compiled + - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 + - shell: bash + run: make generate + - shell: bash + run: | + uncommitted="$(git status -s)" + if [[ -z "$uncommitted" ]]; then + echo "OK" + else + echo "Docs have been updated, but the compiled docs have not been committed." + echo "Run 'make generate', and commit the result to resolve this error." + echo "Generated but uncommitted files:" + echo "$uncommitted" + exit 1 + fi + # Perform the Release + - name: Checkout integration-release-action + uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + with: + repository: hashicorp/integration-release-action + path: ./integration-release-action + - name: Notify Release + uses: ./integration-release-action + with: + integration_identifier: "packer/hashicorp/amazon" + release_version: ${{ needs.strip-version.outputs.packer-version }} + release_sha: ${{ github.event.inputs.branch }} + github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/notify-integration-release-via-tag.yaml b/.github/workflows/notify-integration-release-via-tag.yaml new file mode 100644 index 000000000..a297526fa --- /dev/null +++ b/.github/workflows/notify-integration-release-via-tag.yaml @@ -0,0 +1,55 @@ +name: Notify Integration Release (Tag) +on: + push: + tags: + - 'notused*.*.*' # Used by the upstream only +jobs: + strip-version: + runs-on: ubuntu-latest + outputs: + packer-version: ${{ steps.strip.outputs.packer-version }} + steps: + - name: Strip leading v from version tag + id: strip + env: + REF: ${{ github.ref_name }} + run: | + echo "packer-version=$(echo "$REF" | sed -E 's/v?([0-9]+\.[0-9]+\.[0-9]+)/\1/')" >> "$GITHUB_OUTPUT" + notify-release: + needs: + - strip-version + runs-on: ubuntu-latest + steps: + - name: Checkout this repo + uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + with: + ref: ${{ github.ref }} + # Ensure that Docs are Compiled + - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 + - shell: bash + run: make generate + - shell: bash + run: | + uncommitted="$(git status -s)" + if [[ -z "$uncommitted" ]]; then + echo "OK" + else + echo "Docs have been updated, but the compiled docs have not been committed." + echo "Run 'make generate', and commit the result to resolve this error." + echo "Generated but uncommitted files:" + echo "$uncommitted" + exit 1 + fi + # Perform the Release + - name: Checkout integration-release-action + uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + with: + repository: hashicorp/integration-release-action + path: ./integration-release-action + - name: Notify Release + uses: ./integration-release-action + with: + integration_identifier: "packer/hashicorp/amazon" + release_version: ${{ needs.strip-version.outputs.packer-version }} + release_sha: ${{ github.ref }} + github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5823ed699..d06c08d1a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + # This GitHub action can publish assets for release when a tag is created. # Currently its setup to run on any tag that matches the pattern "v*" (ie. v0.1.0). # @@ -14,23 +17,39 @@ on: push: tags: - 'v*' +permissions: + contents: write + packages: read jobs: + get-go-version: + runs-on: ubuntu-latest + outputs: + go-version: ${{ steps.get-go-version.outputs.go-version }} + steps: + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + - name: 'Determine Go version' + id: get-go-version + run: | + echo "Found Go $(cat .go-version)" + echo "go-version=$(cat .go-version)" >> $GITHUB_OUTPUT goreleaser: + needs: + - get-go-version runs-on: ubuntu-latest permissions: contents: write steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Unshallow run: git fetch --prune --unshallow - name: Set up Go - uses: actions/setup-go@v2 + uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 with: - go-version: 1.17 + go-version: ${{ needs.get-go-version.outputs.go-version }} - name: Describe plugin id: plugin_describe - run: echo "::set-output name=api_version::$(go run . describe | jq -r '.api_version')" + run: echo "api_version=$(go run . describe | jq -r '.api_version')" >> "$GITHUB_OUTPUT" - name: Import GPG key id: import_gpg uses: crazy-max/ghaction-import-gpg@v5.0.0 @@ -38,10 +57,10 @@ jobs: gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} passphrase: ${{ secrets.GPG_PASSPHRASE }} - name: Run GoReleaser - uses: goreleaser/goreleaser-action@v2 + uses: goreleaser/goreleaser-action@7ec5c2b0c6cdda6e8bbb49444bc797dd33d74dd8 # v5.0.0 with: version: latest - args: release --rm-dist + args: release --clean --timeout 120m env: GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/test-plugin-example.yml b/.github/workflows/test-plugin-example.yml deleted file mode 100644 index 2f0eae178..000000000 --- a/.github/workflows/test-plugin-example.yml +++ /dev/null @@ -1,47 +0,0 @@ -# This is a manually triggered action workflow. -# It uses Packer at latest version to init, validate and build -# an example configuration in a folder. -# This action is compatible with Packer v1.7.0 or later. -name: test plugin example - -on: - workflow_dispatch: - inputs: - logs: - description: 'Set 1 to activate full logs' - required: false - default: '0' - folder: - description: 'Example folder' - required: false - default: './example' - -jobs: - build: - runs-on: ubuntu-latest - name: init and build example - steps: - - name: Checkout Repository - uses: actions/checkout@v2 - - - name: Init - uses: hashicorp/packer-github-actions@master - with: - working_directory: ${{ github.event.inputs.folder }} - command: init - - - name: Validate - uses: hashicorp/packer-github-actions@master - with: - working_directory: ${{ github.event.inputs.folder }} - command: validate - env: - PACKER_LOG: ${{ github.event.inputs.logs }} - - - name: Build - uses: hashicorp/packer-github-actions@master - with: - working_directory: ${{ github.event.inputs.folder }} - command: build - env: - PACKER_LOG: ${{ github.event.inputs.logs }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index ac48f6438..71ab8a630 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ packer-plugin-amazon .docs .DS_Store *.sw* +crash.log diff --git a/.go-version b/.go-version index a63f36d96..db98d22c0 100644 --- a/.go-version +++ b/.go-version @@ -1,2 +1,2 @@ -1.18.8 +1.21.8 diff --git a/.golangci.yml b/.golangci.yml index 014dd27b8..78b774dcb 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + issues: # List of regexps of issue texts to exclude, empty list by default. # But independently from this option we use default exclude patterns, diff --git a/.goreleaser.yml b/.goreleaser.yml index 1908c9eff..e86056674 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + # This is an example goreleaser.yaml file with some defaults. # Make sure to check the documentation at http://goreleaser.com env: @@ -7,11 +10,10 @@ before: # We strongly recommend running tests to catch any regression before release. # Even though, this an optional step. - go test ./... - # As part of the release doc files are included as a separate deliverable for - # consumption by Packer.io. To include a separate docs.zip uncomment the following command. - - make ci-release-docs # Check plugin compatibility with required version of the Packer SDK - make plugin-check + # Copy LICENSE file for inclusion in zip archive + - cp LICENSE LICENSE.txt builds: # A separated build to run the packer-plugins-check only once for a linux_amd64 binary - @@ -37,55 +39,56 @@ builds: - linux goarch: - amd64 - - '386' - - arm - - arm64 + # - '386' + # - arm + # - arm64 ignore: - goos: linux goarch: amd64 binary: '{{ .ProjectName }}_v{{ .Version }}_{{ .Env.API_VERSION }}_{{ .Os }}_{{ .Arch }}' - - - id: darwin-builds - mod_timestamp: '{{ .CommitTimestamp }}' - flags: - - -trimpath #removes all file system paths from the compiled executable - ldflags: - - '-s -w -X {{ .ModulePath }}/version.Version={{.Version}} -X {{ .ModulePath }}/version.VersionPrerelease= ' - goos: - - darwin - goarch: - - amd64 - - arm64 - binary: '{{ .ProjectName }}_v{{ .Version }}_{{ .Env.API_VERSION }}_{{ .Os }}_{{ .Arch }}' - - - id: other-builds - mod_timestamp: '{{ .CommitTimestamp }}' - flags: - - -trimpath #removes all file system paths from the compiled executable - ldflags: - - '-s -w -X {{ .ModulePath }}/version.Version={{.Version}} -X {{ .ModulePath }}/version.VersionPrerelease= ' - goos: - - netbsd - - openbsd - - freebsd - - windows - - solaris - goarch: - - amd64 - - '386' - - arm - ignore: - - goos: windows - goarch: arm - - goos: solaris - goarch: arm - - goos: solaris - goarch: '386' - binary: '{{ .ProjectName }}_v{{ .Version }}_{{ .Env.API_VERSION }}_{{ .Os }}_{{ .Arch }}' + # - + # id: darwin-builds + # mod_timestamp: '{{ .CommitTimestamp }}' + # flags: + # - -trimpath #removes all file system paths from the compiled executable + # ldflags: + # - '-s -w -X {{ .ModulePath }}/version.Version={{.Version}} -X {{ .ModulePath }}/version.VersionPrerelease= ' + # goos: + # - darwin + # goarch: + # - amd64 + # - arm64 + # binary: '{{ .ProjectName }}_v{{ .Version }}_{{ .Env.API_VERSION }}_{{ .Os }}_{{ .Arch }}' + # - + # id: other-builds + # mod_timestamp: '{{ .CommitTimestamp }}' + # flags: + # - -trimpath #removes all file system paths from the compiled executable + # ldflags: + # - '-s -w -X {{ .ModulePath }}/version.Version={{.Version}} -X {{ .ModulePath }}/version.VersionPrerelease= ' + # goos: + # - netbsd + # - openbsd + # - freebsd + # - windows + # - solaris + # goarch: + # - amd64 + # - '386' + # - arm + # ignore: + # - goos: windows + # goarch: arm + # - goos: solaris + # goarch: arm + # - goos: solaris + # goarch: '386' + # binary: '{{ .ProjectName }}_v{{ .Version }}_{{ .Env.API_VERSION }}_{{ .Os }}_{{ .Arch }}' archives: - format: zip files: - - none* + - "LICENSE.txt" + name_template: '{{ .ProjectName }}_v{{ .Version }}_{{ .Env.API_VERSION }}_{{ .Os }}_{{ .Arch }}' checksum: name_template: '{{ .ProjectName }}_v{{ .Version }}_SHA256SUMS' @@ -102,13 +105,6 @@ signs: - "${signature}" - "--detach-sign" - "${artifact}" -release: - # If you want to manually examine the release before its live, uncomment this line: - # draft: true - # As part of the release doc files are included as a separate deliverable for consumption by Packer.io. - # To include a separate docs.zip uncomment the extra_files config and the docs.zip command hook above. - extra_files: - - glob: ./docs.zip changelog: use: github-native diff --git a/docs/builders/index.mdx b/.web-docs/README.md similarity index 76% rename from docs/builders/index.mdx rename to .web-docs/README.md index 2616af967..410e2ce9b 100644 --- a/docs/builders/index.mdx +++ b/.web-docs/README.md @@ -1,73 +1,65 @@ ---- -description: | - The Amazon plugin is able to create Amazon AMIs. To achieve this, the plugin comes with - multiple builders depending on the strategy you want to use to build the AMI. -page_title: Amazon AMI - Builders -sidebar_title: Overview ---- +The Amazon plugin can be used with HashiCorp Packer to create custom images on AWS. To achieve this, the plugin comes with +multiple builders, data sources, and a post-processor to build the AMI depending on the strategy you want to use. -# Amazon AMI Builder +### Installation -The Amazon plugin is able to create Amazon AMIs. To achieve this, the plugin comes with -multiple builders depending on the strategy you want to use to build the AMI. +To install this plugin, copy and paste this code into your Packer configuration, then run [`packer init`](https://www.packer.io/docs/commands/init). -The Amazon plugin supports the following builders at the moment: +```hcl +packer { + required_plugins { + amazon = { + source = "github.com/hashicorp/amazon" + version = "~> 1" + } + } +} +``` + +Alternatively, you can use `packer plugins install` to manage installation of this plugin. + +```sh +$ packer plugins install github.com/hashicorp/amazon +``` + +### Components -- [amazon-ebs](/packer/plugins/builders/amazon/ebs) - Create EBS-backed AMIs by +**Don't know which builder to use?** If in doubt, use the [amazon-ebs builder](/packer/plugins/builders/amazon/ebs). +It is much easier to use and Amazon generally recommends EBS-backed images nowadays. + +#### Builders +- [amazon-ebs](/packer/integrations/hashicorp/amazon/latest/components/builder/ebs) - Create EBS-backed AMIs by launching a source AMI and re-packaging it into a new AMI after provisioning. If in doubt, use this builder, which is the easiest to get started with. - -- [amazon-instance](/packer/plugins/builders/amazon/instance) - Create +- [amazon-instance](/packer/integrations/hashicorp/amazon/latest/components/builder/instance) - Create instance-store AMIs by launching and provisioning a source instance, then rebundling it and uploading it to S3. - -- [amazon-chroot](/packer/plugins/builders/amazon/chroot) - Create EBS-backed AMIs +- [amazon-chroot](/packer/integrations/hashicorp/amazon/latest/components/builder/chroot) - Create EBS-backed AMIs from an existing EC2 instance by mounting the root device and using a [Chroot](https://en.wikipedia.org/wiki/Chroot) environment to provision that device. This is an **advanced builder and should not be used by newcomers**. However, it is also the fastest way to build an EBS-backed AMI since no new EC2 instance needs to be launched. - -- [amazon-ebssurrogate](/packer/plugins/builders/amazon/ebssurrogate) - Create EBS +- [amazon-ebssurrogate](/packer/integrations/hashicorp/amazon/latest/components/builder/ebssurrogate) - Create EBS -backed AMIs from scratch. Works similarly to the `chroot` builder but does not require running in AWS. This is an **advanced builder and should not be used by newcomers**. +- [amazon-ebs-volume](/packer/integrations/hashicorp/amazon/latest/components/builder/ebsvolume) - Create prepopulated + EBS volumes by launching an instance and provisioning attached volumes. + This is an **advanced builder and should not be used by newcomers**. --> **Don't know which builder to use?** If in doubt, use the [amazon-ebs -builder](/packer/plugins/builders/amazon/ebs). It is much easier to use and Amazon -generally recommends EBS-backed images nowadays. +#### Data sources +- [amazon-ami](/packer/integrations/hashicorp/amazon/latest/components/data-source/ami) - Filter and fetch an Amazon AMI to output all the AMI information. +- [amazon-secretsmanager](/packer/integrations/hashicorp/amazon/latest/components/data-source/secretsmanager) - Retrieve information + about a Secrets Manager secret version, including its secret value. +- [amazon-parameterstore](/packer/integrations/hashicorp/amazon/latest/components/data-source/parameterstore) - Retrieve information about a parameter in SSM. -## How to use this plugin +#### Post-Processors +- [amazon-import](/packer/integrations/hashicorp/amazon/latest/components/post-processor/import) - The Amazon Import post-processor takes an OVA artifact + from various builders and imports it to an AMI available to Amazon Web Services EC2. -From Packer v1.7.0, copy and paste this code into your Packer configuration to install this plugin. -Then, run [`packer init`](/packer/docs/commands/init). - -```hcl -packer { - required_plugins { - amazon = { - version = ">= 1.1.1" - source = "github.com/hashicorp/amazon" - } - } -} -``` - -# Amazon EBS Volume Builder - -The Amazon Plugin is able to create Amazon EBS Volumes which are preinitialized with a -filesystem and data. - -- [amazon-ebsvolume](/packer/plugins/builders/amazon/ebsvolume) - Create EBS - volumes by launching a source AMI with block devices mapped. Provision the - instance, then destroy it, retaining the EBS volumes and or Snapshot. - - - - - -## Authentication +### Authentication The AWS provider offers a flexible means of providing credentials for authentication. The following methods are supported, in this order, and @@ -78,14 +70,11 @@ explained below: - Shared credentials file - EC2 Role -### Static Credentials +#### Static Credentials Static credentials can be provided in the form of an access key id and secret. These look like: - - - ```json "builders": { "type": "amazon-ebs", @@ -95,20 +84,14 @@ These look like: } ``` - - - ```hcl source "amazon-ebs" "basic-example" { access_key = "AKIAIOSFODNN7EXAMPLE" secret_key = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" - region = "us-east-1" + region = "us-east-1" } ``` - - - If you would like, you may also assume a role using the assume_role configuration option. You must still have one of the valid credential resources explained above, and your user must have permission to assume the role in @@ -164,7 +147,7 @@ JSON config example: - `transitive_tag_keys` ([]string) - Set of assume role session tag keys to pass to any subsequent sessions. -### Environment variables +#### Environment variables You can provide your credentials via the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`, environment variables, representing your AWS Access @@ -180,7 +163,7 @@ Usage: $ export AWS_DEFAULT_REGION="us-west-2" $ packer build template.pkr.hcl -### Shared Credentials file +#### Shared Credentials file You can use an AWS credentials file to specify your credentials. The default location is `$HOME/.aws/credentials` on Linux and OS X, or @@ -198,9 +181,6 @@ The format for the credentials file is like so You may also configure the profile to use by setting the `profile` configuration option, or setting the `AWS_PROFILE` environment variable: - - - ```json "builders": { "type": "amazon-ebs" @@ -209,9 +189,6 @@ configuration option, or setting the `AWS_PROFILE` environment variable: } ``` - - - ```hcl source "amazon-ebs" "basic-example" { profile = "customprofile" @@ -219,10 +196,7 @@ source "amazon-ebs" "basic-example" { } ``` - - - -### IAM Task or Instance Role +#### IAM Task or Instance Role Finally, the plugin will use credentials provided by the task's or instance's IAM role, if it has one. @@ -245,7 +219,7 @@ for the Amazon plugin to work: "ec2:AuthorizeSecurityGroupIngress", "ec2:CopyImage", "ec2:CreateImage", - "ec2:CreateKeypair", + "ec2:CreateKeyPair", "ec2:CreateSecurityGroup", "ec2:CreateSnapshot", "ec2:CreateTags", @@ -295,9 +269,33 @@ If you are using the `vpc_filter` option, you must also add: ec2:DescribeVpcs -## Troubleshooting +This permission may also be needed by the `associate_public_ip_address` option, if specified without a subnet. +In this case the plugin will invoke `DescribeVpcs` to find information about the default VPC. + +When using `associate_public_ip_address` without a subnet, you will also benefit from having: + + ec2:DescribeInstanceTypeOfferings + +This will ensure that the plugin will pick a subnet/AZ that can host the type of instance +you're requesting in your template. + +If you are using the `deprecate_at` attribute in your templates, you will also need: + + ec2:EnableImageDeprecation + +If you are using SSM to connect to the instance, and are specifying a private key file, you must also add: + + ec2-instance-connect:SendSSHPublicKey + +If you are building a Windows AMI, and want to enable fast-launch, you will also need: + + ec2:EnableFastLaunch + ec2:DescribeLaunchTemplates + ec2:DescribeFastLaunchImages + +### Troubleshooting -### Attaching IAM Policies to Roles +#### Attaching IAM Policies to Roles IAM policies can be associated with users or roles. If you use the plugin with IAM roles, you may encounter an error like this one: @@ -373,10 +371,9 @@ using to run the Packer build, your key will also need ("kms:CreateGrant", "kms:DescribeKey") ``` -### Checking that system time is current +#### Check System Time -Amazon uses the current time as part of the [request signing -process](http://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html). If +Amazon uses the current time as part of the [request signing process](http://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html). If your system clock is too skewed from the current time, your requests might fail. If that's the case, you might see an error like this: @@ -386,7 +383,7 @@ If you suspect your system's date is wrong, you can compare it against `http://www.time.gov/`. On Linux/OS X, you can run the `date` command to get the current time. If you're on Linux, you can try setting the time with ntp by running `sudo ntpd -q`. -### ResourceNotReady Error +#### ResourceNotReady Error This error generally appears as either `ResourceNotReady: exceeded wait attempts` or `ResourceNotReady: failed waiting for successful resource state`. diff --git a/.web-docs/components/builder/chroot/README.md b/.web-docs/components/builder/chroot/README.md new file mode 100644 index 000000000..654b99a13 --- /dev/null +++ b/.web-docs/components/builder/chroot/README.md @@ -0,0 +1,1196 @@ +Type: `amazon-chroot` +Artifact BuilderId: `mitchellh.amazon.chroot` + +The `amazon-chroot` Packer builder is able to create Amazon AMIs backed by an +EBS volume as the root device. For more information on the difference between +instance storage and EBS-backed instances, see the ["storage for the root +device" section in the EC2 +documentation](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ComponentsAMIs.html#storage-for-the-root-device). + +The difference between this builder and the `amazon-ebs` builder is that this +builder is able to build an EBS-backed AMI without launching a new EC2 +instance. This can dramatically speed up AMI builds for organizations who need +the extra fast build. + +~> **This is an advanced builder** If you're just getting started with +Packer, we recommend starting with the [amazon-ebs +builder](/packer/integrations/hashicorp/amazon/latest/components/builder/ebs), which is much easier to use. + +The builder does _not_ manage AMIs. Once it creates an AMI and stores it in +your account, it is up to you to use, delete, etc., the AMI. + +## How Does it Work? + +This builder works by creating a new EBS volume from an existing source AMI and +attaching it into an already-running EC2 instance. Once attached, a +[chroot](https://en.wikipedia.org/wiki/Chroot) is used to provision the system +within that volume. After provisioning, the volume is detached, snapshotted, +and an AMI is made. + +Using this process, minutes can be shaved off the AMI creation process because +a new EC2 instance doesn't need to be launched. + +There are some restrictions, however. The host EC2 instance where the volume is +attached to must be a similar system (generally the same OS version, kernel +versions, etc.) as the AMI being built. Additionally, this process is much more +expensive because the EC2 instance must be kept running persistently in order +to build AMIs, whereas the other AMI builders start instances on-demand to +build AMIs as needed. + +## Chroot Specific Configuration Reference + +There are many configuration options available for the builder. In addition to +the items listed here, you will want to look at the general configuration +references for [AMI](#ami-configuration), +[BlockDevices](#block-devices-configuration) and +[Access](#access-config-configuration) configuration references, which are +necessary for this build to succeed and can be found further down the page. + +### Required: + + + +- `source_ami` (string) - The source AMI whose root volume will be copied and provisioned on the + currently running instance. This must be an EBS-backed AMI with a root + volume snapshot that you have access to. Note: this is not used when + from_scratch is set to true. + + + + +### Optional: + + + +- `ami_block_device_mappings` (awscommon.BlockDevices) - Add one or more [block device + mappings](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/block-device-mapping-concepts.html) + to the AMI. If this field is populated, and you are building from an + existing source image, the block device mappings in the source image + will be overwritten. This means you must have a block device mapping + entry for your root volume, `root_volume_size` and `root_device_name`. + See the [BlockDevices](#block-devices-configuration) documentation for + fields. + +- `chroot_mounts` ([][]string) - This is a list of devices to mount into the chroot environment. This + configuration parameter requires some additional documentation which is + in the Chroot Mounts section. Please read that section for more + information on how to use this. + +- `command_wrapper` (string) - How to run shell commands. This defaults to `{{.Command}}`. This may be + useful to set if you want to set environmental variables or perhaps run + it with sudo or so on. This is a configuration template where the + .Command variable is replaced with the command to be run. Defaults to + `{{.Command}}`. + +- `copy_files` ([]string) - Paths to files on the running EC2 instance that will be copied into the + chroot environment prior to provisioning. Defaults to /etc/resolv.conf + so that DNS lookups work. Pass an empty list to skip copying + /etc/resolv.conf. You may need to do this if you're building an image + that uses systemd. + +- `device_path` (string) - The path to the device where the root volume of the source AMI will be + attached. This defaults to "" (empty string), which forces Packer to + find an open device automatically. + +- `nvme_device_path` (string) - When we call the mount command (by default mount -o device dir), the + string provided in nvme_mount_path will replace device in that command. + When this option is not set, device in that command will be something + like /dev/sdf1, mirroring the attached device name. This assumption + works for most instances but will fail with c5 and m5 instances. In + order to use the chroot builder with c5 and m5 instances, you must + manually set nvme_device_path and device_path. + +- `from_scratch` (bool) - Build a new volume instead of starting from an existing AMI root volume + snapshot. Default false. If true, source_ami/source_ami_filter are no + longer used and the following options become required: + ami_virtualization_type, pre_mount_commands and root_volume_size. + +- `mount_options` ([]string) - Options to supply the mount command when mounting devices. Each option + will be prefixed with -o and supplied to the mount command ran by + Packer. Because this command is ran in a shell, user discretion is + advised. See this manual page for the mount command for valid file + system specific options. + +- `mount_partition` (string) - The partition number containing the / partition. By default this is the + first partition of the volume, (for example, xvda1) but you can + designate the entire block device by setting "mount_partition": "0" in + your config, which will mount xvda instead. + +- `mount_path` (string) - The path where the volume will be mounted. This is where the chroot + environment will be. This defaults to + `/mnt/packer-amazon-chroot-volumes/{{.Device}}`. This is a configuration + template where the .Device variable is replaced with the name of the + device where the volume is attached. + +- `post_mount_commands` ([]string) - As pre_mount_commands, but the commands are executed after mounting the + root device and before the extra mount and copy steps. The device and + mount path are provided by `{{.Device}}` and `{{.MountPath}}`. + +- `pre_mount_commands` ([]string) - A series of commands to execute after attaching the root volume and + before mounting the chroot. This is not required unless using + from_scratch. If so, this should include any partitioning and filesystem + creation commands. The path to the device is provided by `{{.Device}}`. + +- `root_device_name` (string) - The root device name. For example, xvda. + +- `root_volume_size` (int64) - The size of the root volume in GB for the chroot environment and the + resulting AMI. Default size is the snapshot size of the source_ami + unless from_scratch is true, in which case this field must be defined. + +- `root_volume_type` (string) - The type of EBS volume for the chroot environment and resulting AMI. The + default value is the type of the source_ami, unless from_scratch is + true, in which case the default value is gp2. You can only specify io1 + if building based on top of a source_ami which is also io1. + +- `source_ami_filter` (awscommon.AmiFilterOptions) - Filters used to populate the source_ami field. Example: + + ```json + { + "source_ami_filter": { + "filters": { + "virtualization-type": "hvm", + "name": "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*", + "root-device-type": "ebs" + }, + "owners": ["099720109477"], + "most_recent": true + } + } + ``` + + This selects the most recent Ubuntu 16.04 HVM EBS AMI from Canonical. NOTE: + This will fail unless *exactly* one AMI is returned. In the above example, + `most_recent` will cause this to succeed by selecting the newest image. + + - `filters` (map[string,string] | multiple filters are allowed when seperated by commas) - + filters used to select a `source_ami`. + NOTE: This will fail unless *exactly* one AMI is returned. Any filter + described in the docs for + [DescribeImages](http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeImages.html) + is valid. + + - `owners` (array of strings) - Filters the images by their owner. You + may specify one or more AWS account IDs, "self" (which will use the + account whose credentials you are using to run Packer), or an AWS owner + alias: for example, "amazon", "aws-marketplace", or "microsoft". This + option is required for security reasons. + + - `most_recent` (boolean) - Selects the newest created image when true. + This is most useful for selecting a daily distro build. + + You may set this in place of `source_ami` or in conjunction with it. If you + set this in conjunction with `source_ami`, the `source_ami` will be added + to the filter. The provided `source_ami` must meet all of the filtering + criteria provided in `source_ami_filter`; this pins the AMI returned by the + filter, but will cause Packer to fail if the `source_ami` does not exist. + +- `root_volume_tags` (map[string]string) - Key/value pair tags to apply to the volumes that are *launched*. This is + a [template engine](/packer/docs/templates/legacy_json_templates/engine), see [Build template + data](#build-template-data) for more information. + +- `root_volume_tag` ([]{key string, value string}) - Same as [`root_volume_tags`](#root_volume_tags) but defined as a + singular block containing a `key` and a `value` field. In HCL2 mode the + [`dynamic_block`](/packer/docs/templates/hcl_templates/expressions#dynamic-blocks) + will allow you to create those programatically. + +- `root_volume_encrypt_boot` (boolean) - Whether or not to encrypt the volumes that are *launched*. By default, Packer will keep + the encryption setting to what it was in the source image when set to `false`. Setting true will + always result in an encrypted one. + +- `root_volume_kms_key_id` (string) - ID, alias or ARN of the KMS key to use for *launched* volumes encryption. + + Set this value if you select `root_volume_encrypt_boot`, but don't want to use the + region's default KMS key. + + If you have a custom kms key you'd like to apply to the launch volume, + and are only building in one region, it is more efficient to set this + and `root_volume_encrypt_boot` to `true` and not use `encrypt_boot` and `kms_key_id`. This saves + potentially many minutes at the end of the build by preventing Packer + from having to copy and re-encrypt the image at the end of the build. + + For valid formats see *KmsKeyId* in the [AWS API docs - + CopyImage](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CopyImage.html). + This field is validated by Packer, when using an alias, you will have to + prefix `kms_key_id` with `alias/`. + +- `ami_architecture` (string) - what architecture to use when registering the final AMI; valid options + are "arm64", "i386", "x86_64", or "x86_64_mac". Defaults to "x86_64". + +- `boot_mode` (string) - The boot mode. Valid options are `legacy-bios` and `uefi`. See the documentation on + [boot modes](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ami-boot.html) for + more information. Defaults to `legacy-bios` when `ami_architecture` is `x86_64` and + `uefi` when `ami_architecture` is `arm64`. + +- `uefi_data` (string) - Base64 representation of the non-volatile UEFI variable store. For more information + see [AWS documentation](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/uefi-secure-boot-optionB.html). + +- `tpm_support` (string) - NitroTPM Support. Valid options are `v2.0`. See the documentation on + [NitroTPM Support](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enable-nitrotpm-support-on-ami.html) for + more information. Only enabled if a valid option is provided, otherwise ignored. + + + + +## General Common Configuration Reference + +Following will be a set of fields that are also settable for other aws +builders. + +### AMI Configuration + +#### Required: + + + +- `ami_name` (string) - The name of the resulting AMI that will appear when managing AMIs in the + AWS console or via APIs. This must be unique. To help make this unique, + use a function like timestamp (see [template + engine](/packer/docs/templates/legacy_json_templates/engine) for more info). + + + + +#### Optional: + + + +- `ami_description` (string) - The description to set for the resulting + AMI(s). By default this description is empty. This is a + [template engine](/packer/docs/templates/legacy_json_templates/engine), see [Build template + data](#build-template-data) for more information. + +- `ami_virtualization_type` (string) - The type of virtualization for the AMI + you are building. This option is required to register HVM images. Can be + paravirtual (default) or hvm. + +- `ami_users` ([]string) - A list of account IDs that have access to + launch the resulting AMI(s). By default no additional users other than the + user creating the AMI has permissions to launch it. + +- `ami_groups` ([]string) - A list of groups that have access to + launch the resulting AMI(s). By default no groups have permission to launch + the AMI. `all` will make the AMI publicly accessible. + AWS currently doesn't accept any value other than "all" + +- `ami_org_arns` ([]string) - A list of Amazon Resource Names (ARN) of AWS Organizations that have access to + launch the resulting AMI(s). By default no organizations have permission to launch + the AMI. + +- `ami_ou_arns` ([]string) - A list of Amazon Resource Names (ARN) of AWS Organizations organizational units (OU) that have access to + launch the resulting AMI(s). By default no organizational units have permission to launch + the AMI. + +- `ami_product_codes` ([]string) - A list of product codes to + associate with the AMI. By default no product codes are associated with the + AMI. + +- `ami_regions` ([]string) - A list of regions to copy the AMI to. + Tags and attributes are copied along with the AMI. AMI copying takes time + depending on the size of the AMI, but will generally take many minutes. + +- `skip_region_validation` (bool) - Set to true if you want to skip + validation of the ami_regions configuration option. Default false. + +- `tags` (map[string]string) - Key/value pair tags applied to the AMI. This is a [template + engine](/packer/docs/templates/legacy_json_templates/engine), see [Build template + data](#build-template-data) for more information. + + The builder no longer adds a "Name": "Packer Builder" entry to the tags. + +- `tag` ([]{key string, value string}) - Same as [`tags`](#tags) but defined as a singular repeatable block + containing a `key` and a `value` field. In HCL2 mode the + [`dynamic_block`](/packer/docs/templates/hcl_templates/expressions#dynamic-blocks) + will allow you to create those programatically. + +- `ena_support` (boolean) - Enable enhanced networking (ENA but not SriovNetSupport) on + HVM-compatible AMIs. If set, add `ec2:ModifyInstanceAttribute` to your + AWS IAM policy. + + Note: you must make sure enhanced networking is enabled on your + instance. See [Amazon's documentation on enabling enhanced + networking](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enhanced-networking.html#enabling_enhanced_networking). + +- `sriov_support` (bool) - Enable enhanced networking (SriovNetSupport but not ENA) on + HVM-compatible AMIs. If true, add `ec2:ModifyInstanceAttribute` to your + AWS IAM policy. Note: you must make sure enhanced networking is enabled + on your instance. See [Amazon's documentation on enabling enhanced + networking](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enhanced-networking.html#enabling_enhanced_networking). + Default `false`. + +- `force_deregister` (bool) - Force Packer to first deregister an existing + AMI if one with the same name already exists. Default false. + +- `force_delete_snapshot` (bool) - Force Packer to delete snapshots + associated with AMIs, which have been deregistered by force_deregister. + Default false. + +- `encrypt_boot` (boolean) - Whether or not to encrypt the resulting AMI when + copying a provisioned instance to an AMI. By default, Packer will keep + the encryption setting to what it was in the source image. Setting false + will result in an unencrypted image, and true will result in an encrypted + one. + + If you have used the `launch_block_device_mappings` to set an encryption + key and that key is the same as the one you want the image encrypted with + at the end, then you don't need to set this field; leaving it empty will + prevent an unnecessary extra copy step and save you some time. + + Please note that if you are using an account with the global "Always + encrypt new EBS volumes" option set to `true`, Packer will be unable to + override this setting, and the final image will be encrypted whether + you set this value or not. + +- `kms_key_id` (string) - ID, alias or ARN of the KMS key to use for AMI encryption. This + only applies to the main `region` -- any regions the AMI gets copied to + will be encrypted by the default EBS KMS key for that region, + unless you set region-specific keys in `region_kms_key_ids`. + + Set this value if you select `encrypt_boot`, but don't want to use the + region's default KMS key. + + If you have a custom kms key you'd like to apply to the launch volume, + and are only building in one region, it is more efficient to leave this + and `encrypt_boot` empty and to instead set the key id in the + launch_block_device_mappings (you can find an example below). This saves + potentially many minutes at the end of the build by preventing Packer + from having to copy and re-encrypt the image at the end of the build. + + For valid formats see *KmsKeyId* in the [AWS API docs - + CopyImage](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CopyImage.html). + This field is validated by Packer, when using an alias, you will have to + prefix `kms_key_id` with `alias/`. + +- `region_kms_key_ids` (map[string]string) - regions to copy the ami to, along with the custom kms key id (alias or + arn) to use for encryption for that region. Keys must match the regions + provided in `ami_regions`. If you just want to encrypt using a default + ID, you can stick with `kms_key_id` and `ami_regions`. If you want a + region to be encrypted with that region's default key ID, you can use an + empty string `""` instead of a key id in this map. (e.g. `"us-east-1": + ""`) However, you cannot use default key IDs if you are using this in + conjunction with `snapshot_users` -- in that situation you must use + custom keys. For valid formats see *KmsKeyId* in the [AWS API docs - + CopyImage](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CopyImage.html). + + This option supercedes the `kms_key_id` option -- if you set both, and + they are different, Packer will respect the value in + `region_kms_key_ids` for your build region and silently disregard the + value provided in `kms_key_id`. + +- `skip_save_build_region` (bool) - If true, Packer will not check whether an AMI with the `ami_name` exists + in the region it is building in. It will use an intermediary AMI name, + which it will not convert to an AMI in the build region. It will copy + the intermediary AMI into any regions provided in `ami_regions`, then + delete the intermediary AMI. Default `false`. + +- `imds_support` (string) - Enforce version of the Instance Metadata Service on the built AMI. + Valid options are unset (legacy) and `v2.0`. See the documentation on + [IMDS](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html) + for more information. Defaults to legacy. + +- `deprecate_at` (string) - The date and time to deprecate the AMI, in UTC, in the following format: YYYY-MM-DDTHH:MM:SSZ. + If you specify a value for seconds, Amazon EC2 rounds the seconds to the nearest minute. + You can’t specify a date in the past. The upper limit for DeprecateAt is 10 years from now. + + + + + + +- `snapshot_tags` (map[string]string) - Key/value pair tags to apply to snapshot. They will override AMI tags if + already applied to snapshot. This is a [template + engine](/packer/docs/templates/legacy_json_templates/engine), see [Build template + data](#build-template-data) for more information. + +- `snapshot_tag` ([]{key string, value string}) - Same as [`snapshot_tags`](#snapshot_tags) but defined as a singular + repeatable block containing a `key` and a `value` field. In HCL2 mode the + [`dynamic_block`](/packer/docs/templates/hcl_templates/expressions#dynamic-blocks) + will allow you to create those programatically. + +- `snapshot_users` ([]string) - A list of account IDs that have + access to create volumes from the snapshot(s). By default no additional + users other than the user creating the AMI has permissions to create + volumes from the backing snapshot(s). + +- `snapshot_groups` ([]string) - A list of groups that have access to + create volumes from the snapshot(s). By default no groups have permission + to create volumes from the snapshot(s). all will make the snapshot + publicly accessible. + + + + +### Block Devices Configuration + +Block devices can be nested in the +[ami_block_device_mappings](#ami_block_device_mappings) array. + + + +These will be attached when launching your instance. Your +options here may vary depending on the type of VM you use. + +Example use case: + +The following mapping will tell Packer to encrypt the root volume of the +build instance at launch using a specific non-default kms key: + +HCL2 example: + +```hcl + + launch_block_device_mappings { + device_name = "/dev/sda1" + encrypted = true + kms_key_id = "1a2b3c4d-5e6f-1a2b-3c4d-5e6f1a2b3c4d" + } + +``` + +JSON example: +```json +"launch_block_device_mappings": [ + + { + "device_name": "/dev/sda1", + "encrypted": true, + "kms_key_id": "1a2b3c4d-5e6f-1a2b-3c4d-5e6f1a2b3c4d" + } + +] +``` + +Please note that the kms_key_id option in this example exists for +launch_block_device_mappings but not ami_block_device_mappings. + +Documentation for Block Devices Mappings can be found here: +https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/block-device-mapping-concepts.html + + + + +#### Optional: + + + +- `delete_on_termination` (bool) - Indicates whether the EBS volume is deleted on instance termination. + Default false. NOTE: If this value is not explicitly set to true and + volumes are not cleaned up by an alternative method, additional volumes + will accumulate after every build. + +- `device_name` (string) - The device name exposed to the instance (for example, /dev/sdh or xvdh). + Required for every device in the block device mapping. + +- `encrypted` (boolean) - Indicates whether or not to encrypt the volume. By default, Packer will + keep the encryption setting to what it was in the source image. Setting + false will result in an unencrypted device, and true will result in an + encrypted one. + +- `iops` (\*int64) - The number of I/O operations per second (IOPS) that the volume supports. + See the documentation on + [IOPs](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_EbsBlockDevice.html) + for more information + +- `no_device` (bool) - Suppresses the specified device included in the block device mapping of + the AMI. + +- `snapshot_id` (string) - The ID of the snapshot. + +- `throughput` (\*int64) - The throughput for gp3 volumes, only valid for gp3 types + See the documentation on + [Throughput](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_EbsBlockDevice.html) + for more information + +- `virtual_name` (string) - The virtual device name. See the documentation on Block Device Mapping + for more information. + +- `volume_type` (string) - The volume type. gp2 & gp3 for General Purpose (SSD) volumes, io1 & io2 + for Provisioned IOPS (SSD) volumes, st1 for Throughput Optimized HDD, + sc1 for Cold HDD, and standard for Magnetic volumes. + +- `volume_size` (int64) - The size of the volume, in GiB. Required if not specifying a + snapshot_id. + +- `kms_key_id` (string) - ID, alias or ARN of the KMS key to use for boot volume encryption. + This option exists for launch_block_device_mappings but not + ami_block_device_mappings. The kms key id defined here only applies to + the original build region; if the AMI gets copied to other regions, the + volume in those regions will be encrypted by the default EBS KMS key. + For valid formats see KmsKeyId in the [AWS API docs - + CopyImage](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CopyImage.html) + This field is validated by Packer. When using an alias, you will have to + prefix kms_key_id with alias/. + + + + +### Access Config Configuration + +#### Required: + + + +- `access_key` (string) - The access key used to communicate with AWS. [Learn how to set this](/packer/integrations/hashicorp/amazon#specifying-amazon-credentials). + On EBS, this is not required if you are using `use_vault_aws_engine` + for authentication instead. + +- `region` (string) - The name of the region, such as `us-east-1`, in which + to launch the EC2 instance to create the AMI. + When chroot building, this value is guessed from environment. + +- `secret_key` (string) - The secret key used to communicate with AWS. [Learn how to set + this](/packer/integrations/hashicorp/amazon#specifying-amazon-credentials). This is not required + if you are using `use_vault_aws_engine` for authentication instead. + + + + +#### Optional: + + + +- `assume_role` (AssumeRoleConfig) - If provided with a role ARN, Packer will attempt to assume this role + using the supplied credentials. See + [AssumeRoleConfig](#assume-role-configuration) below for more + details on all of the options available, and for a usage example. + +- `custom_endpoint_ec2` (string) - This option is useful if you use a cloud + provider whose API is compatible with aws EC2. Specify another endpoint + like this https://ec2.custom.endpoint.com. + +- `shared_credentials_file` (string) - Path to a credentials file to load credentials from + +- `decode_authorization_messages` (bool) - Enable automatic decoding of any encoded authorization (error) messages + using the `sts:DecodeAuthorizationMessage` API. Note: requires that the + effective user/role have permissions to `sts:DecodeAuthorizationMessage` + on resource `*`. Default `false`. + +- `insecure_skip_tls_verify` (bool) - This allows skipping TLS + verification of the AWS EC2 endpoint. The default is false. + +- `max_retries` (int) - This is the maximum number of times an API call is retried, in the case + where requests are being throttled or experiencing transient failures. + The delay between the subsequent API calls increases exponentially. + +- `mfa_code` (string) - The MFA + [TOTP](https://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm) + code. This should probably be a user variable since it changes all the + time. + +- `profile` (string) - The profile to use in the shared credentials file for + AWS. See Amazon's documentation on [specifying + profiles](https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-profiles) + for more details. + +- `skip_metadata_api_check` (bool) - Skip Metadata Api Check + +- `skip_credential_validation` (bool) - Set to true if you want to skip validating AWS credentials before runtime. + +- `token` (string) - The access token to use. This is different from the + access key and secret key. If you're not sure what this is, then you + probably don't need it. This will also be read from the AWS_SESSION_TOKEN + environmental variable. + +- `vault_aws_engine` (VaultAWSEngineOptions) - Get credentials from HashiCorp Vault's aws secrets engine. You must + already have created a role to use. For more information about + generating credentials via the Vault engine, see the [Vault + docs.](https://www.vaultproject.io/api/secret/aws#generate-credentials) + If you set this flag, you must also set the below options: + - `name` (string) - Required. Specifies the name of the role to generate + credentials against. This is part of the request URL. + - `engine_name` (string) - The name of the aws secrets engine. In the + Vault docs, this is normally referred to as "aws", and Packer will + default to "aws" if `engine_name` is not set. + - `role_arn` (string)- The ARN of the role to assume if credential\_type + on the Vault role is assumed\_role. Must match one of the allowed role + ARNs in the Vault role. Optional if the Vault role only allows a single + AWS role ARN; required otherwise. + - `ttl` (string) - Specifies the TTL for the use of the STS token. This + is specified as a string with a duration suffix. Valid only when + credential\_type is assumed\_role or federation\_token. When not + specified, the default\_sts\_ttl set for the role will be used. If that + is also not set, then the default value of 3600s will be used. AWS + places limits on the maximum TTL allowed. See the AWS documentation on + the DurationSeconds parameter for AssumeRole (for assumed\_role + credential types) and GetFederationToken (for federation\_token + credential types) for more details. + + HCL2 example: + + ```hcl + vault_aws_engine { + name = "myrole" + role_arn = "myarn" + ttl = "3600s" + } + ``` + + JSON example: + + ```json + { + "vault_aws_engine": { + "name": "myrole", + "role_arn": "myarn", + "ttl": "3600s" + } + } + ``` + +- `aws_polling` (\*AWSPollingConfig) - [Polling configuration](#polling-configuration) for the AWS waiter. Configures the waiter that checks + resource state. + + + + +### Assume Role Configuration + + + +AssumeRoleConfig lets users set configuration options for assuming a special +role when executing Packer. + +Usage example: + +HCL config example: + +```HCL + + source "amazon-ebs" "example" { + assume_role { + role_arn = "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME" + session_name = "SESSION_NAME" + external_id = "EXTERNAL_ID" + } + } + +``` + +JSON config example: + +```json + + builder{ + "type": "amazon-ebs", + "assume_role": { + "role_arn" : "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME", + "session_name": "SESSION_NAME", + "external_id" : "EXTERNAL_ID" + } + } + +``` + + + + + + +- `role_arn` (string) - Amazon Resource Name (ARN) of the IAM Role to assume. + +- `duration_seconds` (int) - Number of seconds to restrict the assume role session duration. + +- `external_id` (string) - The external ID to use when assuming the role. If omitted, no external + ID is passed to the AssumeRole call. + +- `policy` (string) - IAM Policy JSON describing further restricting permissions for the IAM + Role being assumed. + +- `policy_arns` ([]string) - Set of Amazon Resource Names (ARNs) of IAM Policies describing further + restricting permissions for the IAM Role being + +- `session_name` (string) - Session name to use when assuming the role. + +- `tags` (map[string]string) - Map of assume role session tags. + +- `transitive_tag_keys` ([]string) - Set of assume role session tag keys to pass to any subsequent sessions. + + + + +### Polling Configuration + + + +Polling configuration for the AWS waiter. Configures the waiter for resources creation or actions like attaching +volumes or importing image. + +HCL2 example: +```hcl + + aws_polling { + delay_seconds = 30 + max_attempts = 50 + } + +``` + +JSON example: +```json + + "aws_polling" : { + "delay_seconds": 30, + "max_attempts": 50 + } + +``` + + + + + + +- `max_attempts` (int) - Specifies the maximum number of attempts the waiter will check for resource state. + This value can also be set via the AWS_MAX_ATTEMPTS. + If both option and environment variable are set, the max_attempts will be considered over the AWS_MAX_ATTEMPTS. + If none is set, defaults to AWS waiter default which is 40 max_attempts. + +- `delay_seconds` (int) - Specifies the delay in seconds between attempts to check the resource state. + This value can also be set via the AWS_POLL_DELAY_SECONDS. + If both option and environment variable are set, the delay_seconds will be considered over the AWS_POLL_DELAY_SECONDS. + If none is set, defaults to AWS waiter default which is 15 seconds. + + + + +## Basic Example + +Here is a basic example. It is completely valid except for the access keys: + +**HCL2** + +```hcl +// To make Packer read these variables from the environment into the var object, +// set the environment variables to have the same name as the declared +// variables, with the prefix PKR_VAR_. + +// There are other ways to [set variables](/packer/docs/templates/hcl_templates/variables#assigning-values-to-build-variables), including from a var +// file or as a command argument. + +// export PKR_VAR_aws_access_key=$YOURKEY +variable "aws_access_key" { + type = string + // default = "hardcoded_key" // Not recommended ! +} + +// export PKR_VAR_aws_secret_key=$YOURSECRETKEY +variable "aws_secret_key" { + type = string + // default = "hardcoded_secret_key" // Not recommended ! +} + +source "amazon-chroot" "basic-example" { + access_key = var.aws_access_key + secret_key = var.aws_secret_key + ami_name = "example-chroot" + source_ami = "ami-e81d5881" +} + +build { + sources = [ + "source.amazon-chroot.basic-example" + ] +} +``` + +**JSON** + +```json +{ + "type": "amazon-chroot", + "access_key": "YOUR KEY HERE", + "secret_key": "YOUR SECRET KEY HERE", + "source_ami": "ami-e81d5881", + "ami_name": "packer-amazon-chroot {{timestamp}}" +} +``` + + +## Chroot Mounts + +The `chroot_mounts` configuration can be used to mount specific devices within +the chroot. By default, the following additional mounts are added into the +chroot by Packer: + +- `/proc` (proc) +- `/sys` (sysfs) +- `/dev` (bind to real `/dev`) +- `/dev/pts` (devpts) +- `/proc/sys/fs/binfmt_misc` (binfmt_misc) + +These default mounts are usually good enough for anyone and are reasonable +defaults. However, if you want to change or add the mount points, you may using +the `chroot_mounts` configuration. Here is an example configuration which only +mounts `/proc` and `/dev`: + +**HCL2** + +```hcl +source "amazon-chroot" "basic-example" { + // ... other builder options + chroot_mounts = [ + ["proc", "proc", "/proc"], + ["bind", "/dev", "/dev"] + ] +} +``` + +**JSON** + +```json +... +"builders": [{ + "type": "amazon-chroot" + ... + "chroot_mounts": [ + ["proc", "proc", "/proc"], + ["bind", "/dev", "/dev"] + ] +}] +``` + + +`chroot_mounts` is a list of a 3-tuples of strings. The three components of the +3-tuple, in order, are: + +- The filesystem type. If this is "bind", then Packer will properly bind the + filesystem to another mount point. + +- The source device. + +- The mount directory. + +## Parallelism + +A quick note on parallelism: it is perfectly safe to run multiple _separate_ +Packer processes with the `amazon-chroot` builder on the same EC2 instance. In +fact, this is recommended as a way to push the most performance out of your AMI +builds. + +Packer properly obtains a process lock for the parallelism-sensitive parts of +its internals such as finding an available device. + +## Gotchas + +### Unmounting the Filesystem + +One of the difficulties with using the chroot builder is that your provisioning +scripts must not leave any processes running or packer will be unable to +unmount the filesystem. + +For debian based distributions you can setup a +[policy-rc.d](http://people.debian.org/~hmh/invokerc.d-policyrc.d-specification.txt) +file which will prevent packages installed by your provisioners from starting +services: + +**HCL2** + +```hcl +// ... +build { + sources = [ + "source.amazon-chroot.basic-example" + ] + + // Set policy + provisioner "shell" { + inline = [ + "echo '#!/bin/sh' > /usr/sbin/policy-rc.d", + "echo 'exit 101' >> /usr/sbin/policy-rc.d", + "chmod a+x /usr/sbin/policy-rc.d" + ] + } + + // Un-set policy + provisioner "shell" { + inline = ["rm -f /usr/sbin/policy-rc.d"] + } +} +``` + +**JSON** + +```json +"provisioners": [ + { + "type": "shell", + "inline": [ + "echo '#!/bin/sh' > /usr/sbin/policy-rc.d", + "echo 'exit 101' >> /usr/sbin/policy-rc.d", + "chmod a+x /usr/sbin/policy-rc.d" + ] + }, + { + "type": "shell", + "inline": ["rm -f /usr/sbin/policy-rc.d"] + } +] +``` + + +### Ansible provisioner + +Running ansible against `amazon-chroot` requires changing the Ansible +connection to chroot and running Ansible as root/sudo. + +### Using Instances with NVMe block devices. + +In C5, C5d, M5, and i3.metal instances, EBS volumes are exposed as NVMe block +devices +[reference](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/nvme-ebs-volumes.html). +In order to correctly mount these devices, you have to do some extra legwork, +involving the `nvme_device_path` option above. Read that for more information. + +A working example for mounting an NVMe device is below: + +**HCL2** + +```hcl +// export PKR_VAR_aws_access_key=$YOURKEY +variable "aws_access_key" { + type = string +} + +// export PKR_VAR_aws_secret_key=$YOURSECRETKEY +variable "aws_secret_key" { + type = string +} + +data "amazon-ami" "example" { + filters = { + virtualization-type = "hvm" + name = "amzn-ami-hvm-*" + root-device-type = "ebs" + } + owners = ["137112412989"] + most_recent = true + + # Access Configuration + region = "us-east-1" + access_key = var.aws_access_key + secret_key = var.aws_secret_key +} + +source "amazon-chroot" "basic-example" { + access_key = var.aws_access_key + secret_key = var.aws_secret_key + region = "us-east-1" + source_ami = data.amazon-ami.example.id + ena_support = true + ami_name = "amazon-chroot-test-{{timestamp}}" + nvme_device_path = "/dev/nvme1n1p" + device_path = "/dev/sdf" +} + +build { + sources = [ + "source.amazon-chroot.basic-example" + ] + + provisioner "shell" { + inline = ["echo Test > /tmp/test.txt"] + } +} +``` + +**JSON** + +```json +{ + "variables": { + "region": "us-east-2" + }, + "builders": [ + { + "type": "amazon-chroot", + "region": "{{user `region`}}", + "source_ami_filter": { + "filters": { + "virtualization-type": "hvm", + "name": "amzn-ami-hvm-*", + "root-device-type": "ebs" + }, + "owners": ["137112412989"], + "most_recent": true + }, + "ena_support": true, + "ami_name": "amazon-chroot-test-{{timestamp}}", + "nvme_device_path": "/dev/nvme1n1p", + "device_path": "/dev/sdf" + } + ], + + "provisioners": [ + { + "type": "shell", + "inline": ["echo Test > /tmp/test.txt"] + } + ] +} +``` + + +Note that in the `nvme_device_path` you must end with the `p`; if you try to +define the partition in this path (e.g. `nvme_device_path`: `/dev/nvme1n1p1`) +and haven't also set the `"mount_partition": 0`, a `1` will be appended to the +`nvme_device_path` and Packer will fail. + +## Building From Scratch + +This example demonstrates the essentials of building an image from scratch. A +15G gp2 (SSD) device is created (overriding the default of standard/magnetic). +The device setup commands partition the device with one partition for use as an +HVM image and format it ext4. This builder block should be followed by +provisioning commands to install the os and bootloader. + +**HCL2** + +```hcl +// This example assumes that AWS_SECRET_ACCESS_KEY and AWS_ACCESS_KEY_ID are +// set in your environment, or a ~/.aws/credentials file is configured. +source "amazon-chroot" "basic-example" { + region = "us-east-1" + ami_name = "packer-from-scratch {{timestamp}}" + from_scratch = true + ami_virtualization_type = "hvm" + pre_mount_commands = [ + "parted {{.Device}} mklabel msdos mkpart primary 1M 100% set 1 boot on print", + "mkfs.ext4 {{.Device}}1" + ] + root_volume_size = 15 + root_device_name = "xvda" + ami_block_device_mappings { + device_name = "xvda" + delete_on_termination = true + volume_type = "gp2" + } + +} + +build { + sources = [ + "source.amazon-chroot.basic-example" + ] + + provisioner "shell" { + inline = [ + "echo '#!/bin/sh' > /usr/sbin/policy-rc.d", + "echo 'exit 101' >> /usr/sbin/policy-rc.d", + "chmod a+x /usr/sbin/policy-rc.d" + ] + } + + provisioner "shell" { + inline = ["rm -f /usr/sbin/policy-rc.d"] + } +} +``` + +**JSON** + +```json +{ + "type": "amazon-chroot", + "ami_name": "packer-from-scratch {{timestamp}}", + "from_scratch": true, + "ami_virtualization_type": "hvm", + "pre_mount_commands": [ + "parted {{.Device}} mklabel msdos mkpart primary 1M 100% set 1 boot on print", + "mkfs.ext4 {{.Device}}1" + ], + "root_volume_size": 15, + "root_device_name": "xvda", + "ami_block_device_mappings": [ + { + "device_name": "xvda", + "delete_on_termination": true, + "volume_type": "gp2" + } + ] +} +``` + + +## Build template data + +In configuration directives marked as a template engine above, the following +variables are available: + +- `BuildRegion` - The region (for example `eu-central-1`) where Packer is + building the AMI. +- `SourceAMI` - The source AMI ID (for example `ami-a2412fcd`) used to build + the AMI. +- `SourceAMICreationDate` - The source AMI creation date (for example `"2020-05-14T19:26:34.000Z"`). +- `SourceAMIName` - The source AMI Name (for example + `ubuntu/images/ebs-ssd/ubuntu-xenial-16.04-amd64-server-20180306`) used to + build the AMI. +- `SourceAMIOwner` - The source AMI owner ID. +- `SourceAMIOwnerName` - The source AMI owner alias/name (for example `amazon`). +- `SourceAMITags` - The source AMI Tags, as a `map[string]string` object. + +## Build Shared Information Variables + +This builder generates data that are shared with provisioner and post-processor via build function of [template engine](/packer/docs/templates/legacy_json_templates/engine) for JSON and [contextual variables](/packer/docs/templates/hcl_templates/contextual-variables) for HCL2. + +The generated variables available for this builder are: + +- `BuildRegion` - The region (for example `eu-central-1`) where Packer is + building the AMI. +- `SourceAMI` - The source AMI ID (for example `ami-a2412fcd`) used to build + the AMI. +- `SourceAMICreationDate` - The source AMI creation date (for example `"2020-05-14T19:26:34.000Z"`). +- `SourceAMIName` - The source AMI Name (for example + `ubuntu/images/ebs-ssd/ubuntu-xenial-16.04-amd64-server-20180306`) used to + build the AMI. +- `SourceAMIOwner` - The source AMI owner ID. +- `SourceAMIOwnerName` - The source AMI owner alias/name (for example `amazon`). +- `Device` - Root device path. +- `MountPath` - Device mounting path. + +Usage example: + +**HCL2** + +```hcl +// When accessing one of these variables from inside the builder, you need to +// use the golang templating syntax. This is due to an architectural quirk that +// won't be easily resolvable until legacy json templates are deprecated: + +{ +source "amazon-ebs" "basic-example" { + tags = { + OS_Version = "Ubuntu" + Release = "Latest" + Base_AMI_ID = "{{ .SourceAMI }}" + Base_AMI_Name = "{{ .SourceAMIName }}" + } +} + +// when accessing one of the variables from a provisioner or post-processor, use +// hcl-syntax +post-processor "manifest" { + output = "manifest.json" + strip_path = true + custom_data = { + source_ami_name = "${build.SourceAMIName}" + device = "${build.Device}" + mount_path = "${build.MountPath}" + } +} +``` + +**JSON** + +```json +"post-processors": [ + { + "type": "manifest", + "output": "manifest.json", + "strip_path": true, + "custom_data": { + "source_ami_name": "{{ build `SourceAMIName` }}", + "device": "{{ build `Device` }}", + "mount_path": "{{ build `MountPath` }}" + } + } +] +``` diff --git a/.web-docs/components/builder/ebs/README.md b/.web-docs/components/builder/ebs/README.md new file mode 100644 index 000000000..abd1386e8 --- /dev/null +++ b/.web-docs/components/builder/ebs/README.md @@ -0,0 +1,2170 @@ +Type: `amazon-ebs` +Artifact BuilderId: `mitchellh.amazonebs` + +The `amazon-ebs` Packer builder is able to create Amazon AMIs backed by EBS +volumes for use in [EC2](https://aws.amazon.com/ec2/). For more information on +the difference between EBS-backed instances and instance-store backed +instances, see the ["storage for the root device" section in the EC2 +documentation](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ComponentsAMIs.html#storage-for-the-root-device). + +This builder builds an AMI by launching an EC2 instance from a source AMI, +provisioning that running machine, and then creating an AMI from that machine. +This is all done in your own AWS account. The builder will create temporary +keypairs, security group rules, etc. that provide it temporary access to the +instance while the image is being created. This simplifies configuration quite +a bit. + +The builder does _not_ manage AMIs. Once it creates an AMI and stores it in +your account, it is up to you to use, delete, etc. the AMI. + +-> **Note:** Temporary resources are, by default, all created with the +prefix `packer`. This can be useful if you want to restrict the security groups +and key pairs Packer is able to operate on. + +## EBS Specific Configuration Reference + +There are many configuration options available for the builder. In addition to +the items listed here, you will want to look at the general configuration +references for [AMI](#ami-configuration), +[BlockDevices](#block-devices-configuration), +[Access](#access-configuration), +[Run](#run-configuration) and +[Communicator](#communicator-configuration) +configuration references, which are +necessary for this build to succeed and can be found further down the page. + +**Optional:** + + + +- `skip_create_ami` (bool) - If true, Packer will not create the AMI. Useful for setting to `true` + during a build test stage. Default `false`. + +- `ami_block_device_mappings` (awscommon.BlockDevices) - Add one or more block device mappings to the AMI. These will be attached + when booting a new instance from your AMI. To add a block device during + the Packer build see `launch_block_device_mappings` below. Your options + here may vary depending on the type of VM you use. See the + [BlockDevices](#block-devices-configuration) documentation for fields. + +- `launch_block_device_mappings` (awscommon.BlockDevices) - Add one or more block devices before the Packer build starts. If you add + instance store volumes or EBS volumes in addition to the root device + volume, the created AMI will contain block device mapping information + for those volumes. Amazon creates snapshots of the source instance's + root volume and any other EBS volumes described here. When you launch an + instance from this new AMI, the instance automatically launches with + these additional volumes, and will restore them from snapshots taken + from the source instance. See the + [BlockDevices](#block-devices-configuration) documentation for fields. + +- `run_volume_tags` (map[string]string) - Tags to apply to the volumes that are *launched* to create the AMI. + These tags are *not* applied to the resulting AMI unless they're + duplicated in `tags`. This is a [template + engine](/packer/docs/templates/legacy_json_templates/engine), see [Build template + data](#build-template-data) for more information. + +- `run_volume_tag` ([]{name string, value string}) - Same as [`run_volume_tags`](#run_volume_tags) but defined as a singular + block containing a `name` and a `value` field. In HCL2 mode the + [`dynamic_block`](https://packer.io/docs/templates/hcl_templates/expressions.html#dynamic-blocks) + will allow you to create those programatically. + +- `no_ephemeral` (bool) - Relevant only to Windows guests: If you set this flag, we'll add clauses + to the launch_block_device_mappings that make sure ephemeral drives + don't show up in the EC2 console. If you launched from the EC2 console, + you'd get this automatically, but the SDK does not provide this service. + For more information, see + https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/InstanceStorage.html. + Because we don't validate the OS type of your guest, it is up to you to + make sure you don't set this for *nix guests; behavior may be + unpredictable. + +- `fast_launch` (FastLaunchConfig) - The configuration for fast launch support. + + Fast launch is only relevant for Windows AMIs, and should not be used + for other OSes. + See the [Fast Launch Configuration](#fast-launch-config) section for + information on the attributes supported for this block. + + + + +### AMI Configuration + +**Required:** + + + +- `ami_name` (string) - The name of the resulting AMI that will appear when managing AMIs in the + AWS console or via APIs. This must be unique. To help make this unique, + use a function like timestamp (see [template + engine](/packer/docs/templates/legacy_json_templates/engine) for more info). + + + + +**Optional:** + + + +- `ami_description` (string) - The description to set for the resulting + AMI(s). By default this description is empty. This is a + [template engine](/packer/docs/templates/legacy_json_templates/engine), see [Build template + data](#build-template-data) for more information. + +- `ami_virtualization_type` (string) - The type of virtualization for the AMI + you are building. This option is required to register HVM images. Can be + paravirtual (default) or hvm. + +- `ami_users` ([]string) - A list of account IDs that have access to + launch the resulting AMI(s). By default no additional users other than the + user creating the AMI has permissions to launch it. + +- `ami_groups` ([]string) - A list of groups that have access to + launch the resulting AMI(s). By default no groups have permission to launch + the AMI. `all` will make the AMI publicly accessible. + AWS currently doesn't accept any value other than "all" + +- `ami_org_arns` ([]string) - A list of Amazon Resource Names (ARN) of AWS Organizations that have access to + launch the resulting AMI(s). By default no organizations have permission to launch + the AMI. + +- `ami_ou_arns` ([]string) - A list of Amazon Resource Names (ARN) of AWS Organizations organizational units (OU) that have access to + launch the resulting AMI(s). By default no organizational units have permission to launch + the AMI. + +- `ami_product_codes` ([]string) - A list of product codes to + associate with the AMI. By default no product codes are associated with the + AMI. + +- `ami_regions` ([]string) - A list of regions to copy the AMI to. + Tags and attributes are copied along with the AMI. AMI copying takes time + depending on the size of the AMI, but will generally take many minutes. + +- `skip_region_validation` (bool) - Set to true if you want to skip + validation of the ami_regions configuration option. Default false. + +- `tags` (map[string]string) - Key/value pair tags applied to the AMI. This is a [template + engine](/packer/docs/templates/legacy_json_templates/engine), see [Build template + data](#build-template-data) for more information. + + The builder no longer adds a "Name": "Packer Builder" entry to the tags. + +- `tag` ([]{key string, value string}) - Same as [`tags`](#tags) but defined as a singular repeatable block + containing a `key` and a `value` field. In HCL2 mode the + [`dynamic_block`](/packer/docs/templates/hcl_templates/expressions#dynamic-blocks) + will allow you to create those programatically. + +- `ena_support` (boolean) - Enable enhanced networking (ENA but not SriovNetSupport) on + HVM-compatible AMIs. If set, add `ec2:ModifyInstanceAttribute` to your + AWS IAM policy. + + Note: you must make sure enhanced networking is enabled on your + instance. See [Amazon's documentation on enabling enhanced + networking](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enhanced-networking.html#enabling_enhanced_networking). + +- `sriov_support` (bool) - Enable enhanced networking (SriovNetSupport but not ENA) on + HVM-compatible AMIs. If true, add `ec2:ModifyInstanceAttribute` to your + AWS IAM policy. Note: you must make sure enhanced networking is enabled + on your instance. See [Amazon's documentation on enabling enhanced + networking](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enhanced-networking.html#enabling_enhanced_networking). + Default `false`. + +- `force_deregister` (bool) - Force Packer to first deregister an existing + AMI if one with the same name already exists. Default false. + +- `force_delete_snapshot` (bool) - Force Packer to delete snapshots + associated with AMIs, which have been deregistered by force_deregister. + Default false. + +- `encrypt_boot` (boolean) - Whether or not to encrypt the resulting AMI when + copying a provisioned instance to an AMI. By default, Packer will keep + the encryption setting to what it was in the source image. Setting false + will result in an unencrypted image, and true will result in an encrypted + one. + + If you have used the `launch_block_device_mappings` to set an encryption + key and that key is the same as the one you want the image encrypted with + at the end, then you don't need to set this field; leaving it empty will + prevent an unnecessary extra copy step and save you some time. + + Please note that if you are using an account with the global "Always + encrypt new EBS volumes" option set to `true`, Packer will be unable to + override this setting, and the final image will be encrypted whether + you set this value or not. + +- `kms_key_id` (string) - ID, alias or ARN of the KMS key to use for AMI encryption. This + only applies to the main `region` -- any regions the AMI gets copied to + will be encrypted by the default EBS KMS key for that region, + unless you set region-specific keys in `region_kms_key_ids`. + + Set this value if you select `encrypt_boot`, but don't want to use the + region's default KMS key. + + If you have a custom kms key you'd like to apply to the launch volume, + and are only building in one region, it is more efficient to leave this + and `encrypt_boot` empty and to instead set the key id in the + launch_block_device_mappings (you can find an example below). This saves + potentially many minutes at the end of the build by preventing Packer + from having to copy and re-encrypt the image at the end of the build. + + For valid formats see *KmsKeyId* in the [AWS API docs - + CopyImage](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CopyImage.html). + This field is validated by Packer, when using an alias, you will have to + prefix `kms_key_id` with `alias/`. + +- `region_kms_key_ids` (map[string]string) - regions to copy the ami to, along with the custom kms key id (alias or + arn) to use for encryption for that region. Keys must match the regions + provided in `ami_regions`. If you just want to encrypt using a default + ID, you can stick with `kms_key_id` and `ami_regions`. If you want a + region to be encrypted with that region's default key ID, you can use an + empty string `""` instead of a key id in this map. (e.g. `"us-east-1": + ""`) However, you cannot use default key IDs if you are using this in + conjunction with `snapshot_users` -- in that situation you must use + custom keys. For valid formats see *KmsKeyId* in the [AWS API docs - + CopyImage](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CopyImage.html). + + This option supercedes the `kms_key_id` option -- if you set both, and + they are different, Packer will respect the value in + `region_kms_key_ids` for your build region and silently disregard the + value provided in `kms_key_id`. + +- `skip_save_build_region` (bool) - If true, Packer will not check whether an AMI with the `ami_name` exists + in the region it is building in. It will use an intermediary AMI name, + which it will not convert to an AMI in the build region. It will copy + the intermediary AMI into any regions provided in `ami_regions`, then + delete the intermediary AMI. Default `false`. + +- `imds_support` (string) - Enforce version of the Instance Metadata Service on the built AMI. + Valid options are unset (legacy) and `v2.0`. See the documentation on + [IMDS](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html) + for more information. Defaults to legacy. + +- `deprecate_at` (string) - The date and time to deprecate the AMI, in UTC, in the following format: YYYY-MM-DDTHH:MM:SSZ. + If you specify a value for seconds, Amazon EC2 rounds the seconds to the nearest minute. + You can’t specify a date in the past. The upper limit for DeprecateAt is 10 years from now. + + + + + + +- `snapshot_tags` (map[string]string) - Key/value pair tags to apply to snapshot. They will override AMI tags if + already applied to snapshot. This is a [template + engine](/packer/docs/templates/legacy_json_templates/engine), see [Build template + data](#build-template-data) for more information. + +- `snapshot_tag` ([]{key string, value string}) - Same as [`snapshot_tags`](#snapshot_tags) but defined as a singular + repeatable block containing a `key` and a `value` field. In HCL2 mode the + [`dynamic_block`](/packer/docs/templates/hcl_templates/expressions#dynamic-blocks) + will allow you to create those programatically. + +- `snapshot_users` ([]string) - A list of account IDs that have + access to create volumes from the snapshot(s). By default no additional + users other than the user creating the AMI has permissions to create + volumes from the backing snapshot(s). + +- `snapshot_groups` ([]string) - A list of groups that have access to + create volumes from the snapshot(s). By default no groups have permission + to create volumes from the snapshot(s). all will make the snapshot + publicly accessible. + + + + +### Access Configuration + +**Required:** + + + +- `access_key` (string) - The access key used to communicate with AWS. [Learn how to set this](/packer/integrations/hashicorp/amazon#specifying-amazon-credentials). + On EBS, this is not required if you are using `use_vault_aws_engine` + for authentication instead. + +- `region` (string) - The name of the region, such as `us-east-1`, in which + to launch the EC2 instance to create the AMI. + When chroot building, this value is guessed from environment. + +- `secret_key` (string) - The secret key used to communicate with AWS. [Learn how to set + this](/packer/integrations/hashicorp/amazon#specifying-amazon-credentials). This is not required + if you are using `use_vault_aws_engine` for authentication instead. + + + + +**Optional:** + + + +- `assume_role` (AssumeRoleConfig) - If provided with a role ARN, Packer will attempt to assume this role + using the supplied credentials. See + [AssumeRoleConfig](#assume-role-configuration) below for more + details on all of the options available, and for a usage example. + +- `custom_endpoint_ec2` (string) - This option is useful if you use a cloud + provider whose API is compatible with aws EC2. Specify another endpoint + like this https://ec2.custom.endpoint.com. + +- `shared_credentials_file` (string) - Path to a credentials file to load credentials from + +- `decode_authorization_messages` (bool) - Enable automatic decoding of any encoded authorization (error) messages + using the `sts:DecodeAuthorizationMessage` API. Note: requires that the + effective user/role have permissions to `sts:DecodeAuthorizationMessage` + on resource `*`. Default `false`. + +- `insecure_skip_tls_verify` (bool) - This allows skipping TLS + verification of the AWS EC2 endpoint. The default is false. + +- `max_retries` (int) - This is the maximum number of times an API call is retried, in the case + where requests are being throttled or experiencing transient failures. + The delay between the subsequent API calls increases exponentially. + +- `mfa_code` (string) - The MFA + [TOTP](https://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm) + code. This should probably be a user variable since it changes all the + time. + +- `profile` (string) - The profile to use in the shared credentials file for + AWS. See Amazon's documentation on [specifying + profiles](https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-profiles) + for more details. + +- `skip_metadata_api_check` (bool) - Skip Metadata Api Check + +- `skip_credential_validation` (bool) - Set to true if you want to skip validating AWS credentials before runtime. + +- `token` (string) - The access token to use. This is different from the + access key and secret key. If you're not sure what this is, then you + probably don't need it. This will also be read from the AWS_SESSION_TOKEN + environmental variable. + +- `vault_aws_engine` (VaultAWSEngineOptions) - Get credentials from HashiCorp Vault's aws secrets engine. You must + already have created a role to use. For more information about + generating credentials via the Vault engine, see the [Vault + docs.](https://www.vaultproject.io/api/secret/aws#generate-credentials) + If you set this flag, you must also set the below options: + - `name` (string) - Required. Specifies the name of the role to generate + credentials against. This is part of the request URL. + - `engine_name` (string) - The name of the aws secrets engine. In the + Vault docs, this is normally referred to as "aws", and Packer will + default to "aws" if `engine_name` is not set. + - `role_arn` (string)- The ARN of the role to assume if credential\_type + on the Vault role is assumed\_role. Must match one of the allowed role + ARNs in the Vault role. Optional if the Vault role only allows a single + AWS role ARN; required otherwise. + - `ttl` (string) - Specifies the TTL for the use of the STS token. This + is specified as a string with a duration suffix. Valid only when + credential\_type is assumed\_role or federation\_token. When not + specified, the default\_sts\_ttl set for the role will be used. If that + is also not set, then the default value of 3600s will be used. AWS + places limits on the maximum TTL allowed. See the AWS documentation on + the DurationSeconds parameter for AssumeRole (for assumed\_role + credential types) and GetFederationToken (for federation\_token + credential types) for more details. + + HCL2 example: + + ```hcl + vault_aws_engine { + name = "myrole" + role_arn = "myarn" + ttl = "3600s" + } + ``` + + JSON example: + + ```json + { + "vault_aws_engine": { + "name": "myrole", + "role_arn": "myarn", + "ttl": "3600s" + } + } + ``` + +- `aws_polling` (\*AWSPollingConfig) - [Polling configuration](#polling-configuration) for the AWS waiter. Configures the waiter that checks + resource state. + + + + +### Assume Role Configuration + + + +AssumeRoleConfig lets users set configuration options for assuming a special +role when executing Packer. + +Usage example: + +HCL config example: + +```HCL + + source "amazon-ebs" "example" { + assume_role { + role_arn = "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME" + session_name = "SESSION_NAME" + external_id = "EXTERNAL_ID" + } + } + +``` + +JSON config example: + +```json + + builder{ + "type": "amazon-ebs", + "assume_role": { + "role_arn" : "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME", + "session_name": "SESSION_NAME", + "external_id" : "EXTERNAL_ID" + } + } + +``` + + + + + + +- `role_arn` (string) - Amazon Resource Name (ARN) of the IAM Role to assume. + +- `duration_seconds` (int) - Number of seconds to restrict the assume role session duration. + +- `external_id` (string) - The external ID to use when assuming the role. If omitted, no external + ID is passed to the AssumeRole call. + +- `policy` (string) - IAM Policy JSON describing further restricting permissions for the IAM + Role being assumed. + +- `policy_arns` ([]string) - Set of Amazon Resource Names (ARNs) of IAM Policies describing further + restricting permissions for the IAM Role being + +- `session_name` (string) - Session name to use when assuming the role. + +- `tags` (map[string]string) - Map of assume role session tags. + +- `transitive_tag_keys` ([]string) - Set of assume role session tag keys to pass to any subsequent sessions. + + + + +### Polling Configuration + + + +Polling configuration for the AWS waiter. Configures the waiter for resources creation or actions like attaching +volumes or importing image. + +HCL2 example: +```hcl + + aws_polling { + delay_seconds = 30 + max_attempts = 50 + } + +``` + +JSON example: +```json + + "aws_polling" : { + "delay_seconds": 30, + "max_attempts": 50 + } + +``` + + + + + + +- `max_attempts` (int) - Specifies the maximum number of attempts the waiter will check for resource state. + This value can also be set via the AWS_MAX_ATTEMPTS. + If both option and environment variable are set, the max_attempts will be considered over the AWS_MAX_ATTEMPTS. + If none is set, defaults to AWS waiter default which is 40 max_attempts. + +- `delay_seconds` (int) - Specifies the delay in seconds between attempts to check the resource state. + This value can also be set via the AWS_POLL_DELAY_SECONDS. + If both option and environment variable are set, the delay_seconds will be considered over the AWS_POLL_DELAY_SECONDS. + If none is set, defaults to AWS waiter default which is 15 seconds. + + + + +### Run Configuration + +**Required:** + + + +- `instance_type` (string) - The EC2 instance type to use while building the + AMI, such as t2.small. + +- `source_ami` (string) - The source AMI whose root volume will be copied and + provisioned on the currently running instance. This must be an EBS-backed + AMI with a root volume snapshot that you have access to. + + + + +**Optional:** + + + +- `associate_public_ip_address` (confighelper.Trilean) - If using a non-default VPC, + public IP addresses are not provided by default. If this is true, your + new instance will get a Public IP. default: unset + + Note: when specifying this attribute without a `subnet_[id|filter]` or + `vpc_[id|filter]`, we will attempt to infer this information from the + default VPC/Subnet. + This operation may require some extra permissions to the IAM role that + runs the build: + + * ec2:DescribeVpcs + * ec2:DescribeSubnets + + Additionally, since we filter subnets/AZs by their capability to host + an instance of the selected type, you may also want to define the + `ec2:DescribeInstanceTypeOfferings` action to the role running the build. + Otherwise, Packer will pick the most available subnet in the VPC selected, + which may not be able to host the instance type you provided. + +- `availability_zone` (string) - Destination availability zone to launch + instance in. Leave this empty to allow Amazon to auto-assign. + +- `block_duration_minutes` (int64) - Requires spot_price to be set. The + required duration for the Spot Instances (also known as Spot blocks). This + value must be a multiple of 60 (60, 120, 180, 240, 300, or 360). You can't + specify an Availability Zone group or a launch group if you specify a + duration. Note: This parameter is no longer available to new customers + from July 1, 2021. [See Amazon's + documentation](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-requests.html#fixed-duration-spot-instances). + +- `capacity_reservation_preference` (string) - Set the preference for using a capacity reservation if one exists. + Either will be `open` or `none`. Defaults to `none` + +- `capacity_reservation_id` (string) - Provide the specific EC2 Capacity Reservation ID that will be used + by Packer. + +- `capacity_reservation_group_arn` (string) - Provide the EC2 Capacity Reservation Group ARN that will be used by + Packer. + +- `disable_stop_instance` (bool) - Packer normally stops the build instance after all provisioners have + run. For Windows instances, it is sometimes desirable to [run + Sysprep](https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/Creating_EBSbacked_WinAMI.html) + which will stop the instance for you. If this is set to `true`, Packer + *will not* stop the instance but will assume that you will send the stop + signal yourself through your final provisioner. You can do this with a + [windows-shell provisioner](/packer/integrations/hashicorp/windows-shell). Note that + Packer will still wait for the instance to be stopped, and failing to + send the stop signal yourself, when you have set this flag to `true`, + will cause a timeout. + + An example of a valid windows shutdown command in a `windows-shell` + provisioner is : + ```shell-session + ec2config.exe -sysprep + ``` + or + ```sell-session + "%programfiles%\amazon\ec2configservice\"ec2config.exe -sysprep"" + ``` + -> Note: The double quotation marks in the command are not required if + your CMD shell is already in the + `C:\Program Files\Amazon\EC2ConfigService\` directory. + +- `ebs_optimized` (bool) - Mark instance as [EBS + Optimized](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSOptimized.html). + Default `false`. + +- `enable_nitro_enclave` (bool) - Enable support for Nitro Enclaves on the instance. Note that the instance type must + be able to [support Nitro Enclaves](https://aws.amazon.com/ec2/nitro/nitro-enclaves/faqs/). + This option is not supported for spot instances. + +- `enable_t2_unlimited` (bool) - Deprecated argument - please use "enable_unlimited_credits". + Enabling T2 Unlimited allows the source instance to burst additional CPU + beyond its available [CPU + Credits](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/t2-credits-baseline-concepts.html) + for as long as the demand exists. This is in contrast to the standard + configuration that only allows an instance to consume up to its + available CPU Credits. See the AWS documentation for [T2 + Unlimited](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/t2-unlimited.html) + and the **T2 Unlimited Pricing** section of the [Amazon EC2 On-Demand + Pricing](https://aws.amazon.com/ec2/pricing/on-demand/) document for + more information. By default this option is disabled and Packer will set + up a [T2 + Standard](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/t2-std.html) + instance instead. + + To use T2 Unlimited you must use a T2 instance type, e.g. `t2.micro`. + Additionally, T2 Unlimited cannot be used in conjunction with Spot + Instances, e.g. when the `spot_price` option has been configured. + Attempting to do so will cause an error. + + !> **Warning!** Additional costs may be incurred by enabling T2 + Unlimited - even for instances that would usually qualify for the + [AWS Free Tier](https://aws.amazon.com/free/). + +- `enable_unlimited_credits` (bool) - Enabling Unlimited credits allows the source instance to burst additional CPU + beyond its available [CPU + Credits](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/burstable-performance-instances-unlimited-mode-concepts.html#unlimited-mode-surplus-credits) + for as long as the demand exists. This is in contrast to the standard + configuration that only allows an instance to consume up to its + available CPU Credits. See the AWS documentation for [T2 + Unlimited](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/burstable-performance-instances-unlimited-mode-concepts.html) + and the **Unlimited Pricing** section of the [Amazon EC2 On-Demand + Pricing](https://aws.amazon.com/ec2/pricing/on-demand/) document for + more information. By default this option is disabled and Packer will set + up a [Standard](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/burstable-performance-instances-standard-mode.html) + instance instead. + + To use Unlimited you must use a T2/T3/T3a/T4g instance type, e.g. (`t2.micro`, `t3.micro`). + Additionally, Unlimited cannot be used in conjunction with Spot + Instances for T2 type instances, e.g. when the `spot_price` option has been configured. + Attempting to do so will cause an error if the underlying instance type is a T2 type instance. + By default the supported burstable instance types (including t3/t3a/t4g) will be provisioned with its cpu credits set to standard, + only when `enable_unlimited_credits` is true will the instance be provisioned with unlimited cpu credits. + +- `iam_instance_profile` (string) - The name of an [IAM instance + profile](https://docs.aws.amazon.com/IAM/latest/UserGuide/instance-profiles.html) + to launch the EC2 instance with. + +- `fleet_tags` (map[string]string) - Key/value pair tags to apply tags to the fleet that is issued. + +- `fleet_tag` ([]{key string, value string}) - Same as [`fleet_tags`](#fleet_tags) but defined as a singular repeatable block + containing a `key` and a `value` field. In HCL2 mode the + [`dynamic_block`](/packer/docs/templates/hcl_templates/expressions#dynamic-blocks) + will allow you to create those programatically. + +- `skip_profile_validation` (bool) - Whether or not to check if the IAM instance profile exists. Defaults to false + +- `temporary_iam_instance_profile_policy_document` (\*PolicyDocument) - Temporary IAM instance profile policy document + If IamInstanceProfile is specified it will be used instead. + + HCL2 example: + ```hcl + temporary_iam_instance_profile_policy_document { + Statement { + Action = ["logs:*"] + Effect = "Allow" + Resource = ["*"] + } + Version = "2012-10-17" + } + ``` + + JSON example: + ```json + { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "logs:*" + ], + "Effect": "Allow", + "Resource": ["*"] + } + ] + } + ``` + +- `shutdown_behavior` (string) - Automatically terminate instances on + shutdown in case Packer exits ungracefully. Possible values are stop and + terminate. Defaults to stop. + +- `security_group_filter` (SecurityGroupFilterOptions) - Filters used to populate the `security_group_ids` field. + + HCL2 Example: + + ```hcl + security_group_filter { + filters = { + "tag:Class": "packer" + } + } + ``` + + JSON Example: + ```json + { + "security_group_filter": { + "filters": { + "tag:Class": "packer" + } + } + } + ``` + + This selects the SG's with tag `Class` with the value `packer`. + + - `filters` (map[string,string] | multiple filters are allowed when seperated by commas) - filters used to select a + `security_group_ids`. Any filter described in the docs for + [DescribeSecurityGroups](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSecurityGroups.html) + is valid. + + `security_group_ids` take precedence over this. + +- `run_tags` (map[string]string) - Key/value pair tags to apply to the generated key-pair, security group, iam profile and role, snapshot, network interfaces and instance + that is *launched* to create the EBS volumes. The resulting AMI will also inherit these tags. + This is a [template + engine](/packer/docs/templates/legacy_json_templates/engine), see [Build template + data](#build-template-data) for more information. + +- `run_tag` ([]{key string, value string}) - Same as [`run_tags`](#run_tags) but defined as a singular repeatable + block containing a `key` and a `value` field. In HCL2 mode the + [`dynamic_block`](/packer/docs/templates/hcl_templates/expressions#dynamic-blocks) + will allow you to create those programatically. + +- `security_group_id` (string) - The ID (not the name) of the security + group to assign to the instance. By default this is not set and Packer will + automatically create a new temporary security group to allow SSH access. + Note that if this is specified, you must be sure the security group allows + access to the ssh_port given below. + +- `security_group_ids` ([]string) - A list of security groups as + described above. Note that if this is specified, you must omit the + security_group_id. + +- `source_ami_filter` (AmiFilterOptions) - Filters used to populate the `source_ami` + field. + + HCL2 example: + ```hcl + source "amazon-ebs" "basic-example" { + source_ami_filter { + filters = { + virtualization-type = "hvm" + name = "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*" + root-device-type = "ebs" + } + owners = ["099720109477"] + most_recent = true + } + } + ``` + + JSON Example: + ```json + "builders" [ + { + "type": "amazon-ebs", + "source_ami_filter": { + "filters": { + "virtualization-type": "hvm", + "name": "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*", + "root-device-type": "ebs" + }, + "owners": ["099720109477"], + "most_recent": true + } + } + ] + ``` + + This selects the most recent Ubuntu 16.04 HVM EBS AMI from Canonical. NOTE: + This will fail unless *exactly* one AMI is returned. In the above example, + `most_recent` will cause this to succeed by selecting the newest image. + + - `filters` (map[string,string] | multiple filters are allowed when seperated by commas) - filters used to select a `source_ami`. + NOTE: This will fail unless *exactly* one AMI is returned. Any filter + described in the docs for + [DescribeImages](http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeImages.html) + is valid. + + - `owners` (array of strings) - Filters the images by their owner. You + may specify one or more AWS account IDs, "self" (which will use the + account whose credentials you are using to run Packer), or an AWS owner + alias: for example, `amazon`, `aws-marketplace`, or `microsoft`. This + option is required for security reasons. + + - `most_recent` (boolean) - Selects the newest created image when true. + This is most useful for selecting a daily distro build. + + You may set this in place of `source_ami` or in conjunction with it. If you + set this in conjunction with `source_ami`, the `source_ami` will be added + to the filter. The provided `source_ami` must meet all of the filtering + criteria provided in `source_ami_filter`; this pins the AMI returned by the + filter, but will cause Packer to fail if the `source_ami` does not exist. + +- `spot_instance_types` ([]string) - a list of acceptable instance + types to run your build on. We will request a spot instance using the max + price of spot_price and the allocation strategy of "lowest price". + Your instance will be launched on an instance type of the lowest available + price that you have in your list. This is used in place of instance_type. + You may only set either spot_instance_types or instance_type, not both. + This feature exists to help prevent situations where a Packer build fails + because a particular availability zone does not have capacity for the + specific instance_type requested in instance_type. + +- `spot_price` (string) - With Spot Instances, you pay the Spot price that's in effect for the + time period your instances are running. Spot Instance prices are set by + Amazon EC2 and adjust gradually based on long-term trends in supply and + demand for Spot Instance capacity. + + When this field is set, it represents the maximum hourly price you are + willing to pay for a spot instance. If you do not set this value, it + defaults to a maximum price equal to the on demand price of the + instance. In the situation where the current Amazon-set spot price + exceeds the value set in this field, Packer will not launch an instance + and the build will error. In the situation where the Amazon-set spot + price is less than the value set in this field, Packer will launch and + you will pay the Amazon-set spot price, not this maximum value. + For more information, see the Amazon docs on + [spot pricing](https://aws.amazon.com/ec2/spot/pricing/). + +- `spot_tags` (map[string]string) - Requires spot_price to be set. Key/value pair tags to apply tags to the + spot request that is issued. + +- `spot_tag` ([]{key string, value string}) - Same as [`spot_tags`](#spot_tags) but defined as a singular repeatable block + containing a `key` and a `value` field. In HCL2 mode the + [`dynamic_block`](/packer/docs/templates/hcl_templates/expressions#dynamic-blocks) + will allow you to create those programatically. + +- `subnet_filter` (SubnetFilterOptions) - Filters used to populate the `subnet_id` field. + + HCL2 example: + + ```hcl + source "amazon-ebs" "basic-example" { + subnet_filter { + filters = { + "tag:Class": "build" + } + most_free = true + random = false + } + } + ``` + + JSON Example: + ```json + "builders" [ + { + "type": "amazon-ebs", + "subnet_filter": { + "filters": { + "tag:Class": "build" + }, + "most_free": true, + "random": false + } + } + ] + ``` + + This selects the Subnet with tag `Class` with the value `build`, which has + the most free IP addresses. NOTE: This will fail unless *exactly* one + Subnet is returned. By using `most_free` or `random` one will be selected + from those matching the filter. + + - `filters` (map[string,string] | multiple filters are allowed when seperated by commas) - filters used to select a `subnet_id`. + NOTE: This will fail unless *exactly* one Subnet is returned. Any + filter described in the docs for + [DescribeSubnets](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSubnets.html) + is valid. + + - `most_free` (boolean) - The Subnet with the most free IPv4 addresses + will be used if multiple Subnets matches the filter. + + - `random` (boolean) - A random Subnet will be used if multiple Subnets + matches the filter. `most_free` have precendence over this. + + `subnet_id` take precedence over this. + +- `subnet_id` (string) - If using VPC, the ID of the subnet, such as + subnet-12345def, where Packer will launch the EC2 instance. This field is + required if you are using an non-default VPC. + +- `license_specifications` ([]LicenseSpecification) - The license configurations. + + HCL2 example: + ```hcl + source "amazon-ebs" "basic-example" { + license_specifications { + license_configuration_request = { + license_configuration_arn = "${var.license_configuration_arn}" + } + } + } + ``` + + JSON example: + ```json + "builders" [ + { + "type": "amazon-ebs", + "license_specifications": [ + { + "license_configuration_request": { + "license_configuration_arn": "{{user `license_configuration_arn`}}" + } + } + ] + } + ] + ``` + + Each `license_configuration_request` describes a license configuration, + the properties of which are: + + - `license_configuration_arn` (string) - The Amazon Resource Name (ARN) + of the license configuration. + +- `placement` (Placement) - Describes the placement of an instance. + + HCL2 example: + ```hcl + source "amazon-ebs" "basic-example" { + placement = { + host_resource_group_arn = "${var.host_resource_group_arn}" + tenancy = "${var.placement_tenancy}" + } + } + ``` + + JSON example: + ```json + "builders" [ + { + "type": "amazon-ebs", + "placement": { + "host_resource_group_arn": "{{user `host_resource_group_arn`}}", + "tenancy": "{{user `placement_tenancy`}}" + } + } + ] + ``` + + - `host_resource_group_arn` (string) - The ARN of the host resource + group in which to launch the instances. If you specify a host + resource group ARN, omit the Tenancy parameter or set it to `host`. + - `tenancy` (string) - The tenancy of the instance (if the instance is + running in a VPC). An instance with a tenancy of `dedicated` runs on + single-tenant hardware. The default is `default`, meaning shared + tenancy. Allowed values are `default`, `dedicated` and `host`. + +- `tenancy` (string) - Deprecated: Use Placement Tenancy instead. + +- `temporary_security_group_source_cidrs` ([]string) - A list of IPv4 CIDR blocks to be authorized access to the instance, when + packer is creating a temporary security group. + + The default is [`0.0.0.0/0`] (i.e., allow any IPv4 source). + Use `temporary_security_group_source_public_ip` to allow current host's + public IP instead of any IPv4 source. + This is only used when `security_group_id` or `security_group_ids` is not + specified. + +- `temporary_security_group_source_public_ip` (bool) - When enabled, use public IP of the host (obtained from https://checkip.amazonaws.com) + as CIDR block to be authorized access to the instance, when packer + is creating a temporary security group. Defaults to `false`. + + This is only used when `security_group_id`, `security_group_ids`, + and `temporary_security_group_source_cidrs` are not specified. + +- `user_data` (string) - User data to apply when launching the instance. Note + that you need to be careful about escaping characters due to the templates + being JSON. It is often more convenient to use user_data_file, instead. + Packer will not automatically wait for a user script to finish before + shutting down the instance this must be handled in a provisioner. + +- `user_data_file` (string) - Path to a file that will be used for the user + data when launching the instance. + +- `vpc_filter` (VpcFilterOptions) - Filters used to populate the `vpc_id` field. + + HCL2 example: + ```hcl + source "amazon-ebs" "basic-example" { + vpc_filter { + filters = { + "tag:Class": "build", + "isDefault": "false", + "cidr": "/24" + } + } + } + ``` + + JSON Example: + ```json + "builders" [ + { + "type": "amazon-ebs", + "vpc_filter": { + "filters": { + "tag:Class": "build", + "isDefault": "false", + "cidr": "/24" + } + } + } + ] + ``` + + This selects the VPC with tag `Class` with the value `build`, which is not + the default VPC, and have a IPv4 CIDR block of `/24`. NOTE: This will fail + unless *exactly* one VPC is returned. + + - `filters` (map[string,string] | multiple filters are allowed when seperated by commas) - filters used to select a `vpc_id`. NOTE: + This will fail unless *exactly* one VPC is returned. Any filter + described in the docs for + [DescribeVpcs](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeVpcs.html) + is valid. + + `vpc_id` take precedence over this. + +- `vpc_id` (string) - If launching into a VPC subnet, Packer needs the VPC ID + in order to create a temporary security group within the VPC. Requires + subnet_id to be set. If this field is left blank, Packer will try to get + the VPC ID from the subnet_id. + +- `windows_password_timeout` (duration string | ex: "1h5m2s") - The timeout for waiting for a Windows + password for Windows instances. Defaults to 20 minutes. Example value: + 10m + +- `metadata_options` (MetadataOptions) - [Metadata Settings](#metadata-settings) + +- `ssh_interface` (string) - One of `public_ip`, `private_ip`, `public_dns`, `private_dns` or `session_manager`. + If set, either the public IP address, private IP address, public DNS name + or private DNS name will be used as the host for SSH. The default behaviour + if inside a VPC is to use the public IP address if available, otherwise + the private IP address will be used. If not in a VPC the public DNS name + will be used. Also works for WinRM. + + Where Packer is configured for an outbound proxy but WinRM traffic + should be direct, `ssh_interface` must be set to `private_dns` and + `.compute.internal` included in the `NO_PROXY` environment + variable. + + When using `session_manager` the machine running Packer must have + the AWS Session Manager Plugin installed and within the users' system path. + Connectivity via the `session_manager` interface establishes a secure tunnel + between the local host and the remote host on an available local port to the specified `ssh_port`. + See [Session Manager Connections](#session-manager-connections) for more information. + - Session manager connectivity is currently only implemented for the SSH communicator, not the WinRM communicator. + - Upon termination the secure tunnel will be terminated automatically, if however there is a failure in + terminating the tunnel it will automatically terminate itself after 20 minutes of inactivity. + +- `pause_before_ssm` (duration string | ex: "1h5m2s") - The time to wait before establishing the Session Manager session. + The value of this should be a duration. Examples are + `5s` and `1m30s` which will cause Packer to wait five seconds and one + minute 30 seconds, respectively. If no set, defaults to 10 seconds. + This option is useful when the remote port takes longer to become available. + +- `session_manager_port` (int) - Which port to connect the local end of the session tunnel to. If + left blank, Packer will choose a port for you from available ports. + This option is only used when `ssh_interface` is set `session_manager`. + + + + +#### Metadata Settings + + + +Configures the metadata options. +See [Configure IMDS](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html) for details. + + + + + + +- `http_endpoint` (string) - A string to enable or disable the IMDS endpoint for an instance. Defaults to enabled. + Accepts either "enabled" or "disabled" + +- `http_tokens` (string) - A string to either set the use of IMDSv2 for the instance to optional or required. Defaults to "optional". + Accepts either "optional" or "required" + +- `http_put_response_hop_limit` (int64) - A numerical value to set an upper limit for the amount of hops allowed when communicating with IMDS endpoints. + Defaults to 1. + +- `instance_metadata_tags` (string) - A string to enable or disable access to instance tags from the instance metadata. Defaults to disabled. + Access to instance metadata tags is available for commercial regions. For non-commercial regions please check availability before enabling. + Accepts either "enabled" or "disabled" + + + + +Usage Example + +**HCL2** + +```hcl +source "amazon-ebs" "basic-example" { + region = "us-east-1" + source_ami = "ami-fce3c696" + instance_type = "t2.micro" + ssh_username = "ubuntu" + ami_name = "packer_AWS_example_{{timestamp}}" + metadata_options { + http_endpoint = "enabled" + http_tokens = "required" + http_put_response_hop_limit = 1 + } +} +``` + +**JSON** + +```json +{ + "variables": { + "aws_access_key": "{{env `AWS_ACCESS_KEY_ID`}}", + "aws_secret_key": "{{env `AWS_SECRET_ACCESS_KEY`}}" + }, + "builders": [ + { + "type": "amazon-ebs", + "access_key": "{{user `aws_access_key`}}", + "secret_key": "{{user `aws_secret_key`}}", + "region": "us-east-1", + "source_ami": "ami-fce3c696", + "instance_type": "t2.micro", + "ssh_username": "ubuntu", + "ami_name": "packer_AWS {{timestamp}}", + "metadata_options": { + "http_endpoint": "enabled", + "http_tokens": "required", + "http_put_response_hop_limit": 1 + } + } + ] +} +``` + +##### Enforce Instance Metadata Service v2 + +The Amazon builder has support for enforcing metadata service v2 (imdsv2) on a running instance and on the resulting AMI generated from a Packer build. +To enable support for both there are two key attributes that must be defined. + +**HCL2** + +```hcl +source "amazon-ebs" "basic-example" { + region = "us-east-1" + source_ami = "ami-fce3c696" + instance_type = "t2.micro" + ssh_username = "ubuntu" + ami_name = "packer_AWS_example_{{timestamp}}" + # enforces imdsv2 support on the running instance being provisioned by Packer + metadata_options { + http_endpoint = "enabled" + http_tokens = "required" + http_put_response_hop_limit = 1 + } + imds_support = "v2.0" # enforces imdsv2 support on the resulting AMI +} +``` + +### Session Manager Connections + +Support for the AWS Systems Manager session manager lets users manage EC2 instances without the need to open inbound ports, or maintain bastion hosts. Session manager connectivity relies on the use of the [session manager plugin](#session-manager-plugin) to open a secure tunnel between the local machine and the remote instance. Once the tunnel has been created all SSH communication will be tunneled through SSM to the remote instance. + +-> Note: Session manager connectivity is currently only implemented for the SSH communicator, not the WinRM Communicator. + +To use the session manager as the connection interface for the SSH communicator you need to add the following configuration options to the Amazon builder options: + +- `ssh_interface`: The ssh interface must be set to "session_manager". When using this option the builder will create an SSM tunnel to the configured `ssh_port` (defaults to 22) on the remote host. +- `iam_instance_profile`: A valid instance profile granting Systems Manager permissions to manage the remote instance is required in order for the aws ssm-agent to start and stop session connections. + See below for more details on [IAM instance profile for Systems Manager](#iam-instance-profile-for-systems-manager). + +#### Optional + +- `session_manager_port`: A local port on the host machine that should be used as the local end of the session tunnel to the remote host. If not specified Packer will find an available port to use. +- `temporary_iam_instance_profile_policy_document`: Creates a temporary instance profile policy document to grant Systems Manager permissions to the Ec2 instance. This is an alternative to using an existing `iam_instance_profile`. + +HCL2 example: + +```hcl +# file: example.pkr.hcl + +# In order to get these variables to read from the environment, +# set the environment variables to have the same name as the declared +# variables, with the prefix PKR_VAR_. +# You could also hardcode them into the file, but we do not recommend that. + +data "amazon-ami" "example" { + filters = { + virtualization-type = "hvm" + name = "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*" + root-device-type = "ebs" + } + owners = ["099720109477"] + most_recent = true + region = "us-east-1" +} + +source "amazon-ebs" "ssm-example" { + ami_name = "packer_AWS {{timestamp}}" + instance_type = "t2.micro" + region = "us-east-1" + source_ami = data.amazon-ami.example.id + ssh_username = "ubuntu" + ssh_interface = "session_manager" + communicator = "ssh" + iam_instance_profile = "myinstanceprofile" +} + +build { + sources = ["source.amazon-ebs.ssm-example"] + + provisioner "shell" { + inline = ["echo Connected via SSM at '${build.User}@${build.Host}:${build.Port}'"] + } +} +``` + +JSON example: + +```json +{ + "builders": [ + { + "type": "amazon-ebs", + "ami_name": "packer-ami-{{timestamp}}", + "instance_type": "t2.micro", + "source_ami_filter": { + "filters": { + "virtualization-type": "hvm", + "name": "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*", + "root-device-type": "ebs" + }, + "owners": ["099720109477"], + "most_recent": true + }, + "ssh_username": "ubuntu", + "ssh_interface": "session_manager", + "communicator": "ssh", + "iam_instance_profile": "{{user `iam_instance_profile`}}" + } + ], + "provisioners": [ + { + "type": "shell", + "inline": [ + "echo Connected via SSM at '{{build `User`}}@{{build `Host`}}:{{build `Port`}}'" + ] + } + ] +} +``` + +#### Session Manager Plugin + +Connectivity via the session manager requires the use of a session-manger-plugin, which needs to be installed alongside Packer, and an instance AMI that is capable of running the AWS ssm-agent - see [About SSM Agent](https://docs.aws.amazon.com/systems-manager/latest/userguide/prereqs-ssm-agent.html) for details on supported AMIs. + +In order for Packer to start and end sessions that connect you to your managed instances, you must first install the Session Manager plugin on your local machine. The plugin can be installed on supported versions of Microsoft Windows, macOS, Linux, and Ubuntu Server. +[Installation instructions for the session-manager-plugin](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html) + +#### IAM instance profile for Systems Manager + +By default Systems Manager doesn't have permission to perform actions on created instances so SSM access must be granted by creating an instance profile with the `AmazonSSMManagedInstanceCore` policy. The instance profile can then be attached to any instance you wish to manage via the session-manager-plugin. See [Adding System Manager instance profile](https://docs.aws.amazon.com/systems-manager/latest/userguide/setup-instance-profile.html#instance-profile-add-permissions) for details on creating the required instance profile. + +#### Permissions for Closing the Tunnel + +To close the SSM tunnels created, this plugin relies on being able to call +[DescribeInstanceStatus](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeInstanceStatus.html). +In case this is not possible you might see a `Bad exit status` message in the logs. + +The absence of this permission won't prevent you from building the AMI, and the error only means that packer is not able to close the tunnel gracefully. + + +### Block Devices Configuration + +Block devices can be nested in the +[ami_block_device_mappings](#ami_block_device_mappings) or the +[launch_block_device_mappings](#launch_block_device_mappings) array. + + + +These will be attached when launching your instance. Your +options here may vary depending on the type of VM you use. + +Example use case: + +The following mapping will tell Packer to encrypt the root volume of the +build instance at launch using a specific non-default kms key: + +HCL2 example: + +```hcl + + launch_block_device_mappings { + device_name = "/dev/sda1" + encrypted = true + kms_key_id = "1a2b3c4d-5e6f-1a2b-3c4d-5e6f1a2b3c4d" + } + +``` + +JSON example: +```json +"launch_block_device_mappings": [ + + { + "device_name": "/dev/sda1", + "encrypted": true, + "kms_key_id": "1a2b3c4d-5e6f-1a2b-3c4d-5e6f1a2b3c4d" + } + +] +``` + +Please note that the kms_key_id option in this example exists for +launch_block_device_mappings but not ami_block_device_mappings. + +Documentation for Block Devices Mappings can be found here: +https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/block-device-mapping-concepts.html + + + + +**Optional:** + + + +- `delete_on_termination` (bool) - Indicates whether the EBS volume is deleted on instance termination. + Default false. NOTE: If this value is not explicitly set to true and + volumes are not cleaned up by an alternative method, additional volumes + will accumulate after every build. + +- `device_name` (string) - The device name exposed to the instance (for example, /dev/sdh or xvdh). + Required for every device in the block device mapping. + +- `encrypted` (boolean) - Indicates whether or not to encrypt the volume. By default, Packer will + keep the encryption setting to what it was in the source image. Setting + false will result in an unencrypted device, and true will result in an + encrypted one. + +- `iops` (\*int64) - The number of I/O operations per second (IOPS) that the volume supports. + See the documentation on + [IOPs](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_EbsBlockDevice.html) + for more information + +- `no_device` (bool) - Suppresses the specified device included in the block device mapping of + the AMI. + +- `snapshot_id` (string) - The ID of the snapshot. + +- `throughput` (\*int64) - The throughput for gp3 volumes, only valid for gp3 types + See the documentation on + [Throughput](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_EbsBlockDevice.html) + for more information + +- `virtual_name` (string) - The virtual device name. See the documentation on Block Device Mapping + for more information. + +- `volume_type` (string) - The volume type. gp2 & gp3 for General Purpose (SSD) volumes, io1 & io2 + for Provisioned IOPS (SSD) volumes, st1 for Throughput Optimized HDD, + sc1 for Cold HDD, and standard for Magnetic volumes. + +- `volume_size` (int64) - The size of the volume, in GiB. Required if not specifying a + snapshot_id. + +- `kms_key_id` (string) - ID, alias or ARN of the KMS key to use for boot volume encryption. + This option exists for launch_block_device_mappings but not + ami_block_device_mappings. The kms key id defined here only applies to + the original build region; if the AMI gets copied to other regions, the + volume in those regions will be encrypted by the default EBS KMS key. + For valid formats see KmsKeyId in the [AWS API docs - + CopyImage](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CopyImage.html) + This field is validated by Packer. When using an alias, you will have to + prefix kms_key_id with alias/. + + + + +### Communicator Configuration + +**Optional:** + + + +- `communicator` (string) - Packer currently supports three kinds of communicators: + + - `none` - No communicator will be used. If this is set, most + provisioners also can't be used. + + - `ssh` - An SSH connection will be established to the machine. This + is usually the default. + + - `winrm` - A WinRM connection will be established. + + In addition to the above, some builders have custom communicators they + can use. For example, the Docker builder has a "docker" communicator + that uses `docker exec` and `docker cp` to execute scripts and copy + files. + +- `pause_before_connecting` (duration string | ex: "1h5m2s") - We recommend that you enable SSH or WinRM as the very last step in your + guest's bootstrap script, but sometimes you may have a race condition + where you need Packer to wait before attempting to connect to your + guest. + + If you end up in this situation, you can use the template option + `pause_before_connecting`. By default, there is no pause. For example if + you set `pause_before_connecting` to `10m` Packer will check whether it + can connect, as normal. But once a connection attempt is successful, it + will disconnect and then wait 10 minutes before connecting to the guest + and beginning provisioning. + + + + + + +- `ssh_host` (string) - The address to SSH to. This usually is automatically configured by the + builder. + +- `ssh_port` (int) - The port to connect to SSH. This defaults to `22`. + +- `ssh_username` (string) - The username to connect to SSH with. Required if using SSH. + +- `ssh_password` (string) - A plaintext password to use to authenticate with SSH. + +- `ssh_ciphers` ([]string) - This overrides the value of ciphers supported by default by Golang. + The default value is [ + "aes128-gcm@openssh.com", + "chacha20-poly1305@openssh.com", + "aes128-ctr", "aes192-ctr", "aes256-ctr", + ] + + Valid options for ciphers include: + "aes128-ctr", "aes192-ctr", "aes256-ctr", "aes128-gcm@openssh.com", + "chacha20-poly1305@openssh.com", + "arcfour256", "arcfour128", "arcfour", "aes128-cbc", "3des-cbc", + +- `ssh_clear_authorized_keys` (bool) - If true, Packer will attempt to remove its temporary key from + `~/.ssh/authorized_keys` and `/root/.ssh/authorized_keys`. This is a + mostly cosmetic option, since Packer will delete the temporary private + key from the host system regardless of whether this is set to true + (unless the user has set the `-debug` flag). Defaults to "false"; + currently only works on guests with `sed` installed. + +- `ssh_key_exchange_algorithms` ([]string) - If set, Packer will override the value of key exchange (kex) algorithms + supported by default by Golang. Acceptable values include: + "curve25519-sha256@libssh.org", "ecdh-sha2-nistp256", + "ecdh-sha2-nistp384", "ecdh-sha2-nistp521", + "diffie-hellman-group14-sha1", and "diffie-hellman-group1-sha1". + +- `ssh_certificate_file` (string) - Path to user certificate used to authenticate with SSH. + The `~` can be used in path and will be expanded to the + home directory of current user. + +- `ssh_pty` (bool) - If `true`, a PTY will be requested for the SSH connection. This defaults + to `false`. + +- `ssh_timeout` (duration string | ex: "1h5m2s") - The time to wait for SSH to become available. Packer uses this to + determine when the machine has booted so this is usually quite long. + Example value: `10m`. + This defaults to `5m`, unless `ssh_handshake_attempts` is set. + +- `ssh_disable_agent_forwarding` (bool) - If true, SSH agent forwarding will be disabled. Defaults to `false`. + +- `ssh_handshake_attempts` (int) - The number of handshakes to attempt with SSH once it can connect. + This defaults to `10`, unless a `ssh_timeout` is set. + +- `ssh_bastion_host` (string) - A bastion host to use for the actual SSH connection. + +- `ssh_bastion_port` (int) - The port of the bastion host. Defaults to `22`. + +- `ssh_bastion_agent_auth` (bool) - If `true`, the local SSH agent will be used to authenticate with the + bastion host. Defaults to `false`. + +- `ssh_bastion_username` (string) - The username to connect to the bastion host. + +- `ssh_bastion_password` (string) - The password to use to authenticate with the bastion host. + +- `ssh_bastion_interactive` (bool) - If `true`, the keyboard-interactive used to authenticate with bastion host. + +- `ssh_bastion_private_key_file` (string) - Path to a PEM encoded private key file to use to authenticate with the + bastion host. The `~` can be used in path and will be expanded to the + home directory of current user. + +- `ssh_bastion_certificate_file` (string) - Path to user certificate used to authenticate with bastion host. + The `~` can be used in path and will be expanded to the + home directory of current user. + +- `ssh_file_transfer_method` (string) - `scp` or `sftp` - How to transfer files, Secure copy (default) or SSH + File Transfer Protocol. + + **NOTE**: Guests using Windows with Win32-OpenSSH v9.1.0.0p1-Beta, scp + (the default protocol for copying data) returns a a non-zero error code since the MOTW + cannot be set, which cause any file transfer to fail. As a workaround you can override the transfer protocol + with SFTP instead `ssh_file_transfer_protocol = "sftp"`. + +- `ssh_proxy_host` (string) - A SOCKS proxy host to use for SSH connection + +- `ssh_proxy_port` (int) - A port of the SOCKS proxy. Defaults to `1080`. + +- `ssh_proxy_username` (string) - The optional username to authenticate with the proxy server. + +- `ssh_proxy_password` (string) - The optional password to use to authenticate with the proxy server. + +- `ssh_keep_alive_interval` (duration string | ex: "1h5m2s") - How often to send "keep alive" messages to the server. Set to a negative + value (`-1s`) to disable. Example value: `10s`. Defaults to `5s`. + +- `ssh_read_write_timeout` (duration string | ex: "1h5m2s") - The amount of time to wait for a remote command to end. This might be + useful if, for example, packer hangs on a connection after a reboot. + Example: `5m`. Disabled by default. + +- `ssh_remote_tunnels` ([]string) - + +- `ssh_local_tunnels` ([]string) - + + + + + + +- `temporary_key_pair_type` (string) - `dsa` | `ecdsa` | `ed25519` | `rsa` ( the default ) + + Specifies the type of key to create. The possible values are 'dsa', + 'ecdsa', 'ed25519', or 'rsa'. + + NOTE: DSA is deprecated and no longer recognized as secure, please + consider other alternatives like RSA or ED25519. + +- `temporary_key_pair_bits` (int) - Specifies the number of bits in the key to create. For RSA keys, the + minimum size is 1024 bits and the default is 4096 bits. Generally, 3072 + bits is considered sufficient. DSA keys must be exactly 1024 bits as + specified by FIPS 186-2. For ECDSA keys, bits determines the key length + by selecting from one of three elliptic curve sizes: 256, 384 or 521 + bits. Attempting to use bit lengths other than these three values for + ECDSA keys will fail. Ed25519 keys have a fixed length and bits will be + ignored. + + NOTE: DSA is deprecated and no longer recognized as secure as specified + by FIPS 186-5, please consider other alternatives like RSA or ED25519. + + + + +- `ssh_keypair_name` (string) - If specified, this is the key that will be used for SSH with the + machine. The key must match a key pair name loaded up into the remote. + By default, this is blank, and Packer will generate a temporary keypair + unless [`ssh_password`](#ssh_password) is used. + [`ssh_private_key_file`](#ssh_private_key_file) or + [`ssh_agent_auth`](#ssh_agent_auth) must be specified when + [`ssh_keypair_name`](#ssh_keypair_name) is utilized. + + +- `ssh_private_key_file` (string) - Path to a PEM encoded private key file to use to authenticate with SSH. + The `~` can be used in path and will be expanded to the home directory + of current user. + + +- `ssh_agent_auth` (bool) - If true, the local SSH agent will be used to authenticate connections to + the source instance. No temporary keypair will be created, and the + values of [`ssh_password`](#ssh_password) and + [`ssh_private_key_file`](#ssh_private_key_file) will be ignored. The + environment variable `SSH_AUTH_SOCK` must be set for this option to work + properly. + + +## Basic Example + +Here is a basic example. You will need to provide access keys, and may need to +change the AMI IDs according to what images exist at the time the template is +run: + +**HCL2** + +```hcl +// To make Packer read these variables from the environment into the var object, +// set the environment variables to have the same name as the declared +// variables, with the prefix PKR_VAR_. + +// There are other ways to [set variables](/packer/docs/templates/hcl_templates/variables#assigning-values-to-build-variables) +// including from a var file or as a command argument. + +// export PKR_VAR_aws_access_key=$YOURKEY +variable "aws_access_key" { + type = string + // default = "hardcoded_key" +} + +// export PKR_VAR_aws_secret_key=$YOURSECRETKEY +variable "aws_secret_key" { + type = string + // default = "hardcoded_secret_key" +} + +source "amazon-ebs" "basic-example" { + access_key = var.aws_access_key + secret_key = var.aws_secret_key + region = "us-east-1" + source_ami = "ami-fce3c696" + instance_type = "t2.micro" + ssh_username = "ubuntu" + ami_name = "packer_AWS {{timestamp}}" +} + +build { + sources = [ + "source.amazon-ebs.basic-example" + ] +} +``` + +**JSON** + +```json +{ + "variables": { + "aws_access_key": "{{env `AWS_ACCESS_KEY_ID`}}", + "aws_secret_key": "{{env `AWS_SECRET_ACCESS_KEY`}}" +}, + "builders": [ + { + "type": "amazon-ebs", + "access_key": "{{user `aws_access_key`}}", + "secret_key": "{{user `aws_secret_key`}}", + "region": "us-east-1", + "source_ami": "ami-fce3c696", + "instance_type": "t2.micro", + "ssh_username": "ubuntu", + "ami_name": "packer_AWS {{timestamp}}" + } + ] +} +``` + + +-> **Note:** Packer can also read the access key and secret access key directly +from environmental variables instead of being set as user variables. See the +configuration reference in the section above for more information on what +environmental variables Packer will look for. + +Further information on locating AMI IDs and their relationship to instance +types and regions can be found in the AWS EC2 Documentation [for +Linux](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/finding-an-ami.html) +or [for +Windows](http://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/finding-an-ami.html). + +### Fast Launch Config + + + +FastLaunchConfig is the configuration for setting up fast-launch for Windows AMIs + +NOTE: requires the Windows image to be sysprep'd to enable fast-launch. See the +AWS docs for more information: +https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/win-ami-config-fast-launch.html + + + + +**Optional:** + + + +- `enable_fast_launch` (bool) - Configure fast-launch for Windows AMIs + +- `template_id` (string) - The ID of the launch template to use for fast launch for the main AMI. + + This cannot be specified in conjunction with the template name. + + If no template is specified, the default launch template will be used, + as specified in the AWS docs. + + If you copy the AMI to other regions, this option should not + be used, use instead the `fast_launch_template_config` option. + +- `template_name` (string) - The name of the launch template to use for fast launch for the main AMI. + + This cannot be specified in conjunction with the template ID. + + If no template is specified, the default launch template will be used, + as specified in the AWS docs. + + If you copy the AMI to other regions, this option should not + be used, use instead the `fast_launch_template_config` option. + +- `template_version` (int) - The version of the launch template to use for fast launch for the main AMI. + + If unspecified, and a template is referenced, this will default to + the latest version available for the template. + + If you copy the AMI to other regions, this option should not + be used, use instead the `fast_launch_template_config` option. + +- `region_launch_templates` ([]FastLaunchTemplateConfig) - RegionLaunchTemplates is the list of launch templates per region. + + This should be specified if you want to use a custom launch + template for your fast-launched images, and you are copying + the image to other regions. + + All regions don't need a launch template configuration, but for + each that don't have a launch template specified, AWS will pick + a default one for that purpose. + + For information about each entry, refer to the + [Fast Launch Template Config](#fast-launch-template-config) documentation. + +- `max_parallel_launches` (int) - Maximum number of instances to launch for creating pre-provisioned snapshots + + If specified, must be a minimum of `6` + +- `target_resource_count` (int) - The number of snapshots to pre-provision for later launching windows instances + from the resulting fast-launch AMI. + + If unspecified, this will create the default number of snapshots (as of + march 2023, this defaults to 5 on AWS) + + + + +#### Fast Launch Template Config + + + +- `region` (string) - The region in which to find the launch template to use + + + + +**Optional:** + + + +- `template_id` (string) - The ID of the launch template to use for the fast launch + + This cannot be specified in conjunction with the template name. + + If no template is specified, the default launch template will be used, + as specified in the AWS docs. + +- `template_name` (string) - The name of the launch template to use for fast launch + + This cannot be specified in conjunction with the template ID. + + If no template is specified, the default launch template will be used, + as specified in the AWS docs. + +- `template_version` (int) - The version of the launch template to use + + If unspecified, and a template is referenced, this will default to + the latest version available for the template. + + + + +## Accessing the Instance to Debug + +If you need to access the instance to debug for some reason, run the builder +with the `-debug` flag. In debug mode, the Amazon builder will save the private +key in the current directory and will output the DNS or IP information as well. +You can use this information to access the instance as it is running. + +## AMI Block Device Mappings Example + +Here is an example using the optional AMI block device mappings. Our +configuration of `launch_block_device_mappings` will expand the root volume +(`/dev/sda`) to 40gb during the build (up from the default of 8gb). With +`ami_block_device_mappings` AWS will attach additional volumes `/dev/sdb` and +`/dev/sdc` when we boot a new instance of our AMI. + +**HCL2** + +```hcl +source "amazon-ebs" "basic-example" { + region = "us-east-1" + source_ami = "ami-fce3c696" + instance_type = "t2.micro" + ssh_username = "ubuntu" + ami_name = "packer_AWS_example_{{timestamp}}" + launch_block_device_mappings { + device_name = "/dev/sda1" + volume_size = 40 + volume_type = "gp2" + delete_on_termination = true + } + // Notice that instead of providing a list of mappings, you are just providing + // multiple mappings in a row. This diverges from the JSON template format. + ami_block_device_mappings { + device_name = "/dev/sdb" + virtual_name = "ephemeral0" + } + ami_block_device_mappings { + device_name = "/dev/sdc" + virtual_name = "ephemeral1" + } +} + +build { + sources = [ + "source.amazon-ebs.basic-example" + ] +} +``` + +**JSON** + +```json +{ + "builders": [ + { + "type": "amazon-ebs", + "region": "us-east-1", + "source_ami": "ami-fce3c696", + "instance_type": "t2.micro", + "ssh_username": "ubuntu", + "ami_name": "packer-quick-start {{timestamp}}", + "launch_block_device_mappings": [ + { + "device_name": "/dev/sda1", + "volume_size": 40, + "volume_type": "gp2", + "delete_on_termination": true + } + ], + "ami_block_device_mappings": [ + { + "device_name": "/dev/sdb", + "virtual_name": "ephemeral0" + }, + { + "device_name": "/dev/sdc", + "virtual_name": "ephemeral1" + } + ] + } + ] +} +``` + + +The above build template is functional assuming you have set the environment +variables AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY. + +-> **Note:** Packer uses pre-built AMIs as the source for building images. +These source AMIs may include volumes that are not flagged to be destroyed on +termination of the instance building the new image. Packer will attempt to +clean up all residual volumes that are not designated by the user to remain +after termination. If you need to preserve those source volumes, you can +overwrite the termination setting by setting `delete_on_termination` to `false` +in the `launch_block_device_mappings` block for the device. + +## Build template data + +In configuration directives marked as a template engine above, the following +variables are available: + +- `BuildRegion` - The region (for example `eu-central-1`) where Packer is + building the AMI. +- `SourceAMI` - The source AMI ID (for example `ami-a2412fcd`) used to build + the AMI. +- `SourceAMICreationDate` - The source AMI creation date (for example `"2020-05-14T19:26:34.000Z"`). +- `SourceAMIName` - The source AMI Name (for example + `ubuntu/images/ebs-ssd/ubuntu-xenial-16.04-amd64-server-20180306`) used to + build the AMI. +- `SourceAMIOwner` - The source AMI owner ID. +- `SourceAMIOwnerName` - The source AMI owner alias/name (for example `amazon`). +- `SourceAMITags` - The source AMI Tags, as a `map[string]string` object. + +## Build Shared Information Variables + +This builder generates data that are shared with provisioner and post-processor via build function of [template engine](/packer/docs/templates/legacy_json_templates/engine) for JSON and [contextual variables](/packer/docs/templates/hcl_templates/contextual-variables) for HCL2. + +The generated variables available for this builder are: + +- `BuildRegion` - The region (for example `eu-central-1`) where Packer is + building the AMI. +- `SourceAMI` - The source AMI ID (for example `ami-a2412fcd`) used to build + the AMI. +- `SourceAMICreationDate` - The source AMI creation date (for example `"2020-05-14T19:26:34.000Z"`). +- `SourceAMIName` - The source AMI Name (for example + `ubuntu/images/ebs-ssd/ubuntu-xenial-16.04-amd64-server-20180306`) used to + build the AMI. +- `SourceAMIOwner` - The source AMI owner ID. +- `SourceAMIOwnerName` - The source AMI owner alias/name (for example `amazon`). + +Usage example: + +**HCL2** + +```hcl +# When accessing one of these variables from inside the builder, you need to +# use the golang templating syntax. This is due to an architectural quirk that +# won't be easily resolvable until legacy json templates are deprecated: +build { + source "amazon-ebs" "basic-example" { + tags = { + OS_Version = "Ubuntu" + Release = "Latest" + Base_AMI_ID = "{{ .SourceAMI }}" + Base_AMI_Name = "{{ .SourceAMIName }}" + } + } + + // when accessing one of the variables from a provisioner or post-processor, use + // hcl-syntax + post-processor "manifest" { + output = "manifest.json" + strip_path = true + custom_data = { + source_ami_name = "${build.SourceAMIName}" + } +} +``` + +**JSON** + +```json +"post-processors": [ + { + "type": "manifest", + "output": "manifest.json", + "strip_path": true, + "custom_data": { + "source_ami_name": "{{ build `SourceAMIName` }}" + } + } +] +``` + + +## Tag Example + +Here is an example using the optional AMI tags. This will add the tags +`OS_Version` and `Release` to the finished AMI. As before, you will need to +provide your access keys, and may need to change the source AMI ID based on +what images exist when this template is run: + +**HCL2** + +```hcl +source "amazon-ebs" "basic-example" { + region = "us-east-1" + source_ami = "ami-fce3c696" + instance_type = "t2.micro" + ssh_username = "ubuntu" + ami_name = "packer_tag_example {{timestamp}}" + tags = { + OS_Version = "Ubuntu" + Release = "Latest" + Base_AMI_Name = "{{ .SourceAMIName }}" + Extra = "{{ .SourceAMITags.TagName }}" + } +} + +build { + sources = [ + "source.amazon-ebs.basic-example" + ] +} +``` + +**JSON** + +```json +{ + "builders": [ + { + "type": "amazon-ebs", + "region": "us-east-1", + "source_ami": "ami-fce3c696", + "instance_type": "t2.micro", + "ssh_username": "ubuntu", + "ami_name": "packer-tag-example {{timestamp}}", + "tags": { + "OS_Version": "Ubuntu", + "Release": "Latest", + "Base_AMI_Name": "{{ .SourceAMIName }}", + "Extra": "{{ .SourceAMITags.TagName }}" + } + } + ] +} +``` + + +## Connecting to Windows instances using WinRM + +If you want to launch a Windows instance and connect using WinRM, you will need +to configure WinRM on that instance. The following is a basic powershell script +that can be supplied to AWS using the "user_data_file" option. It enables +WinRM via HTTPS on port 5986, and creates a self-signed certificate to use to +connect. If you are using a certificate from a CA, rather than creating a +self-signed certificate, you can omit the "winrm_insecure" option mentioned +below. + +autogenerated_password_https_bootstrap.txt + +```powershell + + +# MAKE SURE IN YOUR PACKER CONFIG TO SET: +# +# +# "winrm_username": "Administrator", +# "winrm_insecure": true, +# "winrm_use_ssl": true, +# +# + + +write-output "Running User Data Script" +write-host "(host) Running User Data Script" + +Set-ExecutionPolicy Unrestricted -Scope LocalMachine -Force -ErrorAction Ignore + +# Don't set this before Set-ExecutionPolicy as it throws an error +$ErrorActionPreference = "stop" + +# Remove HTTP listener +Remove-Item -Path WSMan:\Localhost\listener\listener* -Recurse + +# Create a self-signed certificate to let ssl work +$Cert = New-SelfSignedCertificate -CertstoreLocation Cert:\LocalMachine\My -DnsName "packer" +New-Item -Path WSMan:\LocalHost\Listener -Transport HTTPS -Address * -CertificateThumbPrint $Cert.Thumbprint -Force + +# WinRM +write-output "Setting up WinRM" +write-host "(host) setting up WinRM" + +cmd.exe /c winrm quickconfig -q +cmd.exe /c winrm set "winrm/config" '@{MaxTimeoutms="1800000"}' +cmd.exe /c winrm set "winrm/config/winrs" '@{MaxMemoryPerShellMB="1024"}' +cmd.exe /c winrm set "winrm/config/service" '@{AllowUnencrypted="true"}' +cmd.exe /c winrm set "winrm/config/client" '@{AllowUnencrypted="true"}' +cmd.exe /c winrm set "winrm/config/service/auth" '@{Basic="true"}' +cmd.exe /c winrm set "winrm/config/client/auth" '@{Basic="true"}' +cmd.exe /c winrm set "winrm/config/service/auth" '@{CredSSP="true"}' +cmd.exe /c winrm set "winrm/config/listener?Address=*+Transport=HTTPS" "@{Port=`"5986`";Hostname=`"packer`";CertificateThumbprint=`"$($Cert.Thumbprint)`"}" +cmd.exe /c netsh advfirewall firewall set rule group="remote administration" new enable=yes +cmd.exe /c netsh firewall add portopening TCP 5986 "Port 5986" +cmd.exe /c net stop winrm +cmd.exe /c sc config winrm start= auto +cmd.exe /c net start winrm + + +``` + +You'll notice that this config does not define a user or password; instead, +Packer will ask AWS to provide a random password that it generates +automatically. The following config will work with the above template: + +**HCL2** + +```hcl +# This example uses a amazon-ami data source rather than a specific AMI. +# this allows us to use the same filter regardless of what region we're in, +# among other benefits. +data "amazon-ami" "example" { + filters = { + virtualization-type = "hvm" + name = "*Windows_Server-2012*English-64Bit-Base*" + root-device-type = "ebs" + } + owners = ["amazon"] + most_recent = true + # Access Region Configuration + region = "us-east-1" +} + +source "amazon-ebs" "winrm-example" { + region = "us-east-1" + source_ami = data.amazon-ami.example.id + instance_type = "t2.micro" + ami_name = "packer_winrm_example {{timestamp}}" + # This user data file sets up winrm and configures it so that the connection + # from Packer is allowed. Without this file being set, Packer will not + # connect to the instance. + user_data_file = "../boot_config/winrm_bootstrap.txt" + communicator = "winrm" + force_deregister = true + winrm_insecure = true + winrm_username = "Administrator" + winrm_use_ssl = true +} + +build { + sources = [ + "source.amazon-ebs.winrm-example" + ] +} +``` + +**JSON** + +```json +{ + "builders": [ + { + "type": "amazon-ebs", + "region": "us-east-1", + "instance_type": "t2.micro", + "source_ami_filter": { + "filters": { + "virtualization-type": "hvm", + "name": "*Windows_Server-2012*English-64Bit-Base*", + "root-device-type": "ebs" + }, + "most_recent": true, + "owners": "amazon" + }, + "ami_name": "default-packer", + "user_data_file": "./boot_config/winrm_bootstrap.txt", + "communicator": "winrm", + "force_deregister": true, + "winrm_insecure": true, + "winrm_username": "Administrator", + "winrm_use_ssl": true + } + ] +} +``` + + +## Windows 2016 Sysprep Commands - For Amazon Windows AMIs Only + +For Amazon Windows 2016 AMIs it is necessary to run Sysprep commands which can +be easily added to the provisioner section. + +**HCL2** + +```hcl +provisioner "powershell" { + inline = [ + "C:/ProgramData/Amazon/EC2-Windows/Launch/Scripts/InitializeInstance.ps1 -Schedule", + "C:/ProgramData/Amazon/EC2-Windows/Launch/Scripts/SysprepInstance.ps1 -NoShutdown" + ] +} +``` + +**JSON** + +```json +{ + "type": "powershell", + "inline": [ + "C:/ProgramData/Amazon/EC2-Windows/Launch/Scripts/InitializeInstance.ps1 -Schedule", + "C:/ProgramData/Amazon/EC2-Windows/Launch/Scripts/SysprepInstance.ps1 -NoShutdown" + ] +} +``` + + +## Which SSH Options to use: + +This chart breaks down what Packer does if you set any of the below SSH options: + +| ssh_password | ssh_private_key_file | ssh_keypair_name | temporary_key_pair_name | Packer will... | +| ------------ | -------------------- | ---------------- | ----------------------- | ------------------------------------------------------------------------------------------ | +| X | - | - | - | ssh authenticating with username and given password | +| - | X | - | - | ssh authenticating with private key file | +| - | X | X | - | ssh authenticating with given private key file and "attaching" the keypair to the instance | +| - | - | - | X | Create a temporary ssh keypair with a particular name, clean it up | +| - | - | - | - | Create a temporary ssh keypair with a default name, clean it up | diff --git a/.web-docs/components/builder/ebssurrogate/README.md b/.web-docs/components/builder/ebssurrogate/README.md new file mode 100644 index 000000000..1c515997c --- /dev/null +++ b/.web-docs/components/builder/ebssurrogate/README.md @@ -0,0 +1,1762 @@ +Type: `amazon-ebssurrogate` +Artifact BuilderId: `mitchellh.amazon.ebssurrogate` + +The `amazon-ebssurrogate` Packer builder is able to create Amazon AMIs by +running a source instance with an attached volume, provisioning the attached +volume in such a way that it can be used as the root volume for the AMI, and +then snapshotting and creating the AMI from that volume. + +This builder can therefore be used to bootstrap scratch-build images - for +example FreeBSD or Ubuntu using ZFS as the root file system. + +This is all done in your own AWS account. This builder will create temporary +key pairs, security group rules, etc., that provide it temporary access to the +instance while the image is being created. + +## Configuration Reference + +There are many configuration options available for the builder. In addition to +the items listed here, you will want to look at the general configuration +references for [AMI](#ami-configuration), +[BlockDevices](#block-devices-configuration), +[Access](#access-configuration), +[Run](#run-configuration) and +[Communicator](#communicator-configuration) +configuration references, which are +necessary for this build to succeed and can be found further down the page. + +### Required: + + + +- `ami_root_device` (RootBlockDevice) - A block device mapping describing the root device of the AMI. This looks + like the mappings in `ami_block_device_mapping`, except with an + additional field: + + - `source_device_name` (string) - The device name of the block device on + the source instance to be used as the root device for the AMI. This + must correspond to a block device in `launch_block_device_mapping`. + + + + +### Optional: + + + +- `ami_block_device_mappings` (awscommon.BlockDevices) - Add one or more block device mappings to the AMI. These will be attached + when booting a new instance from your AMI. To add a block device during + the Packer build see `launch_block_device_mappings` below. Your options + here may vary depending on the type of VM you use. See the + [BlockDevices](#block-devices-configuration) documentation for fields. + +- `launch_block_device_mappings` (BlockDevices) - Add one or more block devices before the Packer build starts. If you add + instance store volumes or EBS volumes in addition to the root device + volume, the created AMI will contain block device mapping information + for those volumes. Amazon creates snapshots of the source instance's + root volume and any other EBS volumes described here. When you launch an + instance from this new AMI, the instance automatically launches with + these additional volumes, and will restore them from snapshots taken + from the source instance. See the + [BlockDevices](#block-devices-configuration) documentation for fields. + +- `run_volume_tags` (map[string]string) - Tags to apply to the volumes that are *launched* to create the AMI. + These tags are *not* applied to the resulting AMI unless they're + duplicated in `tags`. This is a [template + engine](/packer/docs/templates/legacy_json_templates/engine), see [Build template + data](#build-template-data) for more information. + +- `run_volume_tag` ([]{name string, value string}) - Same as [`run_volume_tags`](#run_volume_tags) but defined as a singular + block containing a `name` and a `value` field. In HCL2 mode the + [`dynamic_block`](https://packer.io/docs/templates/hcl_templates/expressions.html#dynamic-blocks) + will allow you to create those programatically. + +- `ami_architecture` (string) - what architecture to use when registering the final AMI; valid options + are "arm64", "i386", "x86_64", or "x86_64_mac". Defaults to "x86_64". + +- `boot_mode` (string) - The boot mode. Valid options are `legacy-bios` and `uefi`. See the documentation on + [boot modes](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ami-boot.html) for + more information. Defaults to `legacy-bios` when `ami_architecture` is `x86_64` and + `uefi` when `ami_architecture` is `arm64`. + +- `uefi_data` (string) - Base64 representation of the non-volatile UEFI variable store. For more information + see [AWS documentation](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/uefi-secure-boot-optionB.html). + +- `tpm_support` (string) - NitroTPM Support. Valid options are `v2.0`. See the documentation on + [NitroTPM Support](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enable-nitrotpm-support-on-ami.html) for + more information. Only enabled if a valid option is provided, otherwise ignored. + +- `use_create_image` (bool) - Whether to use the CreateImage or RegisterImage API when creating the AMI. + When set to `true`, the CreateImage API is used and will create the image + from the instance itself, and inherit properties from the instance. + When set to `false`, the RegisterImage API is used and the image is created using + a snapshot of the specified EBS volume, and no properties are inherited from the instance. + Defaults to `false`. + Ref: https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateImage.html + https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RegisterImage.html + + + + +### AMI Configuration + +#### Required: + + + +- `ami_name` (string) - The name of the resulting AMI that will appear when managing AMIs in the + AWS console or via APIs. This must be unique. To help make this unique, + use a function like timestamp (see [template + engine](/packer/docs/templates/legacy_json_templates/engine) for more info). + + + + +#### Optional: + + + +- `ami_description` (string) - The description to set for the resulting + AMI(s). By default this description is empty. This is a + [template engine](/packer/docs/templates/legacy_json_templates/engine), see [Build template + data](#build-template-data) for more information. + +- `ami_virtualization_type` (string) - The type of virtualization for the AMI + you are building. This option is required to register HVM images. Can be + paravirtual (default) or hvm. + +- `ami_users` ([]string) - A list of account IDs that have access to + launch the resulting AMI(s). By default no additional users other than the + user creating the AMI has permissions to launch it. + +- `ami_groups` ([]string) - A list of groups that have access to + launch the resulting AMI(s). By default no groups have permission to launch + the AMI. `all` will make the AMI publicly accessible. + AWS currently doesn't accept any value other than "all" + +- `ami_org_arns` ([]string) - A list of Amazon Resource Names (ARN) of AWS Organizations that have access to + launch the resulting AMI(s). By default no organizations have permission to launch + the AMI. + +- `ami_ou_arns` ([]string) - A list of Amazon Resource Names (ARN) of AWS Organizations organizational units (OU) that have access to + launch the resulting AMI(s). By default no organizational units have permission to launch + the AMI. + +- `ami_product_codes` ([]string) - A list of product codes to + associate with the AMI. By default no product codes are associated with the + AMI. + +- `ami_regions` ([]string) - A list of regions to copy the AMI to. + Tags and attributes are copied along with the AMI. AMI copying takes time + depending on the size of the AMI, but will generally take many minutes. + +- `skip_region_validation` (bool) - Set to true if you want to skip + validation of the ami_regions configuration option. Default false. + +- `tags` (map[string]string) - Key/value pair tags applied to the AMI. This is a [template + engine](/packer/docs/templates/legacy_json_templates/engine), see [Build template + data](#build-template-data) for more information. + + The builder no longer adds a "Name": "Packer Builder" entry to the tags. + +- `tag` ([]{key string, value string}) - Same as [`tags`](#tags) but defined as a singular repeatable block + containing a `key` and a `value` field. In HCL2 mode the + [`dynamic_block`](/packer/docs/templates/hcl_templates/expressions#dynamic-blocks) + will allow you to create those programatically. + +- `ena_support` (boolean) - Enable enhanced networking (ENA but not SriovNetSupport) on + HVM-compatible AMIs. If set, add `ec2:ModifyInstanceAttribute` to your + AWS IAM policy. + + Note: you must make sure enhanced networking is enabled on your + instance. See [Amazon's documentation on enabling enhanced + networking](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enhanced-networking.html#enabling_enhanced_networking). + +- `sriov_support` (bool) - Enable enhanced networking (SriovNetSupport but not ENA) on + HVM-compatible AMIs. If true, add `ec2:ModifyInstanceAttribute` to your + AWS IAM policy. Note: you must make sure enhanced networking is enabled + on your instance. See [Amazon's documentation on enabling enhanced + networking](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enhanced-networking.html#enabling_enhanced_networking). + Default `false`. + +- `force_deregister` (bool) - Force Packer to first deregister an existing + AMI if one with the same name already exists. Default false. + +- `force_delete_snapshot` (bool) - Force Packer to delete snapshots + associated with AMIs, which have been deregistered by force_deregister. + Default false. + +- `encrypt_boot` (boolean) - Whether or not to encrypt the resulting AMI when + copying a provisioned instance to an AMI. By default, Packer will keep + the encryption setting to what it was in the source image. Setting false + will result in an unencrypted image, and true will result in an encrypted + one. + + If you have used the `launch_block_device_mappings` to set an encryption + key and that key is the same as the one you want the image encrypted with + at the end, then you don't need to set this field; leaving it empty will + prevent an unnecessary extra copy step and save you some time. + + Please note that if you are using an account with the global "Always + encrypt new EBS volumes" option set to `true`, Packer will be unable to + override this setting, and the final image will be encrypted whether + you set this value or not. + +- `kms_key_id` (string) - ID, alias or ARN of the KMS key to use for AMI encryption. This + only applies to the main `region` -- any regions the AMI gets copied to + will be encrypted by the default EBS KMS key for that region, + unless you set region-specific keys in `region_kms_key_ids`. + + Set this value if you select `encrypt_boot`, but don't want to use the + region's default KMS key. + + If you have a custom kms key you'd like to apply to the launch volume, + and are only building in one region, it is more efficient to leave this + and `encrypt_boot` empty and to instead set the key id in the + launch_block_device_mappings (you can find an example below). This saves + potentially many minutes at the end of the build by preventing Packer + from having to copy and re-encrypt the image at the end of the build. + + For valid formats see *KmsKeyId* in the [AWS API docs - + CopyImage](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CopyImage.html). + This field is validated by Packer, when using an alias, you will have to + prefix `kms_key_id` with `alias/`. + +- `region_kms_key_ids` (map[string]string) - regions to copy the ami to, along with the custom kms key id (alias or + arn) to use for encryption for that region. Keys must match the regions + provided in `ami_regions`. If you just want to encrypt using a default + ID, you can stick with `kms_key_id` and `ami_regions`. If you want a + region to be encrypted with that region's default key ID, you can use an + empty string `""` instead of a key id in this map. (e.g. `"us-east-1": + ""`) However, you cannot use default key IDs if you are using this in + conjunction with `snapshot_users` -- in that situation you must use + custom keys. For valid formats see *KmsKeyId* in the [AWS API docs - + CopyImage](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CopyImage.html). + + This option supercedes the `kms_key_id` option -- if you set both, and + they are different, Packer will respect the value in + `region_kms_key_ids` for your build region and silently disregard the + value provided in `kms_key_id`. + +- `skip_save_build_region` (bool) - If true, Packer will not check whether an AMI with the `ami_name` exists + in the region it is building in. It will use an intermediary AMI name, + which it will not convert to an AMI in the build region. It will copy + the intermediary AMI into any regions provided in `ami_regions`, then + delete the intermediary AMI. Default `false`. + +- `imds_support` (string) - Enforce version of the Instance Metadata Service on the built AMI. + Valid options are unset (legacy) and `v2.0`. See the documentation on + [IMDS](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html) + for more information. Defaults to legacy. + +- `deprecate_at` (string) - The date and time to deprecate the AMI, in UTC, in the following format: YYYY-MM-DDTHH:MM:SSZ. + If you specify a value for seconds, Amazon EC2 rounds the seconds to the nearest minute. + You can’t specify a date in the past. The upper limit for DeprecateAt is 10 years from now. + + + + + + +- `snapshot_tags` (map[string]string) - Key/value pair tags to apply to snapshot. They will override AMI tags if + already applied to snapshot. This is a [template + engine](/packer/docs/templates/legacy_json_templates/engine), see [Build template + data](#build-template-data) for more information. + +- `snapshot_tag` ([]{key string, value string}) - Same as [`snapshot_tags`](#snapshot_tags) but defined as a singular + repeatable block containing a `key` and a `value` field. In HCL2 mode the + [`dynamic_block`](/packer/docs/templates/hcl_templates/expressions#dynamic-blocks) + will allow you to create those programatically. + +- `snapshot_users` ([]string) - A list of account IDs that have + access to create volumes from the snapshot(s). By default no additional + users other than the user creating the AMI has permissions to create + volumes from the backing snapshot(s). + +- `snapshot_groups` ([]string) - A list of groups that have access to + create volumes from the snapshot(s). By default no groups have permission + to create volumes from the snapshot(s). all will make the snapshot + publicly accessible. + + + + +### Access Configuration + +#### Required: + + + +- `access_key` (string) - The access key used to communicate with AWS. [Learn how to set this](/packer/integrations/hashicorp/amazon#specifying-amazon-credentials). + On EBS, this is not required if you are using `use_vault_aws_engine` + for authentication instead. + +- `region` (string) - The name of the region, such as `us-east-1`, in which + to launch the EC2 instance to create the AMI. + When chroot building, this value is guessed from environment. + +- `secret_key` (string) - The secret key used to communicate with AWS. [Learn how to set + this](/packer/integrations/hashicorp/amazon#specifying-amazon-credentials). This is not required + if you are using `use_vault_aws_engine` for authentication instead. + + + + +#### Optional: + + + +- `assume_role` (AssumeRoleConfig) - If provided with a role ARN, Packer will attempt to assume this role + using the supplied credentials. See + [AssumeRoleConfig](#assume-role-configuration) below for more + details on all of the options available, and for a usage example. + +- `custom_endpoint_ec2` (string) - This option is useful if you use a cloud + provider whose API is compatible with aws EC2. Specify another endpoint + like this https://ec2.custom.endpoint.com. + +- `shared_credentials_file` (string) - Path to a credentials file to load credentials from + +- `decode_authorization_messages` (bool) - Enable automatic decoding of any encoded authorization (error) messages + using the `sts:DecodeAuthorizationMessage` API. Note: requires that the + effective user/role have permissions to `sts:DecodeAuthorizationMessage` + on resource `*`. Default `false`. + +- `insecure_skip_tls_verify` (bool) - This allows skipping TLS + verification of the AWS EC2 endpoint. The default is false. + +- `max_retries` (int) - This is the maximum number of times an API call is retried, in the case + where requests are being throttled or experiencing transient failures. + The delay between the subsequent API calls increases exponentially. + +- `mfa_code` (string) - The MFA + [TOTP](https://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm) + code. This should probably be a user variable since it changes all the + time. + +- `profile` (string) - The profile to use in the shared credentials file for + AWS. See Amazon's documentation on [specifying + profiles](https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-profiles) + for more details. + +- `skip_metadata_api_check` (bool) - Skip Metadata Api Check + +- `skip_credential_validation` (bool) - Set to true if you want to skip validating AWS credentials before runtime. + +- `token` (string) - The access token to use. This is different from the + access key and secret key. If you're not sure what this is, then you + probably don't need it. This will also be read from the AWS_SESSION_TOKEN + environmental variable. + +- `vault_aws_engine` (VaultAWSEngineOptions) - Get credentials from HashiCorp Vault's aws secrets engine. You must + already have created a role to use. For more information about + generating credentials via the Vault engine, see the [Vault + docs.](https://www.vaultproject.io/api/secret/aws#generate-credentials) + If you set this flag, you must also set the below options: + - `name` (string) - Required. Specifies the name of the role to generate + credentials against. This is part of the request URL. + - `engine_name` (string) - The name of the aws secrets engine. In the + Vault docs, this is normally referred to as "aws", and Packer will + default to "aws" if `engine_name` is not set. + - `role_arn` (string)- The ARN of the role to assume if credential\_type + on the Vault role is assumed\_role. Must match one of the allowed role + ARNs in the Vault role. Optional if the Vault role only allows a single + AWS role ARN; required otherwise. + - `ttl` (string) - Specifies the TTL for the use of the STS token. This + is specified as a string with a duration suffix. Valid only when + credential\_type is assumed\_role or federation\_token. When not + specified, the default\_sts\_ttl set for the role will be used. If that + is also not set, then the default value of 3600s will be used. AWS + places limits on the maximum TTL allowed. See the AWS documentation on + the DurationSeconds parameter for AssumeRole (for assumed\_role + credential types) and GetFederationToken (for federation\_token + credential types) for more details. + + HCL2 example: + + ```hcl + vault_aws_engine { + name = "myrole" + role_arn = "myarn" + ttl = "3600s" + } + ``` + + JSON example: + + ```json + { + "vault_aws_engine": { + "name": "myrole", + "role_arn": "myarn", + "ttl": "3600s" + } + } + ``` + +- `aws_polling` (\*AWSPollingConfig) - [Polling configuration](#polling-configuration) for the AWS waiter. Configures the waiter that checks + resource state. + + + + +### Assume Role Configuration + + + +AssumeRoleConfig lets users set configuration options for assuming a special +role when executing Packer. + +Usage example: + +HCL config example: + +```HCL + + source "amazon-ebs" "example" { + assume_role { + role_arn = "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME" + session_name = "SESSION_NAME" + external_id = "EXTERNAL_ID" + } + } + +``` + +JSON config example: + +```json + + builder{ + "type": "amazon-ebs", + "assume_role": { + "role_arn" : "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME", + "session_name": "SESSION_NAME", + "external_id" : "EXTERNAL_ID" + } + } + +``` + + + + + + +- `role_arn` (string) - Amazon Resource Name (ARN) of the IAM Role to assume. + +- `duration_seconds` (int) - Number of seconds to restrict the assume role session duration. + +- `external_id` (string) - The external ID to use when assuming the role. If omitted, no external + ID is passed to the AssumeRole call. + +- `policy` (string) - IAM Policy JSON describing further restricting permissions for the IAM + Role being assumed. + +- `policy_arns` ([]string) - Set of Amazon Resource Names (ARNs) of IAM Policies describing further + restricting permissions for the IAM Role being + +- `session_name` (string) - Session name to use when assuming the role. + +- `tags` (map[string]string) - Map of assume role session tags. + +- `transitive_tag_keys` ([]string) - Set of assume role session tag keys to pass to any subsequent sessions. + + + + +### Polling Configuration + + + +Polling configuration for the AWS waiter. Configures the waiter for resources creation or actions like attaching +volumes or importing image. + +HCL2 example: +```hcl + + aws_polling { + delay_seconds = 30 + max_attempts = 50 + } + +``` + +JSON example: +```json + + "aws_polling" : { + "delay_seconds": 30, + "max_attempts": 50 + } + +``` + + + + + + +- `max_attempts` (int) - Specifies the maximum number of attempts the waiter will check for resource state. + This value can also be set via the AWS_MAX_ATTEMPTS. + If both option and environment variable are set, the max_attempts will be considered over the AWS_MAX_ATTEMPTS. + If none is set, defaults to AWS waiter default which is 40 max_attempts. + +- `delay_seconds` (int) - Specifies the delay in seconds between attempts to check the resource state. + This value can also be set via the AWS_POLL_DELAY_SECONDS. + If both option and environment variable are set, the delay_seconds will be considered over the AWS_POLL_DELAY_SECONDS. + If none is set, defaults to AWS waiter default which is 15 seconds. + + + + +### Run Configuration + +#### Required: + + + +- `instance_type` (string) - The EC2 instance type to use while building the + AMI, such as t2.small. + +- `source_ami` (string) - The source AMI whose root volume will be copied and + provisioned on the currently running instance. This must be an EBS-backed + AMI with a root volume snapshot that you have access to. + + + + +#### Optional: + + + +- `associate_public_ip_address` (confighelper.Trilean) - If using a non-default VPC, + public IP addresses are not provided by default. If this is true, your + new instance will get a Public IP. default: unset + + Note: when specifying this attribute without a `subnet_[id|filter]` or + `vpc_[id|filter]`, we will attempt to infer this information from the + default VPC/Subnet. + This operation may require some extra permissions to the IAM role that + runs the build: + + * ec2:DescribeVpcs + * ec2:DescribeSubnets + + Additionally, since we filter subnets/AZs by their capability to host + an instance of the selected type, you may also want to define the + `ec2:DescribeInstanceTypeOfferings` action to the role running the build. + Otherwise, Packer will pick the most available subnet in the VPC selected, + which may not be able to host the instance type you provided. + +- `availability_zone` (string) - Destination availability zone to launch + instance in. Leave this empty to allow Amazon to auto-assign. + +- `block_duration_minutes` (int64) - Requires spot_price to be set. The + required duration for the Spot Instances (also known as Spot blocks). This + value must be a multiple of 60 (60, 120, 180, 240, 300, or 360). You can't + specify an Availability Zone group or a launch group if you specify a + duration. Note: This parameter is no longer available to new customers + from July 1, 2021. [See Amazon's + documentation](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-requests.html#fixed-duration-spot-instances). + +- `capacity_reservation_preference` (string) - Set the preference for using a capacity reservation if one exists. + Either will be `open` or `none`. Defaults to `none` + +- `capacity_reservation_id` (string) - Provide the specific EC2 Capacity Reservation ID that will be used + by Packer. + +- `capacity_reservation_group_arn` (string) - Provide the EC2 Capacity Reservation Group ARN that will be used by + Packer. + +- `disable_stop_instance` (bool) - Packer normally stops the build instance after all provisioners have + run. For Windows instances, it is sometimes desirable to [run + Sysprep](https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/Creating_EBSbacked_WinAMI.html) + which will stop the instance for you. If this is set to `true`, Packer + *will not* stop the instance but will assume that you will send the stop + signal yourself through your final provisioner. You can do this with a + [windows-shell provisioner](/packer/integrations/hashicorp/windows-shell). Note that + Packer will still wait for the instance to be stopped, and failing to + send the stop signal yourself, when you have set this flag to `true`, + will cause a timeout. + + An example of a valid windows shutdown command in a `windows-shell` + provisioner is : + ```shell-session + ec2config.exe -sysprep + ``` + or + ```sell-session + "%programfiles%\amazon\ec2configservice\"ec2config.exe -sysprep"" + ``` + -> Note: The double quotation marks in the command are not required if + your CMD shell is already in the + `C:\Program Files\Amazon\EC2ConfigService\` directory. + +- `ebs_optimized` (bool) - Mark instance as [EBS + Optimized](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSOptimized.html). + Default `false`. + +- `enable_nitro_enclave` (bool) - Enable support for Nitro Enclaves on the instance. Note that the instance type must + be able to [support Nitro Enclaves](https://aws.amazon.com/ec2/nitro/nitro-enclaves/faqs/). + This option is not supported for spot instances. + +- `enable_t2_unlimited` (bool) - Deprecated argument - please use "enable_unlimited_credits". + Enabling T2 Unlimited allows the source instance to burst additional CPU + beyond its available [CPU + Credits](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/t2-credits-baseline-concepts.html) + for as long as the demand exists. This is in contrast to the standard + configuration that only allows an instance to consume up to its + available CPU Credits. See the AWS documentation for [T2 + Unlimited](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/t2-unlimited.html) + and the **T2 Unlimited Pricing** section of the [Amazon EC2 On-Demand + Pricing](https://aws.amazon.com/ec2/pricing/on-demand/) document for + more information. By default this option is disabled and Packer will set + up a [T2 + Standard](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/t2-std.html) + instance instead. + + To use T2 Unlimited you must use a T2 instance type, e.g. `t2.micro`. + Additionally, T2 Unlimited cannot be used in conjunction with Spot + Instances, e.g. when the `spot_price` option has been configured. + Attempting to do so will cause an error. + + !> **Warning!** Additional costs may be incurred by enabling T2 + Unlimited - even for instances that would usually qualify for the + [AWS Free Tier](https://aws.amazon.com/free/). + +- `enable_unlimited_credits` (bool) - Enabling Unlimited credits allows the source instance to burst additional CPU + beyond its available [CPU + Credits](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/burstable-performance-instances-unlimited-mode-concepts.html#unlimited-mode-surplus-credits) + for as long as the demand exists. This is in contrast to the standard + configuration that only allows an instance to consume up to its + available CPU Credits. See the AWS documentation for [T2 + Unlimited](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/burstable-performance-instances-unlimited-mode-concepts.html) + and the **Unlimited Pricing** section of the [Amazon EC2 On-Demand + Pricing](https://aws.amazon.com/ec2/pricing/on-demand/) document for + more information. By default this option is disabled and Packer will set + up a [Standard](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/burstable-performance-instances-standard-mode.html) + instance instead. + + To use Unlimited you must use a T2/T3/T3a/T4g instance type, e.g. (`t2.micro`, `t3.micro`). + Additionally, Unlimited cannot be used in conjunction with Spot + Instances for T2 type instances, e.g. when the `spot_price` option has been configured. + Attempting to do so will cause an error if the underlying instance type is a T2 type instance. + By default the supported burstable instance types (including t3/t3a/t4g) will be provisioned with its cpu credits set to standard, + only when `enable_unlimited_credits` is true will the instance be provisioned with unlimited cpu credits. + +- `iam_instance_profile` (string) - The name of an [IAM instance + profile](https://docs.aws.amazon.com/IAM/latest/UserGuide/instance-profiles.html) + to launch the EC2 instance with. + +- `fleet_tags` (map[string]string) - Key/value pair tags to apply tags to the fleet that is issued. + +- `fleet_tag` ([]{key string, value string}) - Same as [`fleet_tags`](#fleet_tags) but defined as a singular repeatable block + containing a `key` and a `value` field. In HCL2 mode the + [`dynamic_block`](/packer/docs/templates/hcl_templates/expressions#dynamic-blocks) + will allow you to create those programatically. + +- `skip_profile_validation` (bool) - Whether or not to check if the IAM instance profile exists. Defaults to false + +- `temporary_iam_instance_profile_policy_document` (\*PolicyDocument) - Temporary IAM instance profile policy document + If IamInstanceProfile is specified it will be used instead. + + HCL2 example: + ```hcl + temporary_iam_instance_profile_policy_document { + Statement { + Action = ["logs:*"] + Effect = "Allow" + Resource = ["*"] + } + Version = "2012-10-17" + } + ``` + + JSON example: + ```json + { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "logs:*" + ], + "Effect": "Allow", + "Resource": ["*"] + } + ] + } + ``` + +- `shutdown_behavior` (string) - Automatically terminate instances on + shutdown in case Packer exits ungracefully. Possible values are stop and + terminate. Defaults to stop. + +- `security_group_filter` (SecurityGroupFilterOptions) - Filters used to populate the `security_group_ids` field. + + HCL2 Example: + + ```hcl + security_group_filter { + filters = { + "tag:Class": "packer" + } + } + ``` + + JSON Example: + ```json + { + "security_group_filter": { + "filters": { + "tag:Class": "packer" + } + } + } + ``` + + This selects the SG's with tag `Class` with the value `packer`. + + - `filters` (map[string,string] | multiple filters are allowed when seperated by commas) - filters used to select a + `security_group_ids`. Any filter described in the docs for + [DescribeSecurityGroups](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSecurityGroups.html) + is valid. + + `security_group_ids` take precedence over this. + +- `run_tags` (map[string]string) - Key/value pair tags to apply to the generated key-pair, security group, iam profile and role, snapshot, network interfaces and instance + that is *launched* to create the EBS volumes. The resulting AMI will also inherit these tags. + This is a [template + engine](/packer/docs/templates/legacy_json_templates/engine), see [Build template + data](#build-template-data) for more information. + +- `run_tag` ([]{key string, value string}) - Same as [`run_tags`](#run_tags) but defined as a singular repeatable + block containing a `key` and a `value` field. In HCL2 mode the + [`dynamic_block`](/packer/docs/templates/hcl_templates/expressions#dynamic-blocks) + will allow you to create those programatically. + +- `security_group_id` (string) - The ID (not the name) of the security + group to assign to the instance. By default this is not set and Packer will + automatically create a new temporary security group to allow SSH access. + Note that if this is specified, you must be sure the security group allows + access to the ssh_port given below. + +- `security_group_ids` ([]string) - A list of security groups as + described above. Note that if this is specified, you must omit the + security_group_id. + +- `source_ami_filter` (AmiFilterOptions) - Filters used to populate the `source_ami` + field. + + HCL2 example: + ```hcl + source "amazon-ebs" "basic-example" { + source_ami_filter { + filters = { + virtualization-type = "hvm" + name = "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*" + root-device-type = "ebs" + } + owners = ["099720109477"] + most_recent = true + } + } + ``` + + JSON Example: + ```json + "builders" [ + { + "type": "amazon-ebs", + "source_ami_filter": { + "filters": { + "virtualization-type": "hvm", + "name": "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*", + "root-device-type": "ebs" + }, + "owners": ["099720109477"], + "most_recent": true + } + } + ] + ``` + + This selects the most recent Ubuntu 16.04 HVM EBS AMI from Canonical. NOTE: + This will fail unless *exactly* one AMI is returned. In the above example, + `most_recent` will cause this to succeed by selecting the newest image. + + - `filters` (map[string,string] | multiple filters are allowed when seperated by commas) - filters used to select a `source_ami`. + NOTE: This will fail unless *exactly* one AMI is returned. Any filter + described in the docs for + [DescribeImages](http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeImages.html) + is valid. + + - `owners` (array of strings) - Filters the images by their owner. You + may specify one or more AWS account IDs, "self" (which will use the + account whose credentials you are using to run Packer), or an AWS owner + alias: for example, `amazon`, `aws-marketplace`, or `microsoft`. This + option is required for security reasons. + + - `most_recent` (boolean) - Selects the newest created image when true. + This is most useful for selecting a daily distro build. + + You may set this in place of `source_ami` or in conjunction with it. If you + set this in conjunction with `source_ami`, the `source_ami` will be added + to the filter. The provided `source_ami` must meet all of the filtering + criteria provided in `source_ami_filter`; this pins the AMI returned by the + filter, but will cause Packer to fail if the `source_ami` does not exist. + +- `spot_instance_types` ([]string) - a list of acceptable instance + types to run your build on. We will request a spot instance using the max + price of spot_price and the allocation strategy of "lowest price". + Your instance will be launched on an instance type of the lowest available + price that you have in your list. This is used in place of instance_type. + You may only set either spot_instance_types or instance_type, not both. + This feature exists to help prevent situations where a Packer build fails + because a particular availability zone does not have capacity for the + specific instance_type requested in instance_type. + +- `spot_price` (string) - With Spot Instances, you pay the Spot price that's in effect for the + time period your instances are running. Spot Instance prices are set by + Amazon EC2 and adjust gradually based on long-term trends in supply and + demand for Spot Instance capacity. + + When this field is set, it represents the maximum hourly price you are + willing to pay for a spot instance. If you do not set this value, it + defaults to a maximum price equal to the on demand price of the + instance. In the situation where the current Amazon-set spot price + exceeds the value set in this field, Packer will not launch an instance + and the build will error. In the situation where the Amazon-set spot + price is less than the value set in this field, Packer will launch and + you will pay the Amazon-set spot price, not this maximum value. + For more information, see the Amazon docs on + [spot pricing](https://aws.amazon.com/ec2/spot/pricing/). + +- `spot_tags` (map[string]string) - Requires spot_price to be set. Key/value pair tags to apply tags to the + spot request that is issued. + +- `spot_tag` ([]{key string, value string}) - Same as [`spot_tags`](#spot_tags) but defined as a singular repeatable block + containing a `key` and a `value` field. In HCL2 mode the + [`dynamic_block`](/packer/docs/templates/hcl_templates/expressions#dynamic-blocks) + will allow you to create those programatically. + +- `subnet_filter` (SubnetFilterOptions) - Filters used to populate the `subnet_id` field. + + HCL2 example: + + ```hcl + source "amazon-ebs" "basic-example" { + subnet_filter { + filters = { + "tag:Class": "build" + } + most_free = true + random = false + } + } + ``` + + JSON Example: + ```json + "builders" [ + { + "type": "amazon-ebs", + "subnet_filter": { + "filters": { + "tag:Class": "build" + }, + "most_free": true, + "random": false + } + } + ] + ``` + + This selects the Subnet with tag `Class` with the value `build`, which has + the most free IP addresses. NOTE: This will fail unless *exactly* one + Subnet is returned. By using `most_free` or `random` one will be selected + from those matching the filter. + + - `filters` (map[string,string] | multiple filters are allowed when seperated by commas) - filters used to select a `subnet_id`. + NOTE: This will fail unless *exactly* one Subnet is returned. Any + filter described in the docs for + [DescribeSubnets](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSubnets.html) + is valid. + + - `most_free` (boolean) - The Subnet with the most free IPv4 addresses + will be used if multiple Subnets matches the filter. + + - `random` (boolean) - A random Subnet will be used if multiple Subnets + matches the filter. `most_free` have precendence over this. + + `subnet_id` take precedence over this. + +- `subnet_id` (string) - If using VPC, the ID of the subnet, such as + subnet-12345def, where Packer will launch the EC2 instance. This field is + required if you are using an non-default VPC. + +- `license_specifications` ([]LicenseSpecification) - The license configurations. + + HCL2 example: + ```hcl + source "amazon-ebs" "basic-example" { + license_specifications { + license_configuration_request = { + license_configuration_arn = "${var.license_configuration_arn}" + } + } + } + ``` + + JSON example: + ```json + "builders" [ + { + "type": "amazon-ebs", + "license_specifications": [ + { + "license_configuration_request": { + "license_configuration_arn": "{{user `license_configuration_arn`}}" + } + } + ] + } + ] + ``` + + Each `license_configuration_request` describes a license configuration, + the properties of which are: + + - `license_configuration_arn` (string) - The Amazon Resource Name (ARN) + of the license configuration. + +- `placement` (Placement) - Describes the placement of an instance. + + HCL2 example: + ```hcl + source "amazon-ebs" "basic-example" { + placement = { + host_resource_group_arn = "${var.host_resource_group_arn}" + tenancy = "${var.placement_tenancy}" + } + } + ``` + + JSON example: + ```json + "builders" [ + { + "type": "amazon-ebs", + "placement": { + "host_resource_group_arn": "{{user `host_resource_group_arn`}}", + "tenancy": "{{user `placement_tenancy`}}" + } + } + ] + ``` + + - `host_resource_group_arn` (string) - The ARN of the host resource + group in which to launch the instances. If you specify a host + resource group ARN, omit the Tenancy parameter or set it to `host`. + - `tenancy` (string) - The tenancy of the instance (if the instance is + running in a VPC). An instance with a tenancy of `dedicated` runs on + single-tenant hardware. The default is `default`, meaning shared + tenancy. Allowed values are `default`, `dedicated` and `host`. + +- `tenancy` (string) - Deprecated: Use Placement Tenancy instead. + +- `temporary_security_group_source_cidrs` ([]string) - A list of IPv4 CIDR blocks to be authorized access to the instance, when + packer is creating a temporary security group. + + The default is [`0.0.0.0/0`] (i.e., allow any IPv4 source). + Use `temporary_security_group_source_public_ip` to allow current host's + public IP instead of any IPv4 source. + This is only used when `security_group_id` or `security_group_ids` is not + specified. + +- `temporary_security_group_source_public_ip` (bool) - When enabled, use public IP of the host (obtained from https://checkip.amazonaws.com) + as CIDR block to be authorized access to the instance, when packer + is creating a temporary security group. Defaults to `false`. + + This is only used when `security_group_id`, `security_group_ids`, + and `temporary_security_group_source_cidrs` are not specified. + +- `user_data` (string) - User data to apply when launching the instance. Note + that you need to be careful about escaping characters due to the templates + being JSON. It is often more convenient to use user_data_file, instead. + Packer will not automatically wait for a user script to finish before + shutting down the instance this must be handled in a provisioner. + +- `user_data_file` (string) - Path to a file that will be used for the user + data when launching the instance. + +- `vpc_filter` (VpcFilterOptions) - Filters used to populate the `vpc_id` field. + + HCL2 example: + ```hcl + source "amazon-ebs" "basic-example" { + vpc_filter { + filters = { + "tag:Class": "build", + "isDefault": "false", + "cidr": "/24" + } + } + } + ``` + + JSON Example: + ```json + "builders" [ + { + "type": "amazon-ebs", + "vpc_filter": { + "filters": { + "tag:Class": "build", + "isDefault": "false", + "cidr": "/24" + } + } + } + ] + ``` + + This selects the VPC with tag `Class` with the value `build`, which is not + the default VPC, and have a IPv4 CIDR block of `/24`. NOTE: This will fail + unless *exactly* one VPC is returned. + + - `filters` (map[string,string] | multiple filters are allowed when seperated by commas) - filters used to select a `vpc_id`. NOTE: + This will fail unless *exactly* one VPC is returned. Any filter + described in the docs for + [DescribeVpcs](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeVpcs.html) + is valid. + + `vpc_id` take precedence over this. + +- `vpc_id` (string) - If launching into a VPC subnet, Packer needs the VPC ID + in order to create a temporary security group within the VPC. Requires + subnet_id to be set. If this field is left blank, Packer will try to get + the VPC ID from the subnet_id. + +- `windows_password_timeout` (duration string | ex: "1h5m2s") - The timeout for waiting for a Windows + password for Windows instances. Defaults to 20 minutes. Example value: + 10m + +- `metadata_options` (MetadataOptions) - [Metadata Settings](#metadata-settings) + +- `ssh_interface` (string) - One of `public_ip`, `private_ip`, `public_dns`, `private_dns` or `session_manager`. + If set, either the public IP address, private IP address, public DNS name + or private DNS name will be used as the host for SSH. The default behaviour + if inside a VPC is to use the public IP address if available, otherwise + the private IP address will be used. If not in a VPC the public DNS name + will be used. Also works for WinRM. + + Where Packer is configured for an outbound proxy but WinRM traffic + should be direct, `ssh_interface` must be set to `private_dns` and + `.compute.internal` included in the `NO_PROXY` environment + variable. + + When using `session_manager` the machine running Packer must have + the AWS Session Manager Plugin installed and within the users' system path. + Connectivity via the `session_manager` interface establishes a secure tunnel + between the local host and the remote host on an available local port to the specified `ssh_port`. + See [Session Manager Connections](#session-manager-connections) for more information. + - Session manager connectivity is currently only implemented for the SSH communicator, not the WinRM communicator. + - Upon termination the secure tunnel will be terminated automatically, if however there is a failure in + terminating the tunnel it will automatically terminate itself after 20 minutes of inactivity. + +- `pause_before_ssm` (duration string | ex: "1h5m2s") - The time to wait before establishing the Session Manager session. + The value of this should be a duration. Examples are + `5s` and `1m30s` which will cause Packer to wait five seconds and one + minute 30 seconds, respectively. If no set, defaults to 10 seconds. + This option is useful when the remote port takes longer to become available. + +- `session_manager_port` (int) - Which port to connect the local end of the session tunnel to. If + left blank, Packer will choose a port for you from available ports. + This option is only used when `ssh_interface` is set `session_manager`. + + + + +#### Metadata Settings + + + +Configures the metadata options. +See [Configure IMDS](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html) for details. + + + + + + +- `http_endpoint` (string) - A string to enable or disable the IMDS endpoint for an instance. Defaults to enabled. + Accepts either "enabled" or "disabled" + +- `http_tokens` (string) - A string to either set the use of IMDSv2 for the instance to optional or required. Defaults to "optional". + Accepts either "optional" or "required" + +- `http_put_response_hop_limit` (int64) - A numerical value to set an upper limit for the amount of hops allowed when communicating with IMDS endpoints. + Defaults to 1. + +- `instance_metadata_tags` (string) - A string to enable or disable access to instance tags from the instance metadata. Defaults to disabled. + Access to instance metadata tags is available for commercial regions. For non-commercial regions please check availability before enabling. + Accepts either "enabled" or "disabled" + + + + +Usage Example + +**HCL2** + +```hcl +source "amazon-ebs" "basic-example" { + region = "us-east-1" + source_ami = "ami-fce3c696" + instance_type = "t2.micro" + ssh_username = "ubuntu" + ami_name = "packer_AWS_example_{{timestamp}}" + metadata_options { + http_endpoint = "enabled" + http_tokens = "required" + http_put_response_hop_limit = 1 + } +} +``` + +**JSON** + +```json +{ + "variables": { + "aws_access_key": "{{env `AWS_ACCESS_KEY_ID`}}", + "aws_secret_key": "{{env `AWS_SECRET_ACCESS_KEY`}}" + }, + "builders": [ + { + "type": "amazon-ebs", + "access_key": "{{user `aws_access_key`}}", + "secret_key": "{{user `aws_secret_key`}}", + "region": "us-east-1", + "source_ami": "ami-fce3c696", + "instance_type": "t2.micro", + "ssh_username": "ubuntu", + "ami_name": "packer_AWS {{timestamp}}", + "metadata_options": { + "http_endpoint": "enabled", + "http_tokens": "required", + "http_put_response_hop_limit": 1 + } + } + ] +} +``` + + +### Session Manager Connections + +Support for the AWS Systems Manager session manager lets users manage EC2 instances without the need to open inbound ports, or maintain bastion hosts. Session manager connectivity relies on the use of the [session manager plugin](#session-manager-plugin) to open a secure tunnel between the local machine and the remote instance. Once the tunnel has been created all SSH communication will be tunneled through SSM to the remote instance. + +-> Note: Session manager connectivity is currently only implemented for the SSH communicator, not the WinRM Communicator. + +To use the session manager as the connection interface for the SSH communicator you need to add the following configuration options to the Amazon builder options: + +- `ssh_interface`: The ssh interface must be set to "session_manager". When using this option the builder will create an SSM tunnel to the configured `ssh_port` (defaults to 22) on the remote host. +- `iam_instance_profile`: A valid instance profile granting Systems Manager permissions to manage the remote instance is required in order for the aws ssm-agent to start and stop session connections. + See below for more details on [IAM instance profile for Systems Manager](#iam-instance-profile-for-systems-manager). + +#### Optional + +- `session_manager_port`: A local port on the host machine that should be used as the local end of the session tunnel to the remote host. If not specified Packer will find an available port to use. +- `temporary_iam_instance_profile_policy_document`: Creates a temporary instance profile policy document to grant Systems Manager permissions to the Ec2 instance. This is an alternative to using an existing `iam_instance_profile`. + +HCL2 example: + +```hcl +# file: example.pkr.hcl + +# In order to get these variables to read from the environment, +# set the environment variables to have the same name as the declared +# variables, with the prefix PKR_VAR_. +# You could also hardcode them into the file, but we do not recommend that. + +data "amazon-ami" "example" { + filters = { + virtualization-type = "hvm" + name = "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*" + root-device-type = "ebs" + } + owners = ["099720109477"] + most_recent = true + region = "us-east-1" +} + +source "amazon-ebs" "ssm-example" { + ami_name = "packer_AWS {{timestamp}}" + instance_type = "t2.micro" + region = "us-east-1" + source_ami = data.amazon-ami.example.id + ssh_username = "ubuntu" + ssh_interface = "session_manager" + communicator = "ssh" + iam_instance_profile = "myinstanceprofile" +} + +build { + sources = ["source.amazon-ebs.ssm-example"] + + provisioner "shell" { + inline = ["echo Connected via SSM at '${build.User}@${build.Host}:${build.Port}'"] + } +} +``` + +JSON example: + +```json +{ + "builders": [ + { + "type": "amazon-ebs", + "ami_name": "packer-ami-{{timestamp}}", + "instance_type": "t2.micro", + "source_ami_filter": { + "filters": { + "virtualization-type": "hvm", + "name": "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*", + "root-device-type": "ebs" + }, + "owners": ["099720109477"], + "most_recent": true + }, + "ssh_username": "ubuntu", + "ssh_interface": "session_manager", + "communicator": "ssh", + "iam_instance_profile": "{{user `iam_instance_profile`}}" + } + ], + "provisioners": [ + { + "type": "shell", + "inline": [ + "echo Connected via SSM at '{{build `User`}}@{{build `Host`}}:{{build `Port`}}'" + ] + } + ] +} +``` + +#### Session Manager Plugin + +Connectivity via the session manager requires the use of a session-manger-plugin, which needs to be installed alongside Packer, and an instance AMI that is capable of running the AWS ssm-agent - see [About SSM Agent](https://docs.aws.amazon.com/systems-manager/latest/userguide/prereqs-ssm-agent.html) for details on supported AMIs. + +In order for Packer to start and end sessions that connect you to your managed instances, you must first install the Session Manager plugin on your local machine. The plugin can be installed on supported versions of Microsoft Windows, macOS, Linux, and Ubuntu Server. +[Installation instructions for the session-manager-plugin](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html) + +#### IAM instance profile for Systems Manager + +By default Systems Manager doesn't have permission to perform actions on created instances so SSM access must be granted by creating an instance profile with the `AmazonSSMManagedInstanceCore` policy. The instance profile can then be attached to any instance you wish to manage via the session-manager-plugin. See [Adding System Manager instance profile](https://docs.aws.amazon.com/systems-manager/latest/userguide/setup-instance-profile.html#instance-profile-add-permissions) for details on creating the required instance profile. + +#### Permissions for Closing the Tunnel + +To close the SSM tunnels created, this plugin relies on being able to call +[DescribeInstanceStatus](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeInstanceStatus.html). +In case this is not possible you might see a `Bad exit status` message in the logs. + +The absence of this permission won't prevent you from building the AMI, and the error only means that packer is not able to close the tunnel gracefully. + + +### Block Devices Configuration + +Block devices can be nested in the +[ami_block_device_mappings](#ami_block_device_mappings) array. + + + +These will be attached when launching your instance. Your +options here may vary depending on the type of VM you use. + +Example use case: + +The following mapping will tell Packer to encrypt the root volume of the +build instance at launch using a specific non-default kms key: + +HCL2 example: + +```hcl + + launch_block_device_mappings { + device_name = "/dev/sda1" + encrypted = true + kms_key_id = "1a2b3c4d-5e6f-1a2b-3c4d-5e6f1a2b3c4d" + } + +``` + +JSON example: +```json +"launch_block_device_mappings": [ + + { + "device_name": "/dev/sda1", + "encrypted": true, + "kms_key_id": "1a2b3c4d-5e6f-1a2b-3c4d-5e6f1a2b3c4d" + } + +] +``` + +Please note that the kms_key_id option in this example exists for +launch_block_device_mappings but not ami_block_device_mappings. + +Documentation for Block Devices Mappings can be found here: +https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/block-device-mapping-concepts.html + + + + +#### Optional only for [launch_block_device_mappings](#launch_block_device_mappings) + + + +- `omit_from_artifact` (bool) - If true, this block device will not be snapshotted and the created AMI + will not contain block device mapping information for this volume. If + false, the block device will be mapped into the final created AMI. Set + this option to true if you need a block device mounted in the surrogate + AMI but not in the final created AMI. + + + + +#### Optional: + + + +- `delete_on_termination` (bool) - Indicates whether the EBS volume is deleted on instance termination. + Default false. NOTE: If this value is not explicitly set to true and + volumes are not cleaned up by an alternative method, additional volumes + will accumulate after every build. + +- `device_name` (string) - The device name exposed to the instance (for example, /dev/sdh or xvdh). + Required for every device in the block device mapping. + +- `encrypted` (boolean) - Indicates whether or not to encrypt the volume. By default, Packer will + keep the encryption setting to what it was in the source image. Setting + false will result in an unencrypted device, and true will result in an + encrypted one. + +- `iops` (\*int64) - The number of I/O operations per second (IOPS) that the volume supports. + See the documentation on + [IOPs](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_EbsBlockDevice.html) + for more information + +- `no_device` (bool) - Suppresses the specified device included in the block device mapping of + the AMI. + +- `snapshot_id` (string) - The ID of the snapshot. + +- `throughput` (\*int64) - The throughput for gp3 volumes, only valid for gp3 types + See the documentation on + [Throughput](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_EbsBlockDevice.html) + for more information + +- `virtual_name` (string) - The virtual device name. See the documentation on Block Device Mapping + for more information. + +- `volume_type` (string) - The volume type. gp2 & gp3 for General Purpose (SSD) volumes, io1 & io2 + for Provisioned IOPS (SSD) volumes, st1 for Throughput Optimized HDD, + sc1 for Cold HDD, and standard for Magnetic volumes. + +- `volume_size` (int64) - The size of the volume, in GiB. Required if not specifying a + snapshot_id. + +- `kms_key_id` (string) - ID, alias or ARN of the KMS key to use for boot volume encryption. + This option exists for launch_block_device_mappings but not + ami_block_device_mappings. The kms key id defined here only applies to + the original build region; if the AMI gets copied to other regions, the + volume in those regions will be encrypted by the default EBS KMS key. + For valid formats see KmsKeyId in the [AWS API docs - + CopyImage](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CopyImage.html) + This field is validated by Packer. When using an alias, you will have to + prefix kms_key_id with alias/. + + + + +### Communicator Configuration + +#### Optional: + + + +- `communicator` (string) - Packer currently supports three kinds of communicators: + + - `none` - No communicator will be used. If this is set, most + provisioners also can't be used. + + - `ssh` - An SSH connection will be established to the machine. This + is usually the default. + + - `winrm` - A WinRM connection will be established. + + In addition to the above, some builders have custom communicators they + can use. For example, the Docker builder has a "docker" communicator + that uses `docker exec` and `docker cp` to execute scripts and copy + files. + +- `pause_before_connecting` (duration string | ex: "1h5m2s") - We recommend that you enable SSH or WinRM as the very last step in your + guest's bootstrap script, but sometimes you may have a race condition + where you need Packer to wait before attempting to connect to your + guest. + + If you end up in this situation, you can use the template option + `pause_before_connecting`. By default, there is no pause. For example if + you set `pause_before_connecting` to `10m` Packer will check whether it + can connect, as normal. But once a connection attempt is successful, it + will disconnect and then wait 10 minutes before connecting to the guest + and beginning provisioning. + + + + + + +- `ssh_host` (string) - The address to SSH to. This usually is automatically configured by the + builder. + +- `ssh_port` (int) - The port to connect to SSH. This defaults to `22`. + +- `ssh_username` (string) - The username to connect to SSH with. Required if using SSH. + +- `ssh_password` (string) - A plaintext password to use to authenticate with SSH. + +- `ssh_ciphers` ([]string) - This overrides the value of ciphers supported by default by Golang. + The default value is [ + "aes128-gcm@openssh.com", + "chacha20-poly1305@openssh.com", + "aes128-ctr", "aes192-ctr", "aes256-ctr", + ] + + Valid options for ciphers include: + "aes128-ctr", "aes192-ctr", "aes256-ctr", "aes128-gcm@openssh.com", + "chacha20-poly1305@openssh.com", + "arcfour256", "arcfour128", "arcfour", "aes128-cbc", "3des-cbc", + +- `ssh_clear_authorized_keys` (bool) - If true, Packer will attempt to remove its temporary key from + `~/.ssh/authorized_keys` and `/root/.ssh/authorized_keys`. This is a + mostly cosmetic option, since Packer will delete the temporary private + key from the host system regardless of whether this is set to true + (unless the user has set the `-debug` flag). Defaults to "false"; + currently only works on guests with `sed` installed. + +- `ssh_key_exchange_algorithms` ([]string) - If set, Packer will override the value of key exchange (kex) algorithms + supported by default by Golang. Acceptable values include: + "curve25519-sha256@libssh.org", "ecdh-sha2-nistp256", + "ecdh-sha2-nistp384", "ecdh-sha2-nistp521", + "diffie-hellman-group14-sha1", and "diffie-hellman-group1-sha1". + +- `ssh_certificate_file` (string) - Path to user certificate used to authenticate with SSH. + The `~` can be used in path and will be expanded to the + home directory of current user. + +- `ssh_pty` (bool) - If `true`, a PTY will be requested for the SSH connection. This defaults + to `false`. + +- `ssh_timeout` (duration string | ex: "1h5m2s") - The time to wait for SSH to become available. Packer uses this to + determine when the machine has booted so this is usually quite long. + Example value: `10m`. + This defaults to `5m`, unless `ssh_handshake_attempts` is set. + +- `ssh_disable_agent_forwarding` (bool) - If true, SSH agent forwarding will be disabled. Defaults to `false`. + +- `ssh_handshake_attempts` (int) - The number of handshakes to attempt with SSH once it can connect. + This defaults to `10`, unless a `ssh_timeout` is set. + +- `ssh_bastion_host` (string) - A bastion host to use for the actual SSH connection. + +- `ssh_bastion_port` (int) - The port of the bastion host. Defaults to `22`. + +- `ssh_bastion_agent_auth` (bool) - If `true`, the local SSH agent will be used to authenticate with the + bastion host. Defaults to `false`. + +- `ssh_bastion_username` (string) - The username to connect to the bastion host. + +- `ssh_bastion_password` (string) - The password to use to authenticate with the bastion host. + +- `ssh_bastion_interactive` (bool) - If `true`, the keyboard-interactive used to authenticate with bastion host. + +- `ssh_bastion_private_key_file` (string) - Path to a PEM encoded private key file to use to authenticate with the + bastion host. The `~` can be used in path and will be expanded to the + home directory of current user. + +- `ssh_bastion_certificate_file` (string) - Path to user certificate used to authenticate with bastion host. + The `~` can be used in path and will be expanded to the + home directory of current user. + +- `ssh_file_transfer_method` (string) - `scp` or `sftp` - How to transfer files, Secure copy (default) or SSH + File Transfer Protocol. + + **NOTE**: Guests using Windows with Win32-OpenSSH v9.1.0.0p1-Beta, scp + (the default protocol for copying data) returns a a non-zero error code since the MOTW + cannot be set, which cause any file transfer to fail. As a workaround you can override the transfer protocol + with SFTP instead `ssh_file_transfer_protocol = "sftp"`. + +- `ssh_proxy_host` (string) - A SOCKS proxy host to use for SSH connection + +- `ssh_proxy_port` (int) - A port of the SOCKS proxy. Defaults to `1080`. + +- `ssh_proxy_username` (string) - The optional username to authenticate with the proxy server. + +- `ssh_proxy_password` (string) - The optional password to use to authenticate with the proxy server. + +- `ssh_keep_alive_interval` (duration string | ex: "1h5m2s") - How often to send "keep alive" messages to the server. Set to a negative + value (`-1s`) to disable. Example value: `10s`. Defaults to `5s`. + +- `ssh_read_write_timeout` (duration string | ex: "1h5m2s") - The amount of time to wait for a remote command to end. This might be + useful if, for example, packer hangs on a connection after a reboot. + Example: `5m`. Disabled by default. + +- `ssh_remote_tunnels` ([]string) - + +- `ssh_local_tunnels` ([]string) - + + + + + + +- `temporary_key_pair_type` (string) - `dsa` | `ecdsa` | `ed25519` | `rsa` ( the default ) + + Specifies the type of key to create. The possible values are 'dsa', + 'ecdsa', 'ed25519', or 'rsa'. + + NOTE: DSA is deprecated and no longer recognized as secure, please + consider other alternatives like RSA or ED25519. + +- `temporary_key_pair_bits` (int) - Specifies the number of bits in the key to create. For RSA keys, the + minimum size is 1024 bits and the default is 4096 bits. Generally, 3072 + bits is considered sufficient. DSA keys must be exactly 1024 bits as + specified by FIPS 186-2. For ECDSA keys, bits determines the key length + by selecting from one of three elliptic curve sizes: 256, 384 or 521 + bits. Attempting to use bit lengths other than these three values for + ECDSA keys will fail. Ed25519 keys have a fixed length and bits will be + ignored. + + NOTE: DSA is deprecated and no longer recognized as secure as specified + by FIPS 186-5, please consider other alternatives like RSA or ED25519. + + + + +- `ssh_keypair_name` (string) - If specified, this is the key that will be used for SSH with the + machine. The key must match a key pair name loaded up into the remote. + By default, this is blank, and Packer will generate a temporary keypair + unless [`ssh_password`](#ssh_password) is used. + [`ssh_private_key_file`](#ssh_private_key_file) or + [`ssh_agent_auth`](#ssh_agent_auth) must be specified when + [`ssh_keypair_name`](#ssh_keypair_name) is utilized. + + +- `ssh_private_key_file` (string) - Path to a PEM encoded private key file to use to authenticate with SSH. + The `~` can be used in path and will be expanded to the home directory + of current user. + + +- `ssh_agent_auth` (bool) - If true, the local SSH agent will be used to authenticate connections to + the source instance. No temporary keypair will be created, and the + values of [`ssh_password`](#ssh_password) and + [`ssh_private_key_file`](#ssh_private_key_file) will be ignored. The + environment variable `SSH_AUTH_SOCK` must be set for this option to work + properly. + + +## Basic Example + +**HCL2** + +```hcl +source "amazon-ebssurrogate" "basic-example" { + region = "us-east-1" + ssh_username = "ubuntu" + instance_type = "t2.medium" + source_ami = "ami-40d28157" + ami_name = "packer-test-ami" + ami_virtualization_type = "paravirtual" + + launch_block_device_mappings { + volume_type = "gp2" + device_name = "/dev/xvdf" + delete_on_termination = false + volume_size = 10 + } + + ami_root_device { + source_device_name = "/dev/xvdf" + device_name = "/dev/xvda" + delete_on_termination = true + volume_size = 16 + volume_type = "gp2" + } +} + +build { + sources = ["sources.amazon-ebssurrogate.basic-example"] + + provisioner "shell" { + inline = ["..."] + } +} +``` + +**JSON** + +```json +{ + "builders": [ + { + "type": "amazon-ebssurrogate", + "secret_key": "YOUR SECRET KEY HERE", + "access_key": "YOUR KEY HERE", + "ami_name": "packer-test-ami", + "ami_virtualization_type": "paravirtual", + "region": "us-east-1", + "ssh_username": "ubuntu", + "instance_type": "t2.medium", + "source_ami": "ami-40d28157", + "launch_block_device_mappings": [ + { + "volume_type": "gp2", + "device_name": "/dev/xvdf", + "delete_on_termination": false, + "volume_size": 10 + } + ], + "ami_root_device": { + "source_device_name": "/dev/xvdf", + "device_name": "/dev/xvda", + "delete_on_termination": true, + "volume_size": 16, + "volume_type": "gp2" + } + } + ] +} +``` + + + -> **Note:** Packer can also read the access key and secret access key from + environmental variables. See the configuration reference in the section above + for more information on what environmental variables Packer will look for. + + Further information on locating AMI IDs and their relationship to instance + types and regions can be found in the AWS EC2 Documentation [for + Linux](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/finding-an-ami.html) + or [for + Windows](http://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/finding-an-ami.html). + + ## Accessing the Instance to Debug + + If you need to access the instance to debug for some reason, run this builder + with the `-debug` flag. In debug mode, the Amazon builder will save the private + key in the current directory and will output the DNS or IP information as well. + You can use this information to access the instance as it is running. + + ## Build template data + + In configuration directives marked as a template engine above, the following + variables are available: + + - `BuildRegion` - The region (for example `eu-central-1`) where Packer is + building the AMI. + - `SourceAMI` - The source AMI ID (for example `ami-a2412fcd`) used to build + the AMI. + - `SourceAMICreationDate` - The source AMI creation date (for example `"2020-05-14T19:26:34.000Z"`). + - `SourceAMIName` - The source AMI Name (for example + `ubuntu/images/ebs-ssd/ubuntu-xenial-16.04-amd64-server-20180306`) used to + build the AMI. + - `SourceAMIOwner` - The source AMI owner ID. + - `SourceAMIOwnerName` - The source AMI owner alias/name (for example `amazon`). + - `SourceAMITags` - The source AMI Tags, as a `map[string]string` object. + + ## Build Shared Information Variables + + This builder generates data that are shared with provisioner and post-processor via build function of [template engine](/packer/docs/templates/legacy_json_templates/engine) for JSON and [contextual variables](/packer/docs/templates/hcl_templates/contextual-variables) for HCL2. + + The generated variables available for this builder are: + + - `BuildRegion` - The region (for example `eu-central-1`) where Packer is + building the AMI. + - `SourceAMI` - The source AMI ID (for example `ami-a2412fcd`) used to build + the AMI. + - `SourceAMICreationDate` - The source AMI creation date (for example `"2020-05-14T19:26:34.000Z"`). + - `SourceAMIName` - The source AMI Name (for example + `ubuntu/images/ebs-ssd/ubuntu-xenial-16.04-amd64-server-20180306`) used to + build the AMI. + - `SourceAMIOwner` - The source AMI owner ID. + - `SourceAMIOwnerName` - The source AMI owner alias/name (for example `amazon`). + + Usage example: + +**HCL2** + +```hcl +// When accessing one of these variables from inside the builder, you need to +// use the golang templating syntax. This is due to an architectural quirk that +// won't be easily resolvable until legacy json templates are deprecated: + +build { + source "amazon-ebs" "basic-example" { + tags = { + OS_Version = "Ubuntu" + Release = "Latest" + Base_AMI_ID = "{{ .SourceAMI }}" + Base_AMI_Name = "{{ .SourceAMIName }}" + } + } + + // when accessing one of the variables from a provisioner or post-processor, use + // hcl-syntax + post-processor "manifest" { + output = "manifest.json" + strip_path = true + custom_data = { + source_ami_name = "${build.SourceAMIName}" + } +} +``` + +**JSON** + +```json +"post-processors": [ + { + "type": "manifest", + "output": "manifest.json", + "strip_path": true, + "custom_data": { + "source_ami_name": "{{ build `SourceAMIName` }}" + } + } +] +``` + + +-> **Note:** Packer uses pre-built AMIs as the source for building images. +These source AMIs may include volumes that are not flagged to be destroyed on +termination of the instance building the new image. In addition to those +volumes created by this builder, any volumes in the source AMI which are not +marked for deletion on termination will remain in your account. + +## Which SSH Options to use: + +This chart breaks down what Packer does if you set any of the below SSH options: + +| ssh_password | ssh_private_key_file | ssh_keypair_name | temporary_key_pair_name | Packer will... | +| ------------ | -------------------- | ---------------- | ----------------------- | ------------------------------------------------------------------------------------------ | +| X | - | - | - | ssh authenticating with username and given password | +| - | X | - | - | ssh authenticating with private key file | +| - | X | X | - | ssh authenticating with given private key file and "attaching" the keypair to the instance | +| - | - | - | X | Create a temporary ssh keypair with a particular name, clean it up | +| - | - | - | - | Create a temporary ssh keypair with a default name, clean it up | diff --git a/.web-docs/components/builder/ebsvolume/README.md b/.web-docs/components/builder/ebsvolume/README.md new file mode 100644 index 000000000..d81d8f116 --- /dev/null +++ b/.web-docs/components/builder/ebsvolume/README.md @@ -0,0 +1,1628 @@ +Type: `amazon-ebsvolume` +Artifact BuilderId: `mitchellh.amazon.ebsvolume` + +The `amazon-ebsvolume` Packer builder is able to create Amazon Elastic Block +Store volumes which are prepopulated with filesystems or data. + +This builder creates EBS volumes by launching an EC2 instance from a source +AMI. One or more EBS volumes are attached to the running instance, allowing +them to be provisioned into from the running machine. Once provisioning is +complete the source machine is destroyed. The provisioned volumes are kept +intact. + +This is all done in your own AWS account. The builder will create temporary key +pairs, security group rules, etc. that provide it temporary access to the +instance while the image is being created. + +The builder does _not_ manage EBS Volumes. Once it creates volumes and stores +it in your account, it is up to you to use, delete, etc. the volumes. + +-> **Note:** Temporary resources are, by default, all created with the +prefix `packer`. This can be useful if you want to restrict the security groups +and key pairs Packer is able to operate on. + +## Configuration Reference + +There are many configuration options available for the builder. In addition to +the items listed here, you will want to look at the general configuration +references for [AMI](#ami-configuration), +[BlockDevices](#block-devices-configuration), +[Access](#access-configuration), +[Run](#run-configuration) and +[Communicator](#communicator-configuration) +configuration references, which are +necessary for this build to succeed and can be found further down the page. + +### Optional: + + + +- `ena_support` (boolean) - Enable enhanced networking (ENA but not SriovNetSupport) on + HVM-compatible AMIs. If set, add `ec2:ModifyInstanceAttribute` to your + AWS IAM policy. Note: you must make sure enhanced networking is enabled + on your instance. See [Amazon's documentation on enabling enhanced + networking](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enhanced-networking.html#enabling_enhanced_networking). + +- `sriov_support` (bool) - Enable enhanced networking (SriovNetSupport but not ENA) on + HVM-compatible AMIs. If true, add `ec2:ModifyInstanceAttribute` to your + AWS IAM policy. Note: you must make sure enhanced networking is enabled + on your instance. See [Amazon's documentation on enabling enhanced + networking](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enhanced-networking.html#enabling_enhanced_networking). + Default `false`. + +- `ebs_volumes` (BlockDevices) - Add the block device mappings to the AMI. If you add instance store + volumes or EBS volumes in addition to the root device volume, the + created AMI will contain block device mapping information for those + volumes. Amazon creates snapshots of the source instance's root volume + and any other EBS volumes described here. When you launch an instance + from this new AMI, the instance automatically launches with these + additional volumes, and will restore them from snapshots taken from the + source instance. See the [BlockDevices](#block-devices-configuration) + documentation for fields. + +- `run_volume_tags` (map[string]string) - Key/value pair tags to apply to the volumes of the instance that is + *launched* to create EBS Volumes. These tags will *not* appear in the + tags of the resulting EBS volumes unless they're duplicated under `tags` + in the `ebs_volumes` setting. This is a [template + engine](/packer/docs/templates/legacy_json_templates/engine), see [Build template + data](#build-template-data) for more information. + + Note: The tags specified here will be *temporarily* applied to volumes + specified in `ebs_volumes` - but only while the instance is being + created. Packer will replace all tags on the volume with the tags + configured in the `ebs_volumes` section as soon as the instance is + reported as 'ready'. + +- `run_volume_tag` ([]{key string, value string}) - Same as [`run_volume_tags`](#run_volume_tags) but defined as a singular + repeatable block containing a `key` and a `value` field. In HCL2 mode + the + [`dynamic_block`](/packer/docs/templates/hcl_templates/expressions#dynamic-blocks) + will allow you to create those programatically. + + + + +### Access Configuration + +#### Required: + + + +- `access_key` (string) - The access key used to communicate with AWS. [Learn how to set this](/packer/integrations/hashicorp/amazon#specifying-amazon-credentials). + On EBS, this is not required if you are using `use_vault_aws_engine` + for authentication instead. + +- `region` (string) - The name of the region, such as `us-east-1`, in which + to launch the EC2 instance to create the AMI. + When chroot building, this value is guessed from environment. + +- `secret_key` (string) - The secret key used to communicate with AWS. [Learn how to set + this](/packer/integrations/hashicorp/amazon#specifying-amazon-credentials). This is not required + if you are using `use_vault_aws_engine` for authentication instead. + + + + +#### Optional: + + + +- `assume_role` (AssumeRoleConfig) - If provided with a role ARN, Packer will attempt to assume this role + using the supplied credentials. See + [AssumeRoleConfig](#assume-role-configuration) below for more + details on all of the options available, and for a usage example. + +- `custom_endpoint_ec2` (string) - This option is useful if you use a cloud + provider whose API is compatible with aws EC2. Specify another endpoint + like this https://ec2.custom.endpoint.com. + +- `shared_credentials_file` (string) - Path to a credentials file to load credentials from + +- `decode_authorization_messages` (bool) - Enable automatic decoding of any encoded authorization (error) messages + using the `sts:DecodeAuthorizationMessage` API. Note: requires that the + effective user/role have permissions to `sts:DecodeAuthorizationMessage` + on resource `*`. Default `false`. + +- `insecure_skip_tls_verify` (bool) - This allows skipping TLS + verification of the AWS EC2 endpoint. The default is false. + +- `max_retries` (int) - This is the maximum number of times an API call is retried, in the case + where requests are being throttled or experiencing transient failures. + The delay between the subsequent API calls increases exponentially. + +- `mfa_code` (string) - The MFA + [TOTP](https://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm) + code. This should probably be a user variable since it changes all the + time. + +- `profile` (string) - The profile to use in the shared credentials file for + AWS. See Amazon's documentation on [specifying + profiles](https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-profiles) + for more details. + +- `skip_metadata_api_check` (bool) - Skip Metadata Api Check + +- `skip_credential_validation` (bool) - Set to true if you want to skip validating AWS credentials before runtime. + +- `token` (string) - The access token to use. This is different from the + access key and secret key. If you're not sure what this is, then you + probably don't need it. This will also be read from the AWS_SESSION_TOKEN + environmental variable. + +- `vault_aws_engine` (VaultAWSEngineOptions) - Get credentials from HashiCorp Vault's aws secrets engine. You must + already have created a role to use. For more information about + generating credentials via the Vault engine, see the [Vault + docs.](https://www.vaultproject.io/api/secret/aws#generate-credentials) + If you set this flag, you must also set the below options: + - `name` (string) - Required. Specifies the name of the role to generate + credentials against. This is part of the request URL. + - `engine_name` (string) - The name of the aws secrets engine. In the + Vault docs, this is normally referred to as "aws", and Packer will + default to "aws" if `engine_name` is not set. + - `role_arn` (string)- The ARN of the role to assume if credential\_type + on the Vault role is assumed\_role. Must match one of the allowed role + ARNs in the Vault role. Optional if the Vault role only allows a single + AWS role ARN; required otherwise. + - `ttl` (string) - Specifies the TTL for the use of the STS token. This + is specified as a string with a duration suffix. Valid only when + credential\_type is assumed\_role or federation\_token. When not + specified, the default\_sts\_ttl set for the role will be used. If that + is also not set, then the default value of 3600s will be used. AWS + places limits on the maximum TTL allowed. See the AWS documentation on + the DurationSeconds parameter for AssumeRole (for assumed\_role + credential types) and GetFederationToken (for federation\_token + credential types) for more details. + + HCL2 example: + + ```hcl + vault_aws_engine { + name = "myrole" + role_arn = "myarn" + ttl = "3600s" + } + ``` + + JSON example: + + ```json + { + "vault_aws_engine": { + "name": "myrole", + "role_arn": "myarn", + "ttl": "3600s" + } + } + ``` + +- `aws_polling` (\*AWSPollingConfig) - [Polling configuration](#polling-configuration) for the AWS waiter. Configures the waiter that checks + resource state. + + + + +### Assume Role Configuration + + + +AssumeRoleConfig lets users set configuration options for assuming a special +role when executing Packer. + +Usage example: + +HCL config example: + +```HCL + + source "amazon-ebs" "example" { + assume_role { + role_arn = "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME" + session_name = "SESSION_NAME" + external_id = "EXTERNAL_ID" + } + } + +``` + +JSON config example: + +```json + + builder{ + "type": "amazon-ebs", + "assume_role": { + "role_arn" : "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME", + "session_name": "SESSION_NAME", + "external_id" : "EXTERNAL_ID" + } + } + +``` + + + + + + +- `role_arn` (string) - Amazon Resource Name (ARN) of the IAM Role to assume. + +- `duration_seconds` (int) - Number of seconds to restrict the assume role session duration. + +- `external_id` (string) - The external ID to use when assuming the role. If omitted, no external + ID is passed to the AssumeRole call. + +- `policy` (string) - IAM Policy JSON describing further restricting permissions for the IAM + Role being assumed. + +- `policy_arns` ([]string) - Set of Amazon Resource Names (ARNs) of IAM Policies describing further + restricting permissions for the IAM Role being + +- `session_name` (string) - Session name to use when assuming the role. + +- `tags` (map[string]string) - Map of assume role session tags. + +- `transitive_tag_keys` ([]string) - Set of assume role session tag keys to pass to any subsequent sessions. + + + + +### Polling Configuration + + + +Polling configuration for the AWS waiter. Configures the waiter for resources creation or actions like attaching +volumes or importing image. + +HCL2 example: +```hcl + + aws_polling { + delay_seconds = 30 + max_attempts = 50 + } + +``` + +JSON example: +```json + + "aws_polling" : { + "delay_seconds": 30, + "max_attempts": 50 + } + +``` + + + + + + +- `max_attempts` (int) - Specifies the maximum number of attempts the waiter will check for resource state. + This value can also be set via the AWS_MAX_ATTEMPTS. + If both option and environment variable are set, the max_attempts will be considered over the AWS_MAX_ATTEMPTS. + If none is set, defaults to AWS waiter default which is 40 max_attempts. + +- `delay_seconds` (int) - Specifies the delay in seconds between attempts to check the resource state. + This value can also be set via the AWS_POLL_DELAY_SECONDS. + If both option and environment variable are set, the delay_seconds will be considered over the AWS_POLL_DELAY_SECONDS. + If none is set, defaults to AWS waiter default which is 15 seconds. + + + + +### Block Devices Configuration + +Block devices can be nested in the +[ebs_volumes](#ebs_volumes) array. + + + +These will be attached when launching your instance. Your +options here may vary depending on the type of VM you use. + +Example use case: + +The following mapping will tell Packer to encrypt the root volume of the +build instance at launch using a specific non-default kms key: + +HCL2 example: + +```hcl + + launch_block_device_mappings { + device_name = "/dev/sda1" + encrypted = true + kms_key_id = "1a2b3c4d-5e6f-1a2b-3c4d-5e6f1a2b3c4d" + } + +``` + +JSON example: +```json +"launch_block_device_mappings": [ + + { + "device_name": "/dev/sda1", + "encrypted": true, + "kms_key_id": "1a2b3c4d-5e6f-1a2b-3c4d-5e6f1a2b3c4d" + } + +] +``` + +Please note that the kms_key_id option in this example exists for +launch_block_device_mappings but not ami_block_device_mappings. + +Documentation for Block Devices Mappings can be found here: +https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/block-device-mapping-concepts.html + + + + +#### Optional: + + + +- `delete_on_termination` (bool) - Indicates whether the EBS volume is deleted on instance termination. + Default false. NOTE: If this value is not explicitly set to true and + volumes are not cleaned up by an alternative method, additional volumes + will accumulate after every build. + +- `device_name` (string) - The device name exposed to the instance (for example, /dev/sdh or xvdh). + Required for every device in the block device mapping. + +- `encrypted` (boolean) - Indicates whether or not to encrypt the volume. By default, Packer will + keep the encryption setting to what it was in the source image. Setting + false will result in an unencrypted device, and true will result in an + encrypted one. + +- `iops` (\*int64) - The number of I/O operations per second (IOPS) that the volume supports. + See the documentation on + [IOPs](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_EbsBlockDevice.html) + for more information + +- `no_device` (bool) - Suppresses the specified device included in the block device mapping of + the AMI. + +- `snapshot_id` (string) - The ID of the snapshot. + +- `throughput` (\*int64) - The throughput for gp3 volumes, only valid for gp3 types + See the documentation on + [Throughput](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_EbsBlockDevice.html) + for more information + +- `virtual_name` (string) - The virtual device name. See the documentation on Block Device Mapping + for more information. + +- `volume_type` (string) - The volume type. gp2 & gp3 for General Purpose (SSD) volumes, io1 & io2 + for Provisioned IOPS (SSD) volumes, st1 for Throughput Optimized HDD, + sc1 for Cold HDD, and standard for Magnetic volumes. + +- `volume_size` (int64) - The size of the volume, in GiB. Required if not specifying a + snapshot_id. + +- `kms_key_id` (string) - ID, alias or ARN of the KMS key to use for boot volume encryption. + This option exists for launch_block_device_mappings but not + ami_block_device_mappings. The kms key id defined here only applies to + the original build region; if the AMI gets copied to other regions, the + volume in those regions will be encrypted by the default EBS KMS key. + For valid formats see KmsKeyId in the [AWS API docs - + CopyImage](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CopyImage.html) + This field is validated by Packer. When using an alias, you will have to + prefix kms_key_id with alias/. + + + + + + +- `tags` (map[string]string) - Key/value pair tags to apply to the volume. These are retained after the builder + completes. This is a [template engine](/packer/docs/templates/legacy_json_templates/engine), see + [Build template data](#build-template-data) for more information. + +- `tag` ([]{key string, value string}) - Same as [`tags`](#tags) but defined as a singular repeatable block + containing a `key` and a `value` field. In HCL2 mode the + [`dynamic_block`](/packer/docs/templates/hcl_templates/expressions#dynamic-blocks) + will allow you to create those programatically. + +- `snapshot_volume` (bool) - Create a Snapshot of this Volume. + +- `snapshot_description` (string) - The description for the snapshot. + + + + + + +- `snapshot_tags` (map[string]string) - Key/value pair tags to apply to snapshot. They will override AMI tags if + already applied to snapshot. This is a [template + engine](/packer/docs/templates/legacy_json_templates/engine), see [Build template + data](#build-template-data) for more information. + +- `snapshot_tag` ([]{key string, value string}) - Same as [`snapshot_tags`](#snapshot_tags) but defined as a singular + repeatable block containing a `key` and a `value` field. In HCL2 mode the + [`dynamic_block`](/packer/docs/templates/hcl_templates/expressions#dynamic-blocks) + will allow you to create those programatically. + +- `snapshot_users` ([]string) - A list of account IDs that have + access to create volumes from the snapshot(s). By default no additional + users other than the user creating the AMI has permissions to create + volumes from the backing snapshot(s). + +- `snapshot_groups` ([]string) - A list of groups that have access to + create volumes from the snapshot(s). By default no groups have permission + to create volumes from the snapshot(s). all will make the snapshot + publicly accessible. + + + + +### Run Configuration + +#### Required: + + + +- `instance_type` (string) - The EC2 instance type to use while building the + AMI, such as t2.small. + +- `source_ami` (string) - The source AMI whose root volume will be copied and + provisioned on the currently running instance. This must be an EBS-backed + AMI with a root volume snapshot that you have access to. + + + + +#### Optional: + + + +- `associate_public_ip_address` (confighelper.Trilean) - If using a non-default VPC, + public IP addresses are not provided by default. If this is true, your + new instance will get a Public IP. default: unset + + Note: when specifying this attribute without a `subnet_[id|filter]` or + `vpc_[id|filter]`, we will attempt to infer this information from the + default VPC/Subnet. + This operation may require some extra permissions to the IAM role that + runs the build: + + * ec2:DescribeVpcs + * ec2:DescribeSubnets + + Additionally, since we filter subnets/AZs by their capability to host + an instance of the selected type, you may also want to define the + `ec2:DescribeInstanceTypeOfferings` action to the role running the build. + Otherwise, Packer will pick the most available subnet in the VPC selected, + which may not be able to host the instance type you provided. + +- `availability_zone` (string) - Destination availability zone to launch + instance in. Leave this empty to allow Amazon to auto-assign. + +- `block_duration_minutes` (int64) - Requires spot_price to be set. The + required duration for the Spot Instances (also known as Spot blocks). This + value must be a multiple of 60 (60, 120, 180, 240, 300, or 360). You can't + specify an Availability Zone group or a launch group if you specify a + duration. Note: This parameter is no longer available to new customers + from July 1, 2021. [See Amazon's + documentation](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-requests.html#fixed-duration-spot-instances). + +- `capacity_reservation_preference` (string) - Set the preference for using a capacity reservation if one exists. + Either will be `open` or `none`. Defaults to `none` + +- `capacity_reservation_id` (string) - Provide the specific EC2 Capacity Reservation ID that will be used + by Packer. + +- `capacity_reservation_group_arn` (string) - Provide the EC2 Capacity Reservation Group ARN that will be used by + Packer. + +- `disable_stop_instance` (bool) - Packer normally stops the build instance after all provisioners have + run. For Windows instances, it is sometimes desirable to [run + Sysprep](https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/Creating_EBSbacked_WinAMI.html) + which will stop the instance for you. If this is set to `true`, Packer + *will not* stop the instance but will assume that you will send the stop + signal yourself through your final provisioner. You can do this with a + [windows-shell provisioner](/packer/integrations/hashicorp/windows-shell). Note that + Packer will still wait for the instance to be stopped, and failing to + send the stop signal yourself, when you have set this flag to `true`, + will cause a timeout. + + An example of a valid windows shutdown command in a `windows-shell` + provisioner is : + ```shell-session + ec2config.exe -sysprep + ``` + or + ```sell-session + "%programfiles%\amazon\ec2configservice\"ec2config.exe -sysprep"" + ``` + -> Note: The double quotation marks in the command are not required if + your CMD shell is already in the + `C:\Program Files\Amazon\EC2ConfigService\` directory. + +- `ebs_optimized` (bool) - Mark instance as [EBS + Optimized](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSOptimized.html). + Default `false`. + +- `enable_nitro_enclave` (bool) - Enable support for Nitro Enclaves on the instance. Note that the instance type must + be able to [support Nitro Enclaves](https://aws.amazon.com/ec2/nitro/nitro-enclaves/faqs/). + This option is not supported for spot instances. + +- `enable_t2_unlimited` (bool) - Deprecated argument - please use "enable_unlimited_credits". + Enabling T2 Unlimited allows the source instance to burst additional CPU + beyond its available [CPU + Credits](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/t2-credits-baseline-concepts.html) + for as long as the demand exists. This is in contrast to the standard + configuration that only allows an instance to consume up to its + available CPU Credits. See the AWS documentation for [T2 + Unlimited](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/t2-unlimited.html) + and the **T2 Unlimited Pricing** section of the [Amazon EC2 On-Demand + Pricing](https://aws.amazon.com/ec2/pricing/on-demand/) document for + more information. By default this option is disabled and Packer will set + up a [T2 + Standard](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/t2-std.html) + instance instead. + + To use T2 Unlimited you must use a T2 instance type, e.g. `t2.micro`. + Additionally, T2 Unlimited cannot be used in conjunction with Spot + Instances, e.g. when the `spot_price` option has been configured. + Attempting to do so will cause an error. + + !> **Warning!** Additional costs may be incurred by enabling T2 + Unlimited - even for instances that would usually qualify for the + [AWS Free Tier](https://aws.amazon.com/free/). + +- `enable_unlimited_credits` (bool) - Enabling Unlimited credits allows the source instance to burst additional CPU + beyond its available [CPU + Credits](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/burstable-performance-instances-unlimited-mode-concepts.html#unlimited-mode-surplus-credits) + for as long as the demand exists. This is in contrast to the standard + configuration that only allows an instance to consume up to its + available CPU Credits. See the AWS documentation for [T2 + Unlimited](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/burstable-performance-instances-unlimited-mode-concepts.html) + and the **Unlimited Pricing** section of the [Amazon EC2 On-Demand + Pricing](https://aws.amazon.com/ec2/pricing/on-demand/) document for + more information. By default this option is disabled and Packer will set + up a [Standard](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/burstable-performance-instances-standard-mode.html) + instance instead. + + To use Unlimited you must use a T2/T3/T3a/T4g instance type, e.g. (`t2.micro`, `t3.micro`). + Additionally, Unlimited cannot be used in conjunction with Spot + Instances for T2 type instances, e.g. when the `spot_price` option has been configured. + Attempting to do so will cause an error if the underlying instance type is a T2 type instance. + By default the supported burstable instance types (including t3/t3a/t4g) will be provisioned with its cpu credits set to standard, + only when `enable_unlimited_credits` is true will the instance be provisioned with unlimited cpu credits. + +- `iam_instance_profile` (string) - The name of an [IAM instance + profile](https://docs.aws.amazon.com/IAM/latest/UserGuide/instance-profiles.html) + to launch the EC2 instance with. + +- `fleet_tags` (map[string]string) - Key/value pair tags to apply tags to the fleet that is issued. + +- `fleet_tag` ([]{key string, value string}) - Same as [`fleet_tags`](#fleet_tags) but defined as a singular repeatable block + containing a `key` and a `value` field. In HCL2 mode the + [`dynamic_block`](/packer/docs/templates/hcl_templates/expressions#dynamic-blocks) + will allow you to create those programatically. + +- `skip_profile_validation` (bool) - Whether or not to check if the IAM instance profile exists. Defaults to false + +- `temporary_iam_instance_profile_policy_document` (\*PolicyDocument) - Temporary IAM instance profile policy document + If IamInstanceProfile is specified it will be used instead. + + HCL2 example: + ```hcl + temporary_iam_instance_profile_policy_document { + Statement { + Action = ["logs:*"] + Effect = "Allow" + Resource = ["*"] + } + Version = "2012-10-17" + } + ``` + + JSON example: + ```json + { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "logs:*" + ], + "Effect": "Allow", + "Resource": ["*"] + } + ] + } + ``` + +- `shutdown_behavior` (string) - Automatically terminate instances on + shutdown in case Packer exits ungracefully. Possible values are stop and + terminate. Defaults to stop. + +- `security_group_filter` (SecurityGroupFilterOptions) - Filters used to populate the `security_group_ids` field. + + HCL2 Example: + + ```hcl + security_group_filter { + filters = { + "tag:Class": "packer" + } + } + ``` + + JSON Example: + ```json + { + "security_group_filter": { + "filters": { + "tag:Class": "packer" + } + } + } + ``` + + This selects the SG's with tag `Class` with the value `packer`. + + - `filters` (map[string,string] | multiple filters are allowed when seperated by commas) - filters used to select a + `security_group_ids`. Any filter described in the docs for + [DescribeSecurityGroups](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSecurityGroups.html) + is valid. + + `security_group_ids` take precedence over this. + +- `run_tags` (map[string]string) - Key/value pair tags to apply to the generated key-pair, security group, iam profile and role, snapshot, network interfaces and instance + that is *launched* to create the EBS volumes. The resulting AMI will also inherit these tags. + This is a [template + engine](/packer/docs/templates/legacy_json_templates/engine), see [Build template + data](#build-template-data) for more information. + +- `run_tag` ([]{key string, value string}) - Same as [`run_tags`](#run_tags) but defined as a singular repeatable + block containing a `key` and a `value` field. In HCL2 mode the + [`dynamic_block`](/packer/docs/templates/hcl_templates/expressions#dynamic-blocks) + will allow you to create those programatically. + +- `security_group_id` (string) - The ID (not the name) of the security + group to assign to the instance. By default this is not set and Packer will + automatically create a new temporary security group to allow SSH access. + Note that if this is specified, you must be sure the security group allows + access to the ssh_port given below. + +- `security_group_ids` ([]string) - A list of security groups as + described above. Note that if this is specified, you must omit the + security_group_id. + +- `source_ami_filter` (AmiFilterOptions) - Filters used to populate the `source_ami` + field. + + HCL2 example: + ```hcl + source "amazon-ebs" "basic-example" { + source_ami_filter { + filters = { + virtualization-type = "hvm" + name = "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*" + root-device-type = "ebs" + } + owners = ["099720109477"] + most_recent = true + } + } + ``` + + JSON Example: + ```json + "builders" [ + { + "type": "amazon-ebs", + "source_ami_filter": { + "filters": { + "virtualization-type": "hvm", + "name": "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*", + "root-device-type": "ebs" + }, + "owners": ["099720109477"], + "most_recent": true + } + } + ] + ``` + + This selects the most recent Ubuntu 16.04 HVM EBS AMI from Canonical. NOTE: + This will fail unless *exactly* one AMI is returned. In the above example, + `most_recent` will cause this to succeed by selecting the newest image. + + - `filters` (map[string,string] | multiple filters are allowed when seperated by commas) - filters used to select a `source_ami`. + NOTE: This will fail unless *exactly* one AMI is returned. Any filter + described in the docs for + [DescribeImages](http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeImages.html) + is valid. + + - `owners` (array of strings) - Filters the images by their owner. You + may specify one or more AWS account IDs, "self" (which will use the + account whose credentials you are using to run Packer), or an AWS owner + alias: for example, `amazon`, `aws-marketplace`, or `microsoft`. This + option is required for security reasons. + + - `most_recent` (boolean) - Selects the newest created image when true. + This is most useful for selecting a daily distro build. + + You may set this in place of `source_ami` or in conjunction with it. If you + set this in conjunction with `source_ami`, the `source_ami` will be added + to the filter. The provided `source_ami` must meet all of the filtering + criteria provided in `source_ami_filter`; this pins the AMI returned by the + filter, but will cause Packer to fail if the `source_ami` does not exist. + +- `spot_instance_types` ([]string) - a list of acceptable instance + types to run your build on. We will request a spot instance using the max + price of spot_price and the allocation strategy of "lowest price". + Your instance will be launched on an instance type of the lowest available + price that you have in your list. This is used in place of instance_type. + You may only set either spot_instance_types or instance_type, not both. + This feature exists to help prevent situations where a Packer build fails + because a particular availability zone does not have capacity for the + specific instance_type requested in instance_type. + +- `spot_price` (string) - With Spot Instances, you pay the Spot price that's in effect for the + time period your instances are running. Spot Instance prices are set by + Amazon EC2 and adjust gradually based on long-term trends in supply and + demand for Spot Instance capacity. + + When this field is set, it represents the maximum hourly price you are + willing to pay for a spot instance. If you do not set this value, it + defaults to a maximum price equal to the on demand price of the + instance. In the situation where the current Amazon-set spot price + exceeds the value set in this field, Packer will not launch an instance + and the build will error. In the situation where the Amazon-set spot + price is less than the value set in this field, Packer will launch and + you will pay the Amazon-set spot price, not this maximum value. + For more information, see the Amazon docs on + [spot pricing](https://aws.amazon.com/ec2/spot/pricing/). + +- `spot_tags` (map[string]string) - Requires spot_price to be set. Key/value pair tags to apply tags to the + spot request that is issued. + +- `spot_tag` ([]{key string, value string}) - Same as [`spot_tags`](#spot_tags) but defined as a singular repeatable block + containing a `key` and a `value` field. In HCL2 mode the + [`dynamic_block`](/packer/docs/templates/hcl_templates/expressions#dynamic-blocks) + will allow you to create those programatically. + +- `subnet_filter` (SubnetFilterOptions) - Filters used to populate the `subnet_id` field. + + HCL2 example: + + ```hcl + source "amazon-ebs" "basic-example" { + subnet_filter { + filters = { + "tag:Class": "build" + } + most_free = true + random = false + } + } + ``` + + JSON Example: + ```json + "builders" [ + { + "type": "amazon-ebs", + "subnet_filter": { + "filters": { + "tag:Class": "build" + }, + "most_free": true, + "random": false + } + } + ] + ``` + + This selects the Subnet with tag `Class` with the value `build`, which has + the most free IP addresses. NOTE: This will fail unless *exactly* one + Subnet is returned. By using `most_free` or `random` one will be selected + from those matching the filter. + + - `filters` (map[string,string] | multiple filters are allowed when seperated by commas) - filters used to select a `subnet_id`. + NOTE: This will fail unless *exactly* one Subnet is returned. Any + filter described in the docs for + [DescribeSubnets](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSubnets.html) + is valid. + + - `most_free` (boolean) - The Subnet with the most free IPv4 addresses + will be used if multiple Subnets matches the filter. + + - `random` (boolean) - A random Subnet will be used if multiple Subnets + matches the filter. `most_free` have precendence over this. + + `subnet_id` take precedence over this. + +- `subnet_id` (string) - If using VPC, the ID of the subnet, such as + subnet-12345def, where Packer will launch the EC2 instance. This field is + required if you are using an non-default VPC. + +- `license_specifications` ([]LicenseSpecification) - The license configurations. + + HCL2 example: + ```hcl + source "amazon-ebs" "basic-example" { + license_specifications { + license_configuration_request = { + license_configuration_arn = "${var.license_configuration_arn}" + } + } + } + ``` + + JSON example: + ```json + "builders" [ + { + "type": "amazon-ebs", + "license_specifications": [ + { + "license_configuration_request": { + "license_configuration_arn": "{{user `license_configuration_arn`}}" + } + } + ] + } + ] + ``` + + Each `license_configuration_request` describes a license configuration, + the properties of which are: + + - `license_configuration_arn` (string) - The Amazon Resource Name (ARN) + of the license configuration. + +- `placement` (Placement) - Describes the placement of an instance. + + HCL2 example: + ```hcl + source "amazon-ebs" "basic-example" { + placement = { + host_resource_group_arn = "${var.host_resource_group_arn}" + tenancy = "${var.placement_tenancy}" + } + } + ``` + + JSON example: + ```json + "builders" [ + { + "type": "amazon-ebs", + "placement": { + "host_resource_group_arn": "{{user `host_resource_group_arn`}}", + "tenancy": "{{user `placement_tenancy`}}" + } + } + ] + ``` + + - `host_resource_group_arn` (string) - The ARN of the host resource + group in which to launch the instances. If you specify a host + resource group ARN, omit the Tenancy parameter or set it to `host`. + - `tenancy` (string) - The tenancy of the instance (if the instance is + running in a VPC). An instance with a tenancy of `dedicated` runs on + single-tenant hardware. The default is `default`, meaning shared + tenancy. Allowed values are `default`, `dedicated` and `host`. + +- `tenancy` (string) - Deprecated: Use Placement Tenancy instead. + +- `temporary_security_group_source_cidrs` ([]string) - A list of IPv4 CIDR blocks to be authorized access to the instance, when + packer is creating a temporary security group. + + The default is [`0.0.0.0/0`] (i.e., allow any IPv4 source). + Use `temporary_security_group_source_public_ip` to allow current host's + public IP instead of any IPv4 source. + This is only used when `security_group_id` or `security_group_ids` is not + specified. + +- `temporary_security_group_source_public_ip` (bool) - When enabled, use public IP of the host (obtained from https://checkip.amazonaws.com) + as CIDR block to be authorized access to the instance, when packer + is creating a temporary security group. Defaults to `false`. + + This is only used when `security_group_id`, `security_group_ids`, + and `temporary_security_group_source_cidrs` are not specified. + +- `user_data` (string) - User data to apply when launching the instance. Note + that you need to be careful about escaping characters due to the templates + being JSON. It is often more convenient to use user_data_file, instead. + Packer will not automatically wait for a user script to finish before + shutting down the instance this must be handled in a provisioner. + +- `user_data_file` (string) - Path to a file that will be used for the user + data when launching the instance. + +- `vpc_filter` (VpcFilterOptions) - Filters used to populate the `vpc_id` field. + + HCL2 example: + ```hcl + source "amazon-ebs" "basic-example" { + vpc_filter { + filters = { + "tag:Class": "build", + "isDefault": "false", + "cidr": "/24" + } + } + } + ``` + + JSON Example: + ```json + "builders" [ + { + "type": "amazon-ebs", + "vpc_filter": { + "filters": { + "tag:Class": "build", + "isDefault": "false", + "cidr": "/24" + } + } + } + ] + ``` + + This selects the VPC with tag `Class` with the value `build`, which is not + the default VPC, and have a IPv4 CIDR block of `/24`. NOTE: This will fail + unless *exactly* one VPC is returned. + + - `filters` (map[string,string] | multiple filters are allowed when seperated by commas) - filters used to select a `vpc_id`. NOTE: + This will fail unless *exactly* one VPC is returned. Any filter + described in the docs for + [DescribeVpcs](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeVpcs.html) + is valid. + + `vpc_id` take precedence over this. + +- `vpc_id` (string) - If launching into a VPC subnet, Packer needs the VPC ID + in order to create a temporary security group within the VPC. Requires + subnet_id to be set. If this field is left blank, Packer will try to get + the VPC ID from the subnet_id. + +- `windows_password_timeout` (duration string | ex: "1h5m2s") - The timeout for waiting for a Windows + password for Windows instances. Defaults to 20 minutes. Example value: + 10m + +- `metadata_options` (MetadataOptions) - [Metadata Settings](#metadata-settings) + +- `ssh_interface` (string) - One of `public_ip`, `private_ip`, `public_dns`, `private_dns` or `session_manager`. + If set, either the public IP address, private IP address, public DNS name + or private DNS name will be used as the host for SSH. The default behaviour + if inside a VPC is to use the public IP address if available, otherwise + the private IP address will be used. If not in a VPC the public DNS name + will be used. Also works for WinRM. + + Where Packer is configured for an outbound proxy but WinRM traffic + should be direct, `ssh_interface` must be set to `private_dns` and + `.compute.internal` included in the `NO_PROXY` environment + variable. + + When using `session_manager` the machine running Packer must have + the AWS Session Manager Plugin installed and within the users' system path. + Connectivity via the `session_manager` interface establishes a secure tunnel + between the local host and the remote host on an available local port to the specified `ssh_port`. + See [Session Manager Connections](#session-manager-connections) for more information. + - Session manager connectivity is currently only implemented for the SSH communicator, not the WinRM communicator. + - Upon termination the secure tunnel will be terminated automatically, if however there is a failure in + terminating the tunnel it will automatically terminate itself after 20 minutes of inactivity. + +- `pause_before_ssm` (duration string | ex: "1h5m2s") - The time to wait before establishing the Session Manager session. + The value of this should be a duration. Examples are + `5s` and `1m30s` which will cause Packer to wait five seconds and one + minute 30 seconds, respectively. If no set, defaults to 10 seconds. + This option is useful when the remote port takes longer to become available. + +- `session_manager_port` (int) - Which port to connect the local end of the session tunnel to. If + left blank, Packer will choose a port for you from available ports. + This option is only used when `ssh_interface` is set `session_manager`. + + + + +#### Metadata Settings + + + +Configures the metadata options. +See [Configure IMDS](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html) for details. + + + + + + +- `http_endpoint` (string) - A string to enable or disable the IMDS endpoint for an instance. Defaults to enabled. + Accepts either "enabled" or "disabled" + +- `http_tokens` (string) - A string to either set the use of IMDSv2 for the instance to optional or required. Defaults to "optional". + Accepts either "optional" or "required" + +- `http_put_response_hop_limit` (int64) - A numerical value to set an upper limit for the amount of hops allowed when communicating with IMDS endpoints. + Defaults to 1. + +- `instance_metadata_tags` (string) - A string to enable or disable access to instance tags from the instance metadata. Defaults to disabled. + Access to instance metadata tags is available for commercial regions. For non-commercial regions please check availability before enabling. + Accepts either "enabled" or "disabled" + + + + +Usage Example + +**HCL2** + +```hcl +source "amazon-ebs" "basic-example" { + region = "us-east-1" + source_ami = "ami-fce3c696" + instance_type = "t2.micro" + ssh_username = "ubuntu" + ami_name = "packer_AWS_example_{{timestamp}}" + metadata_options { + http_endpoint = "enabled" + http_tokens = "required" + http_put_response_hop_limit = 1 + } +} +``` + +**JSON** + +```json +{ + "variables": { + "aws_access_key": "{{env `AWS_ACCESS_KEY_ID`}}", + "aws_secret_key": "{{env `AWS_SECRET_ACCESS_KEY`}}" + }, + "builders": [ + { + "type": "amazon-ebs", + "access_key": "{{user `aws_access_key`}}", + "secret_key": "{{user `aws_secret_key`}}", + "region": "us-east-1", + "source_ami": "ami-fce3c696", + "instance_type": "t2.micro", + "ssh_username": "ubuntu", + "ami_name": "packer_AWS {{timestamp}}", + "metadata_options": { + "http_endpoint": "enabled", + "http_tokens": "required", + "http_put_response_hop_limit": 1 + } + } + ] +} +``` + + +### Session Manager Connections + +Support for the AWS Systems Manager session manager lets users manage EC2 instances without the need to open inbound ports, or maintain bastion hosts. Session manager connectivity relies on the use of the [session manager plugin](#session-manager-plugin) to open a secure tunnel between the local machine and the remote instance. Once the tunnel has been created all SSH communication will be tunneled through SSM to the remote instance. + +-> Note: Session manager connectivity is currently only implemented for the SSH communicator, not the WinRM Communicator. + +To use the session manager as the connection interface for the SSH communicator you need to add the following configuration options to the Amazon builder options: + +- `ssh_interface`: The ssh interface must be set to "session_manager". When using this option the builder will create an SSM tunnel to the configured `ssh_port` (defaults to 22) on the remote host. +- `iam_instance_profile`: A valid instance profile granting Systems Manager permissions to manage the remote instance is required in order for the aws ssm-agent to start and stop session connections. + See below for more details on [IAM instance profile for Systems Manager](#iam-instance-profile-for-systems-manager). + +#### Optional + +- `session_manager_port`: A local port on the host machine that should be used as the local end of the session tunnel to the remote host. If not specified Packer will find an available port to use. +- `temporary_iam_instance_profile_policy_document`: Creates a temporary instance profile policy document to grant Systems Manager permissions to the Ec2 instance. This is an alternative to using an existing `iam_instance_profile`. + +HCL2 example: + +```hcl +# file: example.pkr.hcl + +# In order to get these variables to read from the environment, +# set the environment variables to have the same name as the declared +# variables, with the prefix PKR_VAR_. +# You could also hardcode them into the file, but we do not recommend that. + +data "amazon-ami" "example" { + filters = { + virtualization-type = "hvm" + name = "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*" + root-device-type = "ebs" + } + owners = ["099720109477"] + most_recent = true + region = "us-east-1" +} + +source "amazon-ebs" "ssm-example" { + ami_name = "packer_AWS {{timestamp}}" + instance_type = "t2.micro" + region = "us-east-1" + source_ami = data.amazon-ami.example.id + ssh_username = "ubuntu" + ssh_interface = "session_manager" + communicator = "ssh" + iam_instance_profile = "myinstanceprofile" +} + +build { + sources = ["source.amazon-ebs.ssm-example"] + + provisioner "shell" { + inline = ["echo Connected via SSM at '${build.User}@${build.Host}:${build.Port}'"] + } +} +``` + +JSON example: + +```json +{ + "builders": [ + { + "type": "amazon-ebs", + "ami_name": "packer-ami-{{timestamp}}", + "instance_type": "t2.micro", + "source_ami_filter": { + "filters": { + "virtualization-type": "hvm", + "name": "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*", + "root-device-type": "ebs" + }, + "owners": ["099720109477"], + "most_recent": true + }, + "ssh_username": "ubuntu", + "ssh_interface": "session_manager", + "communicator": "ssh", + "iam_instance_profile": "{{user `iam_instance_profile`}}" + } + ], + "provisioners": [ + { + "type": "shell", + "inline": [ + "echo Connected via SSM at '{{build `User`}}@{{build `Host`}}:{{build `Port`}}'" + ] + } + ] +} +``` + +#### Session Manager Plugin + +Connectivity via the session manager requires the use of a session-manger-plugin, which needs to be installed alongside Packer, and an instance AMI that is capable of running the AWS ssm-agent - see [About SSM Agent](https://docs.aws.amazon.com/systems-manager/latest/userguide/prereqs-ssm-agent.html) for details on supported AMIs. + +In order for Packer to start and end sessions that connect you to your managed instances, you must first install the Session Manager plugin on your local machine. The plugin can be installed on supported versions of Microsoft Windows, macOS, Linux, and Ubuntu Server. +[Installation instructions for the session-manager-plugin](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html) + +#### IAM instance profile for Systems Manager + +By default Systems Manager doesn't have permission to perform actions on created instances so SSM access must be granted by creating an instance profile with the `AmazonSSMManagedInstanceCore` policy. The instance profile can then be attached to any instance you wish to manage via the session-manager-plugin. See [Adding System Manager instance profile](https://docs.aws.amazon.com/systems-manager/latest/userguide/setup-instance-profile.html#instance-profile-add-permissions) for details on creating the required instance profile. + +#### Permissions for Closing the Tunnel + +To close the SSM tunnels created, this plugin relies on being able to call +[DescribeInstanceStatus](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeInstanceStatus.html). +In case this is not possible you might see a `Bad exit status` message in the logs. + +The absence of this permission won't prevent you from building the AMI, and the error only means that packer is not able to close the tunnel gracefully. + + +### Communicator Configuration + +#### Optional: + + + +- `communicator` (string) - Packer currently supports three kinds of communicators: + + - `none` - No communicator will be used. If this is set, most + provisioners also can't be used. + + - `ssh` - An SSH connection will be established to the machine. This + is usually the default. + + - `winrm` - A WinRM connection will be established. + + In addition to the above, some builders have custom communicators they + can use. For example, the Docker builder has a "docker" communicator + that uses `docker exec` and `docker cp` to execute scripts and copy + files. + +- `pause_before_connecting` (duration string | ex: "1h5m2s") - We recommend that you enable SSH or WinRM as the very last step in your + guest's bootstrap script, but sometimes you may have a race condition + where you need Packer to wait before attempting to connect to your + guest. + + If you end up in this situation, you can use the template option + `pause_before_connecting`. By default, there is no pause. For example if + you set `pause_before_connecting` to `10m` Packer will check whether it + can connect, as normal. But once a connection attempt is successful, it + will disconnect and then wait 10 minutes before connecting to the guest + and beginning provisioning. + + + + + + +- `ssh_host` (string) - The address to SSH to. This usually is automatically configured by the + builder. + +- `ssh_port` (int) - The port to connect to SSH. This defaults to `22`. + +- `ssh_username` (string) - The username to connect to SSH with. Required if using SSH. + +- `ssh_password` (string) - A plaintext password to use to authenticate with SSH. + +- `ssh_ciphers` ([]string) - This overrides the value of ciphers supported by default by Golang. + The default value is [ + "aes128-gcm@openssh.com", + "chacha20-poly1305@openssh.com", + "aes128-ctr", "aes192-ctr", "aes256-ctr", + ] + + Valid options for ciphers include: + "aes128-ctr", "aes192-ctr", "aes256-ctr", "aes128-gcm@openssh.com", + "chacha20-poly1305@openssh.com", + "arcfour256", "arcfour128", "arcfour", "aes128-cbc", "3des-cbc", + +- `ssh_clear_authorized_keys` (bool) - If true, Packer will attempt to remove its temporary key from + `~/.ssh/authorized_keys` and `/root/.ssh/authorized_keys`. This is a + mostly cosmetic option, since Packer will delete the temporary private + key from the host system regardless of whether this is set to true + (unless the user has set the `-debug` flag). Defaults to "false"; + currently only works on guests with `sed` installed. + +- `ssh_key_exchange_algorithms` ([]string) - If set, Packer will override the value of key exchange (kex) algorithms + supported by default by Golang. Acceptable values include: + "curve25519-sha256@libssh.org", "ecdh-sha2-nistp256", + "ecdh-sha2-nistp384", "ecdh-sha2-nistp521", + "diffie-hellman-group14-sha1", and "diffie-hellman-group1-sha1". + +- `ssh_certificate_file` (string) - Path to user certificate used to authenticate with SSH. + The `~` can be used in path and will be expanded to the + home directory of current user. + +- `ssh_pty` (bool) - If `true`, a PTY will be requested for the SSH connection. This defaults + to `false`. + +- `ssh_timeout` (duration string | ex: "1h5m2s") - The time to wait for SSH to become available. Packer uses this to + determine when the machine has booted so this is usually quite long. + Example value: `10m`. + This defaults to `5m`, unless `ssh_handshake_attempts` is set. + +- `ssh_disable_agent_forwarding` (bool) - If true, SSH agent forwarding will be disabled. Defaults to `false`. + +- `ssh_handshake_attempts` (int) - The number of handshakes to attempt with SSH once it can connect. + This defaults to `10`, unless a `ssh_timeout` is set. + +- `ssh_bastion_host` (string) - A bastion host to use for the actual SSH connection. + +- `ssh_bastion_port` (int) - The port of the bastion host. Defaults to `22`. + +- `ssh_bastion_agent_auth` (bool) - If `true`, the local SSH agent will be used to authenticate with the + bastion host. Defaults to `false`. + +- `ssh_bastion_username` (string) - The username to connect to the bastion host. + +- `ssh_bastion_password` (string) - The password to use to authenticate with the bastion host. + +- `ssh_bastion_interactive` (bool) - If `true`, the keyboard-interactive used to authenticate with bastion host. + +- `ssh_bastion_private_key_file` (string) - Path to a PEM encoded private key file to use to authenticate with the + bastion host. The `~` can be used in path and will be expanded to the + home directory of current user. + +- `ssh_bastion_certificate_file` (string) - Path to user certificate used to authenticate with bastion host. + The `~` can be used in path and will be expanded to the + home directory of current user. + +- `ssh_file_transfer_method` (string) - `scp` or `sftp` - How to transfer files, Secure copy (default) or SSH + File Transfer Protocol. + + **NOTE**: Guests using Windows with Win32-OpenSSH v9.1.0.0p1-Beta, scp + (the default protocol for copying data) returns a a non-zero error code since the MOTW + cannot be set, which cause any file transfer to fail. As a workaround you can override the transfer protocol + with SFTP instead `ssh_file_transfer_protocol = "sftp"`. + +- `ssh_proxy_host` (string) - A SOCKS proxy host to use for SSH connection + +- `ssh_proxy_port` (int) - A port of the SOCKS proxy. Defaults to `1080`. + +- `ssh_proxy_username` (string) - The optional username to authenticate with the proxy server. + +- `ssh_proxy_password` (string) - The optional password to use to authenticate with the proxy server. + +- `ssh_keep_alive_interval` (duration string | ex: "1h5m2s") - How often to send "keep alive" messages to the server. Set to a negative + value (`-1s`) to disable. Example value: `10s`. Defaults to `5s`. + +- `ssh_read_write_timeout` (duration string | ex: "1h5m2s") - The amount of time to wait for a remote command to end. This might be + useful if, for example, packer hangs on a connection after a reboot. + Example: `5m`. Disabled by default. + +- `ssh_remote_tunnels` ([]string) - + +- `ssh_local_tunnels` ([]string) - + + + + + + +- `temporary_key_pair_type` (string) - `dsa` | `ecdsa` | `ed25519` | `rsa` ( the default ) + + Specifies the type of key to create. The possible values are 'dsa', + 'ecdsa', 'ed25519', or 'rsa'. + + NOTE: DSA is deprecated and no longer recognized as secure, please + consider other alternatives like RSA or ED25519. + +- `temporary_key_pair_bits` (int) - Specifies the number of bits in the key to create. For RSA keys, the + minimum size is 1024 bits and the default is 4096 bits. Generally, 3072 + bits is considered sufficient. DSA keys must be exactly 1024 bits as + specified by FIPS 186-2. For ECDSA keys, bits determines the key length + by selecting from one of three elliptic curve sizes: 256, 384 or 521 + bits. Attempting to use bit lengths other than these three values for + ECDSA keys will fail. Ed25519 keys have a fixed length and bits will be + ignored. + + NOTE: DSA is deprecated and no longer recognized as secure as specified + by FIPS 186-5, please consider other alternatives like RSA or ED25519. + + + + +- `ssh_keypair_name` (string) - If specified, this is the key that will be used for SSH with the + machine. The key must match a key pair name loaded up into the remote. + By default, this is blank, and Packer will generate a temporary keypair + unless [`ssh_password`](#ssh_password) is used. + [`ssh_private_key_file`](#ssh_private_key_file) or + [`ssh_agent_auth`](#ssh_agent_auth) must be specified when + [`ssh_keypair_name`](#ssh_keypair_name) is utilized. + + +- `ssh_private_key_file` (string) - Path to a PEM encoded private key file to use to authenticate with SSH. + The `~` can be used in path and will be expanded to the home directory + of current user. + + +- `ssh_agent_auth` (bool) - If true, the local SSH agent will be used to authenticate connections to + the source instance. No temporary keypair will be created, and the + values of [`ssh_password`](#ssh_password) and + [`ssh_private_key_file`](#ssh_private_key_file) will be ignored. The + environment variable `SSH_AUTH_SOCK` must be set for this option to work + properly. + + +## Basic Example + +**HCL2** + +```hcl +source "amazon-ebsvolume" "basic-example" { + region = "us-east-1" + ssh_username = "ubuntu" + instance_type = "t2.medium" + source_ami = "ami-40d28157" + + ebs_volumes { + volume_type = "gp2" + device_name = "/dev/xvdf" + delete_on_termination = false + tags = { + zpool = "data" + Name = "Data1" + } + volume_size = 10 + } + + ebs_volumes { + volume_type = "gp2" + device_name = "/dev/xvdg" + tags = { + zpool = "data" + Name = "Data2" + } + delete_on_termination = false + volume_size = 10 + } + + ebs_volumes { + volume_size = 10 + tags = { + zpool = "data" + Name = "Data3" + } + delete_on_termination = false + device_name = "/dev/xvdh" + volume_type = "gp2" + } +} + +build { + sources = ["sources.amazon-ebsvolume.basic-example"] +} +``` + +**JSON** + +```json +{ + "builders": [ + { + "type": "amazon-ebsvolume", + "region": "us-east-1", + "ssh_username": "ubuntu", + "instance_type": "t2.medium", + "source_ami": "ami-40d28157", + "ebs_volumes": [ + { + "volume_type": "gp2", + "device_name": "/dev/xvdf", + "delete_on_termination": false, + "tags": { + "zpool": "data", + "Name": "Data1" + }, + "volume_size": 10 + }, + { + "volume_type": "gp2", + "device_name": "/dev/xvdg", + "tags": { + "zpool": "data", + "Name": "Data2" + }, + "delete_on_termination": false, + "volume_size": 10 + }, + { + "volume_size": 10, + "tags": { + "Name": "Data3", + "zpool": "data" + }, + "delete_on_termination": false, + "device_name": "/dev/xvdh", + "volume_type": "gp2" + } + ] + } + ] +} +``` + + +-> **Note:** Packer can also read the access key and secret access key from +environmental variables. See the configuration reference in the section above +for more information on what environmental variables Packer will look for. + +Further information on locating AMI IDs and their relationship to instance +types and regions can be found in the AWS EC2 Documentation [for +Linux](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/finding-an-ami.html) +or [for +Windows](http://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/finding-an-ami.html). + +## Accessing the Instance to Debug + +If you need to access the instance to debug for some reason, run the builder +with the `-debug` flag. In debug mode, the Amazon builder will save the private +key in the current directory and will output the DNS or IP information as well. +You can use this information to access the instance as it is running. + +## Build template data + +In configuration directives marked as a template engine above, the following +variables are available: + +- `BuildRegion` - The region (for example `eu-central-1`) where Packer is + building the AMI. +- `SourceAMI` - The source AMI ID (for example `ami-a2412fcd`) used to build + the AMI. +- `SourceAMICreationDate` - The source AMI creation date (for example `"2020-05-14T19:26:34.000Z"`). +- `SourceAMIName` - The source AMI Name (for example + `ubuntu/images/ebs-ssd/ubuntu-xenial-16.04-amd64-server-20180306`) used to + build the AMI. +- `SourceAMIOwner` - The source AMI owner ID. +- `SourceAMIOwnerName` - The source AMI owner alias/name (for example `amazon`). +- `SourceAMITags` - The source AMI Tags, as a `map[string]string` object. + +## Build Shared Information Variables + +This builder generates data that are shared with provisioner and post-processor via build function of [template engine](/packer/docs/templates/legacy_json_templates/engine) for JSON and [contextual variables](/packer/docs/templates/hcl_templates/contextual-variables) for HCL2. + +The generated variables available for this builder are: + +- `BuildRegion` - The region (for example `eu-central-1`) where Packer is + building the AMI. +- `SourceAMI` - The source AMI ID (for example `ami-a2412fcd`) used to build + the AMI. +- `SourceAMICreationDate` - The source AMI creation date (for example `"2020-05-14T19:26:34.000Z"`). +- `SourceAMIName` - The source AMI Name (for example + `ubuntu/images/ebs-ssd/ubuntu-xenial-16.04-amd64-server-20180306`) used to + build the AMI. +- `SourceAMIOwner` - The source AMI owner ID. +- `SourceAMIOwnerName` - The source AMI owner alias/name (for example `amazon`). + +-> **Note:** Packer uses pre-built AMIs as the source for building images. +These source AMIs may include volumes that are not flagged to be destroyed on +termination of the instance building the new image. In addition to those +volumes created by this builder, any volumes in the source AMI which are not +marked for deletion on termination will remain in your account. + +## Build Shared Information Variables + +This builder generates data that are shared with provisioner and post-processor via build function of [template engine](/packer/docs/templates/legacy_json_templates/engine) for JSON and [contextual variables](/packer/docs/templates/hcl_templates/contextual-variables) for HCL2. + +The generated variables available for this builder are: + +- `SourceAMIName` - The source AMI Name (for example + `ubuntu/images/ebs-ssd/ubuntu-xenial-16.04-amd64-server-20180306`) used to + build the AMI. + +Usage example: + +**HCL2** + +```hcl +// When accessing one of these variables from inside the builder, you need to +// use the golang templating syntax. This is due to an architectural quirk that +// won't be easily resolvable until legacy json templates are deprecated: + +{ +source "amazon-ebs" "basic-example" { + tags = { + OS_Version = "Ubuntu" + Release = "Latest" + Base_AMI_ID = "{{ .SourceAMI }}" + Base_AMI_Name = "{{ .SourceAMIName }}" + } +} + +// when accessing one of the variables from a provisioner or post-processor, use +// hcl-syntax +post-processor "manifest" { + output = "manifest.json" + strip_path = true + custom_data = { + source_ami_name = "${build.SourceAMIName}" + } +} +``` + +**JSON** + +```json +"post-processors": [ + { + "type": "manifest", + "output": "manifest.json", + "strip_path": true, + "custom_data": { + "source_ami_name": "{{ build `SourceAMIName` }}" + } + } +] +``` + + +## Which SSH Options to use: + +This chart breaks down what Packer does if you set any of the below SSH options: + +| ssh_password | ssh_private_key_file | ssh_keypair_name | temporary_key_pair_name | Packer will... | +| ------------ | -------------------- | ---------------- | ----------------------- | ------------------------------------------------------------------------------------------ | +| X | - | - | - | ssh authenticating with username and given password | +| - | X | - | - | ssh authenticating with private key file | +| - | X | X | - | ssh authenticating with given private key file and "attaching" the keypair to the instance | +| - | - | - | X | Create a temporary ssh keypair with a particular name, clean it up | +| - | - | - | - | Create a temporary ssh keypair with a default name, clean it up | diff --git a/.web-docs/components/builder/instance/README.md b/.web-docs/components/builder/instance/README.md new file mode 100644 index 000000000..b470612ad --- /dev/null +++ b/.web-docs/components/builder/instance/README.md @@ -0,0 +1,1721 @@ +Type: `amazon-instance` +Artifact BuilderId: `mitchellh.amazon.instance` + +The `amazon-instance` Packer builder is able to create Amazon AMIs backed by +instance storage as the root device. For more information on the difference +between instance storage and EBS-backed instances, see the ["storage for the +root device" section in the EC2 +documentation](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ComponentsAMIs.html#storage-for-the-root-device). + +This builder builds an AMI by launching an EC2 instance from an existing +instance-storage backed AMI, provisioning that running machine, and then +bundling and creating a new AMI from that machine. This is all done in your own +AWS account. This builder will create temporary key pairs, security group +rules, etc. that provide it temporary access to the instance while the image is +being created. This simplifies configuration quite a bit. + +This builder does _not_ manage AMIs. Once it creates an AMI and stores it in +your account, it is up to you to use, delete, etc. the AMI. + +-> **Note:** Temporary resources are, by default, all created with the +prefix `packer`. This can be useful if you want to restrict the security groups +and key pairs packer is able to operate on. + +-> **Note:** This builder requires that the [Amazon EC2 AMI +Tools](https://aws.amazon.com/developertools/368) are installed onto the +machine. This can be done within a provisioner, but must be done before the +builder finishes running. + +~> Instance builds are not supported for Windows. Use +[`amazon-ebs`](/packer/integrations/hashicorp/amazon/latest/components/builder/ebs) instead. + +## Configuration Reference + +There are many configuration options available for the builder. In addition to +the items listed here, you will want to look at the general configuration +references for [AMI](#ami-configuration), +[BlockDevices](#block-devices-configuration), +[Access](#access-configuration), +[Run](#run-configuration) and +[Communicator](#communicator-configuration) +configuration references, which are +necessary for this build to succeed and can be found further down the page. + +### Required: + + + +- `account_id` (string) - Your AWS account ID. This is required for bundling the AMI. This is not + the same as the access key. You can find your account ID in the security + credentials page of your AWS account. + +- `s3_bucket` (string) - The name of the S3 bucket to upload the AMI. This bucket will be created + if it doesn't exist. + +- `x509_cert_path` (string) - The local path to a valid X509 certificate for your AWS account. This is + used for bundling the AMI. This X509 certificate must be registered with + your account from the security credentials page in the AWS console. + +- `x509_key_path` (string) - The local path to the private key for the X509 certificate specified by + x509_cert_path. This is used for bundling the AMI. + + + + +### Optional: + + + +- `ami_block_device_mappings` (awscommon.BlockDevices) - Add one or more block device mappings to the AMI. These will be attached + when booting a new instance from your AMI. To add a block device during + the Packer build see `launch_block_device_mappings` below. Your options + here may vary depending on the type of VM you use. See the + [BlockDevices](#block-devices-configuration) documentation for fields. + +- `launch_block_device_mappings` (awscommon.BlockDevices) - Add one or more block devices before the Packer build starts. If you add + instance store volumes or EBS volumes in addition to the root device + volume, the created AMI will contain block device mapping information + for those volumes. Amazon creates snapshots of the source instance's + root volume and any other EBS volumes described here. When you launch an + instance from this new AMI, the instance automatically launches with + these additional volumes, and will restore them from snapshots taken + from the source instance. See the + [BlockDevices](#block-devices-configuration) documentation for fields. + +- `bundle_destination` (string) - The directory on the running instance where the bundled AMI will be + saved prior to uploading. By default this is /tmp. This directory must + exist and be writable. + +- `bundle_prefix` (string) - The prefix for files created from bundling the root volume. By default + this is `image-{{timestamp}}`. The timestamp variable should be used to + make sure this is unique, otherwise it can collide with other created + AMIs by Packer in your account. + +- `bundle_upload_command` (string) - The command to use to upload the bundled volume. See the "custom bundle + commands" section below for more information. + +- `bundle_vol_command` (string) - The command to use to bundle the volume. See the "custom bundle + commands" section below for more information. + +- `x509_upload_path` (string) - The path on the remote machine where the X509 certificate will be + uploaded. This path must already exist and be writable. X509 + certificates are uploaded after provisioning is run, so it is perfectly + okay to create this directory as part of the provisioning process. + Defaults to /tmp. + +- `tpm_support` (string) - NitroTPM Support. Valid options are `v2.0`. See the documentation on + [NitroTPM Support](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enable-nitrotpm-support-on-ami.html) for + more information. Only enabled if a valid option is provided, otherwise ignored. + + + + +### AMI Configuration + +#### Required: + + + +- `ami_name` (string) - The name of the resulting AMI that will appear when managing AMIs in the + AWS console or via APIs. This must be unique. To help make this unique, + use a function like timestamp (see [template + engine](/packer/docs/templates/legacy_json_templates/engine) for more info). + + + + +#### Optional: + + + +- `ami_description` (string) - The description to set for the resulting + AMI(s). By default this description is empty. This is a + [template engine](/packer/docs/templates/legacy_json_templates/engine), see [Build template + data](#build-template-data) for more information. + +- `ami_virtualization_type` (string) - The type of virtualization for the AMI + you are building. This option is required to register HVM images. Can be + paravirtual (default) or hvm. + +- `ami_users` ([]string) - A list of account IDs that have access to + launch the resulting AMI(s). By default no additional users other than the + user creating the AMI has permissions to launch it. + +- `ami_groups` ([]string) - A list of groups that have access to + launch the resulting AMI(s). By default no groups have permission to launch + the AMI. `all` will make the AMI publicly accessible. + AWS currently doesn't accept any value other than "all" + +- `ami_org_arns` ([]string) - A list of Amazon Resource Names (ARN) of AWS Organizations that have access to + launch the resulting AMI(s). By default no organizations have permission to launch + the AMI. + +- `ami_ou_arns` ([]string) - A list of Amazon Resource Names (ARN) of AWS Organizations organizational units (OU) that have access to + launch the resulting AMI(s). By default no organizational units have permission to launch + the AMI. + +- `ami_product_codes` ([]string) - A list of product codes to + associate with the AMI. By default no product codes are associated with the + AMI. + +- `ami_regions` ([]string) - A list of regions to copy the AMI to. + Tags and attributes are copied along with the AMI. AMI copying takes time + depending on the size of the AMI, but will generally take many minutes. + +- `skip_region_validation` (bool) - Set to true if you want to skip + validation of the ami_regions configuration option. Default false. + +- `tags` (map[string]string) - Key/value pair tags applied to the AMI. This is a [template + engine](/packer/docs/templates/legacy_json_templates/engine), see [Build template + data](#build-template-data) for more information. + + The builder no longer adds a "Name": "Packer Builder" entry to the tags. + +- `tag` ([]{key string, value string}) - Same as [`tags`](#tags) but defined as a singular repeatable block + containing a `key` and a `value` field. In HCL2 mode the + [`dynamic_block`](/packer/docs/templates/hcl_templates/expressions#dynamic-blocks) + will allow you to create those programatically. + +- `ena_support` (boolean) - Enable enhanced networking (ENA but not SriovNetSupport) on + HVM-compatible AMIs. If set, add `ec2:ModifyInstanceAttribute` to your + AWS IAM policy. + + Note: you must make sure enhanced networking is enabled on your + instance. See [Amazon's documentation on enabling enhanced + networking](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enhanced-networking.html#enabling_enhanced_networking). + +- `sriov_support` (bool) - Enable enhanced networking (SriovNetSupport but not ENA) on + HVM-compatible AMIs. If true, add `ec2:ModifyInstanceAttribute` to your + AWS IAM policy. Note: you must make sure enhanced networking is enabled + on your instance. See [Amazon's documentation on enabling enhanced + networking](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enhanced-networking.html#enabling_enhanced_networking). + Default `false`. + +- `force_deregister` (bool) - Force Packer to first deregister an existing + AMI if one with the same name already exists. Default false. + +- `force_delete_snapshot` (bool) - Force Packer to delete snapshots + associated with AMIs, which have been deregistered by force_deregister. + Default false. + +- `encrypt_boot` (boolean) - Whether or not to encrypt the resulting AMI when + copying a provisioned instance to an AMI. By default, Packer will keep + the encryption setting to what it was in the source image. Setting false + will result in an unencrypted image, and true will result in an encrypted + one. + + If you have used the `launch_block_device_mappings` to set an encryption + key and that key is the same as the one you want the image encrypted with + at the end, then you don't need to set this field; leaving it empty will + prevent an unnecessary extra copy step and save you some time. + + Please note that if you are using an account with the global "Always + encrypt new EBS volumes" option set to `true`, Packer will be unable to + override this setting, and the final image will be encrypted whether + you set this value or not. + +- `kms_key_id` (string) - ID, alias or ARN of the KMS key to use for AMI encryption. This + only applies to the main `region` -- any regions the AMI gets copied to + will be encrypted by the default EBS KMS key for that region, + unless you set region-specific keys in `region_kms_key_ids`. + + Set this value if you select `encrypt_boot`, but don't want to use the + region's default KMS key. + + If you have a custom kms key you'd like to apply to the launch volume, + and are only building in one region, it is more efficient to leave this + and `encrypt_boot` empty and to instead set the key id in the + launch_block_device_mappings (you can find an example below). This saves + potentially many minutes at the end of the build by preventing Packer + from having to copy and re-encrypt the image at the end of the build. + + For valid formats see *KmsKeyId* in the [AWS API docs - + CopyImage](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CopyImage.html). + This field is validated by Packer, when using an alias, you will have to + prefix `kms_key_id` with `alias/`. + +- `region_kms_key_ids` (map[string]string) - regions to copy the ami to, along with the custom kms key id (alias or + arn) to use for encryption for that region. Keys must match the regions + provided in `ami_regions`. If you just want to encrypt using a default + ID, you can stick with `kms_key_id` and `ami_regions`. If you want a + region to be encrypted with that region's default key ID, you can use an + empty string `""` instead of a key id in this map. (e.g. `"us-east-1": + ""`) However, you cannot use default key IDs if you are using this in + conjunction with `snapshot_users` -- in that situation you must use + custom keys. For valid formats see *KmsKeyId* in the [AWS API docs - + CopyImage](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CopyImage.html). + + This option supercedes the `kms_key_id` option -- if you set both, and + they are different, Packer will respect the value in + `region_kms_key_ids` for your build region and silently disregard the + value provided in `kms_key_id`. + +- `skip_save_build_region` (bool) - If true, Packer will not check whether an AMI with the `ami_name` exists + in the region it is building in. It will use an intermediary AMI name, + which it will not convert to an AMI in the build region. It will copy + the intermediary AMI into any regions provided in `ami_regions`, then + delete the intermediary AMI. Default `false`. + +- `imds_support` (string) - Enforce version of the Instance Metadata Service on the built AMI. + Valid options are unset (legacy) and `v2.0`. See the documentation on + [IMDS](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html) + for more information. Defaults to legacy. + +- `deprecate_at` (string) - The date and time to deprecate the AMI, in UTC, in the following format: YYYY-MM-DDTHH:MM:SSZ. + If you specify a value for seconds, Amazon EC2 rounds the seconds to the nearest minute. + You can’t specify a date in the past. The upper limit for DeprecateAt is 10 years from now. + + + + +### Access Configuration + +#### Required: + + + +- `access_key` (string) - The access key used to communicate with AWS. [Learn how to set this](/packer/integrations/hashicorp/amazon#specifying-amazon-credentials). + On EBS, this is not required if you are using `use_vault_aws_engine` + for authentication instead. + +- `region` (string) - The name of the region, such as `us-east-1`, in which + to launch the EC2 instance to create the AMI. + When chroot building, this value is guessed from environment. + +- `secret_key` (string) - The secret key used to communicate with AWS. [Learn how to set + this](/packer/integrations/hashicorp/amazon#specifying-amazon-credentials). This is not required + if you are using `use_vault_aws_engine` for authentication instead. + + + + +#### Optional: + + + +- `assume_role` (AssumeRoleConfig) - If provided with a role ARN, Packer will attempt to assume this role + using the supplied credentials. See + [AssumeRoleConfig](#assume-role-configuration) below for more + details on all of the options available, and for a usage example. + +- `custom_endpoint_ec2` (string) - This option is useful if you use a cloud + provider whose API is compatible with aws EC2. Specify another endpoint + like this https://ec2.custom.endpoint.com. + +- `shared_credentials_file` (string) - Path to a credentials file to load credentials from + +- `decode_authorization_messages` (bool) - Enable automatic decoding of any encoded authorization (error) messages + using the `sts:DecodeAuthorizationMessage` API. Note: requires that the + effective user/role have permissions to `sts:DecodeAuthorizationMessage` + on resource `*`. Default `false`. + +- `insecure_skip_tls_verify` (bool) - This allows skipping TLS + verification of the AWS EC2 endpoint. The default is false. + +- `max_retries` (int) - This is the maximum number of times an API call is retried, in the case + where requests are being throttled or experiencing transient failures. + The delay between the subsequent API calls increases exponentially. + +- `mfa_code` (string) - The MFA + [TOTP](https://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm) + code. This should probably be a user variable since it changes all the + time. + +- `profile` (string) - The profile to use in the shared credentials file for + AWS. See Amazon's documentation on [specifying + profiles](https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-profiles) + for more details. + +- `skip_metadata_api_check` (bool) - Skip Metadata Api Check + +- `skip_credential_validation` (bool) - Set to true if you want to skip validating AWS credentials before runtime. + +- `token` (string) - The access token to use. This is different from the + access key and secret key. If you're not sure what this is, then you + probably don't need it. This will also be read from the AWS_SESSION_TOKEN + environmental variable. + +- `vault_aws_engine` (VaultAWSEngineOptions) - Get credentials from HashiCorp Vault's aws secrets engine. You must + already have created a role to use. For more information about + generating credentials via the Vault engine, see the [Vault + docs.](https://www.vaultproject.io/api/secret/aws#generate-credentials) + If you set this flag, you must also set the below options: + - `name` (string) - Required. Specifies the name of the role to generate + credentials against. This is part of the request URL. + - `engine_name` (string) - The name of the aws secrets engine. In the + Vault docs, this is normally referred to as "aws", and Packer will + default to "aws" if `engine_name` is not set. + - `role_arn` (string)- The ARN of the role to assume if credential\_type + on the Vault role is assumed\_role. Must match one of the allowed role + ARNs in the Vault role. Optional if the Vault role only allows a single + AWS role ARN; required otherwise. + - `ttl` (string) - Specifies the TTL for the use of the STS token. This + is specified as a string with a duration suffix. Valid only when + credential\_type is assumed\_role or federation\_token. When not + specified, the default\_sts\_ttl set for the role will be used. If that + is also not set, then the default value of 3600s will be used. AWS + places limits on the maximum TTL allowed. See the AWS documentation on + the DurationSeconds parameter for AssumeRole (for assumed\_role + credential types) and GetFederationToken (for federation\_token + credential types) for more details. + + HCL2 example: + + ```hcl + vault_aws_engine { + name = "myrole" + role_arn = "myarn" + ttl = "3600s" + } + ``` + + JSON example: + + ```json + { + "vault_aws_engine": { + "name": "myrole", + "role_arn": "myarn", + "ttl": "3600s" + } + } + ``` + +- `aws_polling` (\*AWSPollingConfig) - [Polling configuration](#polling-configuration) for the AWS waiter. Configures the waiter that checks + resource state. + + + + +### Assume Role Configuration + + + +AssumeRoleConfig lets users set configuration options for assuming a special +role when executing Packer. + +Usage example: + +HCL config example: + +```HCL + + source "amazon-ebs" "example" { + assume_role { + role_arn = "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME" + session_name = "SESSION_NAME" + external_id = "EXTERNAL_ID" + } + } + +``` + +JSON config example: + +```json + + builder{ + "type": "amazon-ebs", + "assume_role": { + "role_arn" : "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME", + "session_name": "SESSION_NAME", + "external_id" : "EXTERNAL_ID" + } + } + +``` + + + + + + +- `role_arn` (string) - Amazon Resource Name (ARN) of the IAM Role to assume. + +- `duration_seconds` (int) - Number of seconds to restrict the assume role session duration. + +- `external_id` (string) - The external ID to use when assuming the role. If omitted, no external + ID is passed to the AssumeRole call. + +- `policy` (string) - IAM Policy JSON describing further restricting permissions for the IAM + Role being assumed. + +- `policy_arns` ([]string) - Set of Amazon Resource Names (ARNs) of IAM Policies describing further + restricting permissions for the IAM Role being + +- `session_name` (string) - Session name to use when assuming the role. + +- `tags` (map[string]string) - Map of assume role session tags. + +- `transitive_tag_keys` ([]string) - Set of assume role session tag keys to pass to any subsequent sessions. + + + + +### Polling Configuration + + + +Polling configuration for the AWS waiter. Configures the waiter for resources creation or actions like attaching +volumes or importing image. + +HCL2 example: +```hcl + + aws_polling { + delay_seconds = 30 + max_attempts = 50 + } + +``` + +JSON example: +```json + + "aws_polling" : { + "delay_seconds": 30, + "max_attempts": 50 + } + +``` + + + + + + +- `max_attempts` (int) - Specifies the maximum number of attempts the waiter will check for resource state. + This value can also be set via the AWS_MAX_ATTEMPTS. + If both option and environment variable are set, the max_attempts will be considered over the AWS_MAX_ATTEMPTS. + If none is set, defaults to AWS waiter default which is 40 max_attempts. + +- `delay_seconds` (int) - Specifies the delay in seconds between attempts to check the resource state. + This value can also be set via the AWS_POLL_DELAY_SECONDS. + If both option and environment variable are set, the delay_seconds will be considered over the AWS_POLL_DELAY_SECONDS. + If none is set, defaults to AWS waiter default which is 15 seconds. + + + + +### Run Configuration + +#### Required: + + + +- `instance_type` (string) - The EC2 instance type to use while building the + AMI, such as t2.small. + +- `source_ami` (string) - The source AMI whose root volume will be copied and + provisioned on the currently running instance. This must be an EBS-backed + AMI with a root volume snapshot that you have access to. + + + + +#### Optional: + + + +- `associate_public_ip_address` (confighelper.Trilean) - If using a non-default VPC, + public IP addresses are not provided by default. If this is true, your + new instance will get a Public IP. default: unset + + Note: when specifying this attribute without a `subnet_[id|filter]` or + `vpc_[id|filter]`, we will attempt to infer this information from the + default VPC/Subnet. + This operation may require some extra permissions to the IAM role that + runs the build: + + * ec2:DescribeVpcs + * ec2:DescribeSubnets + + Additionally, since we filter subnets/AZs by their capability to host + an instance of the selected type, you may also want to define the + `ec2:DescribeInstanceTypeOfferings` action to the role running the build. + Otherwise, Packer will pick the most available subnet in the VPC selected, + which may not be able to host the instance type you provided. + +- `availability_zone` (string) - Destination availability zone to launch + instance in. Leave this empty to allow Amazon to auto-assign. + +- `block_duration_minutes` (int64) - Requires spot_price to be set. The + required duration for the Spot Instances (also known as Spot blocks). This + value must be a multiple of 60 (60, 120, 180, 240, 300, or 360). You can't + specify an Availability Zone group or a launch group if you specify a + duration. Note: This parameter is no longer available to new customers + from July 1, 2021. [See Amazon's + documentation](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-requests.html#fixed-duration-spot-instances). + +- `capacity_reservation_preference` (string) - Set the preference for using a capacity reservation if one exists. + Either will be `open` or `none`. Defaults to `none` + +- `capacity_reservation_id` (string) - Provide the specific EC2 Capacity Reservation ID that will be used + by Packer. + +- `capacity_reservation_group_arn` (string) - Provide the EC2 Capacity Reservation Group ARN that will be used by + Packer. + +- `disable_stop_instance` (bool) - Packer normally stops the build instance after all provisioners have + run. For Windows instances, it is sometimes desirable to [run + Sysprep](https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/Creating_EBSbacked_WinAMI.html) + which will stop the instance for you. If this is set to `true`, Packer + *will not* stop the instance but will assume that you will send the stop + signal yourself through your final provisioner. You can do this with a + [windows-shell provisioner](/packer/integrations/hashicorp/windows-shell). Note that + Packer will still wait for the instance to be stopped, and failing to + send the stop signal yourself, when you have set this flag to `true`, + will cause a timeout. + + An example of a valid windows shutdown command in a `windows-shell` + provisioner is : + ```shell-session + ec2config.exe -sysprep + ``` + or + ```sell-session + "%programfiles%\amazon\ec2configservice\"ec2config.exe -sysprep"" + ``` + -> Note: The double quotation marks in the command are not required if + your CMD shell is already in the + `C:\Program Files\Amazon\EC2ConfigService\` directory. + +- `ebs_optimized` (bool) - Mark instance as [EBS + Optimized](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSOptimized.html). + Default `false`. + +- `enable_nitro_enclave` (bool) - Enable support for Nitro Enclaves on the instance. Note that the instance type must + be able to [support Nitro Enclaves](https://aws.amazon.com/ec2/nitro/nitro-enclaves/faqs/). + This option is not supported for spot instances. + +- `enable_t2_unlimited` (bool) - Deprecated argument - please use "enable_unlimited_credits". + Enabling T2 Unlimited allows the source instance to burst additional CPU + beyond its available [CPU + Credits](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/t2-credits-baseline-concepts.html) + for as long as the demand exists. This is in contrast to the standard + configuration that only allows an instance to consume up to its + available CPU Credits. See the AWS documentation for [T2 + Unlimited](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/t2-unlimited.html) + and the **T2 Unlimited Pricing** section of the [Amazon EC2 On-Demand + Pricing](https://aws.amazon.com/ec2/pricing/on-demand/) document for + more information. By default this option is disabled and Packer will set + up a [T2 + Standard](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/t2-std.html) + instance instead. + + To use T2 Unlimited you must use a T2 instance type, e.g. `t2.micro`. + Additionally, T2 Unlimited cannot be used in conjunction with Spot + Instances, e.g. when the `spot_price` option has been configured. + Attempting to do so will cause an error. + + !> **Warning!** Additional costs may be incurred by enabling T2 + Unlimited - even for instances that would usually qualify for the + [AWS Free Tier](https://aws.amazon.com/free/). + +- `enable_unlimited_credits` (bool) - Enabling Unlimited credits allows the source instance to burst additional CPU + beyond its available [CPU + Credits](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/burstable-performance-instances-unlimited-mode-concepts.html#unlimited-mode-surplus-credits) + for as long as the demand exists. This is in contrast to the standard + configuration that only allows an instance to consume up to its + available CPU Credits. See the AWS documentation for [T2 + Unlimited](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/burstable-performance-instances-unlimited-mode-concepts.html) + and the **Unlimited Pricing** section of the [Amazon EC2 On-Demand + Pricing](https://aws.amazon.com/ec2/pricing/on-demand/) document for + more information. By default this option is disabled and Packer will set + up a [Standard](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/burstable-performance-instances-standard-mode.html) + instance instead. + + To use Unlimited you must use a T2/T3/T3a/T4g instance type, e.g. (`t2.micro`, `t3.micro`). + Additionally, Unlimited cannot be used in conjunction with Spot + Instances for T2 type instances, e.g. when the `spot_price` option has been configured. + Attempting to do so will cause an error if the underlying instance type is a T2 type instance. + By default the supported burstable instance types (including t3/t3a/t4g) will be provisioned with its cpu credits set to standard, + only when `enable_unlimited_credits` is true will the instance be provisioned with unlimited cpu credits. + +- `iam_instance_profile` (string) - The name of an [IAM instance + profile](https://docs.aws.amazon.com/IAM/latest/UserGuide/instance-profiles.html) + to launch the EC2 instance with. + +- `fleet_tags` (map[string]string) - Key/value pair tags to apply tags to the fleet that is issued. + +- `fleet_tag` ([]{key string, value string}) - Same as [`fleet_tags`](#fleet_tags) but defined as a singular repeatable block + containing a `key` and a `value` field. In HCL2 mode the + [`dynamic_block`](/packer/docs/templates/hcl_templates/expressions#dynamic-blocks) + will allow you to create those programatically. + +- `skip_profile_validation` (bool) - Whether or not to check if the IAM instance profile exists. Defaults to false + +- `temporary_iam_instance_profile_policy_document` (\*PolicyDocument) - Temporary IAM instance profile policy document + If IamInstanceProfile is specified it will be used instead. + + HCL2 example: + ```hcl + temporary_iam_instance_profile_policy_document { + Statement { + Action = ["logs:*"] + Effect = "Allow" + Resource = ["*"] + } + Version = "2012-10-17" + } + ``` + + JSON example: + ```json + { + "Version": "2012-10-17", + "Statement": [ + { + "Action": [ + "logs:*" + ], + "Effect": "Allow", + "Resource": ["*"] + } + ] + } + ``` + +- `shutdown_behavior` (string) - Automatically terminate instances on + shutdown in case Packer exits ungracefully. Possible values are stop and + terminate. Defaults to stop. + +- `security_group_filter` (SecurityGroupFilterOptions) - Filters used to populate the `security_group_ids` field. + + HCL2 Example: + + ```hcl + security_group_filter { + filters = { + "tag:Class": "packer" + } + } + ``` + + JSON Example: + ```json + { + "security_group_filter": { + "filters": { + "tag:Class": "packer" + } + } + } + ``` + + This selects the SG's with tag `Class` with the value `packer`. + + - `filters` (map[string,string] | multiple filters are allowed when seperated by commas) - filters used to select a + `security_group_ids`. Any filter described in the docs for + [DescribeSecurityGroups](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSecurityGroups.html) + is valid. + + `security_group_ids` take precedence over this. + +- `run_tags` (map[string]string) - Key/value pair tags to apply to the generated key-pair, security group, iam profile and role, snapshot, network interfaces and instance + that is *launched* to create the EBS volumes. The resulting AMI will also inherit these tags. + This is a [template + engine](/packer/docs/templates/legacy_json_templates/engine), see [Build template + data](#build-template-data) for more information. + +- `run_tag` ([]{key string, value string}) - Same as [`run_tags`](#run_tags) but defined as a singular repeatable + block containing a `key` and a `value` field. In HCL2 mode the + [`dynamic_block`](/packer/docs/templates/hcl_templates/expressions#dynamic-blocks) + will allow you to create those programatically. + +- `security_group_id` (string) - The ID (not the name) of the security + group to assign to the instance. By default this is not set and Packer will + automatically create a new temporary security group to allow SSH access. + Note that if this is specified, you must be sure the security group allows + access to the ssh_port given below. + +- `security_group_ids` ([]string) - A list of security groups as + described above. Note that if this is specified, you must omit the + security_group_id. + +- `source_ami_filter` (AmiFilterOptions) - Filters used to populate the `source_ami` + field. + + HCL2 example: + ```hcl + source "amazon-ebs" "basic-example" { + source_ami_filter { + filters = { + virtualization-type = "hvm" + name = "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*" + root-device-type = "ebs" + } + owners = ["099720109477"] + most_recent = true + } + } + ``` + + JSON Example: + ```json + "builders" [ + { + "type": "amazon-ebs", + "source_ami_filter": { + "filters": { + "virtualization-type": "hvm", + "name": "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*", + "root-device-type": "ebs" + }, + "owners": ["099720109477"], + "most_recent": true + } + } + ] + ``` + + This selects the most recent Ubuntu 16.04 HVM EBS AMI from Canonical. NOTE: + This will fail unless *exactly* one AMI is returned. In the above example, + `most_recent` will cause this to succeed by selecting the newest image. + + - `filters` (map[string,string] | multiple filters are allowed when seperated by commas) - filters used to select a `source_ami`. + NOTE: This will fail unless *exactly* one AMI is returned. Any filter + described in the docs for + [DescribeImages](http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeImages.html) + is valid. + + - `owners` (array of strings) - Filters the images by their owner. You + may specify one or more AWS account IDs, "self" (which will use the + account whose credentials you are using to run Packer), or an AWS owner + alias: for example, `amazon`, `aws-marketplace`, or `microsoft`. This + option is required for security reasons. + + - `most_recent` (boolean) - Selects the newest created image when true. + This is most useful for selecting a daily distro build. + + You may set this in place of `source_ami` or in conjunction with it. If you + set this in conjunction with `source_ami`, the `source_ami` will be added + to the filter. The provided `source_ami` must meet all of the filtering + criteria provided in `source_ami_filter`; this pins the AMI returned by the + filter, but will cause Packer to fail if the `source_ami` does not exist. + +- `spot_instance_types` ([]string) - a list of acceptable instance + types to run your build on. We will request a spot instance using the max + price of spot_price and the allocation strategy of "lowest price". + Your instance will be launched on an instance type of the lowest available + price that you have in your list. This is used in place of instance_type. + You may only set either spot_instance_types or instance_type, not both. + This feature exists to help prevent situations where a Packer build fails + because a particular availability zone does not have capacity for the + specific instance_type requested in instance_type. + +- `spot_price` (string) - With Spot Instances, you pay the Spot price that's in effect for the + time period your instances are running. Spot Instance prices are set by + Amazon EC2 and adjust gradually based on long-term trends in supply and + demand for Spot Instance capacity. + + When this field is set, it represents the maximum hourly price you are + willing to pay for a spot instance. If you do not set this value, it + defaults to a maximum price equal to the on demand price of the + instance. In the situation where the current Amazon-set spot price + exceeds the value set in this field, Packer will not launch an instance + and the build will error. In the situation where the Amazon-set spot + price is less than the value set in this field, Packer will launch and + you will pay the Amazon-set spot price, not this maximum value. + For more information, see the Amazon docs on + [spot pricing](https://aws.amazon.com/ec2/spot/pricing/). + +- `spot_tags` (map[string]string) - Requires spot_price to be set. Key/value pair tags to apply tags to the + spot request that is issued. + +- `spot_tag` ([]{key string, value string}) - Same as [`spot_tags`](#spot_tags) but defined as a singular repeatable block + containing a `key` and a `value` field. In HCL2 mode the + [`dynamic_block`](/packer/docs/templates/hcl_templates/expressions#dynamic-blocks) + will allow you to create those programatically. + +- `subnet_filter` (SubnetFilterOptions) - Filters used to populate the `subnet_id` field. + + HCL2 example: + + ```hcl + source "amazon-ebs" "basic-example" { + subnet_filter { + filters = { + "tag:Class": "build" + } + most_free = true + random = false + } + } + ``` + + JSON Example: + ```json + "builders" [ + { + "type": "amazon-ebs", + "subnet_filter": { + "filters": { + "tag:Class": "build" + }, + "most_free": true, + "random": false + } + } + ] + ``` + + This selects the Subnet with tag `Class` with the value `build`, which has + the most free IP addresses. NOTE: This will fail unless *exactly* one + Subnet is returned. By using `most_free` or `random` one will be selected + from those matching the filter. + + - `filters` (map[string,string] | multiple filters are allowed when seperated by commas) - filters used to select a `subnet_id`. + NOTE: This will fail unless *exactly* one Subnet is returned. Any + filter described in the docs for + [DescribeSubnets](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSubnets.html) + is valid. + + - `most_free` (boolean) - The Subnet with the most free IPv4 addresses + will be used if multiple Subnets matches the filter. + + - `random` (boolean) - A random Subnet will be used if multiple Subnets + matches the filter. `most_free` have precendence over this. + + `subnet_id` take precedence over this. + +- `subnet_id` (string) - If using VPC, the ID of the subnet, such as + subnet-12345def, where Packer will launch the EC2 instance. This field is + required if you are using an non-default VPC. + +- `license_specifications` ([]LicenseSpecification) - The license configurations. + + HCL2 example: + ```hcl + source "amazon-ebs" "basic-example" { + license_specifications { + license_configuration_request = { + license_configuration_arn = "${var.license_configuration_arn}" + } + } + } + ``` + + JSON example: + ```json + "builders" [ + { + "type": "amazon-ebs", + "license_specifications": [ + { + "license_configuration_request": { + "license_configuration_arn": "{{user `license_configuration_arn`}}" + } + } + ] + } + ] + ``` + + Each `license_configuration_request` describes a license configuration, + the properties of which are: + + - `license_configuration_arn` (string) - The Amazon Resource Name (ARN) + of the license configuration. + +- `placement` (Placement) - Describes the placement of an instance. + + HCL2 example: + ```hcl + source "amazon-ebs" "basic-example" { + placement = { + host_resource_group_arn = "${var.host_resource_group_arn}" + tenancy = "${var.placement_tenancy}" + } + } + ``` + + JSON example: + ```json + "builders" [ + { + "type": "amazon-ebs", + "placement": { + "host_resource_group_arn": "{{user `host_resource_group_arn`}}", + "tenancy": "{{user `placement_tenancy`}}" + } + } + ] + ``` + + - `host_resource_group_arn` (string) - The ARN of the host resource + group in which to launch the instances. If you specify a host + resource group ARN, omit the Tenancy parameter or set it to `host`. + - `tenancy` (string) - The tenancy of the instance (if the instance is + running in a VPC). An instance with a tenancy of `dedicated` runs on + single-tenant hardware. The default is `default`, meaning shared + tenancy. Allowed values are `default`, `dedicated` and `host`. + +- `tenancy` (string) - Deprecated: Use Placement Tenancy instead. + +- `temporary_security_group_source_cidrs` ([]string) - A list of IPv4 CIDR blocks to be authorized access to the instance, when + packer is creating a temporary security group. + + The default is [`0.0.0.0/0`] (i.e., allow any IPv4 source). + Use `temporary_security_group_source_public_ip` to allow current host's + public IP instead of any IPv4 source. + This is only used when `security_group_id` or `security_group_ids` is not + specified. + +- `temporary_security_group_source_public_ip` (bool) - When enabled, use public IP of the host (obtained from https://checkip.amazonaws.com) + as CIDR block to be authorized access to the instance, when packer + is creating a temporary security group. Defaults to `false`. + + This is only used when `security_group_id`, `security_group_ids`, + and `temporary_security_group_source_cidrs` are not specified. + +- `user_data` (string) - User data to apply when launching the instance. Note + that you need to be careful about escaping characters due to the templates + being JSON. It is often more convenient to use user_data_file, instead. + Packer will not automatically wait for a user script to finish before + shutting down the instance this must be handled in a provisioner. + +- `user_data_file` (string) - Path to a file that will be used for the user + data when launching the instance. + +- `vpc_filter` (VpcFilterOptions) - Filters used to populate the `vpc_id` field. + + HCL2 example: + ```hcl + source "amazon-ebs" "basic-example" { + vpc_filter { + filters = { + "tag:Class": "build", + "isDefault": "false", + "cidr": "/24" + } + } + } + ``` + + JSON Example: + ```json + "builders" [ + { + "type": "amazon-ebs", + "vpc_filter": { + "filters": { + "tag:Class": "build", + "isDefault": "false", + "cidr": "/24" + } + } + } + ] + ``` + + This selects the VPC with tag `Class` with the value `build`, which is not + the default VPC, and have a IPv4 CIDR block of `/24`. NOTE: This will fail + unless *exactly* one VPC is returned. + + - `filters` (map[string,string] | multiple filters are allowed when seperated by commas) - filters used to select a `vpc_id`. NOTE: + This will fail unless *exactly* one VPC is returned. Any filter + described in the docs for + [DescribeVpcs](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeVpcs.html) + is valid. + + `vpc_id` take precedence over this. + +- `vpc_id` (string) - If launching into a VPC subnet, Packer needs the VPC ID + in order to create a temporary security group within the VPC. Requires + subnet_id to be set. If this field is left blank, Packer will try to get + the VPC ID from the subnet_id. + +- `windows_password_timeout` (duration string | ex: "1h5m2s") - The timeout for waiting for a Windows + password for Windows instances. Defaults to 20 minutes. Example value: + 10m + +- `metadata_options` (MetadataOptions) - [Metadata Settings](#metadata-settings) + +- `ssh_interface` (string) - One of `public_ip`, `private_ip`, `public_dns`, `private_dns` or `session_manager`. + If set, either the public IP address, private IP address, public DNS name + or private DNS name will be used as the host for SSH. The default behaviour + if inside a VPC is to use the public IP address if available, otherwise + the private IP address will be used. If not in a VPC the public DNS name + will be used. Also works for WinRM. + + Where Packer is configured for an outbound proxy but WinRM traffic + should be direct, `ssh_interface` must be set to `private_dns` and + `.compute.internal` included in the `NO_PROXY` environment + variable. + + When using `session_manager` the machine running Packer must have + the AWS Session Manager Plugin installed and within the users' system path. + Connectivity via the `session_manager` interface establishes a secure tunnel + between the local host and the remote host on an available local port to the specified `ssh_port`. + See [Session Manager Connections](#session-manager-connections) for more information. + - Session manager connectivity is currently only implemented for the SSH communicator, not the WinRM communicator. + - Upon termination the secure tunnel will be terminated automatically, if however there is a failure in + terminating the tunnel it will automatically terminate itself after 20 minutes of inactivity. + +- `pause_before_ssm` (duration string | ex: "1h5m2s") - The time to wait before establishing the Session Manager session. + The value of this should be a duration. Examples are + `5s` and `1m30s` which will cause Packer to wait five seconds and one + minute 30 seconds, respectively. If no set, defaults to 10 seconds. + This option is useful when the remote port takes longer to become available. + +- `session_manager_port` (int) - Which port to connect the local end of the session tunnel to. If + left blank, Packer will choose a port for you from available ports. + This option is only used when `ssh_interface` is set `session_manager`. + + + + +### Session Manager Connections + +Support for the AWS Systems Manager session manager lets users manage EC2 instances without the need to open inbound ports, or maintain bastion hosts. Session manager connectivity relies on the use of the [session manager plugin](#session-manager-plugin) to open a secure tunnel between the local machine and the remote instance. Once the tunnel has been created all SSH communication will be tunneled through SSM to the remote instance. + +-> Note: Session manager connectivity is currently only implemented for the SSH communicator, not the WinRM Communicator. + +To use the session manager as the connection interface for the SSH communicator you need to add the following configuration options to the Amazon builder options: + +- `ssh_interface`: The ssh interface must be set to "session_manager". When using this option the builder will create an SSM tunnel to the configured `ssh_port` (defaults to 22) on the remote host. +- `iam_instance_profile`: A valid instance profile granting Systems Manager permissions to manage the remote instance is required in order for the aws ssm-agent to start and stop session connections. + See below for more details on [IAM instance profile for Systems Manager](#iam-instance-profile-for-systems-manager). + +#### Optional + +- `session_manager_port`: A local port on the host machine that should be used as the local end of the session tunnel to the remote host. If not specified Packer will find an available port to use. +- `temporary_iam_instance_profile_policy_document`: Creates a temporary instance profile policy document to grant Systems Manager permissions to the Ec2 instance. This is an alternative to using an existing `iam_instance_profile`. + +HCL2 example: + +```hcl +# file: example.pkr.hcl + +# In order to get these variables to read from the environment, +# set the environment variables to have the same name as the declared +# variables, with the prefix PKR_VAR_. +# You could also hardcode them into the file, but we do not recommend that. + +data "amazon-ami" "example" { + filters = { + virtualization-type = "hvm" + name = "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*" + root-device-type = "ebs" + } + owners = ["099720109477"] + most_recent = true + region = "us-east-1" +} + +source "amazon-ebs" "ssm-example" { + ami_name = "packer_AWS {{timestamp}}" + instance_type = "t2.micro" + region = "us-east-1" + source_ami = data.amazon-ami.example.id + ssh_username = "ubuntu" + ssh_interface = "session_manager" + communicator = "ssh" + iam_instance_profile = "myinstanceprofile" +} + +build { + sources = ["source.amazon-ebs.ssm-example"] + + provisioner "shell" { + inline = ["echo Connected via SSM at '${build.User}@${build.Host}:${build.Port}'"] + } +} +``` + +JSON example: + +```json +{ + "builders": [ + { + "type": "amazon-ebs", + "ami_name": "packer-ami-{{timestamp}}", + "instance_type": "t2.micro", + "source_ami_filter": { + "filters": { + "virtualization-type": "hvm", + "name": "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*", + "root-device-type": "ebs" + }, + "owners": ["099720109477"], + "most_recent": true + }, + "ssh_username": "ubuntu", + "ssh_interface": "session_manager", + "communicator": "ssh", + "iam_instance_profile": "{{user `iam_instance_profile`}}" + } + ], + "provisioners": [ + { + "type": "shell", + "inline": [ + "echo Connected via SSM at '{{build `User`}}@{{build `Host`}}:{{build `Port`}}'" + ] + } + ] +} +``` + +#### Session Manager Plugin + +Connectivity via the session manager requires the use of a session-manger-plugin, which needs to be installed alongside Packer, and an instance AMI that is capable of running the AWS ssm-agent - see [About SSM Agent](https://docs.aws.amazon.com/systems-manager/latest/userguide/prereqs-ssm-agent.html) for details on supported AMIs. + +In order for Packer to start and end sessions that connect you to your managed instances, you must first install the Session Manager plugin on your local machine. The plugin can be installed on supported versions of Microsoft Windows, macOS, Linux, and Ubuntu Server. +[Installation instructions for the session-manager-plugin](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html) + +#### IAM instance profile for Systems Manager + +By default Systems Manager doesn't have permission to perform actions on created instances so SSM access must be granted by creating an instance profile with the `AmazonSSMManagedInstanceCore` policy. The instance profile can then be attached to any instance you wish to manage via the session-manager-plugin. See [Adding System Manager instance profile](https://docs.aws.amazon.com/systems-manager/latest/userguide/setup-instance-profile.html#instance-profile-add-permissions) for details on creating the required instance profile. + +#### Permissions for Closing the Tunnel + +To close the SSM tunnels created, this plugin relies on being able to call +[DescribeInstanceStatus](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeInstanceStatus.html). +In case this is not possible you might see a `Bad exit status` message in the logs. + +The absence of this permission won't prevent you from building the AMI, and the error only means that packer is not able to close the tunnel gracefully. + + +### Block Devices Configuration + +Block devices can be nested in the +[ami_block_device_mappings](#ami_block_device_mappings) or the +[launch_block_device_mappings](#launch_block_device_mappings) array. + + + +These will be attached when launching your instance. Your +options here may vary depending on the type of VM you use. + +Example use case: + +The following mapping will tell Packer to encrypt the root volume of the +build instance at launch using a specific non-default kms key: + +HCL2 example: + +```hcl + + launch_block_device_mappings { + device_name = "/dev/sda1" + encrypted = true + kms_key_id = "1a2b3c4d-5e6f-1a2b-3c4d-5e6f1a2b3c4d" + } + +``` + +JSON example: +```json +"launch_block_device_mappings": [ + + { + "device_name": "/dev/sda1", + "encrypted": true, + "kms_key_id": "1a2b3c4d-5e6f-1a2b-3c4d-5e6f1a2b3c4d" + } + +] +``` + +Please note that the kms_key_id option in this example exists for +launch_block_device_mappings but not ami_block_device_mappings. + +Documentation for Block Devices Mappings can be found here: +https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/block-device-mapping-concepts.html + + + + +#### Optional: + + + +- `delete_on_termination` (bool) - Indicates whether the EBS volume is deleted on instance termination. + Default false. NOTE: If this value is not explicitly set to true and + volumes are not cleaned up by an alternative method, additional volumes + will accumulate after every build. + +- `device_name` (string) - The device name exposed to the instance (for example, /dev/sdh or xvdh). + Required for every device in the block device mapping. + +- `encrypted` (boolean) - Indicates whether or not to encrypt the volume. By default, Packer will + keep the encryption setting to what it was in the source image. Setting + false will result in an unencrypted device, and true will result in an + encrypted one. + +- `iops` (\*int64) - The number of I/O operations per second (IOPS) that the volume supports. + See the documentation on + [IOPs](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_EbsBlockDevice.html) + for more information + +- `no_device` (bool) - Suppresses the specified device included in the block device mapping of + the AMI. + +- `snapshot_id` (string) - The ID of the snapshot. + +- `throughput` (\*int64) - The throughput for gp3 volumes, only valid for gp3 types + See the documentation on + [Throughput](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_EbsBlockDevice.html) + for more information + +- `virtual_name` (string) - The virtual device name. See the documentation on Block Device Mapping + for more information. + +- `volume_type` (string) - The volume type. gp2 & gp3 for General Purpose (SSD) volumes, io1 & io2 + for Provisioned IOPS (SSD) volumes, st1 for Throughput Optimized HDD, + sc1 for Cold HDD, and standard for Magnetic volumes. + +- `volume_size` (int64) - The size of the volume, in GiB. Required if not specifying a + snapshot_id. + +- `kms_key_id` (string) - ID, alias or ARN of the KMS key to use for boot volume encryption. + This option exists for launch_block_device_mappings but not + ami_block_device_mappings. The kms key id defined here only applies to + the original build region; if the AMI gets copied to other regions, the + volume in those regions will be encrypted by the default EBS KMS key. + For valid formats see KmsKeyId in the [AWS API docs - + CopyImage](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CopyImage.html) + This field is validated by Packer. When using an alias, you will have to + prefix kms_key_id with alias/. + + + + +### Communicator Configuration + +#### Optional: + + + +- `communicator` (string) - Packer currently supports three kinds of communicators: + + - `none` - No communicator will be used. If this is set, most + provisioners also can't be used. + + - `ssh` - An SSH connection will be established to the machine. This + is usually the default. + + - `winrm` - A WinRM connection will be established. + + In addition to the above, some builders have custom communicators they + can use. For example, the Docker builder has a "docker" communicator + that uses `docker exec` and `docker cp` to execute scripts and copy + files. + +- `pause_before_connecting` (duration string | ex: "1h5m2s") - We recommend that you enable SSH or WinRM as the very last step in your + guest's bootstrap script, but sometimes you may have a race condition + where you need Packer to wait before attempting to connect to your + guest. + + If you end up in this situation, you can use the template option + `pause_before_connecting`. By default, there is no pause. For example if + you set `pause_before_connecting` to `10m` Packer will check whether it + can connect, as normal. But once a connection attempt is successful, it + will disconnect and then wait 10 minutes before connecting to the guest + and beginning provisioning. + + + + + + +- `ssh_host` (string) - The address to SSH to. This usually is automatically configured by the + builder. + +- `ssh_port` (int) - The port to connect to SSH. This defaults to `22`. + +- `ssh_username` (string) - The username to connect to SSH with. Required if using SSH. + +- `ssh_password` (string) - A plaintext password to use to authenticate with SSH. + +- `ssh_ciphers` ([]string) - This overrides the value of ciphers supported by default by Golang. + The default value is [ + "aes128-gcm@openssh.com", + "chacha20-poly1305@openssh.com", + "aes128-ctr", "aes192-ctr", "aes256-ctr", + ] + + Valid options for ciphers include: + "aes128-ctr", "aes192-ctr", "aes256-ctr", "aes128-gcm@openssh.com", + "chacha20-poly1305@openssh.com", + "arcfour256", "arcfour128", "arcfour", "aes128-cbc", "3des-cbc", + +- `ssh_clear_authorized_keys` (bool) - If true, Packer will attempt to remove its temporary key from + `~/.ssh/authorized_keys` and `/root/.ssh/authorized_keys`. This is a + mostly cosmetic option, since Packer will delete the temporary private + key from the host system regardless of whether this is set to true + (unless the user has set the `-debug` flag). Defaults to "false"; + currently only works on guests with `sed` installed. + +- `ssh_key_exchange_algorithms` ([]string) - If set, Packer will override the value of key exchange (kex) algorithms + supported by default by Golang. Acceptable values include: + "curve25519-sha256@libssh.org", "ecdh-sha2-nistp256", + "ecdh-sha2-nistp384", "ecdh-sha2-nistp521", + "diffie-hellman-group14-sha1", and "diffie-hellman-group1-sha1". + +- `ssh_certificate_file` (string) - Path to user certificate used to authenticate with SSH. + The `~` can be used in path and will be expanded to the + home directory of current user. + +- `ssh_pty` (bool) - If `true`, a PTY will be requested for the SSH connection. This defaults + to `false`. + +- `ssh_timeout` (duration string | ex: "1h5m2s") - The time to wait for SSH to become available. Packer uses this to + determine when the machine has booted so this is usually quite long. + Example value: `10m`. + This defaults to `5m`, unless `ssh_handshake_attempts` is set. + +- `ssh_disable_agent_forwarding` (bool) - If true, SSH agent forwarding will be disabled. Defaults to `false`. + +- `ssh_handshake_attempts` (int) - The number of handshakes to attempt with SSH once it can connect. + This defaults to `10`, unless a `ssh_timeout` is set. + +- `ssh_bastion_host` (string) - A bastion host to use for the actual SSH connection. + +- `ssh_bastion_port` (int) - The port of the bastion host. Defaults to `22`. + +- `ssh_bastion_agent_auth` (bool) - If `true`, the local SSH agent will be used to authenticate with the + bastion host. Defaults to `false`. + +- `ssh_bastion_username` (string) - The username to connect to the bastion host. + +- `ssh_bastion_password` (string) - The password to use to authenticate with the bastion host. + +- `ssh_bastion_interactive` (bool) - If `true`, the keyboard-interactive used to authenticate with bastion host. + +- `ssh_bastion_private_key_file` (string) - Path to a PEM encoded private key file to use to authenticate with the + bastion host. The `~` can be used in path and will be expanded to the + home directory of current user. + +- `ssh_bastion_certificate_file` (string) - Path to user certificate used to authenticate with bastion host. + The `~` can be used in path and will be expanded to the + home directory of current user. + +- `ssh_file_transfer_method` (string) - `scp` or `sftp` - How to transfer files, Secure copy (default) or SSH + File Transfer Protocol. + + **NOTE**: Guests using Windows with Win32-OpenSSH v9.1.0.0p1-Beta, scp + (the default protocol for copying data) returns a a non-zero error code since the MOTW + cannot be set, which cause any file transfer to fail. As a workaround you can override the transfer protocol + with SFTP instead `ssh_file_transfer_protocol = "sftp"`. + +- `ssh_proxy_host` (string) - A SOCKS proxy host to use for SSH connection + +- `ssh_proxy_port` (int) - A port of the SOCKS proxy. Defaults to `1080`. + +- `ssh_proxy_username` (string) - The optional username to authenticate with the proxy server. + +- `ssh_proxy_password` (string) - The optional password to use to authenticate with the proxy server. + +- `ssh_keep_alive_interval` (duration string | ex: "1h5m2s") - How often to send "keep alive" messages to the server. Set to a negative + value (`-1s`) to disable. Example value: `10s`. Defaults to `5s`. + +- `ssh_read_write_timeout` (duration string | ex: "1h5m2s") - The amount of time to wait for a remote command to end. This might be + useful if, for example, packer hangs on a connection after a reboot. + Example: `5m`. Disabled by default. + +- `ssh_remote_tunnels` ([]string) - + +- `ssh_local_tunnels` ([]string) - + + + + + + +- `temporary_key_pair_type` (string) - `dsa` | `ecdsa` | `ed25519` | `rsa` ( the default ) + + Specifies the type of key to create. The possible values are 'dsa', + 'ecdsa', 'ed25519', or 'rsa'. + + NOTE: DSA is deprecated and no longer recognized as secure, please + consider other alternatives like RSA or ED25519. + +- `temporary_key_pair_bits` (int) - Specifies the number of bits in the key to create. For RSA keys, the + minimum size is 1024 bits and the default is 4096 bits. Generally, 3072 + bits is considered sufficient. DSA keys must be exactly 1024 bits as + specified by FIPS 186-2. For ECDSA keys, bits determines the key length + by selecting from one of three elliptic curve sizes: 256, 384 or 521 + bits. Attempting to use bit lengths other than these three values for + ECDSA keys will fail. Ed25519 keys have a fixed length and bits will be + ignored. + + NOTE: DSA is deprecated and no longer recognized as secure as specified + by FIPS 186-5, please consider other alternatives like RSA or ED25519. + + + + +- `ssh_keypair_name` (string) - If specified, this is the key that will be used for SSH with the + machine. The key must match a key pair name loaded up into the remote. + By default, this is blank, and Packer will generate a temporary keypair + unless [`ssh_password`](#ssh_password) is used. + [`ssh_private_key_file`](#ssh_private_key_file) or + [`ssh_agent_auth`](#ssh_agent_auth) must be specified when + [`ssh_keypair_name`](#ssh_keypair_name) is utilized. + + +- `ssh_private_key_file` (string) - Path to a PEM encoded private key file to use to authenticate with SSH. + The `~` can be used in path and will be expanded to the home directory + of current user. + + +- `ssh_agent_auth` (bool) - If true, the local SSH agent will be used to authenticate connections to + the source instance. No temporary keypair will be created, and the + values of [`ssh_password`](#ssh_password) and + [`ssh_private_key_file`](#ssh_private_key_file) will be ignored. The + environment variable `SSH_AUTH_SOCK` must be set for this option to work + properly. + + +## Basic Example + +Here is a basic example. It is completely valid except for the access keys: + +**HCL2** + +```hcl +source "amazon-instance" "basic-example" { + region = "us-east-1" + source_ami = "ami-d9d6a6b0" + instance_type = "m1.small" + ssh_username = "ubuntu" + + account_id = "0123-4567-0890" + s3_bucket = "packer-images" + x509_cert_path = "x509.cert" + x509_key_path = "x509.key" + x509_upload_path = "/tmp" +} + +build { + source "sources.amazon-instance.basic-example" { + ami_name = "packer-quick-start {{timestamp}}" + } +} +``` + +**JSON** + +```json +{ + "type": "amazon-instance", + "access_key": "YOUR KEY HERE", + "secret_key": "YOUR SECRET KEY HERE", + "region": "us-east-1", + "source_ami": "ami-d9d6a6b0", + "instance_type": "m1.small", + "ssh_username": "ubuntu", + + "account_id": "0123-4567-0890", + "s3_bucket": "packer-images", + "x509_cert_path": "x509.cert", + "x509_key_path": "x509.key", + "x509_upload_path": "/tmp", + + "ami_name": "packer-quick-start {{timestamp}}" +} +``` + + +-> **Note:** Packer can also read the access key and secret access key from +environmental variables. See the configuration reference in the section above +for more information on what environmental variables Packer will look for. + +## Accessing the Instance to Debug + +If you need to access the instance to debug for some reason, run this builder +with the `-debug` flag. In debug mode, the Amazon builder will save the private +key in the current directory and will output the DNS or IP information as well. +You can use this information to access the instance as it is running. + +## Build template data + +In configuration directives marked as a template engine above, the following +variables are available: + +- `BuildRegion` - The region (for example `eu-central-1`) where Packer is + building the AMI. +- `SourceAMI` - The source AMI ID (for example `ami-a2412fcd`) used to build + the AMI. +- `SourceAMICreationDate` - The source AMI creation date (for example `"2020-05-14T19:26:34.000Z"`). +- `SourceAMIName` - The source AMI Name (for example + `ubuntu/images/ebs-ssd/ubuntu-xenial-16.04-amd64-server-20180306`) used to + build the AMI. +- `SourceAMIOwner` - The source AMI owner ID. +- `SourceAMIOwnerName` - The source AMI owner alias/name (for example `amazon`). +- `SourceAMITags` - The source AMI Tags, as a `map[string]string` object. + +## Build Shared Information Variables + +This builder generates data that are shared with provisioner and post-processor via build function of [template engine](/packer/docs/templates/legacy_json_templates/engine) for JSON and [contextual variables](/packer/docs/templates/hcl_templates/contextual-variables) for HCL2. + +The generated variables available for this builder are: + +- `BuildRegion` - The region (for example `eu-central-1`) where Packer is + building the AMI. +- `SourceAMI` - The source AMI ID (for example `ami-a2412fcd`) used to build + the AMI. +- `SourceAMICreationDate` - The source AMI creation date (for example `"2020-05-14T19:26:34.000Z"`). +- `SourceAMIName` - The source AMI Name (for example + `ubuntu/images/ebs-ssd/ubuntu-xenial-16.04-amd64-server-20180306`) used to + build the AMI. +- `SourceAMIOwner` - The source AMI owner ID. +- `SourceAMIOwnerName` - The source AMI owner alias/name (for example `amazon`). + +Usage example: + +**HCL2** + +```hcl +// When accessing one of these variables from inside the builder, you need to +// use the golang templating syntax. This is due to an architectural quirk that +// won't be easily resolvable until legacy json templates are deprecated: + +{ +source "amazon-ebs" "basic-example" { + tags = { + OS_Version = "Ubuntu" + Release = "Latest" + Base_AMI_ID = "{{ .SourceAMI }}" + Base_AMI_Name = "{{ .SourceAMIName }}" + } +} + +// when accessing one of the variables from a provisioner or post-processor, use +// hcl-syntax +post-processor "manifest" { + output = "manifest.json" + strip_path = true + custom_data = { + source_ami_name = "${build.SourceAMIName}" + } +} +``` + +**JSON** + +```json +"post-processors": [ + { + "type": "manifest", + "output": "manifest.json", + "strip_path": true, + "custom_data": { + "source_ami_name": "{{ build `SourceAMIName` }}" + } + } +] +``` + + +## Custom Bundle Commands + +A lot of the process required for creating an instance-store backed AMI +involves commands being run on the actual source instance. Specifically, the +`ec2-bundle-vol` and `ec2-upload-bundle` commands must be used to bundle the +root filesystem and upload it, respectively. + +Each of these commands have a lot of available flags. Instead of exposing each +possible flag as a template configuration option, the instance-store AMI +builder for Packer lets you customize the entire command used to bundle and +upload the AMI. + +These are configured with `bundle_vol_command` and `bundle_upload_command`. +Both of these configurations are [configuration +templates](/packer/docs/templates/legacy_json_templates/engine) and have support for their own set of +template variables. + +### Bundle Volume Command + +The default value for `bundle_vol_command` is shown below. It is split across +multiple lines for convenience of reading. The bundle volume command is +responsible for executing `ec2-bundle-vol` in order to store and image of the +root filesystem to use to create the AMI. + +```shell-session +$ sudo -i -n ec2-bundle-vol \ + -k {{.KeyPath}} \ + -u {{.AccountId}} \ + -c {{.CertPath}} \ + -r {{.Architecture}} \ + -e {{.PrivatePath}}/* \ + -d {{.Destination}} \ + -p {{.Prefix}} \ + --batch \ + --no-filter +``` + +The available template variables should be self-explanatory based on the +parameters they're used to satisfy the `ec2-bundle-vol` command. + +~> **Warning!** Some versions of ec2-bundle-vol silently ignore all .pem +and .gpg files during the bundling of the AMI, which can cause problems on some +systems, such as Ubuntu. You may want to customize the bundle volume command to +include those files (see the `--no-filter` option of `ec2-bundle-vol`). + +### Bundle Upload Command + +The default value for `bundle_upload_command` is shown below. It is split +across multiple lines for convenience of reading. Access key and secret key are +omitted if using instance profile. The bundle upload command is responsible for +taking the bundled volume and uploading it to S3. + +```shell-session +$ sudo -i -n ec2-upload-bundle \ + -b {{.BucketName}} \ + -m {{.ManifestPath}} \ + -a {{.AccessKey}} \ + -s {{.SecretKey}} \ + -d {{.BundleDirectory}} \ + --batch \ + --region {{.Region}} \ + --retry +``` + +The available template variables should be self-explanatory based on the +parameters they're used to satisfy the `ec2-upload-bundle` command. +Additionally, `{{.Token}}` is available when overriding this command. You must +create your own bundle command with the addition of `-t {{.Token}}` if you are +assuming a role. + +#### Bundle Upload Permissions + +The `ec2-upload-bundle` requires a policy document that looks something like +this: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "s3:PutObject", + "s3:GetObject", + "s3:ListBucket", + "s3:GetBucketLocation", + "s3:PutObjectAcl" + ], + "Resource": "*" + } + ] +} +``` + +You may wish to constrain the resource to a specific bucket. + +## Which SSH Options to use: + +This chart breaks down what Packer does if you set any of the below SSH options: + +| ssh_password | ssh_private_key_file | ssh_keypair_name | temporary_key_pair_name | Packer will... | +| ------------ | -------------------- | ---------------- | ----------------------- | ------------------------------------------------------------------------------------------ | +| X | - | - | - | ssh authenticating with username and given password | +| - | X | - | - | ssh authenticating with private key file | +| - | X | X | - | ssh authenticating with given private key file and "attaching" the keypair to the instance | +| - | - | - | X | Create a temporary ssh keypair with a particular name, clean it up | +| - | - | - | - | Create a temporary ssh keypair with a default name, clean it up | diff --git a/.web-docs/components/data-source/ami/README.md b/.web-docs/components/data-source/ami/README.md new file mode 100644 index 000000000..091d2c3a2 --- /dev/null +++ b/.web-docs/components/data-source/ami/README.md @@ -0,0 +1,88 @@ +Type: `amazon-ami` + +The Amazon AMI data source will filter and fetch an Amazon AMI, and output all the AMI information that will +be then available to use in the [Amazon builders](/packer/integrations/hashicorp/amazon). + +-> **Note:** Data sources is a feature exclusively available to HCL2 templates. + +Basic example of usage: + +```hcl +data "amazon-ami" "basic-example" { + filters = { + virtualization-type = "hvm" + name = "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*" + root-device-type = "ebs" + } + owners = ["099720109477"] + most_recent = true +} +``` +This selects the most recent Ubuntu 16.04 HVM EBS AMI from Canonical. Note that the data source will fail unless +*exactly* one AMI is returned. In the above example, `most_recent` will cause this to succeed by selecting the newest image. + +## Configuration Reference + + + +- `filters` (map[string]string) - Filters used to select an AMI. Any filter described in the docs for + [DescribeImages](http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeImages.html) + is valid. + +- `owners` ([]string) - Filters the images by their owner. You + may specify one or more AWS account IDs, "self" (which will use the + account whose credentials you are using to run Packer), or an AWS owner + alias: for example, `amazon`, `aws-marketplace`, or `microsoft`. This + option is required for security reasons. + +- `most_recent` (bool) - Selects the newest created image when true. + This is most useful for selecting a daily distro build. + +- `include_deprecated` (bool) - Include deprecated AMIs in the filtered response. Defaults to false. + If you are the AMI owner, deprecated AMIs appear in the response + regardless of what is specified for `include_deprecated`. + + + + +## Output Data + + + +- `id` (string) - The ID of the AMI. + +- `name` (string) - The name of the AMI. + +- `creation_date` (string) - The date of creation of the AMI. + +- `owner` (string) - The AWS account ID of the owner. + +- `owner_name` (string) - The owner alias. + +- `block_device_mappings` ([]awscommon.BlockDevice) - Any block device mapping entries. + +- `tags` (map[string]string) - The key/value combination of the tags assigned to the AMI. + + + + +## Authentication + +The authentication for Amazon Data Sources uses the same configuration options as [Amazon Builders](/packer/integrations/hashicorp/amazon). To learn more about all of the available authentication options please see [Amazon Builders authentication](/packer/integrations/hashicorp/amazon#authentication). + +-> **Note:** The authentication session started by a data source is separate from any authentication sessions started by an Amazon builder. Users are encouraged to use `variables` for defining and sharing configuration values between datasources and builders. + +Basic example of an Amazon data source authentication using `assume_role`: + +```hcl +data "amazon-secretsmanager" "basic-example" { + name = "packer_test_secret" + key = "packer_test_key" + + assume_role { + role_arn = "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME" + session_name = "SESSION_NAME" + external_id = "EXTERNAL_ID" + } +} +``` diff --git a/.web-docs/components/data-source/parameterstore/README.md b/.web-docs/components/data-source/parameterstore/README.md new file mode 100644 index 000000000..af2b89880 --- /dev/null +++ b/.web-docs/components/data-source/parameterstore/README.md @@ -0,0 +1,77 @@ +The Parameter Store data source provides information about a parameter in SSM. + +-> **Note:** Data sources is a feature exclusively available to HCL2 templates. + +Basic examples of usage: + +```hcl +data "amazon-parameterstore" "basic-example" { + name = "packer_test_parameter" + with_decryption = false +} + +# usage example of the data source output +locals { + value = data.amazon-parameterstore.basic-example.value + version = data.amazon-parameterstore.basic-example.version + arn = data.amazon-parameterstore.basic-example.arn +} +``` + +## Configuration Reference + +### Required + + + +- `name` (string) - The name of the parameter you want to query. + + + + +### Optional + + + +- `with_decryption` (bool) - Return decrypted values for secure string parameters. + This flag is ignored for String and StringList parameter types. + + + + +## Output Data + + + +- `value` (string) - The parameter value. + +- `version` (string) - The parameter version. + +- `arn` (string) - The Amazon Resource Name (ARN) of the parameter. + + + + +## Authentication + +The Amazon Data Sources authentication works just like for the [Amazon Builders](/packer/plugins/builders). Both +have the same authentication options, and you can refer to the [Amazon Builders authentication](/packer/integrations/hashicorp/index.mdx#authentication) +to learn the options to authenticate for data sources. + +-> **Note:** A data source will start and execute in your own authentication session. The authentication in the data source +doesn't relate with the authentication on Amazon Builders. + +Basic example of an Amazon data source authentication using `assume_role`: + +```hcl +data "amazon-parameterstore" "basic-example" { + name = "packer_test_parameter" + with_decryption = false + + assume_role { + role_arn = "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME" + session_name = "SESSION_NAME" + external_id = "EXTERNAL_ID" + } +} +``` diff --git a/.web-docs/components/data-source/secretsmanager/README.md b/.web-docs/components/data-source/secretsmanager/README.md new file mode 100644 index 000000000..ef521aaa2 --- /dev/null +++ b/.web-docs/components/data-source/secretsmanager/README.md @@ -0,0 +1,95 @@ +The Secrets Manager data source provides information about a Secrets Manager secret version, +including its secret value. + +-> **Note:** Data sources is a feature exclusively available to HCL2 templates. + +Basic examples of usage: + +```hcl +data "amazon-secretsmanager" "basic-example" { + name = "packer_test_secret" + key = "packer_test_key" + version_stage = "example" +} + +# usage example of the data source output +locals { + value = data.amazon-secretsmanager.basic-example.value + secret_string = data.amazon-secretsmanager.basic-example.secret_string + version_id = data.amazon-secretsmanager.basic-example.version_id + secret_value = jsondecode(data.amazon-secretsmanager.basic-example.secret_string)["packer_test_key"] +} +``` + +Reading key-value pairs from JSON back into a native Packer map can be accomplished +with the [jsondecode() function](/packer/docs/templates/hcl_templates/functions/encoding/jsondecode). + +## Configuration Reference + +### Required + + + +- `name` (string) - Specifies the secret containing the version that you want to retrieve. + You can specify either the Amazon Resource Name (ARN) or the friendly name of the secret. + + + + +### Optional + + + +- `key` (string) - Optional key for JSON secrets that contain more than one value. When set, the `value` output will + contain the value for the provided key. + +- `version_id` (string) - Specifies the unique identifier of the version of the secret that you want to retrieve. + Overrides version_stage. + +- `version_stage` (string) - Specifies the secret version that you want to retrieve by the staging label attached to the version. + Defaults to AWSCURRENT. + + + + +## Output Data + + + +- `value` (string) - When a [key](#key) is provided, this will be the value for that key. If a key is not provided, + `value` will contain the first value found in the secret string. + +- `secret_string` (string) - The decrypted part of the protected secret information that + was originally provided as a string. + +- `secret_binary` (string) - The decrypted part of the protected secret information that + was originally provided as a binary. Base64 encoded. + +- `version_id` (string) - The unique identifier of this version of the secret. + + + + +## Authentication + +The Amazon Data Sources authentication works just like for the [Amazon Builders](/packer/integrations/hashicorp/amazon). Both +have the same authentication options, and you can refer to the [Amazon Builders authentication](/packer/integrations/hashicorp/amazon#authentication) +to learn the options to authenticate for data sources. + +-> **Note:** A data source will start and execute in your own authentication session. The authentication in the data source +doesn't relate with the authentication on Amazon Builders. + +Basic example of an Amazon data source authentication using `assume_role`: + +```hcl +data "amazon-secretsmanager" "basic-example" { + name = "packer_test_secret" + key = "packer_test_key" + + assume_role { + role_arn = "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME" + session_name = "SESSION_NAME" + external_id = "EXTERNAL_ID" + } +} +``` diff --git a/.web-docs/components/post-processor/import/README.md b/.web-docs/components/post-processor/import/README.md new file mode 100644 index 000000000..5ffbeda38 --- /dev/null +++ b/.web-docs/components/post-processor/import/README.md @@ -0,0 +1,267 @@ +Type: `amazon-import` +Artifact BuilderId: `packer.post-processor.amazon-import` + +The Packer Amazon Import post-processor takes an OVA artifact from various +builders and imports it to an AMI available to Amazon Web Services EC2. + +~> This post-processor is for advanced users. It depends on specific IAM +roles inside AWS and is best used with images that operate with the EC2 +configuration model (eg, cloud-init for Linux systems). Please ensure you read +the [prerequisites for import](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/VMImportPrerequisites.html) +before using this post-processor. + +## How Does it Work? + +The import process operates making a temporary copy of the OVA to an S3 bucket, +and calling an import task in EC2 on the OVA file. Once completed, an AMI is +returned containing the converted virtual machine. The temporary OVA copy in S3 +can be discarded after the import is complete. + +The import process itself run by AWS includes modifications to the image +uploaded, to allow it to boot and operate in the AWS EC2 environment. However, +not all modifications required to make the machine run well in EC2 are +performed. Take care around console output from the machine, as debugging can +be very difficult without it. On the source OVA artifact make sure to include +tools suitable for instances in EC2 such as the `cloud-init` package for Linux. + +Further information about the import process can be found in AWS's [EC2 +Import/Export Instance +documentation](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instances_of_your_vm.html). + +## Configuration + +There are some configuration options available for the post-processor. They are +segmented below into two categories: required and optional parameters. Within +each category, the available configuration keys are alphabetized. + +Required: + +- `access_key` (string) - The access key used to communicate with AWS. [Learn + how to set this.](/packer/integrations/hashicorp/amazon#specifying-amazon-credentials) + +- `region` (string) - The name of the region, such as `us-east-1` in which to + upload the OVA file to S3 and create the AMI. A list of valid regions can + be obtained with AWS CLI tools or by consulting the AWS website. + +- `s3_bucket_name` (string) - The name of the S3 bucket where the OVA file + will be copied to for import. This bucket must exist when the + post-processor is run. + +- `secret_key` (string) - The secret key used to communicate with AWS. [Learn + how to set this.](/packer/integrations/hashicorp/amazon#specifying-amazon-credentials) + +Optional: + +- `ami_description` (string) - The description to set for the resulting + imported AMI. By default this description is generated by the AMI import + process. + +- `ami_encrypt` (boolean) - Encrypt the resulting AMI using KMS. This defaults + to `false`. + +- `ami_groups` (array of strings) - A list of groups that have access to + launch the imported AMI. By default no groups have permission to launch the + AMI. `all` will make the AMI publicly accessible. AWS currently doesn't + accept any value other than "all". + +- `ami_kms_key` (string) - The ID of the KMS key used to encrypt the AMI + if `ami_encrypt` is true. If set, the role specified in `role_name` must + be granted access to use this key. If not set, the account default KMS key + will be used. + +- `ami_name` (string) - The name of the ami within the console. If not + specified, this will default to something like `ami-import-sfwerwf`. Please + note, specifying this option will result in a slightly longer execution + time. + +- `ami_users` (array of strings) - A list of account IDs that have access to + launch the imported AMI. By default no additional users other than the user + importing the AMI has permission to launch it. + +- `ami_org_arns` (array of strings) - A list of Amazon Resource Names (ARN) of AWS Organizations that have access to + launch the resulting AMI(s). By default no organizations have permission to launch + the AMI. + +- `ami_ou_arns` (array of strings) - A list of Amazon Resource Names (ARN) of AWS Organizations organizational units (OU) that have access to + launch the resulting AMI(s). By default no organizational units have permission to launch + the AMI. + +- `architecture` (string) - The architecture of the resultant AMI. One of: + `i386`, `x86_64`, or `arm64`. Defaults to `x86_64`. + +- `boot_mode` (string) - The supported boot mode of the resultant AMI. One of: + `legacy-bios` or `uefi`. If `architecture` is set to `arm64` then this value + must be set to `uefi`. + +- `platform` (string) - The operating system of the virtual machine. One of: + `linux` or `windows`. If `boot_mode` is set to `uefi` then this value must be + set to either `windows` or `linux` depending on the operating system of the + virtual machine. + +- `custom_endpoint_ec2` (string) - This option is useful if you use a cloud + provider whose API is compatible with aws EC2. Specify another endpoint + like this `https://ec2.custom.endpoint.com`. + +- `format` (string) - One of: `ova`, `raw`, `vhd`, `vhdx`, or `vmdk`. This + specifies the format of the source virtual machine image. The resulting + artifact from the builder is assumed to have a file extension matching the + format. This defaults to `ova`. + +- `insecure_skip_tls_verify` (boolean) - This allows skipping TLS + verification of the AWS EC2 endpoint. The default is `false`. + +- `keep_input_artifact` (boolean) - if true, do not delete the source virtual + machine image after importing it to the cloud. Defaults to false. + +- `license_type` (string) - The license type to be used for the Amazon + Machine Image (AMI) after importing. Valid values: `AWS` or `BYOL` + (default). For more details regarding licensing, see + [Prerequisites](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/VMImportPrerequisites.html) + in the VM Import/Export User Guide. + +- `mfa_code` (string) - The MFA + [TOTP](https://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm) + code. This should probably be a user variable since it changes all the + time. + +- `profile` (string) - The profile to use in the shared credentials file for + AWS. See Amazon's documentation on [specifying + profiles](https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-profiles) + for more details. + +- `role_name` (string) - The name of the role to use when not using the + default role, 'vmimport' + +- `s3_encryption` (string) - One of: `aws:kms`, or `AES256`. The algorithm + used to encrypt the artifact in S3. This **does not** encrypt the + resulting AMI, and is only used to encrypt the uploaded artifact before + it becomes an AMI. By default no encryption is used. + +- `s3_encryption_key` (string) - The KMS key ID to use when `aws:kms` is + specified in `s3_encryption`. This setting is ignored if AES is used + as Amazon does not currently support custom AES keys when using the VM + import service. If set, the role specified in `role_name` must be granted + access to use this key. If not set, and `s3_encryption` is set to `aws:kms`, + the account default KMS key will be used. + +- `s3_key_name` (string) - The name of the key in `s3_bucket_name` where the + OVA file will be copied to for import. If not specified, this will default + to "packer-import-{{timestamp}}.ova". This key (i.e., the uploaded OVA) + will be removed after import, unless `skip_clean` is `true`. This is + treated as a [template engine](/packer/docs/templates/legacy_json_templates/engine). Therefore, you + may use user variables and template functions in this field. + +- `skip_clean` (boolean) - Whether we should skip removing the OVA file + uploaded to S3 after the import process has completed. "true" means that we + should leave it in the S3 bucket, "false" means to clean it out. Defaults + to `false`. + +- `skip_region_validation` (boolean) - Set to true if you want to skip + validation of the region configuration option. Default `false`. + +- `tags` (object of key/value strings) - Tags applied to the created AMI and + relevant snapshots. + +- `token` (string) - The access token to use. This is different from the + access key and secret key. If you're not sure what this is, then you + probably don't need it. This will also be read from the `AWS_SESSION_TOKEN` + environmental variable. + +## Basic Example + +Here is a basic example. This assumes that the builder has produced an OVA +artifact for us to work with, and IAM roles for import exist in the AWS account +being imported into. + +```json +{ + "type": "amazon-import", + "access_key": "YOUR KEY HERE", + "secret_key": "YOUR SECRET KEY HERE", + "region": "us-east-1", + "s3_bucket_name": "importbucket", + "license_type": "BYOL", + "tags": { + "Description": "packer amazon-import {{timestamp}}" + } +} +``` + +## VMWare Example + +This is an example that uses `vmware-iso` builder and exports the `.ova` file +using ovftool. + +```json +"post-processors" : [ + [ + { + "type": "shell-local", + "inline": [ "/usr/bin/ovftool /.vmx /.ova" ] + }, + { + "files": [ + "/.ova" + ], + "type": "artifice" + }, + { + "type": "amazon-import", + "access_key": "YOUR KEY HERE", + "secret_key": "YOUR SECRET KEY HERE", + "region": "us-east-1", + "s3_bucket_name": "importbucket", + "license_type": "BYOL", + "tags": { + "Description": "packer amazon-import {{timestamp}}" + } + } + ] + ] +``` + +## Amazon Permissions + +You'll need at least the following permissions in the policy for your IAM user +in order to successfully upload an image via the amazon-import post-processor. + +```json +("ec2:CancelImportTask", +"ec2:CopyImage", +"ec2:CreateTags", +"ec2:DescribeImages", +"ec2:DescribeImportImageTasks", +"ec2:ImportImage", +"ec2:ModifyImageAttribute", +"ec2:DeregisterImage") +``` + +## Troubleshooting Timeouts + +The amazon-import feature can take a long time to upload and convert your OVAs +into AMIs; if you find that your build is failing because you have exceeded +your max retries or find yourself being rate limited, you can override the max +retries and the delay in between retries by setting the environment variables +`AWS_MAX_ATTEMPTS` and `AWS_POLL_DELAY_SECONDS` on the machine running the +Packer build. By default, the waiter that waits for your image to be imported +from s3 will retry for up to an hour: it retries up to 720 times with a 5 +second delay in between retries. + +This is dramatically higher than many of our other waiters, to account for how +long this process can take. + +-> **Note:** Packer can also read the access key and secret access key from +environmental variables. See the configuration reference in the section above +for more information on what environmental variables Packer will look for. + +This will take the OVA generated by a builder and upload it to S3. In this +case, an existing bucket called `importbucket` in the `us-east-1` region will +be where the copy is placed. The key name of the copy will be a default name +generated by packer. + +Once uploaded, the import process will start, creating an AMI in the +"us-east-1" region with a "Description" tag applied to both the AMI and the +snapshots associated with it. Note: the import process does not allow you to +name the AMI, the name is automatically generated by AWS. + +After tagging is completed, the OVA uploaded to S3 will be removed. diff --git a/.web-docs/metadata.hcl b/.web-docs/metadata.hcl new file mode 100644 index 000000000..92ea93fa2 --- /dev/null +++ b/.web-docs/metadata.hcl @@ -0,0 +1,56 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +# For full specification on the configuration of this file visit: +# https://github.com/hashicorp/integration-template#metadata-configuration +integration { + name = "Amazon" + description = "The Amazon plugin can be used with HashiCorp Packer to create custom images on AWS." + identifier = "packer/hashicorp/amazon" + flags = ["hcp-ready"] + component { + type = "data-source" + name = "Parameter Store" + slug = "parameterstore" + } + component { + type = "data-source" + name = "Secrets Manager" + slug = "secretsmanager" + } + component { + type = "data-source" + name = "Amazon AMI" + slug = "ami" + } + component { + type = "builder" + name = "Amazon chroot" + slug = "chroot" + } + component { + type = "builder" + name = "Amazon EBS" + slug = "ebs" + } + component { + type = "builder" + name = "Amazon EBS Surrogate" + slug = "ebssurrogate" + } + component { + type = "builder" + name = "Amazon instance-store" + slug = "instance" + } + component { + type = "builder" + name = "Amazon EBS Volume" + slug = "ebsvolume" + } + component { + type = "post-processor" + name = "Amazon Import" + slug = "import" + } +} diff --git a/.web-docs/scripts/compile-to-webdocs.sh b/.web-docs/scripts/compile-to-webdocs.sh new file mode 100755 index 000000000..2fc710b87 --- /dev/null +++ b/.web-docs/scripts/compile-to-webdocs.sh @@ -0,0 +1,132 @@ +#!/usr/bin/env bash +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + + +# Converts the folder name that the component documentation file +# is stored in into the integration slug of the component. +componentTypeFromFolderName() { + if [[ "$1" = "builders" ]]; then + echo "builder" + elif [[ "$1" = "provisioners" ]]; then + echo "provisioner" + elif [[ "$1" = "post-processors" ]]; then + echo "post-processor" + elif [[ "$1" = "datasources" ]]; then + echo "data-source" + else + echo "" + fi +} + +# $1: The content to adjust links +# $2: The organization of the integration +rewriteLinks() { + local result="$1" + local organization="$2" + + urlSegment="([^/]+)" + urlAnchor="(#[^/]+)" + + # Rewrite Component Index Page links to the Integration root page. + # + # (\1) (\2) (\3) + # /packer/plugins/datasources/amazon#anchor-tag--> + # /packer/integrations/hashicorp/amazon#anchor-tag + local find="\(\/packer\/plugins\/$urlSegment\/$urlSegment$urlAnchor?\)" + local replace="\(\/packer\/integrations\/$organization\/\2\3\)" + result="$(echo "$result" | sed -E "s/$find/$replace/g")" + + + # Rewrite Component links to the Integration component page + # + # (\1) (\2) (\3) (\4) + # /packer/plugins/datasources/amazon/parameterstore#anchor-tag --> + # /packer/integrations/{organization}/amazon/latest/components/datasources/parameterstore + local find="\(\/packer\/plugins\/$urlSegment\/$urlSegment\/$urlSegment$urlAnchor?\)" + local replace="\(\/packer\/integrations\/$organization\/\2\/latest\/components\/\1\/\3\4\)" + result="$(echo "$result" | sed -E "s/$find/$replace/g")" + + # Rewrite the Component URL segment from the Packer Plugin format + # to the Integrations format + result="$(echo "$result" \ + | sed "s/\/datasources\//\/data-source\//g" \ + | sed "s/\/builders\//\/builder\//g" \ + | sed "s/\/post-processors\//\/post-processor\//g" \ + | sed "s/\/provisioners\//\/provisioner\//g" \ + )" + + echo "$result" +} + +# $1: Docs Dir +# $2: Web Docs Dir +# $3: Component File +# $4: The org of the integration +processComponentFile() { + local docsDir="$1" + local webDocsDir="$2" + local componentFile="$3" + + local escapedDocsDir="$(echo "$docsDir" | sed 's/\//\\\//g' | sed 's/\./\\\./g')" + local componentTypeAndSlug="$(echo "$componentFile" | sed "s/$escapedDocsDir\///g" | sed 's/\.mdx//g')" + + # Parse out the Component Slug & Component Type + local componentSlug="$(echo "$componentTypeAndSlug" | cut -d'/' -f 2)" + local componentType="$(componentTypeFromFolderName "$(echo "$componentTypeAndSlug" | cut -d'/' -f 1)")" + if [[ "$componentType" = "" ]]; then + echo "Failed to process '$componentFile', unexpected folder name." + echo "Documentation for components must be stored in one of:" + echo "builders, provisioners, post-processors, datasources" + exit 1 + fi + + + # Calculate the location of where this file will ultimately go + local webDocsFolder="$webDocsDir/components/$componentType/$componentSlug" + mkdir -p "$webDocsFolder" + local webDocsFile="$webDocsFolder/README.md" + local webDocsFileTmp="$webDocsFolder/README.md.tmp" + + # Copy over the file to its webDocsFile location + cp "$componentFile" "$webDocsFile" + + # Remove the Header + local lastMetadataLine="$(grep -n -m 2 '^\-\-\-' "$componentFile" | tail -n1 | cut -d':' -f1)" + cat "$webDocsFile" | tail -n +"$(($lastMetadataLine+2))" > "$webDocsFileTmp" + mv "$webDocsFileTmp" "$webDocsFile" + + # Remove the top H1, as this will be added automatically on the web + cat "$webDocsFile" | tail -n +3 > "$webDocsFileTmp" + mv "$webDocsFileTmp" "$webDocsFile" + + # Rewrite Links + rewriteLinks "$(cat "$webDocsFile")" "$4" > "$webDocsFileTmp" + mv "$webDocsFileTmp" "$webDocsFile" +} + +# Compiles the Packer SDC compiled docs folder down +# to a integrations-compliant folder (web docs) +# +# $1: The directory of the plugin +# $2: The directory of the SDC compiled docs files +# $3: The output directory to place the web-docs files +# $4: The org of the integration +compileWebDocs() { + local docsDir="$1/$2" + local webDocsDir="$1/$3" + + echo "Compiling MDX docs in '$2' to Markdown in '$3'..." + # Create the web-docs directory if it hasn't already been created + mkdir -p "$webDocsDir" + + # Copy the README over + cp "$docsDir/README.md" "$webDocsDir/README.md" + + # Process all MDX component files (exclude index files, which are unsupported) + for file in $(find "$docsDir" | grep "$docsDir/.*/.*\.mdx" | grep --invert-match "index.mdx"); do + processComponentFile "$docsDir" "$webDocsDir" "$file" "$4" + done +} + +compileWebDocs "$1" "$2" "$3" "$4" diff --git a/GNUmakefile b/GNUmakefile index f5dcb3390..c7ad03ed1 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -1,5 +1,6 @@ NAME=amazon BINARY=packer-plugin-${NAME} +PLUGIN_FQN="$(shell grep -E '^module' 0 { for kmsKeyRegion := range c.AMIRegionKMSKeyIDs { if !stringInSlice(c.AMIRegions, kmsKeyRegion) { @@ -244,6 +258,21 @@ func (c *AMIConfig) Prepare(accessConfig *AccessConfig, ctx *interpolate.Context "filter to automatically clean your ami name.")) } + if c.AMIIMDSSupport != "" && c.AMIIMDSSupport != ec2.ImdsSupportValuesV20 { + errs = append(errs, + fmt.Errorf(`The only valid imds_support values are %q or the empty string`, + ec2.ImdsSupportValuesV20), + ) + } + + if c.DeprecationTime != "" { + if _, err := time.Parse(time.RFC3339, c.DeprecationTime); err != nil { + errs = append(errs, fmt.Errorf( + "deprecate_at is not a valid time: %q. Expect time format: YYYY-MM-DDTHH:MM:SSZ", + c.DeprecationTime)) + } + } + if len(errs) > 0 { return errs } @@ -309,7 +338,7 @@ func ValidateKmsKey(kmsKey string) (valid bool) { } // Check if kmsKey is the full ARN - kmsArnStartPattern := `^arn:aws(-us-gov)?:kms:([a-z]{2}-(gov-)?[a-z]+-\d{1})?:(\d{12}):` + kmsArnStartPattern := `^arn:aws(-[a-z]{2}(-gov)?)?:kms:([a-z]{2}-(gov-)?[a-z]+-\d{1})?:(\d{12}):` if regexp.MustCompile(fmt.Sprintf("%skey/%s", kmsArnStartPattern, kmsKeyIdPattern)).MatchString(kmsKey) { return true } diff --git a/builder/common/ami_config_test.go b/builder/common/ami_config_test.go index 75b191519..6ea1adf99 100644 --- a/builder/common/ami_config_test.go +++ b/builder/common/ami_config_test.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( @@ -214,6 +217,7 @@ func TestAMIConfigPrepare_ValidateKmsKey(t *testing.T) { "arn:aws:kms:us-east-1:012345678910:key/mrk-12345678-1234-abcd-0000-123456789012", "arn:aws:kms:us-east-1:012345678910:key/mrk-f4224f9362ac4ed2b32a6bc77cf43510", "arn:aws-us-gov:kms:us-gov-east-1:123456789012:key/12345678-1234-abcd-0000-123456789012", + "arn:aws-cn:kms:cn-north-1:012345678910:alias/my-alias", } for _, validCase := range validCases { c.AMIKmsKeyId = validCase @@ -233,6 +237,7 @@ func TestAMIConfigPrepare_ValidateKmsKey(t *testing.T) { "arn:aws:kms:us-east-1:012345678910:key/zab-12345678-1234-abcd-0000-123456789012", "arn:aws:kms:us-east-1:012345678910:key/mkr-12345678-1234-abcd-0000-123456789012", "arn:foo:kms:us-east-1:012345678910:key/abcd1234-a123-456a-a12b-a123b4cd56ef", + "arn:aws-gov:kms:cn-north-1:012345678910:alias/my-alias", } for _, invalidCase := range invalidCases { c.AMIKmsKeyId = invalidCase diff --git a/builder/common/ami_filter.go b/builder/common/ami_filter.go index 019638004..febf848f4 100644 --- a/builder/common/ami_filter.go +++ b/builder/common/ami_filter.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + //go:generate packer-sdc struct-markdown package common @@ -22,6 +25,10 @@ type AmiFilterOptions struct { // Selects the newest created image when true. // This is most useful for selecting a daily distro build. MostRecent bool `mapstructure:"most_recent"` + // Include deprecated AMIs in the filtered response. Defaults to false. + // If you are the AMI owner, deprecated AMIs appear in the response + // regardless of what is specified for `include_deprecated`. + IncludeDeprecated bool `mapstructure:"include_deprecated"` } func (d *AmiFilterOptions) GetOwners() []*string { @@ -55,6 +62,8 @@ func (d *AmiFilterOptions) GetFilteredImage(params *ec2.DescribeImagesInput, ec2 params.Owners = d.GetOwners() } + params.IncludeDeprecated = &d.IncludeDeprecated + log.Printf("Using AMI Filters %v", params) req, imageResp := ec2conn.DescribeImagesRequest(params) req.RetryCount = 11 diff --git a/builder/common/artifact.go b/builder/common/artifact.go index c440315e6..c7b7e72d2 100644 --- a/builder/common/artifact.go +++ b/builder/common/artifact.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( diff --git a/builder/common/artifact_test.go b/builder/common/artifact_test.go index 703de779f..69865e7d9 100644 --- a/builder/common/artifact_test.go +++ b/builder/common/artifact_test.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( diff --git a/builder/common/awserrors/utils.go b/builder/common/awserrors/utils.go index 676ef9b4a..8e2705bdc 100644 --- a/builder/common/awserrors/utils.go +++ b/builder/common/awserrors/utils.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package awserrors import ( @@ -7,9 +10,9 @@ import ( ) // Returns true if the err matches all these conditions: -// * err is of type awserr.Error -// * Error.Code() matches code -// * Error.Message() contains message +// - err is of type awserr.Error +// - Error.Code() matches code +// - Error.Message() contains message func Matches(err error, code string, message string) bool { if err, ok := err.(awserr.Error); ok { return err.Code() == code && strings.Contains(err.Message(), message) diff --git a/builder/common/block_device.go b/builder/common/block_device.go index b2bde0084..33607ceb1 100644 --- a/builder/common/block_device.go +++ b/builder/common/block_device.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + //go:generate packer-sdc struct-markdown //go:generate packer-sdc mapstructure-to-hcl2 -type BlockDevice @@ -33,21 +36,25 @@ const ( // HCL2 example: // // ```hcl -// launch_block_device_mappings { -// device_name = "/dev/sda1" -// encrypted = true -// kms_key_id = "1a2b3c4d-5e6f-1a2b-3c4d-5e6f1a2b3c4d" -// } +// +// launch_block_device_mappings { +// device_name = "/dev/sda1" +// encrypted = true +// kms_key_id = "1a2b3c4d-5e6f-1a2b-3c4d-5e6f1a2b3c4d" +// } +// // ``` // // JSON example: // ```json // "launch_block_device_mappings": [ -// { -// "device_name": "/dev/sda1", -// "encrypted": true, -// "kms_key_id": "1a2b3c4d-5e6f-1a2b-3c4d-5e6f1a2b3c4d" -// } +// +// { +// "device_name": "/dev/sda1", +// "encrypted": true, +// "kms_key_id": "1a2b3c4d-5e6f-1a2b-3c4d-5e6f1a2b3c4d" +// } +// // ] // ``` // @@ -56,7 +63,6 @@ const ( // // Documentation for Block Devices Mappings can be found here: // https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/block-device-mapping-concepts.html -// type BlockDevice struct { // Indicates whether the EBS volume is deleted on instance termination. // Default false. NOTE: If this value is not explicitly set to true and @@ -242,8 +248,8 @@ func (b *BlockDevice) Prepare(ctx *interpolate.Context) error { minIopsGp3, maxIopsGp3, b.DeviceName) } } else if b.Throughput != nil { - return fmt.Errorf("Throughput is not available for device %s", - b.DeviceName) + return fmt.Errorf("Throughput is only valid for gp3 volumes, %q is of type %s", + b.DeviceName, b.VolumeType) } _, err := interpolate.RenderInterface(&b, ctx) diff --git a/builder/common/block_device_test.go b/builder/common/block_device_test.go index 8d33b918e..c6bdcd276 100644 --- a/builder/common/block_device_test.go +++ b/builder/common/block_device_test.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( diff --git a/builder/common/boot_mode_validation.go b/builder/common/boot_mode_validation.go new file mode 100644 index 000000000..8f69a97f2 --- /dev/null +++ b/builder/common/boot_mode_validation.go @@ -0,0 +1,19 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package common + +import "fmt" + +// IsValidBootMode checks that the bootmode is a value supported by AWS +func IsValidBootMode(bootmode string) error { + validModes := []string{"legacy-bios", "uefi", "uefi-preferred"} + + for _, mode := range validModes { + if bootmode == mode { + return nil + } + } + + return fmt.Errorf("invalid boot mode %q, valid values are either 'uefi', 'legacy-bios' or 'uefi-preferred'", bootmode) +} diff --git a/builder/common/boot_mode_validation_test.go b/builder/common/boot_mode_validation_test.go new file mode 100644 index 000000000..44aa1313f --- /dev/null +++ b/builder/common/boot_mode_validation_test.go @@ -0,0 +1,47 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package common + +import "testing" + +func TestIsValidBuildMode(t *testing.T) { + tests := []struct { + name string + value string + expectError bool + }{ + { + "Valid value legacy-bios", + "legacy-bios", + false, + }, + { + "Valid value uefi", + "uefi", + false, + }, + { + "Valid value uefi-preferred", + "uefi-preferred", + false, + }, + { + "Invalid value uefipreferred", + "uefipreferred", + true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := IsValidBootMode(tt.value) + if (err != nil) != tt.expectError { + t.Errorf("error mismatch, expected %t, got %t", tt.expectError, err != nil) + if err != nil { + t.Logf("got error: %s", err) + } + } + }) + } +} diff --git a/builder/common/build_filter.go b/builder/common/build_filter.go index f95bcb4ab..3ecc3a7bc 100644 --- a/builder/common/build_filter.go +++ b/builder/common/build_filter.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( diff --git a/builder/common/build_filter_test.go b/builder/common/build_filter_test.go index 6dcd79f15..11c8a2fa2 100644 --- a/builder/common/build_filter_test.go +++ b/builder/common/build_filter_test.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( diff --git a/builder/common/checkip.go b/builder/common/checkip.go index f3e94e58e..11dd5b988 100644 --- a/builder/common/checkip.go +++ b/builder/common/checkip.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( diff --git a/builder/common/errors.go b/builder/common/errors.go index bca247bfa..02c4343bc 100644 --- a/builder/common/errors.go +++ b/builder/common/errors.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( diff --git a/builder/common/errors_test.go b/builder/common/errors_test.go index b2c05390e..22f95af75 100644 --- a/builder/common/errors_test.go +++ b/builder/common/errors_test.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( diff --git a/builder/common/helper_funcs.go b/builder/common/helper_funcs.go index b80d67c5a..1475a6d24 100644 --- a/builder/common/helper_funcs.go +++ b/builder/common/helper_funcs.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( diff --git a/builder/common/interpolate_build_info.go b/builder/common/interpolate_build_info.go index 010e1b20f..1bf4e7c03 100644 --- a/builder/common/interpolate_build_info.go +++ b/builder/common/interpolate_build_info.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( diff --git a/builder/common/interpolate_build_info_test.go b/builder/common/interpolate_build_info_test.go index f371d3ce7..80027eb84 100644 --- a/builder/common/interpolate_build_info_test.go +++ b/builder/common/interpolate_build_info_test.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( diff --git a/builder/common/regions.go b/builder/common/regions.go index 24344c726..6d03c613a 100644 --- a/builder/common/regions.go +++ b/builder/common/regions.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( diff --git a/builder/common/run_config.go b/builder/common/run_config.go index 1df7d7126..84f9b2a2f 100644 --- a/builder/common/run_config.go +++ b/builder/common/run_config.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + //go:generate packer-sdc struct-markdown //go:generate packer-sdc mapstructure-to-hcl2 -type AmiFilterOptions,SecurityGroupFilterOptions,SubnetFilterOptions,VpcFilterOptions,PolicyDocument,Statement,MetadataOptions,LicenseConfigurationRequest,LicenseSpecification,Placement @@ -64,6 +67,8 @@ type LicenseSpecification struct { type Placement struct { // The ARN of the host resource group in which to launch the instances. HostResourceGroupArn string `mapstructure:"host_resource_group_arn" required:"false"` + // The ID of the host used when Packer launches an EC2 instance. + HostId string `mapstructure:"host_id" required:"false"` // [Tenancy](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/dedicated-instance.html) used // when Packer launches the EC2 instance, allowing it to be launched on dedicated hardware. // @@ -72,6 +77,24 @@ type Placement struct { Tenancy string `mapstructure:"tenancy" required:"false"` } +func (p Placement) Prepare() []error { + var errs []error + + if p.HostId != "" && p.HostResourceGroupArn != "" { + errs = append(errs, fmt.Errorf("The `host_id` and `host_resource_group_arn` settings cannot be specified at the same time.")) + } + + if p.HostId != "" || p.HostResourceGroupArn != "" { + switch p.Tenancy { + case "", "host": + default: + errs = append(errs, fmt.Errorf("The tenancy should be `host` if either the `host_id` or `host_resource_group_arn` attributes are specified.")) + } + } + + return errs +} + // Configures the metadata options. // See [Configure IMDS](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html) for details. type MetadataOptions struct { @@ -96,6 +119,21 @@ type RunConfig struct { // If using a non-default VPC, // public IP addresses are not provided by default. If this is true, your // new instance will get a Public IP. default: unset + // + // Note: when specifying this attribute without a `subnet_[id|filter]` or + // `vpc_[id|filter]`, we will attempt to infer this information from the + // default VPC/Subnet. + // This operation may require some extra permissions to the IAM role that + // runs the build: + // + // * ec2:DescribeVpcs + // * ec2:DescribeSubnets + // + // Additionally, since we filter subnets/AZs by their capability to host + // an instance of the selected type, you may also want to define the + // `ec2:DescribeInstanceTypeOfferings` action to the role running the build. + // Otherwise, Packer will pick the most available subnet in the VPC selected, + // which may not be able to host the instance type you provided. AssociatePublicIpAddress confighelper.Trilean `mapstructure:"associate_public_ip_address" required:"false"` // Destination availability zone to launch // instance in. Leave this empty to allow Amazon to auto-assign. @@ -278,7 +316,7 @@ type RunConfig struct { // // `security_group_ids` take precedence over this. SecurityGroupFilter SecurityGroupFilterOptions `mapstructure:"security_group_filter" required:"false"` - // Key/value pair tags to apply to the generated key-pair, security group, snapshot and instance + // Key/value pair tags to apply to the generated key-pair, security group, iam profile and role, snapshot, network interfaces and instance // that is *launched* to create the EBS volumes. The resulting AMI will also inherit these tags. // This is a [template // engine](/packer/docs/templates/legacy_json_templates/engine), see [Build template @@ -849,11 +887,24 @@ func (c *RunConfig) Prepare(ctx *interpolate.Context) []error { } - if c.CapacityReservationPreference == "" { + capacityReservationTargetSet := false + if c.CapacityReservationId != "" || c.CapacityReservationGroupArn != "" { + capacityReservationTargetSet = true + } + + if c.CapacityReservationGroupArn != "" && c.CapacityReservationId != "" { + errs = append(errs, fmt.Errorf("capacity_reservation_id and capacity_reservation_group_arn are mutually exclusive, only one should be used")) + } + + if capacityReservationTargetSet && c.CapacityReservationPreference != "" { + errs = append(errs, fmt.Errorf("capacity_reservation_id, capacity_reservation_group_arn and capacity_reservation_preference are mutually exclusive, only one should be set")) + } + + if c.CapacityReservationPreference == "" && c.CapacityReservationId == "" && c.CapacityReservationGroupArn == "" { c.CapacityReservationPreference = "none" } switch c.CapacityReservationPreference { - case "none", "open": + case "", "none", "open": default: errs = append(errs, fmt.Errorf(`capacity_reservation_preference only accepts 'none' or 'open' values`)) } @@ -877,6 +928,8 @@ func (c *RunConfig) Prepare(ctx *interpolate.Context) []error { errs = append(errs, fmt.Errorf("Error: Unknown tenancy type %s", tenancy)) } + errs = append(errs, c.Placement.Prepare()...) + if c.EnableNitroEnclave { if c.SpotPrice != "" { errs = append(errs, fmt.Errorf("Error: Nitro Enclave cannot be used in conjunction with Spot Instances")) diff --git a/builder/common/run_config.hcl2spec.go b/builder/common/run_config.hcl2spec.go index cdddb0559..565b2d671 100644 --- a/builder/common/run_config.hcl2spec.go +++ b/builder/common/run_config.hcl2spec.go @@ -11,9 +11,10 @@ import ( // FlatAmiFilterOptions is an auto-generated flat version of AmiFilterOptions. // Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. type FlatAmiFilterOptions struct { - Filters map[string]string `mapstructure:"filters" cty:"filters" hcl:"filters"` - Owners []string `mapstructure:"owners" cty:"owners" hcl:"owners"` - MostRecent *bool `mapstructure:"most_recent" cty:"most_recent" hcl:"most_recent"` + Filters map[string]string `mapstructure:"filters" cty:"filters" hcl:"filters"` + Owners []string `mapstructure:"owners" cty:"owners" hcl:"owners"` + MostRecent *bool `mapstructure:"most_recent" cty:"most_recent" hcl:"most_recent"` + IncludeDeprecated *bool `mapstructure:"include_deprecated" cty:"include_deprecated" hcl:"include_deprecated"` } // FlatMapstructure returns a new FlatAmiFilterOptions. @@ -28,9 +29,10 @@ func (*AmiFilterOptions) FlatMapstructure() interface{ HCL2Spec() map[string]hcl // The decoded values from this spec will then be applied to a FlatAmiFilterOptions. func (*FlatAmiFilterOptions) HCL2Spec() map[string]hcldec.Spec { s := map[string]hcldec.Spec{ - "filters": &hcldec.AttrSpec{Name: "filters", Type: cty.Map(cty.String), Required: false}, - "owners": &hcldec.AttrSpec{Name: "owners", Type: cty.List(cty.String), Required: false}, - "most_recent": &hcldec.AttrSpec{Name: "most_recent", Type: cty.Bool, Required: false}, + "filters": &hcldec.AttrSpec{Name: "filters", Type: cty.Map(cty.String), Required: false}, + "owners": &hcldec.AttrSpec{Name: "owners", Type: cty.List(cty.String), Required: false}, + "most_recent": &hcldec.AttrSpec{Name: "most_recent", Type: cty.Bool, Required: false}, + "include_deprecated": &hcldec.AttrSpec{Name: "include_deprecated", Type: cty.Bool, Required: false}, } return s } @@ -114,6 +116,7 @@ func (*FlatMetadataOptions) HCL2Spec() map[string]hcldec.Spec { // Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. type FlatPlacement struct { HostResourceGroupArn *string `mapstructure:"host_resource_group_arn" required:"false" cty:"host_resource_group_arn" hcl:"host_resource_group_arn"` + HostId *string `mapstructure:"host_id" required:"false" cty:"host_id" hcl:"host_id"` Tenancy *string `mapstructure:"tenancy" required:"false" cty:"tenancy" hcl:"tenancy"` } @@ -130,6 +133,7 @@ func (*Placement) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spe func (*FlatPlacement) HCL2Spec() map[string]hcldec.Spec { s := map[string]hcldec.Spec{ "host_resource_group_arn": &hcldec.AttrSpec{Name: "host_resource_group_arn", Type: cty.String, Required: false}, + "host_id": &hcldec.AttrSpec{Name: "host_id", Type: cty.String, Required: false}, "tenancy": &hcldec.AttrSpec{Name: "tenancy", Type: cty.String, Required: false}, } return s diff --git a/builder/common/run_config_test.go b/builder/common/run_config_test.go index 7c2308a68..b7f793e71 100644 --- a/builder/common/run_config_test.go +++ b/builder/common/run_config_test.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( @@ -389,3 +392,193 @@ func TestRunConfigPrepare_EnableNitroEnclaveGood(t *testing.T) { t.Fatalf("Should not error with valid Nitro Enclave config") } } + +func TestRunConfigPrepare_FailIfBothHostIDAndGroupSpecified(t *testing.T) { + c := testConfig() + c.Placement.HostId = "host" + c.Placement.HostResourceGroupArn = "group" + err := c.Prepare(nil) + if len(err) != 1 { + t.Fatalf("Should error if both host_id and host_resource_group_arn are set") + } +} + +func TestRunConfigPrepare_InvalidTenantForHost(t *testing.T) { + tests := []struct { + name string + setHost string + setGroup string + setTenant string + expectErrors int + }{ + { + "no host_id, no host_resource_group_arn, with valid tenant", + "", + "", + "", + 0, + }, + { + "host_id set, tenant host", + "host", + "", + "host", + 0, + }, + { + "no host_id, host_resource_group_arn set, with tenant host", + "", + "group", + "host", + 0, + }, + { + "host_id set, invalid tenant", + "host", + "", + "dedicated", + 1, + }, + { + "no host_id, host_resource_group_arn set, invalid tenant", + "", + "group", + "dedicated", + 1, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := testConfig() + c.Placement.HostId = tt.setHost + c.Placement.HostResourceGroupArn = tt.setGroup + c.Placement.Tenancy = tt.setTenant + errs := c.Prepare(nil) + if len(errs) != tt.expectErrors { + t.Errorf("expected %d errors, got %d", tt.expectErrors, len(errs)) + } + }) + } +} + +func TestRunConfigPrepare_WithCapacityReservations(t *testing.T) { + tests := []struct { + name string + reservationID string + reservationPreference string + reservationARN string + expectedReservationID string + expectedReservationPreference string + expectedReservationARN string + expectError bool + }{ + { + name: "None set, preference should be set to none, no error", + reservationID: "", + reservationPreference: "", + reservationARN: "", + expectedReservationID: "", + expectedReservationPreference: "none", + expectedReservationARN: "", + expectError: false, + }, + { + name: "Preference set to none, preference should be set to none, no error", + reservationID: "", + reservationPreference: "none", + reservationARN: "", + expectedReservationID: "", + expectedReservationPreference: "none", + expectedReservationARN: "", + expectError: false, + }, + { + name: "Preference set to open, preference should be set to open, no error", + reservationID: "", + reservationPreference: "open", + reservationARN: "", + expectedReservationID: "", + expectedReservationPreference: "open", + expectedReservationARN: "", + expectError: false, + }, + { + name: "Preference set to and invalid value, expect an error", + reservationID: "", + reservationPreference: "invalid", + reservationARN: "", + expectedReservationID: "", + expectedReservationPreference: "invalid", + expectedReservationARN: "", + expectError: true, + }, + { + name: "ID set to something, no preference, no error, no changes to config", + reservationID: "cr-123456", + reservationPreference: "", + reservationARN: "", + expectedReservationID: "cr-123456", + expectedReservationPreference: "", + expectedReservationARN: "", + expectError: false, + }, + { + name: "ARN set to something, no preference, no error, no changes to config", + reservationID: "", + reservationPreference: "", + reservationARN: "arn-asduilovgf", + expectedReservationID: "", + expectedReservationPreference: "", + expectedReservationARN: "arn-asduilovgf", + expectError: false, + }, + { + name: "Preference set to none, ID not empty, should error as both are incompatible", + reservationID: "cr-123456", + reservationPreference: "none", + reservationARN: "", + expectedReservationID: "cr-123456", + expectedReservationPreference: "none", + expectedReservationARN: "", + expectError: true, + }, + { + name: "ID and ARN not empty, should error as both are incompatible", + reservationID: "cr-123456", + reservationPreference: "", + reservationARN: "arn-aseldigubh", + expectedReservationID: "cr-123456", + expectedReservationPreference: "", + expectedReservationARN: "arn-aseldigubh", + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := testConfig() + c.CapacityReservationGroupArn = tt.reservationARN + c.CapacityReservationId = tt.reservationID + c.CapacityReservationPreference = tt.reservationPreference + + errs := c.Prepare(nil) + if (len(errs) != 0) != tt.expectError { + t.Errorf("expected %t errors, got %t", tt.expectError, len(errs) != 0) + t.Logf("errors: %v", errs) + } + + if c.CapacityReservationGroupArn != tt.expectedReservationARN { + t.Errorf("expected Reservation ARN %q, got %q", tt.expectedReservationARN, c.CapacityReservationGroupArn) + } + + if c.CapacityReservationId != tt.expectedReservationID { + t.Errorf("expected Reservation ID %q, got %q", tt.expectedReservationARN, c.CapacityReservationId) + } + + if c.CapacityReservationPreference != tt.expectedReservationPreference { + t.Errorf("expected Reservation Preference %q, got %q", tt.expectedReservationPreference, c.CapacityReservationPreference) + } + }) + } +} diff --git a/builder/common/snapshot_config.go b/builder/common/snapshot_config.go index 542b893bb..5b61c8e9f 100644 --- a/builder/common/snapshot_config.go +++ b/builder/common/snapshot_config.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + //go:generate packer-sdc struct-markdown package common diff --git a/builder/common/ssh.go b/builder/common/ssh.go index 9535d7036..817dcd3ff 100644 --- a/builder/common/ssh.go +++ b/builder/common/ssh.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( @@ -60,7 +63,9 @@ func SSHHost(e ec2Describer, sshInterface string, host string) func(multistep.St } else if i.VpcId != nil && *i.VpcId != "" { if i.PublicIpAddress != nil && *i.PublicIpAddress != "" { host = *i.PublicIpAddress - } else if i.PrivateIpAddress != nil && *i.PrivateIpAddress != "" { + } else if i.PrivateIpAddress != nil && *i.PrivateIpAddress != "" && j == tries { + // if this is the final try, fallback to private ip address, otherwise continue + // trying to get a public ip address. host = *i.PrivateIpAddress } } else if i.PublicDnsName != nil && *i.PublicDnsName != "" { diff --git a/builder/common/ssh_test.go b/builder/common/ssh_test.go index 27bedca80..27171363f 100644 --- a/builder/common/ssh_test.go +++ b/builder/common/ssh_test.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( diff --git a/builder/common/ssm/session.go b/builder/common/ssm/session.go index 146d54647..3e33eb0f1 100644 --- a/builder/common/ssm/session.go +++ b/builder/common/ssm/session.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package ssm import ( @@ -10,6 +13,7 @@ import ( "time" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/ssm" "github.com/aws/aws-sdk-go/service/ssm/ssmiface" "github.com/hashicorp/packer-plugin-amazon/builder/common/awserrors" @@ -23,6 +27,7 @@ type Session struct { Region string InstanceID string LocalPort, RemotePort int + Ec2Conn *ec2.EC2 } func (s Session) buildTunnelInput() *ssm.StartSessionInput { @@ -84,20 +89,60 @@ func (s Session) getCommand(ctx context.Context) ([]string, string, error) { return args, *session.SessionId, nil } +// terminate an interactive Systems Manager session with a remote instance via the +// AWS session-manager-plugin. Session cannot be resumed after termination. +func (s Session) terminateSession(sessionID string, ui packersdk.Ui) { + log.Printf("ssm: Terminating PortForwarding session %q", sessionID) + _, err := s.SvcClient.TerminateSession(&ssm.TerminateSessionInput{SessionId: aws.String(sessionID)}) + if err != nil { + ui.Error(fmt.Sprintf("Error terminating SSM Session %q, this does not affect the built AMI. Please terminate the session manually: %s", sessionID, err)) + } +} + // Start an interactive Systems Manager session with a remote instance via the -// AWS session-manager-plugin. To terminate the session you must cancell the +// AWS session-manager-plugin. To terminate the session you must cancel the // context. If you do not wish to terminate the session manually: calling // StopSession on a instance of this driver will terminate the active session // created from calling StartSession. -func (s Session) Start(ctx context.Context, ui packersdk.Ui) error { - for ctx.Err() == nil { +// To stop the session you must cancel the context. +func (s Session) Start(ctx context.Context, ui packersdk.Ui, sessionChan chan struct{}) error { + exitSession := false + for ctx.Err() == nil && !exitSession { log.Printf("ssm: Starting PortForwarding session to instance %s", s.InstanceID) args, sessionID, err := s.getCommand(ctx) + sessionFinished := make(chan struct{}) + defer close(sessionFinished) if sessionID != "" { - defer func() { - _, err := s.SvcClient.TerminateSession(&ssm.TerminateSessionInput{SessionId: aws.String(sessionID)}) - if err != nil { - ui.Error(fmt.Sprintf("Error terminating SSM Session %q. Please terminate the session manually: %s", sessionID, err)) + // If the instance is terminated the session must be terminated as well + // Otherwise the start-session command will exit with status -1 + go func() { + timer := time.NewTicker(2 * time.Second) + defer timer.Stop() + for { + select { + // in cases where the session is terminated naturally + // e.g. the RunAndStream command exits + // session will be terminated but exitSession is not set to true + // because the instance is still running and we might want to do a reconnect + case <-sessionFinished: + s.terminateSession(sessionID, ui) + return + case <-timer.C: // wait for the session to be created + instanceState, err := s.Ec2Conn.DescribeInstanceStatus(&ec2.DescribeInstanceStatusInput{ + InstanceIds: []*string{aws.String(s.InstanceID)}, + }) + if err != nil { + log.Printf("ssm: Error describing instance status: %s", err) + } else if instanceState != nil && len(instanceState.InstanceStatuses) == 0 { + // if no instance status is returned, the instance is terminated + exitSession = true + s.terminateSession(sessionID, ui) + return + } + case <-ctx.Done(): + s.terminateSession(sessionID, ui) + return + } } }() } @@ -105,13 +150,17 @@ func (s Session) Start(ctx context.Context, ui packersdk.Ui) error { return err } + sessionChan <- struct{}{} cmd := exec.CommandContext(ctx, "session-manager-plugin", args...) ui.Message(fmt.Sprintf("Starting portForwarding session %q.", sessionID)) err = localexec.RunAndStream(cmd, ui, nil) + sessionFinished <- struct{}{} if err != nil { ui.Error(err.Error()) } } + ui.Say("ssm: PortForwarding session is finished") + close(sessionChan) return nil } diff --git a/builder/common/state.go b/builder/common/state.go index 48b5f0e05..c396b043f 100644 --- a/builder/common/state.go +++ b/builder/common/state.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + //go:generate packer-sdc struct-markdown //go:generate packer-sdc mapstructure-to-hcl2 -type AWSPollingConfig package common @@ -45,18 +48,22 @@ type StateChangeConf struct { // // HCL2 example: // ```hcl -// aws_polling { -// delay_seconds = 30 -// max_attempts = 50 -// } +// +// aws_polling { +// delay_seconds = 30 +// max_attempts = 50 +// } +// // ``` // // JSON example: // ```json -// "aws_polling" : { -// "delay_seconds": 30, -// "max_attempts": 50 -// } +// +// "aws_polling" : { +// "delay_seconds": 30, +// "max_attempts": 50 +// } +// // ``` type AWSPollingConfig struct { // Specifies the maximum number of attempts the waiter will check for resource state. @@ -99,7 +106,7 @@ func (w *AWSPollingConfig) WaitUntilAMIAvailable(ctx aws.Context, conn ec2iface. return err } -func (w *AWSPollingConfig) WaitUntilInstanceRunning(ctx aws.Context, conn *ec2.EC2, instanceId string) error { +func (w *AWSPollingConfig) WaitUntilInstanceRunning(ctx aws.Context, conn ec2iface.EC2API, instanceId string) error { instanceInput := ec2.DescribeInstancesInput{ InstanceIds: []*string{&instanceId}, @@ -206,6 +213,20 @@ func (w *AWSPollingConfig) WaitUntilImageImported(ctx aws.Context, conn *ec2.EC2 return err } +func (w *AWSPollingConfig) WaitUntilFastLaunchEnabled(ctx aws.Context, conn *ec2.EC2, imageID string) error { + fastLaunchDescribeInput := &ec2.DescribeFastLaunchImagesInput{ + ImageIds: []*string{ + &imageID, + }, + } + + err := WaitUntilFastLaunchEnabled(conn, + ctx, + fastLaunchDescribeInput, + w.getWaiterOptions()...) + return err +} + // Custom waiters using AWS's request.Waiter func WaitForVolumeToBeAttached(c *ec2.EC2, ctx aws.Context, input *ec2.DescribeVolumesInput, opts ...request.WaiterOption) error { @@ -307,6 +328,49 @@ func WaitForImageToBeImported(c *ec2.EC2, ctx aws.Context, input *ec2.DescribeIm return w.WaitWithContext(ctx) } +func WaitUntilFastLaunchEnabled(c *ec2.EC2, ctx aws.Context, input *ec2.DescribeFastLaunchImagesInput, opts ...request.WaiterOption) error { + w := request.Waiter{ + Name: "DescribeFastLaunchImages", + MaxAttempts: 500, + Delay: request.ConstantWaiterDelay(15 * time.Second), + Acceptors: []request.WaiterAcceptor{ + { + State: request.SuccessWaiterState, + Matcher: request.PathAllWaiterMatch, + Argument: "FastLaunchImages[].State", + Expected: "enabled", + }, + { + State: request.FailureWaiterState, + Matcher: request.PathAllWaiterMatch, + Argument: "FastLaunchImages[].State", + Expected: "enabling-failed", + }, + { + State: request.FailureWaiterState, + Matcher: request.PathAllWaiterMatch, + Argument: "FastLaunchImages[].State", + Expected: "enabled-failed", + }, + }, + Logger: c.Config.Logger, + NewRequest: func(opts []request.Option) (*request.Request, error) { + var inCpy *ec2.DescribeFastLaunchImagesInput + if input != nil { + tmp := *input + inCpy = &tmp + } + req, _ := c.DescribeFastLaunchImagesRequest(inCpy) + req.SetContext(ctx) + req.ApplyOptions(opts...) + return req, nil + }, + } + w.ApplyOptions(opts...) + + return w.WaitWithContext(ctx) +} + // This helper function uses the environment variables AWS_TIMEOUT_SECONDS and // AWS_POLL_DELAY_SECONDS to generate waiter options that can be passed into any // request.Waiter function. These options will control how many times the waiter diff --git a/builder/common/step_ami_region_copy.go b/builder/common/step_ami_region_copy.go index 503d98be9..d635955ed 100644 --- a/builder/common/step_ami_region_copy.go +++ b/builder/common/step_ami_region_copy.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( @@ -202,12 +205,14 @@ func (s *StepAMIRegionCopy) amiRegionCopy(ctx context.Context, state multistep.S if err != nil { return "", snapshotIds, err } + t := true resp, err := regionconn.CopyImage(&ec2.CopyImageInput{ SourceRegion: &source, SourceImageId: &imageId, Name: &name, Encrypted: encrypt, KmsKeyId: aws.String(keyId), + CopyImageTags: &t, }) if err != nil { diff --git a/builder/common/step_ami_region_copy_test.go b/builder/common/step_ami_region_copy_test.go index 4c809b665..c2601b09b 100644 --- a/builder/common/step_ami_region_copy_test.go +++ b/builder/common/step_ami_region_copy_test.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( @@ -32,6 +35,9 @@ type mockEC2Conn struct { } func (m *mockEC2Conn) CopyImage(copyInput *ec2.CopyImageInput) (*ec2.CopyImageOutput, error) { + if !*copyInput.CopyImageTags { + return nil, fmt.Errorf("CopyImageTags should always be true, but was %t", *copyInput.CopyImageTags) + } m.lock.Lock() m.copyImageCount++ m.lock.Unlock() diff --git a/builder/common/step_cleanup_volumes.go b/builder/common/step_cleanup_volumes.go index 69613b84b..4738e73f2 100644 --- a/builder/common/step_cleanup_volumes.go +++ b/builder/common/step_cleanup_volumes.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( diff --git a/builder/common/step_create_ssm_tunnel.go b/builder/common/step_create_ssm_tunnel.go index 5022e1583..b6083527a 100644 --- a/builder/common/step_create_ssm_tunnel.go +++ b/builder/common/step_create_ssm_tunnel.go @@ -1,15 +1,23 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( "context" "fmt" + "log" + "strings" "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go/service/ec2instanceconnect" "github.com/aws/aws-sdk-go/service/ssm" pssm "github.com/hashicorp/packer-plugin-amazon/builder/common/ssm" + "github.com/hashicorp/packer-plugin-sdk/communicator" + "github.com/hashicorp/packer-plugin-sdk/communicator/sshkey" "github.com/hashicorp/packer-plugin-sdk/multistep" "github.com/hashicorp/packer-plugin-sdk/net" packersdk "github.com/hashicorp/packer-plugin-sdk/packer" @@ -21,6 +29,7 @@ type StepCreateSSMTunnel struct { LocalPortNumber int RemotePortNumber int SSMAgentEnabled bool + SSHConfig *communicator.SSH PauseBeforeSSM time.Duration stopSSMCommand func() } @@ -65,23 +74,74 @@ func (s *StepCreateSSMTunnel) Run(ctx context.Context, state multistep.StateBag) ssmCtx, ssmCancel := context.WithCancel(ctx) s.stopSSMCommand = ssmCancel + ec2Conn := state.Get("ec2").(*ec2.EC2) + + ssmconn := ssm.New(s.AWSSession) + session := pssm.Session{ + SvcClient: ssmconn, + InstanceID: aws.StringValue(instance.InstanceId), + RemotePort: s.RemotePortNumber, + LocalPort: s.LocalPortNumber, + Region: s.Region, + Ec2Conn: ec2Conn, + } + go s.CreatePersistentSSMSession(ssmCtx, ui, &session, instance) + + return multistep.ActionContinue +} + +func (s *StepCreateSSMTunnel) CreatePersistentSSMSession(ctx context.Context, ui packersdk.Ui, session *pssm.Session, instance *ec2.Instance) { + sessionChan := make(chan struct{}) go func() { - ssmconn := ssm.New(s.AWSSession) - err := pssm.Session{ - SvcClient: ssmconn, - InstanceID: aws.StringValue(instance.InstanceId), - RemotePort: s.RemotePortNumber, - LocalPort: s.LocalPortNumber, - Region: s.Region, - }.Start(ssmCtx, ui) - - if err != nil { - ui.Error(fmt.Sprintf("ssm error: %s", err)) + // SSH public key sent expires every minute. + // Send it upon each reconnect to ensure it is always valid. + for range sessionChan { + if len(s.SSHConfig.SSHPrivateKey) != 0 && s.SSHConfig.SSHKeyPairName == "" { + ui.Say("Uploading SSH public key to instance") + err := s.sendUserSSHPublicKey(instance, s.SSHConfig.SSHPrivateKey) + if err != nil { + ui.Error(err.Error()) + } + } } }() - return multistep.ActionContinue + err := session.Start(ctx, ui, sessionChan) + if err != nil { + ui.Error(fmt.Sprintf("ssm error: %s", err)) + } +} + +func (s *StepCreateSSMTunnel) sendUserSSHPublicKey( + instance *ec2.Instance, + privateKey []byte, +) error { + publicKey, err := sshkey.PublicKeyFromPrivate(privateKey) + if err != nil { + return fmt.Errorf("Error getting public key from private key: %s", err) + } + svc := ec2instanceconnect.New(s.AWSSession) + input := &ec2instanceconnect.SendSSHPublicKeyInput{ + AvailabilityZone: aws.String(*instance.Placement.AvailabilityZone), + InstanceId: aws.String(*instance.InstanceId), + InstanceOSUser: aws.String(s.SSHConfig.SSHUsername), + SSHPublicKey: aws.String(strings.TrimSuffix(string(publicKey), "\n")), + } + log.Printf("Sending public key to instance: %s", *input.InstanceId) + result, err := svc.SendSSHPublicKey(input) + if err != nil { + err := fmt.Errorf(` + error encountered in sending public key to instance: %s + Check the key type and length are valid in AWS API. + https://docs.aws.amazon.com/ec2-instance-connect/latest/APIReference/API_SendSSHPublicKey.html`, err) + return err + } else { + if *result.Success { + return nil + } + } + return fmt.Errorf("Failed to send public key to instance") } // Cleanup terminates an active session on AWS, which in turn terminates the associated tunnel process running on the local machine. diff --git a/builder/common/step_create_tags.go b/builder/common/step_create_tags.go index ccb3a9352..9c3f7cc84 100644 --- a/builder/common/step_create_tags.go +++ b/builder/common/step_create_tags.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( diff --git a/builder/common/step_deregister_ami.go b/builder/common/step_deregister_ami.go index 135052229..cc42bca26 100644 --- a/builder/common/step_deregister_ami.go +++ b/builder/common/step_deregister_ami.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( diff --git a/builder/ebs/step_enable_deprecation.go b/builder/common/step_enable_deprecation.go similarity index 80% rename from builder/ebs/step_enable_deprecation.go rename to builder/common/step_enable_deprecation.go index 6ae89e0de..7d7dfe84a 100644 --- a/builder/ebs/step_enable_deprecation.go +++ b/builder/common/step_enable_deprecation.go @@ -1,4 +1,7 @@ -package ebs +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package common import ( "context" @@ -6,18 +9,17 @@ import ( "time" "github.com/aws/aws-sdk-go/service/ec2" - "github.com/hashicorp/packer-plugin-amazon/builder/common" "github.com/hashicorp/packer-plugin-sdk/multistep" packersdk "github.com/hashicorp/packer-plugin-sdk/packer" ) -type stepEnableDeprecation struct { - AccessConfig *common.AccessConfig +type StepEnableDeprecation struct { + AccessConfig *AccessConfig DeprecationTime string AMISkipCreateImage bool } -func (s *stepEnableDeprecation) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { +func (s *StepEnableDeprecation) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { ui := state.Get("ui").(packersdk.Ui) if s.AMISkipCreateImage || s.DeprecationTime == "" { ui.Say("Skipping Enable AMI deprecation...") @@ -36,7 +38,7 @@ func (s *stepEnableDeprecation) Run(ctx context.Context, state multistep.StateBa for region, ami := range amis { ui.Say(fmt.Sprintf("Enabling deprecation on AMI (%s) in region %q ...", ami, region)) - conn, err := common.GetRegionConn(s.AccessConfig, region) + conn, err := GetRegionConn(s.AccessConfig, region) if err != nil { err := fmt.Errorf("failed to connect to region %s: %s", region, err) state.Put("error", err.Error()) @@ -57,6 +59,6 @@ func (s *stepEnableDeprecation) Run(ctx context.Context, state multistep.StateBa } return multistep.ActionContinue } -func (s *stepEnableDeprecation) Cleanup(state multistep.StateBag) { +func (s *StepEnableDeprecation) Cleanup(state multistep.StateBag) { // No cleanup... } diff --git a/builder/common/step_get_password.go b/builder/common/step_get_password.go index dac97f92f..a6c14e64a 100644 --- a/builder/common/step_get_password.go +++ b/builder/common/step_get_password.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( diff --git a/builder/common/step_iam_instance_profile.go b/builder/common/step_iam_instance_profile.go index 0b950e6b5..23731fc5d 100644 --- a/builder/common/step_iam_instance_profile.go +++ b/builder/common/step_iam_instance_profile.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( @@ -10,10 +13,12 @@ import ( "github.com/aws/aws-sdk-go/service/iam" "github.com/hashicorp/packer-plugin-sdk/multistep" packersdk "github.com/hashicorp/packer-plugin-sdk/packer" + "github.com/hashicorp/packer-plugin-sdk/template/interpolate" "github.com/hashicorp/packer-plugin-sdk/uuid" ) type StepIamInstanceProfile struct { + PollingConfig *AWSPollingConfig IamInstanceProfile string SkipProfileValidation bool TemporaryIamInstanceProfilePolicyDocument *PolicyDocument @@ -21,6 +26,8 @@ type StepIamInstanceProfile struct { createdRoleName string createdPolicyName string roleIsAttached bool + Tags map[string]string + Ctx interpolate.Context } func (s *StepIamInstanceProfile) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { @@ -61,8 +68,16 @@ func (s *StepIamInstanceProfile) Run(ctx context.Context, state multistep.StateB ui.Say(fmt.Sprintf("Creating temporary instance profile for this instance: %s", profileName)) + region := state.Get("region").(*string) + iamProfileTags, err := TagMap(s.Tags).IamTags(s.Ctx, *region, state) + if err != nil { + err := fmt.Errorf("Error creating IAM tags: %s", err) + state.Put("error", err) + return multistep.ActionHalt + } profileResp, err := iamsvc.CreateInstanceProfile(&iam.CreateInstanceProfileInput{ InstanceProfileName: aws.String(profileName), + Tags: iamProfileTags, }) if err != nil { ui.Error(err.Error()) @@ -91,6 +106,7 @@ func (s *StepIamInstanceProfile) Run(ctx context.Context, state multistep.StateB RoleName: aws.String(profileName), Description: aws.String("Temporary role for Packer"), AssumeRolePolicyDocument: aws.String("{\"Version\": \"2012-10-17\",\"Statement\": [{\"Effect\": \"Allow\",\"Principal\": {\"Service\": \"ec2.amazonaws.com\"},\"Action\": \"sts:AssumeRole\"}]}"), + Tags: iamProfileTags, }) if err != nil { ui.Error(err.Error()) @@ -101,9 +117,13 @@ func (s *StepIamInstanceProfile) Run(ctx context.Context, state multistep.StateB s.createdRoleName = aws.StringValue(roleResp.Role.RoleName) log.Printf("[DEBUG] Waiting for temporary role: %s", s.createdInstanceProfileName) - err = iamsvc.WaitUntilRoleExists(&iam.GetRoleInput{ - RoleName: aws.String(s.createdRoleName), - }) + err = iamsvc.WaitUntilRoleExistsWithContext( + aws.BackgroundContext(), + &iam.GetRoleInput{ + RoleName: aws.String(s.createdRoleName), + }, + s.PollingConfig.getWaiterOptions()..., + ) if err == nil { log.Printf("[DEBUG] Found temporary role %s", s.createdRoleName) } else { diff --git a/builder/common/step_key_pair.go b/builder/common/step_key_pair.go index f7c74069e..a12246592 100644 --- a/builder/common/step_key_pair.go +++ b/builder/common/step_key_pair.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( diff --git a/builder/common/step_key_pair_test.go b/builder/common/step_key_pair_test.go index 02351c31a..1680bc614 100644 --- a/builder/common/step_key_pair_test.go +++ b/builder/common/step_key_pair_test.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( diff --git a/builder/common/step_modify_ami_attributes.go b/builder/common/step_modify_ami_attributes.go index ac3e4fec3..3304d96ee 100644 --- a/builder/common/step_modify_ami_attributes.go +++ b/builder/common/step_modify_ami_attributes.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( @@ -23,6 +26,7 @@ type StepModifyAMIAttributes struct { SnapshotUsers []string SnapshotGroups []string ProductCodes []string + IMDSSupport string Description string Ctx interpolate.Context @@ -52,6 +56,7 @@ func (s *StepModifyAMIAttributes) Run(ctx context.Context, state multistep.State valid = valid || (s.ProductCodes != nil && len(s.ProductCodes) > 0) valid = valid || (s.SnapshotUsers != nil && len(s.SnapshotUsers) > 0) valid = valid || (s.SnapshotGroups != nil && len(s.SnapshotGroups) > 0) + valid = valid || s.IMDSSupport != "" if !valid { return multistep.ActionContinue @@ -188,6 +193,14 @@ func (s *StepModifyAMIAttributes) Run(ctx context.Context, state multistep.State } } + if s.IMDSSupport != "" { + options["imds_support"] = &ec2.ModifyImageAttributeInput{ + ImdsSupport: &ec2.AttributeValue{ + Value: &s.IMDSSupport, + }, + } + } + // Modifying image attributes for region, ami := range amis { ui.Say(fmt.Sprintf("Modifying attributes on AMI (%s)...", ami)) diff --git a/builder/common/step_modify_ebs_instance.go b/builder/common/step_modify_ebs_instance.go index d58196d9e..a8222d6ff 100644 --- a/builder/common/step_modify_ebs_instance.go +++ b/builder/common/step_modify_ebs_instance.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( diff --git a/builder/common/step_network_info.go b/builder/common/step_network_info.go index e47c68132..1c0b4649e 100644 --- a/builder/common/step_network_info.go +++ b/builder/common/step_network_info.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( @@ -7,26 +10,35 @@ import ( "math/rand" "sort" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go/service/ec2/ec2iface" "github.com/hashicorp/packer-plugin-sdk/multistep" packersdk "github.com/hashicorp/packer-plugin-sdk/packer" + confighelper "github.com/hashicorp/packer-plugin-sdk/template/config" ) // StepNetworkInfo queries AWS for information about // VPC's and Subnets that is used throughout the AMI creation process. // // Produces (adding them to the state bag): -// vpc_id string - the VPC ID -// subnet_id string - the Subnet ID -// availability_zone string - the AZ name +// +// vpc_id string - the VPC ID +// subnet_id string - the Subnet ID +// availability_zone string - the AZ name type StepNetworkInfo struct { - VpcId string - VpcFilter VpcFilterOptions - SubnetId string - SubnetFilter SubnetFilterOptions - AvailabilityZone string - SecurityGroupIds []string - SecurityGroupFilter SecurityGroupFilterOptions + VpcId string + VpcFilter VpcFilterOptions + SubnetId string + SubnetFilter SubnetFilterOptions + AssociatePublicIpAddress confighelper.Trilean + AvailabilityZone string + SecurityGroupIds []string + SecurityGroupFilter SecurityGroupFilterOptions + // RequestedMachineType is the machine type of the instance we want to create. + // This is used for selecting a subnet/AZ which supports the type of instance + // selected, and not just the most available / random one. + RequestedMachineType string } type subnetsSort []*ec2.Subnet @@ -45,10 +57,10 @@ func mostFreeSubnet(subnets []*ec2.Subnet) *ec2.Subnet { } func (s *StepNetworkInfo) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - ec2conn := state.Get("ec2").(*ec2.EC2) + ec2conn := state.Get("ec2").(ec2iface.EC2API) ui := state.Get("ui").(packersdk.Ui) - // VPC + // Set VpcID if none was specified but filters are defined in the template. if s.VpcId == "" && !s.VpcFilter.Empty() { params := &ec2.DescribeVpcsInput{} vpcFilters, err := buildEc2Filters(s.VpcFilter.Filters) @@ -82,7 +94,7 @@ func (s *StepNetworkInfo) Run(ctx context.Context, state multistep.StateBag) mul ui.Message(fmt.Sprintf("Found VPC ID: %s", s.VpcId)) } - // Subnet + // Set SubnetID if none was specified but filters are defined in the template. if s.SubnetId == "" && !s.SubnetFilter.Empty() { params := &ec2.DescribeSubnetsInput{} s.SubnetFilter.Filters["state"] = "available" @@ -138,6 +150,17 @@ func (s *StepNetworkInfo) Run(ctx context.Context, state multistep.StateBag) mul ui.Message(fmt.Sprintf("Found Subnet ID: %s", s.SubnetId)) } + // Set VPC/Subnet if we explicitely enable or disable public IP assignment to the instance + // and we did not set or get a subnet ID before + if s.AssociatePublicIpAddress != confighelper.TriUnset && s.SubnetId == "" { + err := s.GetDefaultVPCAndSubnet(ui, ec2conn, state) + if err != nil { + ui.Say("associate_public_ip_address is set without a subnet_id.") + ui.Say(fmt.Sprintf("Packer attempted to infer a subnet from default VPC (if unspecified), but failed due to: %s", err)) + ui.Say("The associate_public_ip_address will be ignored for the remainder of the build, and a public IP will only be associated if the VPC chosen enables it by default.") + } + } + // Try to find AZ and VPC Id from Subnet if they are not yet found/given if s.SubnetId != "" && (s.AvailabilityZone == "" || s.VpcId == "") { log.Printf("[INFO] Finding AZ and VpcId for the given subnet '%s'", s.SubnetId) @@ -164,4 +187,142 @@ func (s *StepNetworkInfo) Run(ctx context.Context, state multistep.StateBag) mul return multistep.ActionContinue } +func (s *StepNetworkInfo) GetDefaultVPCAndSubnet(ui packersdk.Ui, ec2conn ec2iface.EC2API, state multistep.StateBag) error { + ui.Say(fmt.Sprintf("Setting public IP address to %t on instance without a subnet ID", + *s.AssociatePublicIpAddress.ToBoolPointer())) + + var vpc = s.VpcId + if vpc == "" { + ui.Say("No VPC ID provided, Packer will use the default VPC") + vpcs, err := ec2conn.DescribeVpcs(&ec2.DescribeVpcsInput{ + Filters: []*ec2.Filter{ + { + Name: aws.String("is-default"), + Values: []*string{aws.String("true")}, + }, + }, + }) + if err != nil { + return fmt.Errorf("Failed to describe VPCs: %s", err) + } + + if len(vpcs.Vpcs) != 1 { + return fmt.Errorf("No default VPC found") + } + vpc = *vpcs.Vpcs[0].VpcId + } + + var err error + + ui.Say(fmt.Sprintf("Inferring subnet from the selected VPC %q", vpc)) + params := &ec2.DescribeSubnetsInput{} + filters := map[string]string{ + "vpc-id": vpc, + "state": "available", + } + params.Filters, err = buildEc2Filters(filters) + if err != nil { + return fmt.Errorf("Failed to prepare subnet filters: %s", err) + } + subnetOut, err := ec2conn.DescribeSubnets(params) + if err != nil { + return fmt.Errorf("Failed to describe subnets: %s", err) + } + + subnets := subnetOut.Subnets + + // Filter by AZ with support for machine type + azs := getAZFromSubnets(subnets) + azs, err = filterAZByMachineType(azs, s.RequestedMachineType, ec2conn) + if err == nil { + subnets = filterSubnetsByAZ(subnets, azs) + if subnets == nil { + return fmt.Errorf("Failed to get subnets for the filtered AZs") + } + } else { + ui.Say(fmt.Sprintf( + "Failed to filter subnets/AZ for the requested machine type %q: %s", + s.RequestedMachineType, err)) + ui.Say("This may result in Packer picking a subnet/AZ that can't host the requested machine type") + ui.Say("Please check that you have the permissions required to run DescribeInstanceTypeOfferings and try again.") + } + + subnet := mostFreeSubnet(subnets) + + s.SubnetId = *subnet.SubnetId + s.VpcId = vpc + s.AvailabilityZone = *subnet.AvailabilityZone + + ui.Say(fmt.Sprintf("Set subnet as %q", s.SubnetId)) + + return nil +} + +func getAZFromSubnets(subnets []*ec2.Subnet) []string { + azs := map[string]struct{}{} + for _, sub := range subnets { + azs[*sub.AvailabilityZone] = struct{}{} + } + + retAZ := make([]string, 0, len(azs)) + for az := range azs { + retAZ = append(retAZ, az) + } + + return retAZ +} + +func filterAZByMachineType(azs []string, machineType string, ec2conn ec2iface.EC2API) ([]string, error) { + var retAZ []string + + for _, az := range azs { + resp, err := ec2conn.DescribeInstanceTypeOfferings(&ec2.DescribeInstanceTypeOfferingsInput{ + LocationType: aws.String("availability-zone"), + Filters: []*ec2.Filter{ + { + Name: aws.String("location"), + Values: []*string{&az}, + }, + { + Name: aws.String("instance-type"), + Values: []*string{&machineType}, + }, + }, + }) + if err != nil { + err = fmt.Errorf("failed to get offerings for AZ %q: %s", az, err) + return nil, err + } + + for _, off := range resp.InstanceTypeOfferings { + if *off.InstanceType == machineType { + retAZ = append(retAZ, az) + break + } + } + } + + if retAZ == nil { + return nil, fmt.Errorf("no AZ match the requested machine type %q", machineType) + } + + return retAZ, nil +} + +func filterSubnetsByAZ(subnets []*ec2.Subnet, azs []string) []*ec2.Subnet { + var retSubs []*ec2.Subnet + +outLoop: + for _, sub := range subnets { + for _, az := range azs { + if *sub.AvailabilityZone == az { + retSubs = append(retSubs, sub) + continue outLoop + } + } + } + + return retSubs +} + func (s *StepNetworkInfo) Cleanup(multistep.StateBag) {} diff --git a/builder/common/step_network_info_test.go b/builder/common/step_network_info_test.go new file mode 100644 index 000000000..5dcc17d16 --- /dev/null +++ b/builder/common/step_network_info_test.go @@ -0,0 +1,573 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package common + +import ( + "context" + "fmt" + "strings" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go/service/ec2/ec2iface" + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/packer-plugin-sdk/multistep" + packersdk "github.com/hashicorp/packer-plugin-sdk/packer" + confighelper "github.com/hashicorp/packer-plugin-sdk/template/config" +) + +type mockEC2ClientStepNetworkTests struct { + ec2iface.EC2API + + describeInstanceTypeOfferings func(in *ec2.DescribeInstanceTypeOfferingsInput) (*ec2.DescribeInstanceTypeOfferingsOutput, error) + describeVpcs func(*ec2.DescribeVpcsInput) (*ec2.DescribeVpcsOutput, error) + describeSubnets func(*ec2.DescribeSubnetsInput) (*ec2.DescribeSubnetsOutput, error) +} + +func (m *mockEC2ClientStepNetworkTests) DescribeInstanceTypeOfferings(in *ec2.DescribeInstanceTypeOfferingsInput) (*ec2.DescribeInstanceTypeOfferingsOutput, error) { + if m.describeInstanceTypeOfferings != nil { + return m.describeInstanceTypeOfferings(in) + } + + return nil, fmt.Errorf("unimplemented: describeInstanceTypeOfferings") +} + +func (m *mockEC2ClientStepNetworkTests) DescribeVpcs(in *ec2.DescribeVpcsInput) (*ec2.DescribeVpcsOutput, error) { + if m.describeVpcs != nil { + return m.describeVpcs(in) + } + + return nil, fmt.Errorf("unimplemented: describeVpcs") +} + +func (m *mockEC2ClientStepNetworkTests) DescribeSubnets(in *ec2.DescribeSubnetsInput) (*ec2.DescribeSubnetsOutput, error) { + if m.describeSubnets != nil { + return m.describeSubnets(in) + } + + return nil, fmt.Errorf("unimplemented: describeSubnets") +} + +func TestStepNetwork_GetFilterAZByMachineType(t *testing.T) { + testcases := []struct { + name string + describeImpl func(in *ec2.DescribeInstanceTypeOfferingsInput) (*ec2.DescribeInstanceTypeOfferingsOutput, error) + machineType string + inputAZs []string + expectedAZs []string + expectError bool + }{ + { + name: "Fail: describe returns an error", + describeImpl: func(in *ec2.DescribeInstanceTypeOfferingsInput) (*ec2.DescribeInstanceTypeOfferingsOutput, error) { + return nil, fmt.Errorf("STOP") + }, + machineType: "t2.micro", + inputAZs: []string{"us-east-1a", "us-east-1b"}, + expectedAZs: nil, + expectError: true, + }, + { + name: "Fail, no AZ match machine type", + describeImpl: func(in *ec2.DescribeInstanceTypeOfferingsInput) (*ec2.DescribeInstanceTypeOfferingsOutput, error) { + return &ec2.DescribeInstanceTypeOfferingsOutput{ + InstanceTypeOfferings: []*ec2.InstanceTypeOffering{ + { + InstanceType: aws.String("t3.mini"), + }, + { + InstanceType: aws.String("t2.mini"), + }, + }, + }, nil + }, + machineType: "t2.micro", + inputAZs: []string{"us-east-1b", "us-east-1c"}, + expectedAZs: nil, + expectError: true, + }, + { + name: "OK, found at least one AZ matching machine type", + describeImpl: func(in *ec2.DescribeInstanceTypeOfferingsInput) (*ec2.DescribeInstanceTypeOfferingsOutput, error) { + return &ec2.DescribeInstanceTypeOfferingsOutput{ + InstanceTypeOfferings: []*ec2.InstanceTypeOffering{ + { + InstanceType: aws.String("t2.micro"), + }, + }, + }, nil + }, + machineType: "t2.micro", + inputAZs: []string{"us-east-1a", "us-east-1b"}, + expectedAZs: []string{"us-east-1a", "us-east-1b"}, + expectError: false, + }, + } + + for _, tt := range testcases { + t.Run(tt.name, func(t *testing.T) { + conn := &mockEC2ClientStepNetworkTests{} + conn.describeInstanceTypeOfferings = tt.describeImpl + + retAZ, err := filterAZByMachineType(tt.inputAZs, tt.machineType, conn) + + diff := cmp.Diff(retAZ, tt.expectedAZs) + if diff != "" { + t.Errorf("AZ mismatch between computed and expected: %s", diff) + } + + if (err != nil) != tt.expectError { + t.Errorf("Error mismatch, got %t, expected %t", err != nil, tt.expectError) + } + + if err != nil { + t.Logf("Got an error: %s", err) + } + }) + } +} + +func TestStepNetwork_FilterSubnetsByAZ(t *testing.T) { + testcases := []struct { + name string + inSubnets []*ec2.Subnet + azs []string + outSubnets []*ec2.Subnet + }{ + { + name: "No subnet matching", + inSubnets: []*ec2.Subnet{ + { + AvailabilityZone: aws.String("us-east-1-c"), + }, + }, + azs: []string{"us-east-1a"}, + outSubnets: nil, + }, + { + name: "Found subnet matching", + inSubnets: []*ec2.Subnet{ + { + SubnetId: aws.String("subnet1"), + AvailabilityZone: aws.String("us-east-1c"), + }, + { + SubnetId: aws.String("subnet2"), + AvailabilityZone: aws.String("us-east-1b"), + }, + }, + azs: []string{"us-east-1c"}, + outSubnets: []*ec2.Subnet{ + { + SubnetId: aws.String("subnet1"), + AvailabilityZone: aws.String("us-east-1c"), + }, + }, + }, + { + name: "Found multiple subnets matching", + inSubnets: []*ec2.Subnet{ + { + SubnetId: aws.String("subnet1"), + AvailabilityZone: aws.String("us-east-1c"), + }, + { + SubnetId: aws.String("subnet2"), + AvailabilityZone: aws.String("us-east-1c"), + }, + }, + azs: []string{"us-east-1c"}, + outSubnets: []*ec2.Subnet{ + { + SubnetId: aws.String("subnet1"), + AvailabilityZone: aws.String("us-east-1c"), + }, + { + SubnetId: aws.String("subnet2"), + AvailabilityZone: aws.String("us-east-1c"), + }, + }, + }, + } + + for _, tt := range testcases { + t.Run(tt.name, func(t *testing.T) { + subnets := filterSubnetsByAZ(tt.inSubnets, tt.azs) + diff := cmp.Diff(subnets, tt.outSubnets) + if diff != "" { + t.Errorf("subnet mismatch between computed and expected: %s", diff) + } + }) + } +} + +func TestStepNetwork_WithPublicIPSetAndNoVPCOrSubnet(t *testing.T) { + mockConn := &mockEC2ClientStepNetworkTests{ + describeVpcs: func(dvi *ec2.DescribeVpcsInput) (*ec2.DescribeVpcsOutput, error) { + ok := false + for _, filter := range dvi.Filters { + if *filter.Name == "is-default" { + ok = true + break + } + } + + if !ok { + return nil, fmt.Errorf("expected to filter on default VPC = true, did not find that filter") + } + + return &ec2.DescribeVpcsOutput{ + Vpcs: []*ec2.Vpc{ + { + VpcId: aws.String("default-vpc"), + }, + }, + }, nil + }, + describeSubnets: func(dsi *ec2.DescribeSubnetsInput) (*ec2.DescribeSubnetsOutput, error) { + if dsi.SubnetIds != nil { + sub := dsi.SubnetIds[0] + if *sub != "subnet1" { + return nil, fmt.Errorf("expected selected subnet to be us-east-1a, but was %q", *sub) + } + + return &ec2.DescribeSubnetsOutput{ + Subnets: []*ec2.Subnet{ + { + SubnetId: aws.String("subnet1"), + AvailabilityZone: aws.String("us-east-1a"), + VpcId: aws.String("default-vpc"), + }, + }, + }, nil + } + + vpcFilterFound := false + for _, filter := range dsi.Filters { + if *filter.Name != "vpc-id" { + continue + } + filterVal := *filter.Values[0] + if filterVal != "default-vpc" { + return nil, fmt.Errorf("expected vpc-id filter to be %q, got %q", "default-vpc", filterVal) + } + + vpcFilterFound = true + } + + if !vpcFilterFound { + return nil, fmt.Errorf("expected to find vpc-id filter, but did not find it") + } + + return &ec2.DescribeSubnetsOutput{ + Subnets: []*ec2.Subnet{ + { + AvailabilityZone: aws.String("us-east-1a"), + SubnetId: aws.String("subnet1"), + AvailableIpAddressCount: aws.Int64(256), + }, + { + AvailabilityZone: aws.String("us-east-1b"), + SubnetId: aws.String("subnet2"), + AvailableIpAddressCount: aws.Int64(512), + }, + }, + }, nil + }, + describeInstanceTypeOfferings: func(in *ec2.DescribeInstanceTypeOfferingsInput) (*ec2.DescribeInstanceTypeOfferingsOutput, error) { + if *in.LocationType != "availability-zone" { + return nil, fmt.Errorf("called DescribeInstanceTypeOfferings with LocationType = %q, expected availability_zone", *in.LocationType) + } + + var machines []*ec2.InstanceTypeOffering + + foundLocation := false + for _, filter := range in.Filters { + if *filter.Name != "location" { + continue + } + foundLocation = true + + filterVal := *filter.Values[0] + switch filterVal { + case "us-east-1a": + machines = []*ec2.InstanceTypeOffering{ + { + InstanceType: aws.String("t2.mini"), + }, + { + InstanceType: aws.String("t3.large"), + }, + } + case "us-east-1b": + machines = []*ec2.InstanceTypeOffering{ + { + InstanceType: aws.String("t2.mini"), + }, + { + InstanceType: aws.String("t2.micro"), + }, + } + default: + return nil, fmt.Errorf("error: location %q not expected", filterVal) + } + } + + if !foundLocation { + return nil, fmt.Errorf("couldn't find location in filters") + } + + return &ec2.DescribeInstanceTypeOfferingsOutput{ + InstanceTypeOfferings: machines, + }, nil + }, + } + + stepConfig := &StepNetworkInfo{ + AssociatePublicIpAddress: confighelper.TriTrue, + RequestedMachineType: "t3.large", + } + + state := &multistep.BasicStateBag{} + state.Put("ec2", mockConn) + state.Put("ui", &packersdk.MockUi{}) + + actRet := stepConfig.Run(context.Background(), state) + if actRet == multistep.ActionHalt { + t.Fatalf("running the step failed: %s", state.Get("error").(error)) + } + + vpcid, ok := state.GetOk("vpc_id") + if !ok || vpcid != "default-vpc" { + t.Errorf("error: vpc should be 'default-vpc', but is %q", vpcid) + } + t.Logf("set vpc is %q", vpcid) + + subnetid, ok := state.GetOk("subnet_id") + if !ok || subnetid != "subnet1" { + t.Errorf("error: subnet should be 'subnet1', but is %q", subnetid) + } + t.Logf("set subnet is %q", subnetid) + + az, ok := state.GetOk("availability_zone") + if !ok || az != "us-east-1a" { + t.Errorf("error: availability_zone should be 'us-east-1a', but is %q", az) + } + t.Logf("set AZ is %q", az) +} + +func TestStepNetwork_GetDefaultVPCFailDueToPermissions(t *testing.T) { + mockConn := &mockEC2ClientStepNetworkTests{ + describeVpcs: func(dvi *ec2.DescribeVpcsInput) (*ec2.DescribeVpcsOutput, error) { + return nil, fmt.Errorf("Insufficient permissions: missing ec2:DescribeVpcs") + }, + } + + stepConfig := &StepNetworkInfo{ + AssociatePublicIpAddress: confighelper.TriTrue, + RequestedMachineType: "t3.large", + } + + ui := &packersdk.MockUi{} + + state := &multistep.BasicStateBag{} + state.Put("ec2", mockConn) + state.Put("ui", ui) + + actRet := stepConfig.Run(context.Background(), state) + if actRet == multistep.ActionHalt { + t.Fatalf("running the step failed: %s", state.Get("error").(error)) + } + + vpcid, ok := state.GetOk("vpc_id") + if !ok || vpcid != "" { + t.Errorf("error: vpc should be empty, but is %q", vpcid) + } + + subnetid, ok := state.GetOk("subnet_id") + if !ok || subnetid != "" { + t.Errorf("error: subnet should be empty, but is %q", subnetid) + } + + az, ok := state.GetOk("availability_zone") + if !ok || az != "" { + t.Errorf("error: availability_zone should be empty, but is %q", az) + } + + var foundMsg bool + + for _, msg := range ui.SayMessages { + if msg.Message == "associate_public_ip_address is set without a subnet_id." { + t.Log("found warning on associate_public_ip_address") + foundMsg = true + } + } + + if !foundMsg { + t.Errorf("failed to find a message that states that associate_public_ip_address will be ignored.") + } +} + +func TestStepNetwork_SetVPCAndSubnetWithoutAssociatePublicIP(t *testing.T) { + mockConn := &mockEC2ClientStepNetworkTests{} + + stepConfig := &StepNetworkInfo{ + AssociatePublicIpAddress: confighelper.TriUnset, + RequestedMachineType: "t3.large", + VpcId: "default-vpc", + SubnetId: "subnet1", + AvailabilityZone: "us-east-1a", + } + + ui := &packersdk.MockUi{} + + state := &multistep.BasicStateBag{} + state.Put("ec2", mockConn) + state.Put("ui", ui) + + actRet := stepConfig.Run(context.Background(), state) + if actRet == multistep.ActionHalt { + t.Fatalf("running the step failed: %s", state.Get("error").(error)) + } + + vpcid, ok := state.GetOk("vpc_id") + if !ok || vpcid != "default-vpc" { + t.Errorf("error: vpc should be 'default-vpc', but is %q", vpcid) + } + + subnetid, ok := state.GetOk("subnet_id") + if !ok || subnetid != "subnet1" { + t.Errorf("error: subnet should be 'subnet_id', but is %q", subnetid) + } + + az, ok := state.GetOk("availability_zone") + if !ok || az != "us-east-1a" { + t.Errorf("error: availability_zone should be 'us-east-1a', but is %q", az) + } + + var foundDefaultVPCMsg bool + for _, msg := range ui.SayMessages { + if strings.Contains(msg.Message, "Setting public IP address to") { + foundDefaultVPCMsg = true + } + } + + if foundDefaultVPCMsg { + t.Errorf("Should not have found a message that stated that we need to process public IP address setting") + } +} + +func TestStepNetwork_SetPublicIPAddressWithoutSubnetAndMissingDescribeInstanceTypeOfferings(t *testing.T) { + mockConn := &mockEC2ClientStepNetworkTests{ + describeVpcs: func(dvi *ec2.DescribeVpcsInput) (*ec2.DescribeVpcsOutput, error) { + ok := false + for _, filter := range dvi.Filters { + if *filter.Name == "is-default" { + ok = true + break + } + } + + if !ok { + return nil, fmt.Errorf("expected to filter on default VPC = true, did not find that filter") + } + + return &ec2.DescribeVpcsOutput{ + Vpcs: []*ec2.Vpc{ + { + VpcId: aws.String("default-vpc"), + }, + }, + }, nil + }, + describeSubnets: func(dsi *ec2.DescribeSubnetsInput) (*ec2.DescribeSubnetsOutput, error) { + if dsi.SubnetIds != nil { + sub := dsi.SubnetIds[0] + if *sub != "subnet1" { + return nil, fmt.Errorf("expected selected subnet to be us-east-1a, but was %q", *sub) + } + + return &ec2.DescribeSubnetsOutput{ + Subnets: []*ec2.Subnet{ + { + SubnetId: aws.String("subnet1"), + AvailabilityZone: aws.String("us-east-1a"), + VpcId: aws.String("default-vpc"), + }, + }, + }, nil + } + + vpcFilterFound := false + for _, filter := range dsi.Filters { + if *filter.Name != "vpc-id" { + continue + } + filterVal := *filter.Values[0] + if filterVal != "default-vpc" { + return nil, fmt.Errorf("expected vpc-id filter to be %q, got %q", "default-vpc", filterVal) + } + + vpcFilterFound = true + } + + if !vpcFilterFound { + return nil, fmt.Errorf("expected to find vpc-id filter, but did not find it") + } + + return &ec2.DescribeSubnetsOutput{ + Subnets: []*ec2.Subnet{ + { + AvailabilityZone: aws.String("us-east-1a"), + SubnetId: aws.String("subnet1"), + AvailableIpAddressCount: aws.Int64(256), + }, + { + AvailabilityZone: aws.String("us-east-1b"), + SubnetId: aws.String("subnet2"), + AvailableIpAddressCount: aws.Int64(512), + }, + }, + }, nil + }, + describeInstanceTypeOfferings: func(in *ec2.DescribeInstanceTypeOfferingsInput) (*ec2.DescribeInstanceTypeOfferingsOutput, error) { + return nil, fmt.Errorf("Missing permission: ec2:DescribeInstanceTypeOfferings") + }, + } + + stepConfig := &StepNetworkInfo{ + AssociatePublicIpAddress: confighelper.TriTrue, + RequestedMachineType: "t3.large", + } + + ui := &packersdk.MockUi{} + + state := &multistep.BasicStateBag{} + state.Put("ec2", mockConn) + state.Put("ui", ui) + + actRet := stepConfig.Run(context.Background(), state) + if actRet == multistep.ActionHalt { + t.Fatalf("running the step failed: %s", state.Get("error").(error)) + } + + vpcid, ok := state.GetOk("vpc_id") + if !ok || vpcid != "default-vpc" { + t.Errorf("error: vpc should be 'default-vpc', but is %q", vpcid) + } + t.Logf("set vpc is %q", vpcid) + + subnetid, ok := state.GetOk("subnet_id") + if !ok || subnetid != "subnet2" { + t.Errorf("error: subnet should be 'subnet2', but is %q", subnetid) + } + t.Logf("set subnet is %q", subnetid) + + az, ok := state.GetOk("availability_zone") + if !ok || az != "us-east-1b" { + t.Errorf("error: availability_zone should be 'us-east-1a', but is %q", az) + } + t.Logf("set AZ is %q", az) +} diff --git a/builder/common/step_pre_validate.go b/builder/common/step_pre_validate.go index a8a18089c..ba83cacfb 100644 --- a/builder/common/step_pre_validate.go +++ b/builder/common/step_pre_validate.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( @@ -17,11 +20,11 @@ import ( // StepPreValidate provides an opportunity to pre-validate any configuration for // the build before actually doing any time consuming work -// type StepPreValidate struct { DestAmiName string ForceDeregister bool AMISkipBuildRegion bool + AMISkipCreateImage bool VpcId string SubnetId string HasSubnetFilter bool @@ -87,6 +90,11 @@ func (s *StepPreValidate) Run(ctx context.Context, state multistep.StateBag) mul return multistep.ActionContinue } + if s.AMISkipCreateImage { + ui.Say("skip_create_ami was set; not prevalidating AMI name") + return multistep.ActionContinue + } + ec2conn := state.Get("ec2").(*ec2.EC2) // Validate VPC settings for non-default VPCs @@ -99,6 +107,7 @@ func (s *StepPreValidate) Run(ctx context.Context, state multistep.StateBag) mul ui.Say(fmt.Sprintf("Prevalidating AMI Name: %s", s.DestAmiName)) req, resp := ec2conn.DescribeImagesRequest(&ec2.DescribeImagesInput{ + Owners: []*string{aws.String("self")}, Filters: []*ec2.Filter{{ Name: aws.String("name"), Values: []*string{aws.String(s.DestAmiName)}, diff --git a/builder/common/step_pre_validate_test.go b/builder/common/step_pre_validate_test.go index ffaf946f9..e29d6baad 100644 --- a/builder/common/step_pre_validate_test.go +++ b/builder/common/step_pre_validate_test.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( @@ -9,7 +12,7 @@ import ( "github.com/aws/aws-sdk-go/service/ec2" ) -//DescribeVpcs mocks an ec2.DescribeVpcsOutput for a given input +// DescribeVpcs mocks an ec2.DescribeVpcsOutput for a given input func (m *mockEC2Conn) DescribeVpcs(input *ec2.DescribeVpcsInput) (*ec2.DescribeVpcsOutput, error) { if input == nil || aws.StringValue(input.VpcIds[0]) == "" { diff --git a/builder/common/step_run_source_instance.go b/builder/common/step_run_source_instance.go index 904e9a44e..0897b3e40 100644 --- a/builder/common/step_run_source_instance.go +++ b/builder/common/step_run_source_instance.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( @@ -10,6 +13,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go/service/ec2/ec2iface" "github.com/hashicorp/packer-plugin-amazon/builder/common/awserrors" "github.com/hashicorp/packer-plugin-sdk/communicator" @@ -44,6 +48,7 @@ type StepRunSourceInstance struct { Tags map[string]string LicenseSpecifications []LicenseSpecification HostResourceGroupArn string + HostId string Tenancy string UserData string UserDataFile string @@ -181,6 +186,13 @@ func (s *StepRunSourceInstance) Run(ctx context.Context, state multistep.StateBa } tagSpecs = append(tagSpecs, runTags) + + networkInterfaceTags := &ec2.TagSpecification{ + ResourceType: aws.String("network-interface"), + Tags: ec2Tags, + } + + tagSpecs = append(tagSpecs, networkInterfaceTags) } if len(volTags) > 0 { @@ -206,6 +218,9 @@ func (s *StepRunSourceInstance) Run(ctx context.Context, state multistep.StateBa subnetId := state.Get("subnet_id").(string) if subnetId != "" && s.AssociatePublicIpAddress != confighelper.TriUnset { + ui.Say(fmt.Sprintf("changing public IP address config to %t for instance on subnet %q", + *s.AssociatePublicIpAddress.ToBoolPointer(), + subnetId)) runOpts.NetworkInterfaces = []*ec2.InstanceNetworkInterfaceSpecification{ { DeviceIndex: aws.Int64(0), @@ -258,6 +273,10 @@ func (s *StepRunSourceInstance) Run(ctx context.Context, state multistep.StateBa runOpts.Placement.HostResourceGroupArn = aws.String(s.HostResourceGroupArn) } + if s.HostId != "" { + runOpts.Placement.HostId = aws.String(s.HostId) + } + if s.Tenancy != "" { runOpts.Placement.Tenancy = aws.String(s.Tenancy) } @@ -294,33 +313,13 @@ func (s *StepRunSourceInstance) Run(ctx context.Context, state multistep.StateBa // Set the instance ID so that the cleanup works properly s.instanceId = instanceId - - ui.Message(fmt.Sprintf("Instance ID: %s", instanceId)) - ui.Say(fmt.Sprintf("Waiting for instance (%v) to become ready...", instanceId)) - + if err := waitForInstanceReadiness(ctx, instanceId, ec2conn, ui, state, s.PollingConfig.WaitUntilInstanceRunning); err != nil { + return multistep.ActionHalt + } describeInstance := &ec2.DescribeInstancesInput{ InstanceIds: []*string{aws.String(instanceId)}, } - if err := s.PollingConfig.WaitUntilInstanceRunning(ctx, ec2conn, instanceId); err != nil { - err := fmt.Errorf("Error waiting for instance (%s) to become ready: %s", instanceId, err) - state.Put("error", err) - ui.Error(err.Error()) - - // try to get some context from AWS on why was instance - // transitioned to the unexpected state - if resp, e := ec2conn.DescribeInstances(describeInstance); e == nil { - if len(resp.Reservations) > 0 && len(resp.Reservations[0].Instances) > 0 { - instance := resp.Reservations[0].Instances[0] - if instance.StateTransitionReason != nil && instance.StateReason != nil && instance.StateReason.Message != nil { - ui.Error(fmt.Sprintf("Instance state change details: %s: %s", - *instance.StateTransitionReason, *instance.StateReason.Message)) - } - } - } - return multistep.ActionHalt - } - // there's a race condition that can happen because of AWS's eventual // consistency where even though the wait is complete, the describe call // will fail. Retry a couple of times to try to mitigate that race. @@ -396,6 +395,18 @@ func (s *StepRunSourceInstance) Run(ctx context.Context, state multistep.StateBa return multistep.ActionHalt } + if len(ec2Tags) > 0 { + for _, networkInterface := range instance.NetworkInterfaces { + log.Printf("Tagging network interface %s", *networkInterface.NetworkInterfaceId) + _, err := ec2conn.CreateTags(&ec2.CreateTagsInput{ + Tags: ec2Tags, + Resources: []*string{networkInterface.NetworkInterfaceId}, + }) + if err != nil { + ui.Error(fmt.Sprintf("Error tagging source instance's network interface %q: %s", *networkInterface.NetworkInterfaceId, err)) + } + } + } // Now tag volumes volumeIds := make([]*string, 0) @@ -434,6 +445,42 @@ func (s *StepRunSourceInstance) Run(ctx context.Context, state multistep.StateBa return multistep.ActionContinue } +func waitForInstanceReadiness( + ctx context.Context, + instanceId string, + ec2conn ec2iface.EC2API, + ui packersdk.Ui, + state multistep.StateBag, + waitUntilInstanceRunning func(context.Context, ec2iface.EC2API, string) error, +) error { + ui.Message(fmt.Sprintf("Instance ID: %s", instanceId)) + ui.Say(fmt.Sprintf("Waiting for instance (%v) to become ready...", instanceId)) + + describeInstance := &ec2.DescribeInstancesInput{ + InstanceIds: []*string{aws.String(instanceId)}, + } + + if err := waitUntilInstanceRunning(ctx, ec2conn, instanceId); err != nil { + err := fmt.Errorf("Error waiting for instance (%s) to become ready: %s", instanceId, err) + state.Put("error", err) + ui.Error(err.Error()) + + // try to get some context from AWS on why was instance + // transitioned to the unexpected state + if resp, e := ec2conn.DescribeInstances(describeInstance); e == nil { + if len(resp.Reservations) > 0 && len(resp.Reservations[0].Instances) > 0 { + instance := resp.Reservations[0].Instances[0] + if instance.StateTransitionReason != nil && instance.StateReason != nil && instance.StateReason.Message != nil { + ui.Error(fmt.Sprintf("Instance state change details: %s: %s", + *instance.StateTransitionReason, *instance.StateReason.Message)) + } + } + } + return err + } + return nil +} + func (s *StepRunSourceInstance) Cleanup(state multistep.StateBag) { ec2conn := state.Get("ec2").(*ec2.EC2) diff --git a/builder/common/step_run_spot_instance.go b/builder/common/step_run_spot_instance.go index d8b2b2632..f76092ef9 100644 --- a/builder/common/step_run_spot_instance.go +++ b/builder/common/step_run_spot_instance.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( @@ -114,6 +117,8 @@ func (s *StepRunSpotInstance) CreateTemplateData(userData *string, az string, } + ui := state.Get("ui").(packersdk.Ui) + iamInstanceProfile := aws.String(state.Get("iamInstanceProfile").(string)) // Create a launch template. @@ -142,6 +147,9 @@ func (s *StepRunSpotInstance) CreateTemplateData(userData *string, az string, SubnetId: aws.String(subnetId), } if s.AssociatePublicIpAddress != confighelper.TriUnset { + ui.Say(fmt.Sprintf("changing public IP address config to %t for instance on subnet %q", + *s.AssociatePublicIpAddress.ToBoolPointer(), + subnetId)) networkInterface.SetAssociatePublicIpAddress(*s.AssociatePublicIpAddress.ToBoolPointer()) } templateData.SetNetworkInterfaces([]*ec2.LaunchTemplateInstanceNetworkInterfaceSpecificationRequest{&networkInterface}) @@ -316,6 +324,14 @@ func (s *StepRunSpotInstance) Run(ctx context.Context, state multistep.StateBag) Tags: ec2Tags, }, ) + + launchTemplate.LaunchTemplateData.TagSpecifications = append( + launchTemplate.LaunchTemplateData.TagSpecifications, + &ec2.LaunchTemplateTagSpecificationRequest{ + ResourceType: aws.String("network-interface"), + Tags: ec2Tags, + }, + ) } if len(volumeTags) > 0 { @@ -438,8 +454,9 @@ func (s *StepRunSpotInstance) Run(ctx context.Context, state multistep.StateBag) instanceId = *createOutput.Instances[0].InstanceIds[0] // Set the instance ID so that the cleanup works properly s.instanceId = instanceId - - ui.Message(fmt.Sprintf("Instance ID: %s", instanceId)) + if err := waitForInstanceReadiness(ctx, instanceId, ec2conn, ui, state, s.PollingConfig.WaitUntilInstanceRunning); err != nil { + return multistep.ActionHalt + } // Get information about the created instance var describeOutput *ec2.DescribeInstancesOutput diff --git a/builder/common/step_run_spot_instance_test.go b/builder/common/step_run_spot_instance_test.go index 91ce542b2..11f51e048 100644 --- a/builder/common/step_run_spot_instance_test.go +++ b/builder/common/step_run_spot_instance_test.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( @@ -7,6 +10,7 @@ import ( "testing" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/ec2/ec2iface" "github.com/hashicorp/packer-plugin-sdk/communicator" @@ -182,6 +186,10 @@ func (m *runSpotEC2ConnMock) DescribeInstances(req *ec2.DescribeInstancesInput) } } +func (m *runSpotEC2ConnMock) WaitUntilInstanceRunningWithContext(ctx context.Context, _ *ec2.DescribeInstancesInput, opts ...request.WaiterOption) error { + return nil +} + func (m *runSpotEC2ConnMock) CreateTags(req *ec2.CreateTagsInput) (*ec2.CreateTagsOutput, error) { m.CreateTagsParams = append(m.CreateTagsParams, req) if m.CreateTagsFn != nil { diff --git a/builder/common/step_security_group.go b/builder/common/step_security_group.go index 6fcb41a50..7bd28a79e 100644 --- a/builder/common/step_security_group.go +++ b/builder/common/step_security_group.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( diff --git a/builder/common/step_set_generated_data.go b/builder/common/step_set_generated_data.go index 6a28c18a0..c879ca171 100644 --- a/builder/common/step_set_generated_data.go +++ b/builder/common/step_set_generated_data.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( diff --git a/builder/common/step_source_ami_info.go b/builder/common/step_source_ami_info.go index 200460ca9..28bf002c8 100644 --- a/builder/common/step_source_ami_info.go +++ b/builder/common/step_source_ami_info.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( @@ -16,13 +19,15 @@ import ( // that is used throughout the AMI creation process. // // Produces: -// source_image *ec2.Image - the source AMI info +// +// source_image *ec2.Image - the source AMI info type StepSourceAMIInfo struct { SourceAmi string EnableAMISriovNetSupport bool EnableAMIENASupport confighelper.Trilean AMIVirtType string AmiFilters AmiFilterOptions + IncludeDeprecated bool } type imageSort []*ec2.Image @@ -46,7 +51,9 @@ func (s *StepSourceAMIInfo) Run(ctx context.Context, state multistep.StateBag) m ec2conn := state.Get("ec2").(*ec2.EC2) ui := state.Get("ui").(packersdk.Ui) - params := &ec2.DescribeImagesInput{} + params := &ec2.DescribeImagesInput{ + IncludeDeprecated: &s.IncludeDeprecated, + } if s.SourceAmi != "" { params.ImageIds = []*string{&s.SourceAmi} diff --git a/builder/common/step_source_ami_info_test.go b/builder/common/step_source_ami_info_test.go index 4941180cd..96259c75f 100644 --- a/builder/common/step_source_ami_info_test.go +++ b/builder/common/step_source_ami_info_test.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( diff --git a/builder/common/step_stop_ebs_instance.go b/builder/common/step_stop_ebs_instance.go index 1283b4404..b42b1f30f 100644 --- a/builder/common/step_stop_ebs_instance.go +++ b/builder/common/step_stop_ebs_instance.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( diff --git a/builder/common/tags.go b/builder/common/tags.go index 567a77f4f..1c7eaff2d 100644 --- a/builder/common/tags.go +++ b/builder/common/tags.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( @@ -5,6 +8,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go/service/iam" "github.com/hashicorp/packer-plugin-sdk/multistep" packersdk "github.com/hashicorp/packer-plugin-sdk/packer" "github.com/hashicorp/packer-plugin-sdk/packerbuilderdata" @@ -43,6 +47,28 @@ func (t TagMap) EC2Tags(ictx interpolate.Context, region string, state multistep return ec2Tags, nil } +func (t TagMap) IamTags(ictx interpolate.Context, region string, state multistep.StateBag) ([]*iam.Tag, error) { + var iamTags []*iam.Tag + generatedData := packerbuilderdata.GeneratedData{State: state} + ictx.Data = extractBuildInfo(region, state, &generatedData) + + for key, value := range t { + interpolatedKey, err := interpolate.Render(key, &ictx) + if err != nil { + return nil, fmt.Errorf("Error processing tag: %s:%s - %s", key, value, err) + } + interpolatedValue, err := interpolate.Render(value, &ictx) + if err != nil { + return nil, fmt.Errorf("Error processing tag: %s:%s - %s", key, value, err) + } + iamTags = append(iamTags, &iam.Tag{ + Key: aws.String(interpolatedKey), + Value: aws.String(interpolatedValue), + }) + } + return iamTags, nil +} + func (t EC2Tags) TagSpecifications(resourceType ...string) []*ec2.TagSpecification { var tagSpecs []*ec2.TagSpecification if len(t) > 0 { diff --git a/builder/common/template_funcs.go b/builder/common/template_funcs.go index 14dd65d83..fcbe00f6e 100644 --- a/builder/common/template_funcs.go +++ b/builder/common/template_funcs.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( diff --git a/builder/common/template_funcs_test.go b/builder/common/template_funcs_test.go index 11ad70aac..414b8864d 100644 --- a/builder/common/template_funcs_test.go +++ b/builder/common/template_funcs_test.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( diff --git a/builder/common/test_helper_funcs.go b/builder/common/test_helper_funcs.go index c951ba855..612f92470 100644 --- a/builder/common/test_helper_funcs.go +++ b/builder/common/test_helper_funcs.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package common import ( diff --git a/builder/ebs/acceptance/aws.go b/builder/ebs/acceptance/aws.go index 022dccfe1..6fc4a1f05 100644 --- a/builder/ebs/acceptance/aws.go +++ b/builder/ebs/acceptance/aws.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package amazon_acc import ( diff --git a/builder/ebs/acceptance/utils.go b/builder/ebs/acceptance/utils.go new file mode 100644 index 000000000..9ca3eee48 --- /dev/null +++ b/builder/ebs/acceptance/utils.go @@ -0,0 +1,36 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package amazon_acc + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "encoding/pem" + "fmt" + "os" +) + +func GenerateSSHPrivateKeyFile() (string, error) { + outFile := fmt.Sprintf("%s/temp_key", os.TempDir()) + + priv, err := rsa.GenerateKey(rand.Reader, 4096) + if err != nil { + return "", fmt.Errorf("failed to generate SSH key: %s", err) + } + + x509key := x509.MarshalPKCS1PrivateKey(priv) + + pemKey := pem.EncodeToMemory(&pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: x509key, + }) + + err = os.WriteFile(outFile, pemKey, 0600) + if err != nil { + return "", fmt.Errorf("failed to write private key to %q: %s", outFile, err) + } + + return outFile, nil +} diff --git a/builder/ebs/builder.go b/builder/ebs/builder.go index ffd9b87eb..47c0c1fa5 100644 --- a/builder/ebs/builder.go +++ b/builder/ebs/builder.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + //go:generate packer-sdc struct-markdown //go:generate packer-sdc mapstructure-to-hcl2 -type Config @@ -11,7 +14,6 @@ package ebs import ( "context" "fmt" - "time" "github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/iam" @@ -75,10 +77,13 @@ type Config struct { // make sure you don't set this for *nix guests; behavior may be // unpredictable. NoEphemeral bool `mapstructure:"no_ephemeral" required:"false"` - // The date and time to deprecate the AMI, in UTC, in the following format: YYYY-MM-DDTHH:MM:SSZ. - // If you specify a value for seconds, Amazon EC2 rounds the seconds to the nearest minute. - // You can’t specify a date in the past. The upper limit for DeprecateAt is 10 years from now. - DeprecationTime string `mapstructure:"deprecate_at"` + // The configuration for fast launch support. + // + // Fast launch is only relevant for Windows AMIs, and should not be used + // for other OSes. + // See the [Fast Launch Configuration](#fast-launch-config) section for + // information on the attributes supported for this block. + FastLaunch FastLaunchConfig `mapstructure:"fast_launch" required:"false"` ctx interpolate.Context } @@ -135,6 +140,25 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) { errs = packersdk.MultiErrorAppend(errs, b.config.LaunchMappings.Prepare(&b.config.ctx)...) errs = packersdk.MultiErrorAppend(errs, b.config.RunConfig.Prepare(&b.config.ctx)...) + b.config.FastLaunch.defaultRegion = b.config.RawRegion + errs = packersdk.MultiErrorAppend(errs, b.config.FastLaunch.Prepare()...) + for _, templateConfig := range b.config.FastLaunch.RegionLaunchTemplates { + exists := false + for _, cpRegion := range b.config.AMIRegions { + if cpRegion == templateConfig.Region { + exists = true + break + } + } + if b.config.RawRegion == templateConfig.Region { + exists = true + } + + if !exists { + errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("Launch template specified for enabling fast-launch on region %q, but the AMI won't be copied there.", templateConfig.Region)) + } + } + if b.config.IsSpotInstance() && (b.config.AMIENASupport.True() || b.config.AMISriovNetSupport) { errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("Spot instances do not support modification, which is required "+ @@ -142,12 +166,6 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) { "you use an AMI that already has either SR-IOV or ENA enabled.")) } - if b.config.DeprecationTime != "" { - if _, err := time.Parse(time.RFC3339, b.config.DeprecationTime); err != nil { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("deprecate_at is not a valid time. Expect time format: YYYY-MM-DDTHH:MM:SSZ")) - } - } - if b.config.RunConfig.SpotPriceAutoProduct != "" { warns = append(warns, "spot_price_auto_product is deprecated and no "+ "longer necessary for Packer builds. In future versions of "+ @@ -264,6 +282,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) Tags: b.config.RunTags, LicenseSpecifications: b.config.LicenseSpecifications, HostResourceGroupArn: b.config.Placement.HostResourceGroupArn, + HostId: b.config.Placement.HostId, Tenancy: tenancy, UserData: b.config.UserData, UserDataFile: b.config.UserDataFile, @@ -278,6 +297,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) DestAmiName: b.config.AMIName, ForceDeregister: b.config.AMIForceDeregister, AMISkipBuildRegion: b.config.AMISkipBuildRegion, + AMISkipCreateImage: b.config.AMISkipCreateImage, VpcId: b.config.VpcId, SubnetId: b.config.SubnetId, HasSubnetFilter: !b.config.SubnetFilter.Empty(), @@ -290,13 +310,15 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) AMIVirtType: b.config.AMIVirtType, }, &awscommon.StepNetworkInfo{ - VpcId: b.config.VpcId, - VpcFilter: b.config.VpcFilter, - SecurityGroupIds: b.config.SecurityGroupIds, - SecurityGroupFilter: b.config.SecurityGroupFilter, - SubnetId: b.config.SubnetId, - SubnetFilter: b.config.SubnetFilter, - AvailabilityZone: b.config.AvailabilityZone, + VpcId: b.config.VpcId, + VpcFilter: b.config.VpcFilter, + SecurityGroupIds: b.config.SecurityGroupIds, + SecurityGroupFilter: b.config.SecurityGroupFilter, + SubnetId: b.config.SubnetId, + SubnetFilter: b.config.SubnetFilter, + AvailabilityZone: b.config.AvailabilityZone, + AssociatePublicIpAddress: b.config.AssociatePublicIpAddress, + RequestedMachineType: b.config.InstanceType, }, &awscommon.StepKeyPair{ Debug: b.config.PackerDebug, @@ -318,9 +340,12 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) Ctx: b.config.ctx, }, &awscommon.StepIamInstanceProfile{ + PollingConfig: b.config.PollingConfig, IamInstanceProfile: b.config.IamInstanceProfile, SkipProfileValidation: b.config.SkipProfileValidation, TemporaryIamInstanceProfilePolicyDocument: b.config.TemporaryIamInstanceProfilePolicyDocument, + Tags: b.config.RunTags, + Ctx: b.config.ctx, }, &awscommon.StepCleanupVolumes{ LaunchMappings: b.config.LaunchMappings, @@ -339,6 +364,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) LocalPortNumber: b.config.SessionManagerPort, RemotePortNumber: b.config.Comm.Port(), SSMAgentEnabled: b.config.SSMAgentEnabled(), + SSHConfig: &b.config.Comm.SSH, }, &awscommon.StepEC2InstanceConnect{ AWSSession: session, @@ -402,7 +428,21 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) AMISkipCreateImage: b.config.AMISkipCreateImage, AMISkipBuildRegion: b.config.AMISkipBuildRegion, }, - &stepEnableDeprecation{ + &stepPrepareFastLaunchTemplate{ + AccessConfig: &b.config.AccessConfig, + AMISkipCreateImage: b.config.AMISkipCreateImage, + EnableFastLaunch: b.config.FastLaunch.UseFastLaunch, + RegionTemplates: b.config.FastLaunch.RegionLaunchTemplates, + }, + &stepEnableFastLaunch{ + AccessConfig: &b.config.AccessConfig, + PollingConfig: b.config.PollingConfig, + ResourceCount: b.config.FastLaunch.TargetResourceCount, + AMISkipCreateImage: b.config.AMISkipCreateImage, + EnableFastLaunch: b.config.FastLaunch.UseFastLaunch, + MaxInstances: b.config.FastLaunch.MaxParallelLaunches, + }, + &awscommon.StepEnableDeprecation{ AccessConfig: &b.config.AccessConfig, DeprecationTime: b.config.DeprecationTime, AMISkipCreateImage: b.config.AMISkipCreateImage, @@ -417,6 +457,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) ProductCodes: b.config.AMIProductCodes, SnapshotUsers: b.config.SnapshotUsers, SnapshotGroups: b.config.SnapshotGroups, + IMDSSupport: b.config.AMIIMDSSupport, Ctx: b.config.ctx, GeneratedData: generatedData, }, diff --git a/builder/ebs/builder.hcl2spec.go b/builder/ebs/builder.hcl2spec.go index 1444ee1ca..710e365fa 100644 --- a/builder/ebs/builder.hcl2spec.go +++ b/builder/ebs/builder.hcl2spec.go @@ -56,6 +56,8 @@ type FlatConfig struct { AMIKmsKeyId *string `mapstructure:"kms_key_id" required:"false" cty:"kms_key_id" hcl:"kms_key_id"` AMIRegionKMSKeyIDs map[string]string `mapstructure:"region_kms_key_ids" required:"false" cty:"region_kms_key_ids" hcl:"region_kms_key_ids"` AMISkipBuildRegion *bool `mapstructure:"skip_save_build_region" cty:"skip_save_build_region" hcl:"skip_save_build_region"` + AMIIMDSSupport *string `mapstructure:"imds_support" required:"false" cty:"imds_support" hcl:"imds_support"` + DeprecationTime *string `mapstructure:"deprecate_at" cty:"deprecate_at" hcl:"deprecate_at"` SnapshotTags map[string]string `mapstructure:"snapshot_tags" required:"false" cty:"snapshot_tags" hcl:"snapshot_tags"` SnapshotTag []config.FlatKeyValue `mapstructure:"snapshot_tag" required:"false" cty:"snapshot_tag" hcl:"snapshot_tag"` SnapshotUsers []string `mapstructure:"snapshot_users" required:"false" cty:"snapshot_users" hcl:"snapshot_users"` @@ -161,7 +163,7 @@ type FlatConfig struct { VolumeRunTags map[string]string `mapstructure:"run_volume_tags" cty:"run_volume_tags" hcl:"run_volume_tags"` VolumeRunTag []config.FlatNameValue `mapstructure:"run_volume_tag" required:"false" cty:"run_volume_tag" hcl:"run_volume_tag"` NoEphemeral *bool `mapstructure:"no_ephemeral" required:"false" cty:"no_ephemeral" hcl:"no_ephemeral"` - DeprecationTime *string `mapstructure:"deprecate_at" cty:"deprecate_at" hcl:"deprecate_at"` + FastLaunch *FlatFastLaunchConfig `mapstructure:"fast_launch" required:"false" cty:"fast_launch" hcl:"fast_launch"` } // FlatMapstructure returns a new FlatConfig. @@ -220,6 +222,8 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "kms_key_id": &hcldec.AttrSpec{Name: "kms_key_id", Type: cty.String, Required: false}, "region_kms_key_ids": &hcldec.AttrSpec{Name: "region_kms_key_ids", Type: cty.Map(cty.String), Required: false}, "skip_save_build_region": &hcldec.AttrSpec{Name: "skip_save_build_region", Type: cty.Bool, Required: false}, + "imds_support": &hcldec.AttrSpec{Name: "imds_support", Type: cty.String, Required: false}, + "deprecate_at": &hcldec.AttrSpec{Name: "deprecate_at", Type: cty.String, Required: false}, "snapshot_tags": &hcldec.AttrSpec{Name: "snapshot_tags", Type: cty.Map(cty.String), Required: false}, "snapshot_tag": &hcldec.BlockListSpec{TypeName: "snapshot_tag", Nested: hcldec.ObjectSpec((*config.FlatKeyValue)(nil).HCL2Spec())}, "snapshot_users": &hcldec.AttrSpec{Name: "snapshot_users", Type: cty.List(cty.String), Required: false}, @@ -325,7 +329,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "run_volume_tags": &hcldec.AttrSpec{Name: "run_volume_tags", Type: cty.Map(cty.String), Required: false}, "run_volume_tag": &hcldec.BlockListSpec{TypeName: "run_volume_tag", Nested: hcldec.ObjectSpec((*config.FlatNameValue)(nil).HCL2Spec())}, "no_ephemeral": &hcldec.AttrSpec{Name: "no_ephemeral", Type: cty.Bool, Required: false}, - "deprecate_at": &hcldec.AttrSpec{Name: "deprecate_at", Type: cty.String, Required: false}, + "fast_launch": &hcldec.BlockSpec{TypeName: "fast_launch", Nested: hcldec.ObjectSpec((*FlatFastLaunchConfig)(nil).HCL2Spec())}, } return s } diff --git a/builder/ebs/builder_acc_test.go b/builder/ebs/builder_acc_test.go index cf4df2583..afc70d853 100644 --- a/builder/ebs/builder_acc_test.go +++ b/builder/ebs/builder_acc_test.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + /* deregister the test image with aws ec2 deregister-image --image-id $(aws ec2 describe-images --output text --filters "Name=name,Values=packer-test-packer-test-dereg" --query 'Images[*].{ID:ImageId}') @@ -20,8 +23,10 @@ import ( "github.com/aws/aws-sdk-go/service/ec2" "github.com/hashicorp/go-multierror" "github.com/hashicorp/packer-plugin-amazon/builder/common" + awscommon "github.com/hashicorp/packer-plugin-amazon/builder/common" amazon_acc "github.com/hashicorp/packer-plugin-amazon/builder/ebs/acceptance" "github.com/hashicorp/packer-plugin-sdk/acctest" + packersdk "github.com/hashicorp/packer-plugin-sdk/packer" ) func TestAccBuilder_EbsBasic(t *testing.T) { @@ -286,22 +291,20 @@ func TestAccBuilder_EbsAmiSharing(t *testing.T) { Name: fmt.Sprintf("packer-sharing-acc-test %d", time.Now().Unix()), } + missing_v := []string{} + env_vars := []string{"TESTACC_AWS_ACCOUNT_ID", "TESTACC_AWS_ORG_ARN", "TESTACC_AWS_OU_ARN"} + for _, var_name := range env_vars { + v := os.Getenv(var_name) + if v == "" { + missing_v = append(missing_v, var_name) + } + } + if len(missing_v) > 0 { + t.Skipf("%s must be set for AMI sharing test, skipping", strings.Join(missing_v, ",")) + } + testCase := &acctest.PluginTestCase{ - Name: "amazon-ebs_ami_sharing_test", - Setup: func() error { - missing_v := []string{} - env_vars := []string{"TESTACC_AWS_ACCOUNT_ID", "TESTACC_AWS_ORG_ARN", "TESTACC_AWS_OU_ARN"} - for _, var_name := range env_vars { - v := os.Getenv(var_name) - if v == "" { - missing_v = append(missing_v, var_name) - } - } - if len(missing_v) > 0 { - return fmt.Errorf("%s must be set for acceptance tests", strings.Join(missing_v, ",")) - } - return nil - }, + Name: "amazon-ebs_ami_sharing_test", Template: buildSharingConfig(os.Getenv("TESTACC_AWS_ACCOUNT_ID"), os.Getenv("TESTACC_AWS_ORG_ARN"), os.Getenv("TESTACC_AWS_OU_ARN"), ami.Name), Teardown: func() error { return ami.CleanUpAmi() @@ -540,6 +543,51 @@ func TestAccBuilder_EbsSessionManagerInterface(t *testing.T) { return fmt.Errorf("Bad exit code. Logfile: %s", logfile) } } + + logs, err := os.ReadFile(logfile) + if err != nil { + return fmt.Errorf("couldn't read logs from logfile %s: %s", logfile, err) + } + if strings.Contains(string(logs), "Uploading SSH public key") { + return fmt.Errorf("SSH key was uploaded, but shouldn't have been") + } + + if strings.Contains(string(logs), "Bad exit status") { + return fmt.Errorf("SSM session did not terminate gracefully and exited with a non-zero exit code") + } + + return nil + }, + } + acctest.TestPlugin(t, testCase) +} + +func TestAccBuilder_EbsSSMRebootProvisioner(t *testing.T) { + ami := amazon_acc.AMIHelper{ + Region: "us-east-1", + Name: fmt.Sprintf("packer-ssm-reboot-acc-test %d", time.Now().Unix()), + } + testCase := &acctest.PluginTestCase{ + Name: "amazon-ebs_sessionmanager_interface_test_with_reboot", + Template: fmt.Sprintf(testBuilderAccSSMWithReboot, ami.Name), + Teardown: func() error { + return ami.CleanUpAmi() + }, + Check: func(buildCommand *exec.Cmd, logfile string) error { + if buildCommand.ProcessState != nil { + if buildCommand.ProcessState.ExitCode() != 0 { + return fmt.Errorf("Bad exit code. Logfile: %s", logfile) + } + } + + logs, err := os.ReadFile(logfile) + if err != nil { + return fmt.Errorf("couldn't read logs from logfile %s: %s", logfile, err) + } + if strings.Contains(string(logs), "Uploading SSH public key") { + return fmt.Errorf("SSH key was uploaded, but shouldn't have been") + } + return nil }, } @@ -770,6 +818,69 @@ func TestAccBuilder_EbsKeyPair_rsaSHA2OnlyServer(t *testing.T) { acctest.TestPlugin(t, testcase) } +func TestAccBuilder_PrivateKeyFile(t *testing.T) { + ami := amazon_acc.AMIHelper{ + Region: "us-east-1", + Name: fmt.Sprintf("packer-pkey-file-acc-test-%d", time.Now().Unix()), + } + + sshFile, err := amazon_acc.GenerateSSHPrivateKeyFile() + if err != nil { + t.Fatalf("failed to generate SSH key file: %s", err) + } + + defer os.Remove(sshFile) + + testcase := &acctest.PluginTestCase{ + Name: "amazon-ebs_test_private_key_file", + Template: buildPrivateKeyFileConfig(ami.Name, sshFile), + Check: func(buildCommand *exec.Cmd, logfile string) error { + if buildCommand.ProcessState.ExitCode() != 0 { + return fmt.Errorf("Bad exit code. Logfile: %s", logfile) + } + return nil + }, + } + + acctest.TestPlugin(t, testcase) +} + +func TestAccBuilder_PrivateKeyFileWithReboot(t *testing.T) { + ami := amazon_acc.AMIHelper{ + Region: "us-east-1", + Name: fmt.Sprintf("packer-pkey-file-reboot-acc-test-%d", time.Now().Unix()), + } + + sshFile, err := amazon_acc.GenerateSSHPrivateKeyFile() + if err != nil { + t.Fatalf("failed to generate SSH key file: %s", err) + } + + defer os.Remove(sshFile) + + testcase := &acctest.PluginTestCase{ + Name: "amazon-ebs_test_private_key_file_reboot", + Template: buildPrivateKeyFileRebootConfig(ami.Name, sshFile), + Check: func(buildCommand *exec.Cmd, logfile string) error { + if buildCommand.ProcessState.ExitCode() != 0 { + return fmt.Errorf("Bad exit code. Logfile: %s", logfile) + } + + logs, err := os.ReadFile(logfile) + if err != nil { + return fmt.Errorf("couldn't read logs from logfile %s: %s", logfile, err) + } + if !strings.Contains(string(logs), "Uploading SSH public key") { + return fmt.Errorf("SSH key was not uploaded, but should have been") + } + + return nil + }, + } + + acctest.TestPlugin(t, testcase) +} + //go:embed test-fixtures/unlimited-credits/burstable_instances.pkr.hcl var testBurstableInstanceTypes string @@ -798,6 +909,7 @@ func TestAccBuilder_EnableUnlimitedCredits_withSpotInstances(t *testing.T) { if buildCommand.ProcessState.ExitCode() != 0 { return fmt.Errorf("Bad exit code. Logfile: %s", logfile) } + return nil }, } @@ -814,6 +926,604 @@ func testEC2Conn(region string) (*ec2.EC2, error) { return ec2.New(session), nil } +func TestAccBuilder_EbsBasicWithIMDSv2(t *testing.T) { + ami := amazon_acc.AMIHelper{ + Region: "us-east-1", + Name: fmt.Sprintf("packer-ebs-imds-acc-test-%d", time.Now().Unix()), + } + + testcase := &acctest.PluginTestCase{ + Name: "amazon-ebs-with-imdsv2", + Template: fmt.Sprintf(testIMDSv2Support, ami.Name), + Check: func(buildCommand *exec.Cmd, logfile string) error { + if buildCommand.ProcessState.ExitCode() != 0 { + return fmt.Errorf("Bad exit code. Logfile: %s", logfile) + } + + amis, err := ami.GetAmi() + if err != nil { + return fmt.Errorf("failed to get AMI: %s", err) + } + if len(amis) != 1 { + return fmt.Errorf("got too many AMIs, expected 1, got %d", len(amis)) + } + + ami := amis[0] + + imds := ami.ImdsSupport + if imds == nil { + return fmt.Errorf("expected AMI's IMDSSupport to be set, but is null") + } + + if *imds != "v2.0" { + return fmt.Errorf("expected AMI's IMDSSupport to be v2.0, got %q", *imds) + } + + return nil + }, + } + acctest.TestPlugin(t, testcase) +} + +func TestAccBuilder_EbsCopyRegionKeepTagsInAllAMI(t *testing.T) { + tests := []struct { + name string + amiName string + template string + }{ + { + name: "amazon-ebs_region_copy_keep_tags", + amiName: fmt.Sprintf( + "packer-test-builder-region-copy-keep-tags-%d", + time.Now().Unix()), + template: testAMIRunTagsCopyKeepTags, + }, + { + name: "amazon-ebs_region_copy_keep_run_tags", + amiName: fmt.Sprintf( + "packer-test-builder-region-copy-keep-run-tags-%d", + time.Now().Unix()), + template: testAMIRunTagsCopyKeepRunTags, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + amis := []amazon_acc.AMIHelper{ + { + Region: "us-east-1", + Name: tt.amiName, + }, + { + Region: "us-west-1", + Name: tt.amiName, + }, + } + + expectedTags := map[string]string{ + "build_name": "build_name", + "version": "packer", + "built_by": "ebs", + "simple": "Simple String", + } + + testCase := &acctest.PluginTestCase{ + Name: tt.name, + Template: fmt.Sprintf(tt.template, tt.amiName), + Teardown: func() error { + err := amis[0].CleanUpAmi() + if err != nil { + t.Logf("ami %s cleanup failed: %s", amis[0].Name, err) + } + err = amis[1].CleanUpAmi() + if err != nil { + t.Logf("ami %s cleanup failed: %s", amis[1].Name, err) + } + return nil + }, + Check: func(buildCommand *exec.Cmd, logfile string) error { + var result error + + if buildCommand.ProcessState != nil { + if buildCommand.ProcessState.ExitCode() != 0 { + return fmt.Errorf("Bad exit code. Logfile: %s", logfile) + } + } + + err := checkRegionCopy( + tt.amiName, + []string{"us-east-1", "us-west-1"}) + if err != nil { + result = multierror.Append(result, err) + } + + for _, ami := range amis { + err := checkAMITags(ami, expectedTags) + if err != nil { + result = multierror.Append(result, err) + } + } + + return result + }, + } + + acctest.TestPlugin(t, testCase) + }) + } +} + +func TestAccBuilder_EbsWindowsFastLaunch(t *testing.T) { + fastlaunchami := amazon_acc.AMIHelper{ + Region: "us-east-1", + Name: fmt.Sprintf("packer-ebs-windows-fastlaunch-%d", time.Now().Unix()), + } + + fastlaunchamiwithTemplate := amazon_acc.AMIHelper{ + Region: "us-east-1", + Name: fmt.Sprintf("packer-ebs-windows-fastlaunch-with-template-%d", time.Now().Unix()), + } + + tests := []struct { + name string + ami amazon_acc.AMIHelper + template string + }{ + { + "basic fast-launch enable test", + fastlaunchami, + fmt.Sprintf(testWindowsFastBoot, fastlaunchami.Name), + }, + { + "basic fast-launch enable test with template", + fastlaunchamiwithTemplate, + fmt.Sprintf(testWindowsFastBootWithTemplateID, fastlaunchamiwithTemplate.Name), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + testcase := &acctest.PluginTestCase{ + Name: tt.name, + Template: tt.template, + Teardown: func() error { + return tt.ami.CleanUpAmi() + }, + Check: func(buildCommand *exec.Cmd, logfile string) error { + if buildCommand.ProcessState.ExitCode() != 0 { + return fmt.Errorf("Bad exit code. Logfile: %s", logfile) + } + + amis, err := tt.ami.GetAmi() + if err != nil { + return fmt.Errorf("failed to get AMI: %s", err) + } + if len(amis) != 1 { + return fmt.Errorf("got too many AMIs, expected 1, got %d", len(amis)) + } + + accessConfig := &awscommon.AccessConfig{} + session, err := accessConfig.Session() + if err != nil { + return fmt.Errorf("Unable to create aws session %s", err.Error()) + } + + regionconn := ec2.New(session.Copy(&aws.Config{ + Region: aws.String(tt.ami.Region), + })) + + ami := amis[0] + + fastLaunchImages, err := regionconn.DescribeFastLaunchImages(&ec2.DescribeFastLaunchImagesInput{ + ImageIds: []*string{ami.ImageId}, + }) + + if err != nil { + return fmt.Errorf("failed to get fast-launch images: %s", err) + } + + if len(fastLaunchImages.FastLaunchImages) != 1 { + return fmt.Errorf("got too many fast-launch images, expected 1, got %d", len(fastLaunchImages.FastLaunchImages)) + } + + img := fastLaunchImages.FastLaunchImages[0] + if img.State == nil { + return fmt.Errorf("unexpected null fast-launch state") + } + + if *img.State != "enabled" { + return fmt.Errorf("expected fast-launch state to be enabled, but is %q: transition state was %q", *img.State, *img.StateTransitionReason) + } + + return nil + }, + } + acctest.TestPlugin(t, testcase) + }) + } +} + +func TestAccBuilder_EbsWindowsFastLaunchWithAMICopies(t *testing.T) { + amiNameWithoutLT := fmt.Sprintf("packer-ebs-windows-fastlaunch-with-copies-%d", time.Now().Unix()) + amiNameWithLT := fmt.Sprintf("packer-ebs-windows-fastlaunch-with-copies-and-launch-templates-%d", time.Now().Unix()) + + flWithCopiesAMIs := []amazon_acc.AMIHelper{ + { + Region: "us-east-1", + Name: amiNameWithoutLT, + }, + { + Region: "us-east-2", + Name: amiNameWithoutLT, + }, + } + + flWithCopiesAMIsAndLTs := []amazon_acc.AMIHelper{ + { + Region: "us-east-1", + Name: amiNameWithLT, + }, + { + Region: "us-east-2", + Name: amiNameWithLT, + }, + } + + tests := []struct { + name string + amiName string + amiSpec []amazon_acc.AMIHelper + stringsToFindInLog []string + template string + }{ + { + "ebs-windows-fast-launch-with-copies", + amiNameWithoutLT, + flWithCopiesAMIs, + []string{ + "no launch-template configured, will use defaults.", + "no template specified for region \"us-east-1\"", + "no template specified for region \"us-east-2\"", + }, + testWindowsFastBootWithAMICopies, + }, + { + "ebs-windows-fast-launch-with-copies-and-launch-templates", + amiNameWithLT, + flWithCopiesAMIsAndLTs, + []string{ + "found template in region \"us-east-1\": ID \"lt-0c82d8943c032fc0b\"", + "found template in region \"us-east-2\": ID \"lt-0083091b6614b118c\"", + }, + testWindowsFastBootWithAMICopiesAndLTs, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + testcase := &acctest.PluginTestCase{ + Name: tt.name, + Template: fmt.Sprintf(tt.template, tt.amiName), + Teardown: func() error { + var errs error + + for _, ami := range tt.amiSpec { + err := ami.CleanUpAmi() + if err != nil { + t.Logf("cleaning up AMI %q in region %q failed: %s. It will need to be manually removed", ami.Name, ami.Region, err) + errs = packersdk.MultiErrorAppend(errs, err) + } + } + + return errs + }, + Check: func(buildCommand *exec.Cmd, logfile string) error { + if buildCommand.ProcessState.ExitCode() != 0 { + return fmt.Errorf("Bad exit code. Logfile: %s", logfile) + } + + for _, ami := range tt.amiSpec { + amis, err := ami.GetAmi() + if err != nil { + return fmt.Errorf("failed to get AMI: %s", err) + } + if len(amis) != 1 { + return fmt.Errorf("got too many AMIs, expected 1, got %d", len(amis)) + } + + accessConfig := &awscommon.AccessConfig{} + session, err := accessConfig.Session() + if err != nil { + return fmt.Errorf("Unable to create aws session %s", err.Error()) + } + + regionconn := ec2.New(session.Copy(&aws.Config{ + Region: aws.String(ami.Region), + })) + + ami := amis[0] + + fastLaunchImages, err := regionconn.DescribeFastLaunchImages(&ec2.DescribeFastLaunchImagesInput{ + ImageIds: []*string{ami.ImageId}, + }) + + if err != nil { + return fmt.Errorf("failed to get fast-launch images: %s", err) + } + + if len(fastLaunchImages.FastLaunchImages) != 1 { + return fmt.Errorf("got too many fast-launch images, expected 1, got %d", len(fastLaunchImages.FastLaunchImages)) + } + + img := fastLaunchImages.FastLaunchImages[0] + if img.State == nil { + return fmt.Errorf("unexpected null fast-launch state") + } + + if *img.State != "enabled" { + return fmt.Errorf("expected fast-launch state to be enabled, but is %q: transition state was %q", *img.State, *img.StateTransitionReason) + } + } + + logs, err := os.ReadFile(logfile) + if err != nil { + t.Fatalf("failed to read logs from logifle: %s", err) + } + logStr := string(logs) + for _, str := range tt.stringsToFindInLog { + if !strings.Contains(logStr, str) { + t.Errorf("exptected to find %q in logs, but did not", str) + } + } + + return nil + }, + } + acctest.TestPlugin(t, testcase) + }) + } +} + +func checkAMITags(ami amazon_acc.AMIHelper, tagList map[string]string) error { + images, err := ami.GetAmi() + if err != nil || len(images) == 0 { + return fmt.Errorf("failed to find ami %s at region %s", ami.Name, ami.Region) + } + + amiNameRegion := fmt.Sprintf("%s/%s", ami.Region, ami.Name) + + // describe the image, get block devices with a snapshot + ec2conn, _ := testEC2Conn(ami.Region) + imageResp, err := ec2conn.DescribeImages(&ec2.DescribeImagesInput{ + ImageIds: []*string{images[0].ImageId}, + }) + if err != nil { + return fmt.Errorf("failed to describe AMI %q: %s", amiNameRegion, err) + } + + var errs error + image := imageResp.Images[0] // Only requested a single AMI ID + for tagKey, tagVal := range tagList { + found := false + for _, imgTag := range image.Tags { + if *imgTag.Key != tagKey { + continue + } + found = true + if *imgTag.Value != tagVal { + errs = multierror.Append(errs, fmt.Errorf("wrong value for tag %q, expected %q, got %q", + tagKey, tagVal, *imgTag.Value)) + } + break + } + if !found { + errs = multierror.Append(errs, fmt.Errorf("tag %q not found in image tags", tagKey)) + } + } + + return errs +} + +func TestAccBuilder_EBSWithSSHPassword_NoTempKeyCreated(t *testing.T) { + ami := amazon_acc.AMIHelper{ + Region: "us-east-1", + Name: fmt.Sprintf("packer-ebs-ssh-password-auth-test-%d", time.Now().Unix()), + } + + testcase := &acctest.PluginTestCase{ + Name: "amazon-ebs-with-ssh-pass-auth", + Template: fmt.Sprintf(testBuildWithSSHPassword, ami.Name), + Teardown: func() error { + return ami.CleanUpAmi() + }, + Check: func(buildCommand *exec.Cmd, logfile string) error { + if buildCommand.ProcessState.ExitCode() != 0 { + return fmt.Errorf("Bad exit code. Logfile: %s", logfile) + } + + logs, err := os.ReadFile(logfile) + if err != nil { + return fmt.Errorf("couldn't read logs from logfile %s: %s", logfile, err) + } + if strings.Contains(string(logs), "Creating temporary keypair") { + return fmt.Errorf("ssh password specified, should not create temp keypair.") + } + + return nil + }, + } + acctest.TestPlugin(t, testcase) +} + +func TestAccBuilder_AssociatePublicIPWithoutSubnet(t *testing.T) { + nonSpotInstance := amazon_acc.AMIHelper{ + Region: "us-east-1", + Name: fmt.Sprintf("packer-ebs-explicit-public-ip-%d", time.Now().Unix()), + } + + spotInstance := amazon_acc.AMIHelper{ + Region: "us-east-1", + Name: fmt.Sprintf("packer-ebs-spot-explicit-public-ip-%d", time.Now().Unix()), + } + tests := []struct { + name string + IPVal bool + amiSetup amazon_acc.AMIHelper + template string + expectErr bool + }{ + { + "Spot instance, with public IP explicitely set", + true, + spotInstance, + testSetupPublicIPWithoutVPCOrSubnetOnSpotInstance, + false, + }, + { + "Spot instance, with public IP explicitely unset", + false, + spotInstance, + testSetupPublicIPWithoutVPCOrSubnetOnSpotInstance, + true, // We expect an error without a public IP since no outbound connections work in this case, so SSM doesn't work with the current config + }, + { + "Non-Spot instance, with public IP explicitely set", + true, + nonSpotInstance, + testSetupPublicIPWithoutVPCOrSubnet, + false, + }, + { + "Non-Spot instance, with public IP explicitely unset", + false, + nonSpotInstance, + testSetupPublicIPWithoutVPCOrSubnet, + true, // We expect an error without a public IP since no outbound connections work in this case, so SSM doesn't work with the current config + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + testcase := &acctest.PluginTestCase{ + Name: tt.name, + Template: fmt.Sprintf(tt.template, tt.amiSetup.Name, tt.IPVal), + Check: func(buildCommand *exec.Cmd, logfile string) error { + if (buildCommand.ProcessState.ExitCode() != 0) != tt.expectErr { + return fmt.Errorf("Bad exit code, expected %t error, got %d. Logfile: %s", + tt.expectErr, + buildCommand.ProcessState.ExitCode(), + logfile) + } + + logs, err := os.ReadFile(logfile) + if err != nil { + return fmt.Errorf("couldn't read logs from logfile %s: %s", logfile, err) + } + + expectMsg := fmt.Sprintf("changing public IP address config to %t for instance on subnet", tt.IPVal) + + if !strings.Contains(string(logs), expectMsg) { + return fmt.Errorf("did not change the public IP setting for the instance") + } + + if !strings.Contains(string(logs), "No VPC ID provided, Packer will use the default VPC") { + return fmt.Errorf("did not pick the default VPC when setting subnet") + } + + return nil + }, + } + acctest.TestPlugin(t, testcase) + }) + } +} + +func TestAccBuilder_AssociatePublicIPWithSubnetFilter(t *testing.T) { + ami := amazon_acc.AMIHelper{ + Region: "us-east-1", + Name: fmt.Sprintf("packer-ebs-with-subnet-filter-%d", time.Now().Unix()), + } + + testcase := &acctest.PluginTestCase{ + Name: "ebs-subnet-filter-associate-ip-test", + Template: fmt.Sprintf(testSubnetFilterWithPublicIP, ami.Name, true), + Check: func(buildCommand *exec.Cmd, logfile string) error { + if buildCommand.ProcessState.ExitCode() != 0 { + return fmt.Errorf("Bad exit code, got %d. Logfile: %s", + buildCommand.ProcessState.ExitCode(), + logfile) + } + + logs, err := os.ReadFile(logfile) + if err != nil { + return fmt.Errorf("couldn't read logs from logfile %s: %s", logfile, err) + } + + if ok := strings.Contains(string(logs), "changing public IP address config to true for instance on subnet"); !ok { + return fmt.Errorf("did not change the public IP setting for the instance") + } + + if ok := strings.Contains(string(logs), "Using Subnet Filters"); !ok { + return fmt.Errorf("did not select subnet with filters") + } + + if ok := strings.Contains(string(logs), "AvailabilityZone found"); !ok { + return fmt.Errorf("did not get AZ from subnet") + } + + if ok := strings.Contains(string(logs), "VpcId found"); !ok { + return fmt.Errorf("did not get VPC ID from subnet") + } + + if ok := strings.Contains(string(logs), "Inferring subnet from the selected"); ok { + return fmt.Errorf("should not have selected a subnet for public IP address config") + } + + return nil + }, + } + acctest.TestPlugin(t, testcase) +} + +func TestAccBuilder_BasicSubnetFilter(t *testing.T) { + ami := amazon_acc.AMIHelper{ + Region: "us-east-1", + Name: fmt.Sprintf("packer-ebs-basic-subnet-filter-%d", time.Now().Unix()), + } + + testcase := &acctest.PluginTestCase{ + Name: "ebs-subnet-filter-test", + Template: fmt.Sprintf(testBasicSubnetFilter, ami.Name), + Check: func(buildCommand *exec.Cmd, logfile string) error { + if buildCommand.ProcessState.ExitCode() != 0 { + return fmt.Errorf("Bad exit code, got %d. Logfile: %s", + buildCommand.ProcessState.ExitCode(), + logfile) + } + + logs, err := os.ReadFile(logfile) + if err != nil { + return fmt.Errorf("couldn't read logs from logfile %s: %s", logfile, err) + } + + if ok := strings.Contains(string(logs), "Using Subnet Filters"); !ok { + return fmt.Errorf("did not select subnet with filters") + } + + if ok := strings.Contains(string(logs), "AvailabilityZone found"); !ok { + return fmt.Errorf("did not get AZ from subnet") + } + + if ok := strings.Contains(string(logs), "VpcId found"); !ok { + return fmt.Errorf("did not get VPC ID from subnet") + } + + return nil + }, + } + acctest.TestPlugin(t, testcase) +} + const testBuilderAccBasic = ` { "builders": [{ @@ -956,7 +1666,7 @@ const testBuilderAccSessionManagerInterface = ` "source_ami_filter": { "filters": { "virtualization-type": "hvm", - "name": "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*", + "name": "ubuntu/images/*ubuntu-jammy-22.04-amd64-server-*", "root-device-type": "ebs" }, "owners": [ @@ -972,6 +1682,32 @@ const testBuilderAccSessionManagerInterface = ` } ` +const testBuilderAccSSMWithReboot = ` +source "amazon-ebs" "test" { + ami_name = "%s" + source_ami = "ami-00874d747dde814fa" # Ubuntu Server 22.04 LTS + instance_type = "m3.medium" + region = "us-east-1" + ssh_username = "ubuntu" + ssh_interface = "session_manager" + iam_instance_profile = "SSMInstanceProfile" + communicator = "ssh" +} + +build { + sources = ["amazon-ebs.test"] + + provisioner "shell" { + expect_disconnect = true + inline = ["echo 'waiting for 1 minute'; sleep 60; echo 'rebooting VM'; sudo reboot now"] + } + + provisioner "shell" { + inline = ["echo 'reboot done!'"] + } +} +` + const testBuilderAccEnableDeprecation = ` { "builders": [{ @@ -986,6 +1722,392 @@ const testBuilderAccEnableDeprecation = ` } ` +const testPrivateKeyFile = ` +source "amazon-ebs" "test" { + ami_name = "%s" + source_ami = "ami-0b5eea76982371e91" # Amazon Linux 2 AMI - kernel 5.10 + instance_type = "m3.medium" + region = "us-east-1" + ssh_username = "ec2-user" + ssh_interface = "session_manager" + iam_instance_profile = "SSMInstanceProfile" + communicator = "ssh" + ssh_private_key_file = "%s" +} + +build { + sources = ["amazon-ebs.test"] +} +` + +const testPrivateKeyFileWithReboot = ` +source "amazon-ebs" "test" { + ami_name = "%s" + source_ami = "ami-00874d747dde814fa" # Ubuntu Server 22.04 LTS + instance_type = "m3.medium" + region = "us-east-1" + ssh_username = "ubuntu" + ssh_interface = "session_manager" + iam_instance_profile = "SSMInstanceProfile" + communicator = "ssh" + ssh_private_key_file = "%s" +} + +build { + sources = ["amazon-ebs.test"] + + provisioner "shell" { + expect_disconnect = true + inline = ["echo 'waiting for 1 minute'; sleep 60; echo 'rebooting VM'; sudo reboot now"] + } + + provisioner "shell" { + inline = ["echo 'reboot done!'"] + } +} +` + +const testIMDSv2Support = ` +source "amazon-ebs" "test" { + ami_name = "%s" + source_ami = "ami-00874d747dde814fa" # Ubuntu Server 22.04 LTS + instance_type = "m3.medium" + region = "us-east-1" + ssh_username = "ubuntu" + ssh_interface = "session_manager" + iam_instance_profile = "SSMInstanceProfile" + communicator = "ssh" + imds_support = "v2.0" +} + +build { + sources = ["amazon-ebs.test"] +} +` + +const testAMIRunTagsCopyKeepRunTags = ` +source "amazon-ebs" "test" { + region = "us-east-1" + source_ami = "ami-00874d747dde814fa" # Ubuntu Server 22.04 LTS + instance_type = "m3.medium" + ami_name = "%s" + communicator = "ssh" + ssh_username = "ubuntu" + ami_regions = ["us-west-1"] + + run_tags = { + "build_name" = "build_name" + "version" = "packer" + "built_by" = "ebs" + "simple" = "Simple String" + } +} + +build { + sources = [ + "source.amazon-ebs.test" + ] +} +` + +const testAMIRunTagsCopyKeepTags = ` +source "amazon-ebs" "test" { + region = "us-east-1" + source_ami = "ami-00874d747dde814fa" # Ubuntu Server 22.04 LTS + instance_type = "m3.medium" + ami_name = "%s" + communicator = "ssh" + ssh_username = "ubuntu" + ami_regions = ["us-west-1"] + + tags = { + "build_name" = "build_name" + "version" = "packer" + "built_by" = "ebs" + "simple" = "Simple String" + } +} + +build { + sources = [ + "source.amazon-ebs.test" + ] +} +` + +const testBuildWithSSHPassword = ` +source "amazon-ebs" "test" { + region = "us-east-1" + source_ami = "ami-089158c0576f477a7" # Ubuntu Server 22.04 LTS custom with ssh user/password auth setup + instance_type = "t3.micro" + ami_name = "%s" + communicator = "ssh" + ssh_interface = "session_manager" + iam_instance_profile = "SSMInstanceProfile" + ssh_username = "user" + ssh_password = "password" +} + +build { + sources = ["amazon-ebs.test"] +} +` + +const testSetupPublicIPWithoutVPCOrSubnet = ` +source "amazon-ebs" "test_build" { + region = "us-east-1" + ami_name = "%s" + source_ami = "ami-06e46074ae430fba6" # Amazon Linux 2023 x86-64 + instance_type = "t2.micro" + communicator = "ssh" + ssh_username = "ec2-user" + ssh_timeout = "45s" + associate_public_ip_address = %t + skip_create_ami = true +} + +build { + sources = ["amazon-ebs.test_build"] +} +` + +const testSetupPublicIPWithoutVPCOrSubnetOnSpotInstance = ` +source "amazon-ebs" "test" { + region = "us-east-1" + spot_price = "auto" + source_ami = "ami-06e46074ae430fba6" # Amazon Linux 2023 x86-64 + instance_type = "t2.micro" + ssh_username = "ec2-user" + ssh_timeout = "45s" + ami_name = "%s" + skip_create_ami = true + associate_public_ip_address = %t + temporary_iam_instance_profile_policy_document { + Version = "2012-10-17" + Statement { + Effect = "Allow" + Action = [ + "ec2:GetDefaultCreditSpecification", + "ec2:DescribeInstanceTypeOfferings", + "ec2:DescribeInstanceCreditSpecifications" + ] + Resource = ["*"] + } + } +} + +build { + sources = ["source.amazon-ebs.test"] +} +` + +const testWindowsFastBoot = ` +data "amazon-ami" "windows-ami" { + filters = { + name = "Windows_Server-2016-English-Core-Base-*" + } + owners = ["801119661308"] + most_recent = true + region = "us-east-1" +} + +source "amazon-ebs" "windows-fastboot" { + ami_name = "%s" + source_ami = data.amazon-ami.windows-ami.id + instance_type = "m3.medium" + region = "us-east-1" + communicator = "winrm" + winrm_username = "Administrator" + winrm_password = "e4sypa55!" + user_data_file = "test-fixtures/ps_enable.ps" + fast_launch { + enable_fast_launch = true + target_resource_count = 1 + } +} + +build { + sources = ["amazon-ebs.windows-fastboot"] + + provisioner "powershell" { + inline = [ + "C:/ProgramData/Amazon/EC2-Windows/Launch/Scripts/InitializeInstance.ps1 -Schedule", + "C:/ProgramData/Amazon/EC2-Windows/Launch/Scripts/SysprepInstance.ps1 -NoShutdown" + ] + } +} +` + +const testWindowsFastBootWithTemplateID = ` +data "amazon-ami" "windows-ami" { + filters = { + name = "Windows_Server-2016-English-Core-Base-*" + } + owners = ["801119661308"] + most_recent = true + region = "us-east-1" +} + +source "amazon-ebs" "windows-fastboot" { + ami_name = "%s" + source_ami = data.amazon-ami.windows-ami.id + instance_type = "m3.medium" + region = "us-east-1" + communicator = "winrm" + winrm_username = "Administrator" + winrm_password = "e4sypa55!" + user_data_file = "test-fixtures/ps_enable.ps" + + fast_launch { + enable_fast_launch = true + target_resource_count = 1 + template_id = "lt-0c82d8943c032fc0b" + } +} + +build { + sources = ["amazon-ebs.windows-fastboot"] + + provisioner "powershell" { + inline = [ + "C:/ProgramData/Amazon/EC2-Windows/Launch/Scripts/InitializeInstance.ps1 -Schedule", + "C:/ProgramData/Amazon/EC2-Windows/Launch/Scripts/SysprepInstance.ps1 -NoShutdown" + ] + } +} +` + +const testWindowsFastBootWithAMICopies = ` +data "amazon-ami" "windows-ami" { + filters = { + name = "Windows_Server-2016-English-Core-Base-*" + } + owners = ["801119661308"] + most_recent = true + region = "us-east-1" +} + +source "amazon-ebs" "windows-fastboot" { + ami_name = "%s" + source_ami = data.amazon-ami.windows-ami.id + instance_type = "m3.medium" + region = "us-east-1" + ami_regions = ["us-east-2", "us-east-1"] + communicator = "winrm" + winrm_username = "Administrator" + winrm_password = "e4sypa55!" + user_data_file = "test-fixtures/ps_enable.ps" + + fast_launch { + enable_fast_launch = true + target_resource_count = 1 + } +} + +build { + sources = ["amazon-ebs.windows-fastboot"] + + provisioner "powershell" { + inline = [ + "C:/ProgramData/Amazon/EC2-Windows/Launch/Scripts/InitializeInstance.ps1 -Schedule", + "C:/ProgramData/Amazon/EC2-Windows/Launch/Scripts/SysprepInstance.ps1 -NoShutdown" + ] + } +} +` + +const testWindowsFastBootWithAMICopiesAndLTs = ` +data "amazon-ami" "windows-ami" { + filters = { + name = "Windows_Server-2016-English-Core-Base-*" + } + owners = ["801119661308"] + most_recent = true + region = "us-east-1" +} + +source "amazon-ebs" "windows-fastboot" { + ami_name = "%s" + source_ami = data.amazon-ami.windows-ami.id + instance_type = "m3.medium" + region = "us-east-1" + ami_regions = ["us-east-2", "us-east-1"] + communicator = "winrm" + winrm_username = "Administrator" + winrm_password = "e4sypa55!" + user_data_file = "test-fixtures/ps_enable.ps" + + fast_launch { + enable_fast_launch = true + target_resource_count = 1 + + region_launch_templates { + region = "us-east-1" + template_id = "lt-0c82d8943c032fc0b" + } + + region_launch_templates { + region = "us-east-2" + template_id = "lt-0083091b6614b118c" + } + } +} + +build { + sources = ["amazon-ebs.windows-fastboot"] + + provisioner "powershell" { + inline = [ + "C:/ProgramData/Amazon/EC2-Windows/Launch/Scripts/InitializeInstance.ps1 -Schedule", + "C:/ProgramData/Amazon/EC2-Windows/Launch/Scripts/SysprepInstance.ps1 -NoShutdown" + ] + } +} +` + +const testSubnetFilterWithPublicIP = ` +source "amazon-ebs" "test-subnet-filter" { + subnet_filter { + filters = { + availability-zone = "us-east-1a" +} + } + region = "us-east-1" + ami_name = "%s" + source_ami = "ami-06e46074ae430fba6" # Amazon Linux 2023 x86-64 + instance_type = "t2.micro" + communicator = "ssh" + ssh_username = "ec2-user" + associate_public_ip_address = %t + skip_create_ami = true +} + +build { + sources = ["amazon-ebs.test-subnet-filter"] +} +` + +const testBasicSubnetFilter = ` +source "amazon-ebs" "test-subnet-filter" { + subnet_filter { + filters = { + availability-zone = "us-east-1a" +} + } + region = "us-east-1" + ami_name = "%s" + source_ami = "ami-06e46074ae430fba6" # Amazon Linux 2023 x86-64 + instance_type = "t2.micro" + communicator = "ssh" + ssh_username = "ec2-user" + skip_create_ami = true +} + +build { + sources = ["amazon-ebs.test-subnet-filter"] +} +` + func buildForceDeregisterConfig(val, name string) string { return fmt.Sprintf(testBuilderAccForceDeregister, val, name) } @@ -1001,3 +2123,11 @@ func buildSharingConfig(val, val2, val3, name string) string { func buildEnableDeprecationConfig(val, name string) string { return fmt.Sprintf(testBuilderAccEnableDeprecation, val, name) } + +func buildPrivateKeyFileConfig(name, keyPath string) string { + return fmt.Sprintf(testPrivateKeyFile, name, keyPath) +} + +func buildPrivateKeyFileRebootConfig(name, keyPath string) string { + return fmt.Sprintf(testPrivateKeyFileWithReboot, name, keyPath) +} diff --git a/builder/ebs/builder_test.go b/builder/ebs/builder_test.go index cc433a220..6e543fd7e 100644 --- a/builder/ebs/builder_test.go +++ b/builder/ebs/builder_test.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package ebs import ( @@ -197,3 +200,188 @@ func TestBuilderPrepare_ReturnGeneratedData(t *testing.T) { t.Fatalf("Generated data should contain SourceAMIOwnerName") } } + +func TestBuilerPrepare_IMDSSupport(t *testing.T) { + testcases := []struct { + name string + imdsSupportValue string + isErr bool + }{ + { + name: "define valid IMDSv2 support", + imdsSupportValue: "v2.0", + isErr: false, + }, + { + name: "don't define IMDSv2 support", + imdsSupportValue: "", + isErr: false, + }, + { + name: "invalid IMDS support", + imdsSupportValue: "v1.0", + isErr: true, + }, + } + + for _, tt := range testcases { + t.Run(tt.name, func(t *testing.T) { + var b Builder + config := testConfig() + + config["imds_support"] = tt.imdsSupportValue + _, warnings, err := b.Prepare(config) + + if len(warnings) > 0 { + t.Fatalf("bad: %#v", warnings) + } + if (err != nil) != tt.isErr { + t.Errorf("error mismatch, expected %t, got %t", tt.isErr, err != nil) + } + + if err != nil { + t.Logf("error: %s", err) + } + }) + } +} + +func TestBuilderPrepare_FastLaunch(t *testing.T) { + tests := []struct { + name string + fastLaunchConfig map[string]interface{} + expectError bool + }{ + { + "OK - empty config", + map[string]interface{}{}, + false, + }, + { + "OK - all specified, with template id", + map[string]interface{}{ + "fast_launch": map[string]interface{}{ + "enable_fast_launch": true, + "template_id": "id", + "template_version": 2, + "max_parallel_launches": 10, + "target_resource_count": 20, + }, + }, + false, + }, + { + "OK - all specified, with template name", + map[string]interface{}{ + "fast_launch": map[string]interface{}{ + "enable_fast_launch": true, + "template_name": "name", + "template_version": 2, + "max_parallel_launches": 10, + "target_resource_count": 20, + }, + }, + false, + }, + { + "Error - regional launch template specified, with same region as top-level", + map[string]interface{}{ + "fast_launch": map[string]interface{}{ + "region_launch_templates": map[string]interface{}{ + "region": "us-east-1", + "template_name": "name", + "template_version": 2, + }, + "template_name": "test", + "max_parallel_launches": 10, + "target_resource_count": 1, + }, + }, + true, + }, + { + "Error - regional launch template specified, without region", + map[string]interface{}{ + "fast_launch": map[string]interface{}{ + "region_launch_templates": map[string]interface{}{ + "template_name": "name", + "template_version": 2, + }, + "max_parallel_launches": 10, + "target_resource_count": 1, + }, + }, + true, + }, + { + "Error - max parallel launches < 6", + map[string]interface{}{ + "fast_launch": map[string]interface{}{ + "max_parallel_launches": 3, + }, + }, + true, + }, + { + "Error - target resource count < 0", + map[string]interface{}{ + "fast_launch": map[string]interface{}{ + "target_resource_count": -1, + }, + }, + true, + }, + { + "Error - launch template ID & name specified", + map[string]interface{}{ + "fast_launch": map[string]interface{}{ + "template_id": "id", + "template_name": "name", + }, + }, + true, + }, + { + "Error - launch template version without name/id", + map[string]interface{}{ + "fast_launch": map[string]interface{}{ + "template_version": 2, + }, + }, + true, + }, + { + "Error - launch template version < 0", + map[string]interface{}{ + "fast_launch": map[string]interface{}{ + "template_version": -1, + }, + }, + true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var b Builder + config := testConfig() + + for k, v := range tt.fastLaunchConfig { + config[k] = v + } + + _, warnings, err := b.Prepare(config) + + if len(warnings) > 0 { + t.Errorf("got unexpected warnings: %#v", warnings) + } + if (err != nil) != tt.expectError { + t.Errorf("error mismatch, expected %t, got %t", tt.expectError, err != nil) + } + + if err != nil { + t.Logf("got error: %s", err) + } + }) + } +} diff --git a/builder/ebs/fast_launch_setup.go b/builder/ebs/fast_launch_setup.go new file mode 100644 index 000000000..aac68e41a --- /dev/null +++ b/builder/ebs/fast_launch_setup.go @@ -0,0 +1,211 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +//go:generate packer-sdc struct-markdown +//go:generate packer-sdc mapstructure-to-hcl2 -type FastLaunchConfig,FastLaunchTemplateConfig + +package ebs + +import ( + "fmt" + "log" +) + +// FastLaunchTemplateConfig is the launch template configuration for a region. +// +// This must be used if the configuration has more than one region specified +// in the template, as each fast-launch enablement step occurs after the +// copy, and each region may pick their own launch template. +type FastLaunchTemplateConfig struct { + // The region in which to find the launch template to use + Region string `mapstructure:"region" required:"true"` + // The ID of the launch template to use for the fast launch + // + // This cannot be specified in conjunction with the template name. + // + // If no template is specified, the default launch template will be used, + // as specified in the AWS docs. + LaunchTemplateID string `mapstructure:"template_id"` + // The name of the launch template to use for fast launch + // + // This cannot be specified in conjunction with the template ID. + // + // If no template is specified, the default launch template will be used, + // as specified in the AWS docs. + LaunchTemplateName string `mapstructure:"template_name"` + // The version of the launch template to use + // + // If unspecified, and a template is referenced, this will default to + // the latest version available for the template. + LaunchTemplateVersion int `mapstructure:"template_version"` +} + +func (tc *FastLaunchTemplateConfig) Prepare() []error { + var errs []error + + if tc.Region == "" { + return append(errs, fmt.Errorf("region cannot be empty for a regional fast template config")) + } + + if tc.LaunchTemplateID != "" && tc.LaunchTemplateName != "" { + errs = append(errs, fmt.Errorf("fast_launch_template_config region %q: both template ID and name cannot be specified at the same time", tc.Region)) + } + + if tc.LaunchTemplateVersion != 0 && tc.LaunchTemplateVersion < 1 { + errs = append(errs, fmt.Errorf("fast_launch_template_config region %q: the launch template version must be >= 1, provided value is %d", tc.Region, tc.LaunchTemplateVersion)) + } + + if tc.LaunchTemplateVersion != 0 && tc.LaunchTemplateID == "" && tc.LaunchTemplateName == "" { + errs = append(errs, fmt.Errorf("fast_launch_template_config region %q: launch template version specified without an ID or name", tc.Region)) + } + + return errs +} + +// FastLaunchConfig is the configuration for setting up fast-launch for Windows AMIs +// +// NOTE: requires the Windows image to be sysprep'd to enable fast-launch. See the +// AWS docs for more information: +// https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/win-ami-config-fast-launch.html +type FastLaunchConfig struct { + // Configure fast-launch for Windows AMIs + UseFastLaunch bool `mapstructure:"enable_fast_launch"` + // The region in which the AMI will be built + // + // This is only set by the builder, and not by the client. + // Its only use is to move the launch template configuration if it has + // been specified into the map of region -> FastLaunchTemplateConfig + // for easier processing later. + defaultRegion string + // The ID of the launch template to use for fast launch for the main AMI. + // + // This cannot be specified in conjunction with the template name. + // + // If no template is specified, the default launch template will be used, + // as specified in the AWS docs. + // + // If you copy the AMI to other regions, this option should not + // be used, use instead the `fast_launch_template_config` option. + LaunchTemplateID string `mapstructure:"template_id"` + // The name of the launch template to use for fast launch for the main AMI. + // + // This cannot be specified in conjunction with the template ID. + // + // If no template is specified, the default launch template will be used, + // as specified in the AWS docs. + // + // If you copy the AMI to other regions, this option should not + // be used, use instead the `fast_launch_template_config` option. + LaunchTemplateName string `mapstructure:"template_name"` + // The version of the launch template to use for fast launch for the main AMI. + // + // If unspecified, and a template is referenced, this will default to + // the latest version available for the template. + // + // If you copy the AMI to other regions, this option should not + // be used, use instead the `fast_launch_template_config` option. + LaunchTemplateVersion int `mapstructure:"template_version"` + // RegionLaunchTemplates is the list of launch templates per region. + // + // This should be specified if you want to use a custom launch + // template for your fast-launched images, and you are copying + // the image to other regions. + // + // All regions don't need a launch template configuration, but for + // each that don't have a launch template specified, AWS will pick + // a default one for that purpose. + // + // For information about each entry, refer to the + // [Fast Launch Template Config](#fast-launch-template-config) documentation. + RegionLaunchTemplates []FastLaunchTemplateConfig `mapstructure:"region_launch_templates"` + // Maximum number of instances to launch for creating pre-provisioned snapshots + // + // If specified, must be a minimum of `6` + MaxParallelLaunches int `mapstructure:"max_parallel_launches"` + // The number of snapshots to pre-provision for later launching windows instances + // from the resulting fast-launch AMI. + // + // If unspecified, this will create the default number of snapshots (as of + // march 2023, this defaults to 5 on AWS) + TargetResourceCount int `mapstructure:"target_resource_count"` +} + +func (c FastLaunchConfig) isDefault() bool { + if c.UseFastLaunch { + return false + } + + if c.MaxParallelLaunches != 0 { + return false + } + + if c.LaunchTemplateID != "" { + return false + } + + if c.LaunchTemplateName != "" { + return false + } + + if c.LaunchTemplateVersion != 0 { + return false + } + + if c.TargetResourceCount != 0 { + return false + } + + if len(c.RegionLaunchTemplates) != 0 { + return false + } + + return true +} + +func (c *FastLaunchConfig) Prepare() []error { + if c.isDefault() { + return nil + } + + // If any fast_launch option is set, we enable it. + c.UseFastLaunch = true + + var errs []error + + if c.MaxParallelLaunches != 0 && c.MaxParallelLaunches < 6 { + errs = append(errs, fmt.Errorf("max_parallel_launches must be >= 6, provided value is %d", c.MaxParallelLaunches)) + } + + if c.TargetResourceCount != 0 && c.TargetResourceCount < 1 { + errs = append(errs, fmt.Errorf("target_resource_count must be >= 1, provided value is %d", c.TargetResourceCount)) + } + + if c.LaunchTemplateID != "" || c.LaunchTemplateName != "" || c.LaunchTemplateVersion != 0 { + log.Printf("[INFO] fast_launch: setting default region %q for top-level template config", c.defaultRegion) + c.RegionLaunchTemplates = append(c.RegionLaunchTemplates, FastLaunchTemplateConfig{ + Region: c.defaultRegion, + LaunchTemplateID: c.LaunchTemplateID, + LaunchTemplateName: c.LaunchTemplateName, + LaunchTemplateVersion: c.LaunchTemplateVersion, + }) + } + + // Duplication check + regions := map[string]struct{}{} + + for _, templateConfig := range c.RegionLaunchTemplates { + _, ok := regions[templateConfig.Region] + if ok { + errs = append(errs, fmt.Errorf("fast launch: launch template specified twice for region %q, only once is supported", templateConfig.Region)) + } + + regions[templateConfig.Region] = struct{}{} + + err := templateConfig.Prepare() + if err != nil { + errs = append(errs, err...) + } + } + + return errs +} diff --git a/builder/ebs/fast_launch_setup.hcl2spec.go b/builder/ebs/fast_launch_setup.hcl2spec.go new file mode 100644 index 000000000..166df0388 --- /dev/null +++ b/builder/ebs/fast_launch_setup.hcl2spec.go @@ -0,0 +1,72 @@ +// Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT. + +package ebs + +import ( + "github.com/hashicorp/hcl/v2/hcldec" + "github.com/zclconf/go-cty/cty" +) + +// FlatFastLaunchConfig is an auto-generated flat version of FastLaunchConfig. +// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. +type FlatFastLaunchConfig struct { + UseFastLaunch *bool `mapstructure:"enable_fast_launch" cty:"enable_fast_launch" hcl:"enable_fast_launch"` + LaunchTemplateID *string `mapstructure:"template_id" cty:"template_id" hcl:"template_id"` + LaunchTemplateName *string `mapstructure:"template_name" cty:"template_name" hcl:"template_name"` + LaunchTemplateVersion *int `mapstructure:"template_version" cty:"template_version" hcl:"template_version"` + RegionLaunchTemplates []FlatFastLaunchTemplateConfig `mapstructure:"region_launch_templates" cty:"region_launch_templates" hcl:"region_launch_templates"` + MaxParallelLaunches *int `mapstructure:"max_parallel_launches" cty:"max_parallel_launches" hcl:"max_parallel_launches"` + TargetResourceCount *int `mapstructure:"target_resource_count" cty:"target_resource_count" hcl:"target_resource_count"` +} + +// FlatMapstructure returns a new FlatFastLaunchConfig. +// FlatFastLaunchConfig is an auto-generated flat version of FastLaunchConfig. +// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. +func (*FastLaunchConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { + return new(FlatFastLaunchConfig) +} + +// HCL2Spec returns the hcl spec of a FastLaunchConfig. +// This spec is used by HCL to read the fields of FastLaunchConfig. +// The decoded values from this spec will then be applied to a FlatFastLaunchConfig. +func (*FlatFastLaunchConfig) HCL2Spec() map[string]hcldec.Spec { + s := map[string]hcldec.Spec{ + "enable_fast_launch": &hcldec.AttrSpec{Name: "enable_fast_launch", Type: cty.Bool, Required: false}, + "template_id": &hcldec.AttrSpec{Name: "template_id", Type: cty.String, Required: false}, + "template_name": &hcldec.AttrSpec{Name: "template_name", Type: cty.String, Required: false}, + "template_version": &hcldec.AttrSpec{Name: "template_version", Type: cty.Number, Required: false}, + "region_launch_templates": &hcldec.BlockListSpec{TypeName: "region_launch_templates", Nested: hcldec.ObjectSpec((*FlatFastLaunchTemplateConfig)(nil).HCL2Spec())}, + "max_parallel_launches": &hcldec.AttrSpec{Name: "max_parallel_launches", Type: cty.Number, Required: false}, + "target_resource_count": &hcldec.AttrSpec{Name: "target_resource_count", Type: cty.Number, Required: false}, + } + return s +} + +// FlatFastLaunchTemplateConfig is an auto-generated flat version of FastLaunchTemplateConfig. +// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. +type FlatFastLaunchTemplateConfig struct { + Region *string `mapstructure:"region" required:"true" cty:"region" hcl:"region"` + LaunchTemplateID *string `mapstructure:"template_id" cty:"template_id" hcl:"template_id"` + LaunchTemplateName *string `mapstructure:"template_name" cty:"template_name" hcl:"template_name"` + LaunchTemplateVersion *int `mapstructure:"template_version" cty:"template_version" hcl:"template_version"` +} + +// FlatMapstructure returns a new FlatFastLaunchTemplateConfig. +// FlatFastLaunchTemplateConfig is an auto-generated flat version of FastLaunchTemplateConfig. +// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. +func (*FastLaunchTemplateConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { + return new(FlatFastLaunchTemplateConfig) +} + +// HCL2Spec returns the hcl spec of a FastLaunchTemplateConfig. +// This spec is used by HCL to read the fields of FastLaunchTemplateConfig. +// The decoded values from this spec will then be applied to a FlatFastLaunchTemplateConfig. +func (*FlatFastLaunchTemplateConfig) HCL2Spec() map[string]hcldec.Spec { + s := map[string]hcldec.Spec{ + "region": &hcldec.AttrSpec{Name: "region", Type: cty.String, Required: false}, + "template_id": &hcldec.AttrSpec{Name: "template_id", Type: cty.String, Required: false}, + "template_name": &hcldec.AttrSpec{Name: "template_name", Type: cty.String, Required: false}, + "template_version": &hcldec.AttrSpec{Name: "template_version", Type: cty.Number, Required: false}, + } + return s +} diff --git a/builder/ebs/fast_launch_setup_test.go b/builder/ebs/fast_launch_setup_test.go new file mode 100644 index 000000000..db65d27a0 --- /dev/null +++ b/builder/ebs/fast_launch_setup_test.go @@ -0,0 +1,98 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package ebs + +import "testing" + +func TestFastLaunchPrepare(t *testing.T) { + tests := []struct { + name string + config FastLaunchConfig + expectErr bool + }{ + { + "OK - empty config", + FastLaunchConfig{}, + false, + }, + { + "OK - all specified, with template id", + FastLaunchConfig{ + defaultRegion: "us-east-1", + UseFastLaunch: true, + LaunchTemplateID: "id", + LaunchTemplateVersion: 2, + MaxParallelLaunches: 10, + TargetResourceCount: 20, + }, + false, + }, + { + "OK - all specified, with template name", + FastLaunchConfig{ + defaultRegion: "us-east-1", + UseFastLaunch: true, + LaunchTemplateName: "name", + LaunchTemplateVersion: 2, + MaxParallelLaunches: 10, + TargetResourceCount: 20, + }, + false, + }, + { + "Error - max parallel launches < 6", + FastLaunchConfig{ + defaultRegion: "us-east-1", + MaxParallelLaunches: 3, + }, + true, + }, + { + "Error - target resource count < 0", + FastLaunchConfig{ + defaultRegion: "us-east-1", + TargetResourceCount: -1, + }, + true, + }, + { + "Error - launch template ID & name specified", + FastLaunchConfig{ + defaultRegion: "us-east-1", + LaunchTemplateID: "id", + LaunchTemplateName: "name", + }, + true, + }, + { + "Error - launch template version without name/id", + FastLaunchConfig{ + defaultRegion: "us-east-1", + LaunchTemplateVersion: 2, + }, + true, + }, + { + "Error - launch template version < 0", + FastLaunchConfig{ + defaultRegion: "us-east-1", + LaunchTemplateVersion: -1, + }, + true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + errs := tt.config.Prepare() + if (len(errs) != 0) != tt.expectErr { + t.Errorf("error mismatch, expected %t, got %d errors", tt.expectErr, len(errs)) + } + + for _, err := range errs { + t.Logf("got error %q", err) + } + }) + } +} diff --git a/builder/ebs/step_create_ami.go b/builder/ebs/step_create_ami.go index 760165755..44a599712 100644 --- a/builder/ebs/step_create_ami.go +++ b/builder/ebs/step_create_ami.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package ebs import ( diff --git a/builder/ebs/step_enable_fast_launch.go b/builder/ebs/step_enable_fast_launch.go new file mode 100644 index 000000000..6ca0c8ee0 --- /dev/null +++ b/builder/ebs/step_enable_fast_launch.go @@ -0,0 +1,196 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package ebs + +import ( + "context" + "errors" + "fmt" + "log" + "sync" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/hashicorp/packer-plugin-amazon/builder/common" + awscommon "github.com/hashicorp/packer-plugin-amazon/builder/common" + "github.com/hashicorp/packer-plugin-sdk/multistep" + packersdk "github.com/hashicorp/packer-plugin-sdk/packer" + "github.com/hashicorp/packer-plugin-sdk/retry" +) + +type stepEnableFastLaunch struct { + AccessConfig *common.AccessConfig + PollingConfig *awscommon.AWSPollingConfig + AMISkipCreateImage bool + EnableFastLaunch bool + MaxInstances int + ResourceCount int +} + +func (s *stepEnableFastLaunch) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { + if !s.EnableFastLaunch { + // Nothing to do if fast boot is disabled + return multistep.ActionContinue + } + + ui := state.Get("ui").(packersdk.Ui) + + if s.AMISkipCreateImage { + ui.Say("Skipping fast-launch setup...") + return multistep.ActionContinue + } + + amis := state.Get("amis").(map[string]string) + + if len(amis) == 0 { + ui.Say("No AMI found in state, skipping fast-launch setup...") + return multistep.ActionContinue + } + + wg := &sync.WaitGroup{} + wg.Add(len(amis)) + + errWg := &sync.WaitGroup{} + errWg.Add(1) + + errCh := make(chan (error), 1) + var errs []error + go func() { + defer errWg.Done() + for err := range errCh { + errs = append(errs, err) + } + }() + + for region, ami := range amis { + ec2connif, err := common.GetRegionConn(s.AccessConfig, region) + if err != nil { + state.Put("error", fmt.Errorf("Failed to get connection to region %q: %s", region, err)) + return multistep.ActionHalt + } + + go func(region, ami string) { + defer wg.Done() + + // Casting is somewhat unsafe, but since the retryer below only + // accepts this type, and not ec2iface.EC2API, we can safely + // do this here, unless the `GetRegionConn` function evolves + // later, in which case this will fail. + ec2conn := ec2connif.(*ec2.EC2) + + ui.Say(fmt.Sprintf("Enabling fast boot for AMI %s in region %s", ami, region)) + + fastLaunchInput := s.prepareFastLaunchRequest(ami, region, state) + + // Create a timeout for the EnableFastLaunch call. + timeoutCtx, cancel := context.WithTimeout(ctx, time.Minute) + defer cancel() + + err = retry.Config{ + Tries: 5, + ShouldRetry: func(err error) bool { + log.Printf("Enabling fast launch failed: %s", err) + return true + }, + RetryDelay: (&retry.Backoff{InitialBackoff: 500 * time.Millisecond, MaxBackoff: 30 * time.Second, Multiplier: 2}).Linear, + }.Run(timeoutCtx, func(ctx context.Context) error { + var err error + _, err = ec2conn.EnableFastLaunch(fastLaunchInput) + return err + }) + if err != nil { + errCh <- fmt.Errorf("Error enabling fast boot for AMI in region %s: %s", region, err) + return + } + + // Wait for the image to become ready + ui.Say(fmt.Sprintf("Waiting for fast launch to become ready on AMI %q in region %s...", ami, region)) + waitErr := s.PollingConfig.WaitUntilFastLaunchEnabled(ctx, ec2conn, ami) + if waitErr != nil { + errCh <- fmt.Errorf("Failed to enable fast launch: %s", err) + return + } + + flStatus, err := ec2conn.DescribeFastLaunchImages(&ec2.DescribeFastLaunchImagesInput{ + ImageIds: []*string{ + &ami, + }, + }) + if err != nil { + errCh <- fmt.Errorf("Failed to get fast-launch status for AMI %q: %s", ami, err) + return + } + + for _, img := range flStatus.FastLaunchImages { + if *img.State != "enabled" { + errCh <- fmt.Errorf("Failed to enable fast-launch for AMI %q: %s", ami, *img.StateTransitionReason) + return + } + } + }(region, ami) + } + + wg.Wait() + close(errCh) + // Wait until we finished queueing the errors before continuing + // + // Otherwise we may end-up queueing an error and leaving the routine + // that processes with an error, and the error check below may execute + // before the error gets queued up, which may result in a build + // succeeding even if there was an error with the fast-launch on one AMI. + errWg.Wait() + + for _, err := range errs { + ui.Error(err.Error()) + } + + if errs != nil { + err := errors.New("Failed to enable fast-launch because of errors") + ui.Error(err.Error()) + state.Put("error", err) + return multistep.ActionHalt + } + + return multistep.ActionContinue +} + +func (s *stepEnableFastLaunch) prepareFastLaunchRequest(ami string, region string, state multistep.StateBag) *ec2.EnableFastLaunchInput { + fastLaunchInput := &ec2.EnableFastLaunchInput{ + ImageId: &ami, + } + + if s.MaxInstances > 0 { + mi := int64(s.MaxInstances) + fastLaunchInput.MaxParallelLaunches = &mi + } + + if s.ResourceCount > 0 { + rc := int64(s.ResourceCount) + fastLaunchInput.SnapshotConfiguration = &ec2.FastLaunchSnapshotConfigurationRequest{ + TargetResourceCount: &rc, + } + } + + templateIDsByRegion, ok := state.GetOk("launch_template_version") + if !ok { + log.Printf("[TRACE] no template specified for region %q", region) + return fastLaunchInput + } + + templateConfig, ok := templateIDsByRegion.(map[string]TemplateSpec)[region] + if !ok { + log.Printf("[TRACE] no template specified for region %q", region) + return fastLaunchInput + } + + fastLaunchInput.LaunchTemplate = &ec2.FastLaunchLaunchTemplateSpecificationRequest{ + LaunchTemplateId: &templateConfig.TemplateID, + Version: aws.String(fmt.Sprintf("%d", templateConfig.Version)), + } + + return fastLaunchInput +} + +func (s *stepEnableFastLaunch) Cleanup(state multistep.StateBag) {} diff --git a/builder/ebs/step_prepare_fast_launch_template.go b/builder/ebs/step_prepare_fast_launch_template.go new file mode 100644 index 000000000..273af1c22 --- /dev/null +++ b/builder/ebs/step_prepare_fast_launch_template.go @@ -0,0 +1,126 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package ebs + +import ( + "context" + "fmt" + "log" + + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go/service/ec2/ec2iface" + "github.com/hashicorp/packer-plugin-amazon/builder/common" + "github.com/hashicorp/packer-plugin-sdk/multistep" + packersdk "github.com/hashicorp/packer-plugin-sdk/packer" +) + +type stepPrepareFastLaunchTemplate struct { + AccessConfig *common.AccessConfig + AMISkipCreateImage bool + EnableFastLaunch bool + RegionTemplates []FastLaunchTemplateConfig +} + +type TemplateSpec struct { + TemplateID string + Version int +} + +func (s *stepPrepareFastLaunchTemplate) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { + ui := state.Get("ui").(packersdk.Ui) + + if s.AMISkipCreateImage { + ui.Say("Skipping fast-launch template setup...") + return multistep.ActionContinue + } + + if !s.EnableFastLaunch { + log.Printf("fast-boot disabled, no launch-template to set") + return multistep.ActionContinue + } + + if len(s.RegionTemplates) == 0 { + log.Printf("[INFO] no launch-template configured, will use defaults.") + return multistep.ActionContinue + } + + templateIDsByRegion := map[string]TemplateSpec{} + for _, templateSpec := range s.RegionTemplates { + region := templateSpec.Region + + if templateSpec.LaunchTemplateID == "" && templateSpec.LaunchTemplateName == "" { + log.Printf("[INFO] No fast-launch template specified for region %q", region) + continue + } + + ec2conn, err := common.GetRegionConn(s.AccessConfig, region) + if err != nil { + state.Put("error", fmt.Errorf("Failed to get connection to region %q: %s", region, err)) + return multistep.ActionHalt + } + + tmpl, err := getTemplate(ec2conn, templateSpec) + if err != nil { + ui.Error(fmt.Sprintf("Failed to get launch template from region %q: %s", region, err)) + state.Put("error", err) + return multistep.ActionHalt + } + + ts := TemplateSpec{ + TemplateID: *tmpl.LaunchTemplateId, + Version: templateSpec.LaunchTemplateVersion, + } + + log.Printf("found template in region %q: ID %q, name %q", region, *tmpl.LaunchTemplateId, *tmpl.LaunchTemplateName) + + if templateSpec.LaunchTemplateVersion == 0 { + ts.Version = int(*tmpl.LatestVersionNumber) + } + + if *tmpl.LatestVersionNumber < int64(templateSpec.LaunchTemplateVersion) { + err := fmt.Errorf("specified version (%d) is higher than the latest launch template version (%d) for region %q", + templateSpec.LaunchTemplateVersion, + tmpl.LatestVersionNumber, + region) + ui.Error(err.Error()) + state.Put("error", err) + return multistep.ActionHalt + } + + templateIDsByRegion[region] = ts + } + + state.Put("launch_template_version", templateIDsByRegion) + + return multistep.ActionContinue +} + +func getTemplate(ec2conn ec2iface.EC2API, templateSpec FastLaunchTemplateConfig) (*ec2.LaunchTemplate, error) { + requestInput := &ec2.DescribeLaunchTemplatesInput{} + + if templateSpec.LaunchTemplateID != "" { + requestInput.LaunchTemplateIds = []*string{&templateSpec.LaunchTemplateID} + } + if templateSpec.LaunchTemplateName != "" { + requestInput.LaunchTemplateNames = []*string{&templateSpec.LaunchTemplateName} + } + + lts, err := ec2conn.DescribeLaunchTemplates(requestInput) + if err != nil { + return nil, err + } + + tmpls := lts.LaunchTemplates + if len(tmpls) != 1 { + return nil, fmt.Errorf("failed to get launch template %q; received %d responses, expected only one to match", + templateSpec.LaunchTemplateID, + len(tmpls)) + } + + tmpl := tmpls[0] + + return tmpl, nil +} + +func (s *stepPrepareFastLaunchTemplate) Cleanup(state multistep.StateBag) {} diff --git a/builder/ebs/tags_acc_test.go b/builder/ebs/tags_acc_test.go index f023ab24a..c36cafb27 100644 --- a/builder/ebs/tags_acc_test.go +++ b/builder/ebs/tags_acc_test.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package ebs import ( diff --git a/builder/ebs/test-fixtures/interpolated_run_tags.json b/builder/ebs/test-fixtures/interpolated_run_tags.json index 0c8b6fd82..5fc09c5c0 100644 --- a/builder/ebs/test-fixtures/interpolated_run_tags.json +++ b/builder/ebs/test-fixtures/interpolated_run_tags.json @@ -10,7 +10,7 @@ "source_ami_filter": { "filters": { "virtualization-type": "hvm", - "name": "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*", + "name": "ubuntu/images/*ubuntu-jammy-22.04-amd64-server-*", "root-device-type": "ebs" }, "owners": [ diff --git a/builder/ebs/test-fixtures/interpolated_run_tags.pkr.hcl b/builder/ebs/test-fixtures/interpolated_run_tags.pkr.hcl index 0263133c7..1bdf759ef 100644 --- a/builder/ebs/test-fixtures/interpolated_run_tags.pkr.hcl +++ b/builder/ebs/test-fixtures/interpolated_run_tags.pkr.hcl @@ -1,6 +1,9 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + data "amazon-ami" "test" { filters = { - name = "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*" + name = "ubuntu/images/*ubuntu-jammy-22.04-amd64-server-*" root-device-type = "ebs" virtualization-type = "hvm" } diff --git a/builder/ebs/test-fixtures/ps_enable.ps b/builder/ebs/test-fixtures/ps_enable.ps new file mode 100644 index 000000000..275cd4a28 Binary files /dev/null and b/builder/ebs/test-fixtures/ps_enable.ps differ diff --git a/builder/ebs/test-fixtures/ssh-keys/ed25519_ssh_keypair.pkr.hcl b/builder/ebs/test-fixtures/ssh-keys/ed25519_ssh_keypair.pkr.hcl index 8faefd3ee..93ecb68cd 100644 --- a/builder/ebs/test-fixtures/ssh-keys/ed25519_ssh_keypair.pkr.hcl +++ b/builder/ebs/test-fixtures/ssh-keys/ed25519_ssh_keypair.pkr.hcl @@ -1,6 +1,9 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + data "amazon-ami" "test" { filters = { - name = "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*" + name = "ubuntu/images/*ubuntu-jammy-22.04-amd64-server-*" root-device-type = "ebs" virtualization-type = "hvm" } diff --git a/builder/ebs/test-fixtures/ssh-keys/rsa_sha2_only_server.pkr.hcl b/builder/ebs/test-fixtures/ssh-keys/rsa_sha2_only_server.pkr.hcl index 58a2a715b..1803072ba 100644 --- a/builder/ebs/test-fixtures/ssh-keys/rsa_sha2_only_server.pkr.hcl +++ b/builder/ebs/test-fixtures/ssh-keys/rsa_sha2_only_server.pkr.hcl @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + /* OpenSSH migrated the ssh-rsa key type, which historically used the ssh-rsa signature algorithm based on SHA-1, to the new rsa-sha2-256 and rsa-sha2-512 signature algorithms. diff --git a/builder/ebs/test-fixtures/ssh-keys/rsa_ssh_keypair.pkr.hcl b/builder/ebs/test-fixtures/ssh-keys/rsa_ssh_keypair.pkr.hcl index 3767fa544..2eaf121d0 100644 --- a/builder/ebs/test-fixtures/ssh-keys/rsa_ssh_keypair.pkr.hcl +++ b/builder/ebs/test-fixtures/ssh-keys/rsa_ssh_keypair.pkr.hcl @@ -1,6 +1,9 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + data "amazon-ami" "test" { filters = { - name = "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*" + name = "ubuntu/images/*ubuntu-jammy-22.04-amd64-server-*" root-device-type = "ebs" virtualization-type = "hvm" } diff --git a/builder/ebs/test-fixtures/unlimited-credits/burstable_instances.pkr.hcl b/builder/ebs/test-fixtures/unlimited-credits/burstable_instances.pkr.hcl index 18984b2bb..a638503bf 100644 --- a/builder/ebs/test-fixtures/unlimited-credits/burstable_instances.pkr.hcl +++ b/builder/ebs/test-fixtures/unlimited-credits/burstable_instances.pkr.hcl @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + variables { standardCPUCredit = "standard" unlimitedCPUCredit = "unlimited" diff --git a/builder/ebs/test-fixtures/unlimited-credits/burstable_spot_instances.pkr.hcl b/builder/ebs/test-fixtures/unlimited-credits/burstable_spot_instances.pkr.hcl index f6b92bc4d..d6fb1f8e1 100644 --- a/builder/ebs/test-fixtures/unlimited-credits/burstable_spot_instances.pkr.hcl +++ b/builder/ebs/test-fixtures/unlimited-credits/burstable_spot_instances.pkr.hcl @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + variables { standardCPUCredit = "standard" unlimitedCPUCredit = "unlimited" diff --git a/builder/ebssurrogate/block_device.go b/builder/ebssurrogate/block_device.go index 85f290456..bd5aee7d1 100644 --- a/builder/ebssurrogate/block_device.go +++ b/builder/ebssurrogate/block_device.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + //go:generate packer-sdc struct-markdown package ebssurrogate diff --git a/builder/ebssurrogate/builder.go b/builder/ebssurrogate/builder.go index 70670da77..fb16b0d58 100644 --- a/builder/ebssurrogate/builder.go +++ b/builder/ebssurrogate/builder.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + //go:generate packer-sdc struct-markdown //go:generate packer-sdc mapstructure-to-hcl2 -type Config,RootBlockDevice,BlockDevice @@ -78,11 +81,19 @@ type Config struct { // Base64 representation of the non-volatile UEFI variable store. For more information // see [AWS documentation](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/uefi-secure-boot-optionB.html). UefiData string `mapstructure:"uefi_data" required:"false"` - // Enforce version of the Instance Metadata Service on the built AMI. - // Valid options are unset (legacy) and `v2.0`. See the documentation on - // [IMDS](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html) - // for more information. Defaults to legacy. - IMDSSupport string `mapstructure:"imds_support" required:"false"` + // NitroTPM Support. Valid options are `v2.0`. See the documentation on + // [NitroTPM Support](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enable-nitrotpm-support-on-ami.html) for + // more information. Only enabled if a valid option is provided, otherwise ignored. + TpmSupport string `mapstructure:"tpm_support" required:"false"` + // Whether to use the CreateImage or RegisterImage API when creating the AMI. + // When set to `true`, the CreateImage API is used and will create the image + // from the instance itself, and inherit properties from the instance. + // When set to `false`, the RegisterImage API is used and the image is created using + // a snapshot of the specified EBS volume, and no properties are inherited from the instance. + // Defaults to `false`. + //Ref: https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateImage.html + // https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RegisterImage.html + UseCreateImage bool `mapstructure:"use_create_image" required:"false"` ctx interpolate.Context } @@ -185,20 +196,14 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) { errs = packersdk.MultiErrorAppend(errs, errors.New(`The only valid ami_architecture values are "arm64", "i386", "x86_64", or "x86_64_mac"`)) } - if b.config.IMDSSupport != "" && b.config.IMDSSupport != ec2.ImdsSupportValuesV20 { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf(`The only valid imds_support values are %q or the empty string`, ec2.ImdsSupportValuesV20)) + if b.config.TpmSupport != "" && b.config.TpmSupport != ec2.TpmSupportValuesV20 { + errs = packersdk.MultiErrorAppend(errs, fmt.Errorf(`The only valid tpm_support value is %q`, ec2.TpmSupportValuesV20)) } if b.config.BootMode != "" { - valid := false - for _, validBootMode := range []string{"legacy-bios", "uefi"} { - if validBootMode == b.config.BootMode { - valid = true - break - } - } - if !valid { - errs = packersdk.MultiErrorAppend(errs, errors.New(`The only valid boot_mode values are "legacy-bios" and "uefi"`)) + err := awscommon.IsValidBootMode(b.config.BootMode) + if err != nil { + errs = packersdk.MultiErrorAppend(errs, err) } } @@ -322,6 +327,52 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) amiDevices := b.config.AMIMappings.BuildEC2BlockDeviceMappings() launchDevices := b.config.LaunchMappings.BuildEC2BlockDeviceMappings() + var buildAmiStep multistep.Step + var volumeStep multistep.Step + + if b.config.UseCreateImage { + volumeStep = &StepSwapVolumes{ + PollingConfig: b.config.PollingConfig, + RootDevice: b.config.RootDevice, + LaunchDevices: launchDevices, + LaunchOmitMap: b.config.LaunchMappings.GetOmissions(), + Ctx: b.config.ctx, + } + + buildAmiStep = &StepCreateAMI{ + AMISkipBuildRegion: b.config.AMISkipBuildRegion, + RootDevice: b.config.RootDevice, + AMIDevices: amiDevices, + LaunchDevices: launchDevices, + PollingConfig: b.config.PollingConfig, + IsRestricted: b.config.IsChinaCloud() || b.config.IsGovCloud(), + Tags: b.config.RunTags, + Ctx: b.config.ctx, + } + } else { + volumeStep = &StepSnapshotVolumes{ + PollingConfig: b.config.PollingConfig, + LaunchDevices: launchDevices, + SnapshotOmitMap: b.config.LaunchMappings.GetOmissions(), + SnapshotTags: b.config.SnapshotTags, + Ctx: b.config.ctx, + } + buildAmiStep = &StepRegisterAMI{ + RootDevice: b.config.RootDevice, + AMIDevices: amiDevices, + LaunchDevices: launchDevices, + EnableAMISriovNetSupport: b.config.AMISriovNetSupport, + EnableAMIENASupport: b.config.AMIENASupport, + Architecture: b.config.Architecture, + LaunchOmitMap: b.config.LaunchMappings.GetOmissions(), + AMISkipBuildRegion: b.config.AMISkipBuildRegion, + PollingConfig: b.config.PollingConfig, + BootMode: b.config.BootMode, + UefiData: b.config.UefiData, + TpmSupport: b.config.TpmSupport, + } + } + // Build the steps steps := []multistep.Step{ &awscommon.StepPreValidate{ @@ -340,13 +391,15 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) AMIVirtType: b.config.AMIVirtType, }, &awscommon.StepNetworkInfo{ - VpcId: b.config.VpcId, - VpcFilter: b.config.VpcFilter, - SecurityGroupIds: b.config.SecurityGroupIds, - SecurityGroupFilter: b.config.SecurityGroupFilter, - SubnetId: b.config.SubnetId, - SubnetFilter: b.config.SubnetFilter, - AvailabilityZone: b.config.AvailabilityZone, + VpcId: b.config.VpcId, + VpcFilter: b.config.VpcFilter, + SecurityGroupIds: b.config.SecurityGroupIds, + SecurityGroupFilter: b.config.SecurityGroupFilter, + SubnetId: b.config.SubnetId, + SubnetFilter: b.config.SubnetFilter, + AvailabilityZone: b.config.AvailabilityZone, + AssociatePublicIpAddress: b.config.AssociatePublicIpAddress, + RequestedMachineType: b.config.InstanceType, }, &awscommon.StepKeyPair{ Debug: b.config.PackerDebug, @@ -368,6 +421,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) Ctx: b.config.ctx, }, &awscommon.StepIamInstanceProfile{ + PollingConfig: b.config.PollingConfig, IamInstanceProfile: b.config.IamInstanceProfile, SkipProfileValidation: b.config.SkipProfileValidation, TemporaryIamInstanceProfilePolicyDocument: b.config.TemporaryIamInstanceProfilePolicyDocument, @@ -389,6 +443,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) LocalPortNumber: b.config.SessionManagerPort, RemotePortNumber: b.config.Comm.Port(), SSMAgentEnabled: b.config.SSMAgentEnabled(), + SSHConfig: &b.config.Comm.SSH, }, &awscommon.StepEC2InstanceConnect{ AWSSession: session, @@ -427,13 +482,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) EnableAMISriovNetSupport: b.config.AMISriovNetSupport, EnableAMIENASupport: b.config.AMIENASupport, }, - &StepSnapshotVolumes{ - PollingConfig: b.config.PollingConfig, - LaunchDevices: launchDevices, - SnapshotOmitMap: b.config.LaunchMappings.GetOmissions(), - SnapshotTags: b.config.SnapshotTags, - Ctx: b.config.ctx, - }, + volumeStep, &awscommon.StepDeregisterAMI{ AccessConfig: &b.config.AccessConfig, ForceDeregister: b.config.AMIForceDeregister, @@ -441,20 +490,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) AMIName: b.config.AMIName, Regions: b.config.AMIRegions, }, - &StepRegisterAMI{ - RootDevice: b.config.RootDevice, - AMIDevices: amiDevices, - LaunchDevices: launchDevices, - EnableAMISriovNetSupport: b.config.AMISriovNetSupport, - EnableAMIENASupport: b.config.AMIENASupport, - Architecture: b.config.Architecture, - LaunchOmitMap: b.config.LaunchMappings.GetOmissions(), - AMISkipBuildRegion: b.config.AMISkipBuildRegion, - PollingConfig: b.config.PollingConfig, - BootMode: b.config.BootMode, - UefiData: b.config.UefiData, - IMDSSupport: b.config.IMDSSupport, - }, + buildAmiStep, &awscommon.StepAMIRegionCopy{ AccessConfig: &b.config.AccessConfig, Regions: b.config.AMIRegions, @@ -465,6 +501,10 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) OriginalRegion: *ec2conn.Config.Region, AMISkipBuildRegion: b.config.AMISkipBuildRegion, }, + &awscommon.StepEnableDeprecation{ + AccessConfig: &b.config.AccessConfig, + DeprecationTime: b.config.DeprecationTime, + }, &awscommon.StepModifyAMIAttributes{ Description: b.config.AMIDescription, Users: b.config.AMIUsers, @@ -474,6 +514,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) ProductCodes: b.config.AMIProductCodes, SnapshotUsers: b.config.SnapshotUsers, SnapshotGroups: b.config.SnapshotGroups, + IMDSSupport: b.config.AMIIMDSSupport, Ctx: b.config.ctx, GeneratedData: generatedData, }, diff --git a/builder/ebssurrogate/builder.hcl2spec.go b/builder/ebssurrogate/builder.hcl2spec.go index 58d3d5ed7..b4b4cf148 100644 --- a/builder/ebssurrogate/builder.hcl2spec.go +++ b/builder/ebssurrogate/builder.hcl2spec.go @@ -196,6 +196,8 @@ type FlatConfig struct { AMIKmsKeyId *string `mapstructure:"kms_key_id" required:"false" cty:"kms_key_id" hcl:"kms_key_id"` AMIRegionKMSKeyIDs map[string]string `mapstructure:"region_kms_key_ids" required:"false" cty:"region_kms_key_ids" hcl:"region_kms_key_ids"` AMISkipBuildRegion *bool `mapstructure:"skip_save_build_region" cty:"skip_save_build_region" hcl:"skip_save_build_region"` + AMIIMDSSupport *string `mapstructure:"imds_support" required:"false" cty:"imds_support" hcl:"imds_support"` + DeprecationTime *string `mapstructure:"deprecate_at" cty:"deprecate_at" hcl:"deprecate_at"` SnapshotTags map[string]string `mapstructure:"snapshot_tags" required:"false" cty:"snapshot_tags" hcl:"snapshot_tags"` SnapshotTag []config.FlatKeyValue `mapstructure:"snapshot_tag" required:"false" cty:"snapshot_tag" hcl:"snapshot_tag"` SnapshotUsers []string `mapstructure:"snapshot_users" required:"false" cty:"snapshot_users" hcl:"snapshot_users"` @@ -208,7 +210,8 @@ type FlatConfig struct { Architecture *string `mapstructure:"ami_architecture" required:"false" cty:"ami_architecture" hcl:"ami_architecture"` BootMode *string `mapstructure:"boot_mode" required:"false" cty:"boot_mode" hcl:"boot_mode"` UefiData *string `mapstructure:"uefi_data" required:"false" cty:"uefi_data" hcl:"uefi_data"` - IMDSSupport *string `mapstructure:"imds_support" required:"false" cty:"imds_support" hcl:"imds_support"` + TpmSupport *string `mapstructure:"tpm_support" required:"false" cty:"tpm_support" hcl:"tpm_support"` + UseCreateImage *bool `mapstructure:"use_create_image" required:"false" cty:"use_create_image" hcl:"use_create_image"` } // FlatMapstructure returns a new FlatConfig. @@ -362,6 +365,8 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "kms_key_id": &hcldec.AttrSpec{Name: "kms_key_id", Type: cty.String, Required: false}, "region_kms_key_ids": &hcldec.AttrSpec{Name: "region_kms_key_ids", Type: cty.Map(cty.String), Required: false}, "skip_save_build_region": &hcldec.AttrSpec{Name: "skip_save_build_region", Type: cty.Bool, Required: false}, + "imds_support": &hcldec.AttrSpec{Name: "imds_support", Type: cty.String, Required: false}, + "deprecate_at": &hcldec.AttrSpec{Name: "deprecate_at", Type: cty.String, Required: false}, "snapshot_tags": &hcldec.AttrSpec{Name: "snapshot_tags", Type: cty.Map(cty.String), Required: false}, "snapshot_tag": &hcldec.BlockListSpec{TypeName: "snapshot_tag", Nested: hcldec.ObjectSpec((*config.FlatKeyValue)(nil).HCL2Spec())}, "snapshot_users": &hcldec.AttrSpec{Name: "snapshot_users", Type: cty.List(cty.String), Required: false}, @@ -374,7 +379,8 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "ami_architecture": &hcldec.AttrSpec{Name: "ami_architecture", Type: cty.String, Required: false}, "boot_mode": &hcldec.AttrSpec{Name: "boot_mode", Type: cty.String, Required: false}, "uefi_data": &hcldec.AttrSpec{Name: "uefi_data", Type: cty.String, Required: false}, - "imds_support": &hcldec.AttrSpec{Name: "imds_support", Type: cty.String, Required: false}, + "tpm_support": &hcldec.AttrSpec{Name: "tpm_support", Type: cty.String, Required: false}, + "use_create_image": &hcldec.AttrSpec{Name: "use_create_image", Type: cty.Bool, Required: false}, } return s } diff --git a/builder/ebssurrogate/builder_acc_test.go b/builder/ebssurrogate/builder_acc_test.go index 0a8da36da..e123c1332 100644 --- a/builder/ebssurrogate/builder_acc_test.go +++ b/builder/ebssurrogate/builder_acc_test.go @@ -1,14 +1,32 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package ebssurrogate import ( "fmt" + "os" "os/exec" "testing" + "time" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/hashicorp/packer-plugin-amazon/builder/common" amazon_acc "github.com/hashicorp/packer-plugin-amazon/builder/ebs/acceptance" "github.com/hashicorp/packer-plugin-sdk/acctest" ) +func testEC2Conn(region string) (*ec2.EC2, error) { + access := &common.AccessConfig{RawRegion: region} + session, err := access.Session() + if err != nil { + return nil, err + } + + return ec2.New(session), nil +} + func TestAccBuilder_EbssurrogateBasic(t *testing.T) { ami := amazon_acc.AMIHelper{ Region: "us-east-1", @@ -71,6 +89,161 @@ func TestAccBuilder_EbssurrogateBasic_forceIMDSv2(t *testing.T) { acctest.TestPlugin(t, testCase) } +func TestAccBuilder_Ebssurrogate_SSHPrivateKeyFile_SSM(t *testing.T) { + if os.Getenv(acctest.TestEnvVar) == "" { + t.Skipf("Acceptance tests skipped unless env '%s' set", + acctest.TestEnvVar) + return + } + + ami := amazon_acc.AMIHelper{ + Region: "us-east-1", + Name: fmt.Sprintf("packer-ebssurrogate-pkey-file-acc-test-%d", time.Now().Unix()), + } + + sshFile, err := amazon_acc.GenerateSSHPrivateKeyFile() + if err != nil { + t.Fatalf("failed to generate SSH key file: %s", err) + } + + defer os.Remove(sshFile) + + testcase := &acctest.PluginTestCase{ + Name: "amazon-ebssurrogate_test_private_key_file", + Template: fmt.Sprintf(testPrivateKeyFile, ami.Name, sshFile), + Check: func(buildCommand *exec.Cmd, logfile string) error { + if buildCommand.ProcessState.ExitCode() != 0 { + return fmt.Errorf("Bad exit code. Logfile: %s", logfile) + } + return nil + }, + } + + acctest.TestPlugin(t, testcase) +} + +func TestAccBuilder_EbssurrogateUseCreateImageTrue(t *testing.T) { + ami := amazon_acc.AMIHelper{ + Region: "us-east-1", + Name: "ebs-image-method-create-acc-test", + } + testCase := &acctest.PluginTestCase{ + Name: "amazon-ebssurrogate_image_method_create_test", + Template: fmt.Sprintf(testBuilderAccUseCreateImageTrue, ami.Name), + Teardown: func() error { + return ami.CleanUpAmi() + }, + Check: func(buildCommand *exec.Cmd, logfile string) error { + if buildCommand.ProcessState != nil { + if buildCommand.ProcessState.ExitCode() != 0 { + return fmt.Errorf("Bad exit code. Logfile: %s", logfile) + } + } + return nil + }, + } + acctest.TestPlugin(t, testCase) +} + +func TestAccBuilder_EbssurrogateUseCreateImageFalse(t *testing.T) { + ami := amazon_acc.AMIHelper{ + Region: "us-east-1", + Name: "ebs-image-method-register-acc-test", + } + testCase := &acctest.PluginTestCase{ + Name: "amazon-ebssurrogate_image_method_register_test", + Template: fmt.Sprintf(testBuilderAccUseCreateImageFalse, ami.Name), + Teardown: func() error { + return ami.CleanUpAmi() + }, + Check: func(buildCommand *exec.Cmd, logfile string) error { + if buildCommand.ProcessState != nil { + if buildCommand.ProcessState.ExitCode() != 0 { + return fmt.Errorf("Bad exit code. Logfile: %s", logfile) + } + } + return nil + }, + } + acctest.TestPlugin(t, testCase) +} + +func TestAccBuilder_EbssurrogateUseCreateImageOptional(t *testing.T) { + ami := amazon_acc.AMIHelper{ + Region: "us-east-1", + Name: "ebs-image-method-empty-acc-test", + } + testCase := &acctest.PluginTestCase{ + Name: "amazon-ebssurrogate_image_method_empty_test", + Template: fmt.Sprintf(testBuilderAccUseCreateImageOptional, ami.Name), + Teardown: func() error { + return ami.CleanUpAmi() + }, + Check: func(buildCommand *exec.Cmd, logfile string) error { + if buildCommand.ProcessState != nil { + if buildCommand.ProcessState.ExitCode() != 0 { + return fmt.Errorf("Bad exit code. Logfile: %s", logfile) + } + } + return nil + }, + } + acctest.TestPlugin(t, testCase) +} + +func TestAccBuilder_EbssurrogateWithAMIDeprecate(t *testing.T) { + ami := amazon_acc.AMIHelper{ + Region: "us-east-1", + Name: fmt.Sprintf("ebssurrogate-deprecate-at-acctest-%d", time.Now().Unix()), + } + testCase := &acctest.PluginTestCase{ + Name: "ebssurrogate - deprecate at set", + Template: fmt.Sprintf(testBuilderAcc_WithDeprecateAt, ami.Name, time.Now().Add(time.Hour).UTC().Format("2006-01-02T15:04:05Z")), + Teardown: func() error { + return ami.CleanUpAmi() + }, + Check: func(buildCommand *exec.Cmd, logfile string) error { + if buildCommand.ProcessState != nil { + if buildCommand.ProcessState.ExitCode() != 0 { + return fmt.Errorf("Bad exit code. Logfile: %s", logfile) + } + + conn, err := testEC2Conn("us-east-1") + if err != nil { + return fmt.Errorf("failed to get connection to us-east-1: %s", err) + } + + out, err := conn.DescribeImages(&ec2.DescribeImagesInput{ + Filters: []*ec2.Filter{{ + Name: aws.String("name"), + Values: []*string{&ami.Name}, + }}, + }) + if err != nil { + return fmt.Errorf("unable to describe images: %s", err) + } + + if len(out.Images) != 1 { + return fmt.Errorf("got %d images, should have been one", len(out.Images)) + } + + img := out.Images[0] + if img.DeprecationTime == nil { + return fmt.Errorf("no depreciation time set for image %s", ami.Name) + } + + if *img.DeprecationTime == "" { + return fmt.Errorf("no depreciation time set for image %s", ami.Name) + } + + return nil + } + return nil + }, + } + acctest.TestPlugin(t, testCase) +} + const testBuilderAccBasic = ` source "amazon-ebssurrogate" "test" { ami_name = "%s" @@ -127,3 +300,150 @@ build { sources = ["amazon-ebssurrogate.test"] } ` + +const testPrivateKeyFile = ` +source "amazon-ebssurrogate" "test" { + ami_name = "%s" + source_ami = "ami-0b5eea76982371e91" # Amazon Linux 2 AMI - kernel 5.10 + instance_type = "m3.medium" + region = "us-east-1" + ssh_username = "ec2-user" + ssh_interface = "session_manager" + iam_instance_profile = "SSMInstanceProfile" + communicator = "ssh" + ssh_private_key_file = "%s" + launch_block_device_mappings { + device_name = "/dev/xvda" + delete_on_termination = true + volume_size = 8 + volume_type = "gp2" + } + ami_virtualization_type = "hvm" + ami_root_device { + source_device_name = "/dev/xvda" + device_name = "/dev/sda1" + delete_on_termination = true + volume_size = 8 + volume_type = "gp2" + } +} + +build { + sources = ["amazon-ebssurrogate.test"] +} +` + +const testBuilderAccUseCreateImageTrue = ` +source "amazon-ebssurrogate" "test" { + ami_name = "%s" + region = "us-east-1" + instance_type = "m3.medium" + source_ami = "ami-76b2a71e" + ssh_username = "ubuntu" + use_create_image = true + launch_block_device_mappings { + device_name = "/dev/xvda" + delete_on_termination = true + volume_size = 8 + volume_type = "gp2" + } + ami_virtualization_type = "hvm" + ami_root_device { + source_device_name = "/dev/xvda" + device_name = "/dev/sda1" + delete_on_termination = true + volume_size = 8 + volume_type = "gp2" + } +} + +build { + sources = ["amazon-ebssurrogate.test"] +} +` + +const testBuilderAccUseCreateImageFalse = ` +source "amazon-ebssurrogate" "test" { + ami_name = "%s" + region = "us-east-1" + instance_type = "m3.medium" + source_ami = "ami-76b2a71e" + ssh_username = "ubuntu" + use_create_image = false + launch_block_device_mappings { + device_name = "/dev/xvda" + delete_on_termination = true + volume_size = 8 + volume_type = "gp2" + } + ami_virtualization_type = "hvm" + ami_root_device { + source_device_name = "/dev/xvda" + device_name = "/dev/sda1" + delete_on_termination = true + volume_size = 8 + volume_type = "gp2" + } +} + +build { + sources = ["amazon-ebssurrogate.test"] +} +` + +const testBuilderAccUseCreateImageOptional = ` +source "amazon-ebssurrogate" "test" { + ami_name = "%s" + region = "us-east-1" + instance_type = "m3.medium" + source_ami = "ami-76b2a71e" + ssh_username = "ubuntu" + launch_block_device_mappings { + device_name = "/dev/xvda" + delete_on_termination = true + volume_size = 8 + volume_type = "gp2" + } + ami_virtualization_type = "hvm" + ami_root_device { + source_device_name = "/dev/xvda" + device_name = "/dev/sda1" + delete_on_termination = true + volume_size = 8 + volume_type = "gp2" + } +} + +build { + sources = ["amazon-ebssurrogate.test"] +} +` + +const testBuilderAcc_WithDeprecateAt = ` +source "amazon-ebssurrogate" "test" { + ami_name = "%s" + region = "us-east-1" + instance_type = "m3.medium" + source_ami = "ami-76b2a71e" + ssh_username = "ubuntu" + launch_block_device_mappings { + device_name = "/dev/xvda" + delete_on_termination = true + volume_size = 8 + volume_type = "gp2" + } + ami_virtualization_type = "hvm" + ami_root_device { + source_device_name = "/dev/xvda" + device_name = "/dev/sda1" + delete_on_termination = true + volume_size = 8 + volume_type = "gp2" + } + deprecate_at = "%s" +} + +build { + sources = ["amazon-ebssurrogate.test"] +} +` diff --git a/builder/ebssurrogate/builder_test.go b/builder/ebssurrogate/builder_test.go index f063a3163..83910f337 100644 --- a/builder/ebssurrogate/builder_test.go +++ b/builder/ebssurrogate/builder_test.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package ebssurrogate import ( @@ -240,3 +243,64 @@ func TestBuilderPrepare_IMDSSupportValue(t *testing.T) { }) } } + +func TestBuilderPrepare_TpmSupportValue(t *testing.T) { + tests := []struct { + name string + optValue string + expectError bool + }{ + { + name: "OK - no value set", + optValue: "", + expectError: false, + }, + { + name: "OK - v2.0", + optValue: "v2.0", + expectError: false, + }, + { + name: "Error - bad value set", + optValue: "v3.0", + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + config := testConfig() + config["ami_name"] = "name" + config["ami_virtualization_type"] = "kvm" + + config["tpm_support"] = tt.optValue + + b := &Builder{} + // Basic configuration + b.config.RootDevice = RootBlockDevice{ + SourceDeviceName: "device name", + DeviceName: "device name", + } + b.config.LaunchMappings = BlockDevices{ + BlockDevice{ + BlockDevice: common.BlockDevice{ + DeviceName: "device name", + }, + OmitFromArtifact: false, + }, + } + + _, _, err := b.Prepare(config) + if err != nil && !tt.expectError { + t.Fatalf("got unexpected error: %s", err) + } + if err == nil && tt.expectError { + t.Fatalf("expected an error, got a success instead") + } + + if err != nil { + t.Logf("OK: b.Prepare produced expected error: %s", err) + } + }) + } +} diff --git a/builder/ebssurrogate/root_block_device.go b/builder/ebssurrogate/root_block_device.go index 997539ccb..0373dfbf1 100644 --- a/builder/ebssurrogate/root_block_device.go +++ b/builder/ebssurrogate/root_block_device.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + //go:generate packer-sdc struct-markdown package ebssurrogate diff --git a/builder/ebssurrogate/step_create_ami.go b/builder/ebssurrogate/step_create_ami.go new file mode 100644 index 000000000..36a1b37d9 --- /dev/null +++ b/builder/ebssurrogate/step_create_ami.go @@ -0,0 +1,250 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package ebssurrogate + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + awscommon "github.com/hashicorp/packer-plugin-amazon/builder/common" + "github.com/hashicorp/packer-plugin-amazon/builder/common/awserrors" + "github.com/hashicorp/packer-plugin-sdk/multistep" + packersdk "github.com/hashicorp/packer-plugin-sdk/packer" + "github.com/hashicorp/packer-plugin-sdk/random" + "github.com/hashicorp/packer-plugin-sdk/retry" + "github.com/hashicorp/packer-plugin-sdk/template/interpolate" +) + +type StepCreateAMI struct { + PollingConfig *awscommon.AWSPollingConfig + RootDevice RootBlockDevice + AMIDevices []*ec2.BlockDeviceMapping + LaunchDevices []*ec2.BlockDeviceMapping + LaunchOmitMap map[string]bool + image *ec2.Image + AMISkipBuildRegion bool + IsRestricted bool + Ctx interpolate.Context + Tags map[string]string +} + +func (s *StepCreateAMI) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { + config := state.Get("config").(*Config) + ec2conn := state.Get("ec2").(*ec2.EC2) + instance := state.Get("instance").(*ec2.Instance) + ui := state.Get("ui").(packersdk.Ui) + + blockDevices := s.combineDevices() + + // Create the image + amiName := config.AMIName + state.Put("intermediary_image", false) + if config.AMIEncryptBootVolume.True() || s.AMISkipBuildRegion { + state.Put("intermediary_image", true) + + // From AWS SDK docs: You can encrypt a copy of an unencrypted snapshot, + // but you cannot use it to create an unencrypted copy of an encrypted + // snapshot. Your default CMK for EBS is used unless you specify a + // non-default key using KmsKeyId. + + // If encrypt_boot is nil or true, we need to create a temporary image + // so that in step_region_copy, we can copy it with the correct + // encryption + amiName = random.AlphaNum(7) + } + + ui.Say(fmt.Sprintf("Creating AMI %s from instance %s", amiName, *instance.InstanceId)) + createOpts := &ec2.CreateImageInput{ + InstanceId: instance.InstanceId, + Name: &amiName, + BlockDeviceMappings: blockDevices, + } + + if !s.IsRestricted { + ec2Tags, err := awscommon.TagMap(s.Tags).EC2Tags(s.Ctx, *ec2conn.Config.Region, state) + if err != nil { + err := fmt.Errorf("Error tagging AMI: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + createOpts.TagSpecifications = ec2Tags.TagSpecifications(ec2.ResourceTypeImage, ec2.ResourceTypeSnapshot) + } + + var createResp *ec2.CreateImageOutput + + // Create a timeout for the CreateImage call. + timeoutCtx, cancel := context.WithTimeout(ctx, time.Minute*15) + defer cancel() + + err := retry.Config{ + Tries: 0, + ShouldRetry: func(err error) bool { + return awserrors.Matches(err, "InvalidParameterValue", "Instance is not in state") + }, + RetryDelay: (&retry.Backoff{InitialBackoff: 200 * time.Millisecond, MaxBackoff: 30 * time.Second, Multiplier: 2}).Linear, + }.Run(timeoutCtx, func(ctx context.Context) error { + var err error + createResp, err = ec2conn.CreateImage(createOpts) + return err + }) + if err != nil { + err := fmt.Errorf("Error creating AMI: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + // Set the AMI ID in the state + ui.Message(fmt.Sprintf("AMI: %s", *createResp.ImageId)) + amis := make(map[string]string) + amis[*ec2conn.Config.Region] = *createResp.ImageId + state.Put("amis", amis) + + // Wait for the image to become ready + ui.Say("Waiting for AMI to become ready...") + if waitErr := s.PollingConfig.WaitUntilAMIAvailable(ctx, ec2conn, *createResp.ImageId); waitErr != nil { + // waitErr should get bubbled up if the issue is a wait timeout + err := fmt.Errorf("Error waiting for AMI: %s", waitErr) + imResp, imerr := ec2conn.DescribeImages(&ec2.DescribeImagesInput{ImageIds: []*string{createResp.ImageId}}) + if imerr != nil { + // If there's a failure describing images, bubble that error up too, but don't erase the waitErr. + log.Printf("DescribeImages call was unable to determine reason waiting for AMI failed: %s", imerr) + err = fmt.Errorf("Unknown error waiting for AMI; %s. DescribeImages returned an error: %s", waitErr, imerr) + } + if imResp != nil && len(imResp.Images) > 0 { + // Finally, if there's a stateReason, store that with the wait err + image := imResp.Images[0] + if image != nil { + stateReason := image.StateReason + if stateReason != nil { + err = fmt.Errorf("Error waiting for AMI: %s. DescribeImages returned the state reason: %s", waitErr, stateReason) + } + } + } + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + imagesResp, err := ec2conn.DescribeImages(&ec2.DescribeImagesInput{ImageIds: []*string{createResp.ImageId}}) + if err != nil { + err := fmt.Errorf("Error searching for AMI: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + s.image = imagesResp.Images[0] + + snapshots := make(map[string][]string) + for _, blockDeviceMapping := range imagesResp.Images[0].BlockDeviceMappings { + if blockDeviceMapping.Ebs != nil && blockDeviceMapping.Ebs.SnapshotId != nil { + + snapshots[*ec2conn.Config.Region] = append(snapshots[*ec2conn.Config.Region], *blockDeviceMapping.Ebs.SnapshotId) + } + } + state.Put("snapshots", snapshots) + + return multistep.ActionContinue +} + +func (s *StepCreateAMI) combineDevices() []*ec2.BlockDeviceMapping { + devices := map[string]*ec2.BlockDeviceMapping{} + + for _, device := range s.AMIDevices { + devices[*device.DeviceName] = device + } + + // Devices in launch_block_device_mappings override any with + // the same name in ami_block_device_mappings + // If launch device name is equal to Root SourceDeviceName + // then set the device's deviceName to RootDevice.DeviceName from root ami_root_device + // and overwrite / add the device in the devices map + for _, device := range s.LaunchDevices { + // Skip devices we've flagged for omission + omit, ok := s.LaunchOmitMap[*device.DeviceName] + if ok && omit { + continue + } + + // Use root device name for the new source root device + if *device.DeviceName == s.RootDevice.SourceDeviceName { + device.DeviceName = aws.String(s.RootDevice.DeviceName) + } + devices[*device.DeviceName] = device + } + + blockDevices := []*ec2.BlockDeviceMapping{} + for _, device := range devices { + + blockDevices = append(blockDevices, device) + } + return blockDevices +} + +func (s *StepCreateAMI) Cleanup(state multistep.StateBag) { + if s.image == nil { + return + } + + _, cancelled := state.GetOk(multistep.StateCancelled) + _, halted := state.GetOk(multistep.StateHalted) + if !cancelled && !halted { + return + } + + ec2conn := state.Get("ec2").(*ec2.EC2) + ui := state.Get("ui").(packersdk.Ui) + + ui.Say("Deregistering the AMI and deleting associated snapshots because " + + "of cancellation, or error...") + + resp, err := ec2conn.DescribeImages(&ec2.DescribeImagesInput{ + ImageIds: []*string{s.image.ImageId}, + }) + + if err != nil { + err := fmt.Errorf("Error describing AMI: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return + } + + // Deregister image by name. + for _, i := range resp.Images { + _, err := ec2conn.DeregisterImage(&ec2.DeregisterImageInput{ + ImageId: i.ImageId, + }) + + if err != nil { + err := fmt.Errorf("Error deregistering existing AMI: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return + } + ui.Say(fmt.Sprintf("Deregistered AMI id: %s", *i.ImageId)) + + // Delete snapshot(s) by image + for _, b := range i.BlockDeviceMappings { + if b.Ebs != nil && aws.StringValue(b.Ebs.SnapshotId) != "" { + _, err := ec2conn.DeleteSnapshot(&ec2.DeleteSnapshotInput{ + SnapshotId: b.Ebs.SnapshotId, + }) + + if err != nil { + err := fmt.Errorf("Error deleting existing snapshot: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return + } + ui.Say(fmt.Sprintf("Deleted snapshot: %s", *b.Ebs.SnapshotId)) + } + } + } +} diff --git a/builder/ebssurrogate/step_register_ami.go b/builder/ebssurrogate/step_register_ami.go index 48aac9fe4..275386426 100644 --- a/builder/ebssurrogate/step_register_ami.go +++ b/builder/ebssurrogate/step_register_ami.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package ebssurrogate import ( @@ -27,7 +30,7 @@ type StepRegisterAMI struct { AMISkipBuildRegion bool BootMode string UefiData string - IMDSSupport string + TpmSupport string } func (s *StepRegisterAMI) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { @@ -81,8 +84,8 @@ func (s *StepRegisterAMI) Run(ctx context.Context, state multistep.StateBag) mul if s.UefiData != "" { registerOpts.UefiData = aws.String(s.UefiData) } - if s.IMDSSupport != "" { - registerOpts.ImdsSupport = aws.String(s.IMDSSupport) + if s.TpmSupport != "" { + registerOpts.TpmSupport = aws.String(s.TpmSupport) } registerResp, err := ec2conn.RegisterImage(registerOpts) if err != nil { diff --git a/builder/ebssurrogate/step_register_ami_test.go b/builder/ebssurrogate/step_register_ami_test.go index 2973f3a9e..8de563709 100644 --- a/builder/ebssurrogate/step_register_ami_test.go +++ b/builder/ebssurrogate/step_register_ami_test.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package ebssurrogate import ( diff --git a/builder/ebssurrogate/step_snapshot_volumes.go b/builder/ebssurrogate/step_snapshot_volumes.go index fba4ac444..e4239c12c 100644 --- a/builder/ebssurrogate/step_snapshot_volumes.go +++ b/builder/ebssurrogate/step_snapshot_volumes.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package ebssurrogate import ( @@ -18,7 +21,8 @@ import ( // StepSnapshotVolumes creates snapshots of the created volumes. // // Produces: -// snapshot_ids map[string]string - IDs of the created snapshots +// +// snapshot_ids map[string]string - IDs of the created snapshots type StepSnapshotVolumes struct { PollingConfig *awscommon.AWSPollingConfig LaunchDevices []*ec2.BlockDeviceMapping diff --git a/builder/ebssurrogate/step_swap_volumes.go b/builder/ebssurrogate/step_swap_volumes.go new file mode 100644 index 000000000..7a19c02b2 --- /dev/null +++ b/builder/ebssurrogate/step_swap_volumes.go @@ -0,0 +1,117 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package ebssurrogate + +import ( + "context" + "fmt" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + awscommon "github.com/hashicorp/packer-plugin-amazon/builder/common" + "github.com/hashicorp/packer-plugin-sdk/multistep" + packersdk "github.com/hashicorp/packer-plugin-sdk/packer" + "github.com/hashicorp/packer-plugin-sdk/template/interpolate" +) + +// StepSwapVolumes detaches omitted volumes and original root volume and reattaches +// the new root volume specified by ami_root_device.source_device_name. +type StepSwapVolumes struct { + PollingConfig *awscommon.AWSPollingConfig + RootDevice RootBlockDevice + LaunchDevices []*ec2.BlockDeviceMapping + LaunchOmitMap map[string]bool + Ctx interpolate.Context +} + +func (s *StepSwapVolumes) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { + ec2conn := state.Get("ec2").(*ec2.EC2) + ui := state.Get("ui").(packersdk.Ui) + instance := state.Get("instance").(*ec2.Instance) + + // Describe the instance + input := &ec2.DescribeInstancesInput{ + InstanceIds: []*string{ + aws.String(*instance.InstanceId), + }, + } + + result, err := ec2conn.DescribeInstances(input) + if err != nil { + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + deviceToVolumeMap := make(map[string]string) + + // Iterate through block device mappings and populate the map + for _, reservation := range result.Reservations { + for _, instance := range reservation.Instances { + for _, blockDevice := range instance.BlockDeviceMappings { + deviceToVolumeMap[*blockDevice.DeviceName] = *blockDevice.Ebs.VolumeId + } + } + } + + for deviceName, volumeID := range deviceToVolumeMap { + omit, ok := s.LaunchOmitMap[deviceName] + if ok && omit { + ui.Say(fmt.Sprintf("Detaching Ommitted EBS Device Name: %s, Volume ID: %s\n", deviceName, volumeID)) + err = s.detachVolume(ctx, ec2conn, deviceName, volumeID) + } else if deviceName == s.RootDevice.DeviceName || deviceName == s.RootDevice.SourceDeviceName || deviceName == "/dev/sda1" { + ui.Say(fmt.Sprintf("Detaching Root EBS Device Name: %s, Volume ID: %s\n", deviceName, volumeID)) + err = s.detachVolume(ctx, ec2conn, deviceName, volumeID) + } else { + ui.Say(fmt.Sprintf("Skip Detach of EBS Device Name: %s, Volume ID: %s\n", deviceName, volumeID)) + } + + if err != nil { + err := fmt.Errorf("error detaching volume: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + } + + rootVolumeId := aws.String(deviceToVolumeMap[s.RootDevice.SourceDeviceName]) + rootDeviceName := aws.String(s.RootDevice.DeviceName) + ui.Say(fmt.Sprintf("Attaching Root EBS Device Name %s, Volume ID: %s", *rootDeviceName, *rootVolumeId)) + + _, err = ec2conn.AttachVolume(&ec2.AttachVolumeInput{ + InstanceId: instance.InstanceId, + VolumeId: rootVolumeId, + Device: rootDeviceName, + }) + + if err != nil { + err := fmt.Errorf("error attaching volume: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + // Wait for the volume to become attached + err = s.PollingConfig.WaitUntilVolumeAttached(ctx, ec2conn, *rootVolumeId) + if err != nil { + err := fmt.Errorf("error waiting for volume: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + return multistep.ActionContinue +} + +func (s *StepSwapVolumes) detachVolume(ctx context.Context, ec2conn *ec2.EC2, deviceName string, volumeId string) error { + _, err := ec2conn.DetachVolume(&ec2.DetachVolumeInput{VolumeId: &volumeId}) + if err == nil { + return s.PollingConfig.WaitUntilVolumeDetached(ctx, ec2conn, volumeId) + } + + return err +} + +func (s *StepSwapVolumes) Cleanup(state multistep.StateBag) {} diff --git a/builder/ebsvolume/artifact.go b/builder/ebsvolume/artifact.go index 3dd1999a3..679770949 100644 --- a/builder/ebsvolume/artifact.go +++ b/builder/ebsvolume/artifact.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package ebsvolume import ( diff --git a/builder/ebsvolume/artifact_test.go b/builder/ebsvolume/artifact_test.go index fcaa98b3e..a12acf8fe 100644 --- a/builder/ebsvolume/artifact_test.go +++ b/builder/ebsvolume/artifact_test.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package ebsvolume import ( diff --git a/builder/ebsvolume/block_device.go b/builder/ebsvolume/block_device.go index d46f40043..26a6217c2 100644 --- a/builder/ebsvolume/block_device.go +++ b/builder/ebsvolume/block_device.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + //go:generate packer-sdc struct-markdown package ebsvolume @@ -24,6 +27,9 @@ type BlockDevice struct { // Create a Snapshot of this Volume. SnapshotVolume bool `mapstructure:"snapshot_volume" required:"false"` + // The description for the snapshot. + SnapshotDescription string `mapstructure:"snapshot_description" required:"false"` + awscommon.SnapshotConfig `mapstructure:",squash"` } diff --git a/builder/ebsvolume/builder.go b/builder/ebsvolume/builder.go index 825ae5f82..a39d77e4f 100644 --- a/builder/ebsvolume/builder.go +++ b/builder/ebsvolume/builder.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + //go:generate packer-sdc struct-markdown //go:generate packer-sdc mapstructure-to-hcl2 -type Config,BlockDevice @@ -158,6 +161,13 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) { "Packer, inclusion of enable_t2_unlimited will error your builds.") } + for _, configVolumeMapping := range b.config.VolumeMappings { + if configVolumeMapping.SnapshotDescription != "" && !configVolumeMapping.SnapshotVolume { + errs = packersdk.MultiErrorAppend(errs, + fmt.Errorf("All `ebs_volumes` blocks setting `snapshot_description` must also set `snapshot_volume`.")) + } + } + if errs != nil && len(errs.Errors) > 0 { return nil, warns, errs } @@ -272,13 +282,15 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) AmiFilters: b.config.SourceAmiFilter, }, &awscommon.StepNetworkInfo{ - VpcId: b.config.VpcId, - VpcFilter: b.config.VpcFilter, - SecurityGroupIds: b.config.SecurityGroupIds, - SecurityGroupFilter: b.config.SecurityGroupFilter, - SubnetId: b.config.SubnetId, - SubnetFilter: b.config.SubnetFilter, - AvailabilityZone: b.config.AvailabilityZone, + VpcId: b.config.VpcId, + VpcFilter: b.config.VpcFilter, + SecurityGroupIds: b.config.SecurityGroupIds, + SecurityGroupFilter: b.config.SecurityGroupFilter, + SubnetId: b.config.SubnetId, + SubnetFilter: b.config.SubnetFilter, + AvailabilityZone: b.config.AvailabilityZone, + AssociatePublicIpAddress: b.config.AssociatePublicIpAddress, + RequestedMachineType: b.config.InstanceType, }, &awscommon.StepKeyPair{ Debug: b.config.PackerDebug, @@ -300,6 +312,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) Ctx: b.config.ctx, }, &awscommon.StepIamInstanceProfile{ + PollingConfig: b.config.PollingConfig, IamInstanceProfile: b.config.IamInstanceProfile, SkipProfileValidation: b.config.SkipProfileValidation, TemporaryIamInstanceProfilePolicyDocument: b.config.TemporaryIamInstanceProfilePolicyDocument, @@ -322,6 +335,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) LocalPortNumber: b.config.SessionManagerPort, RemotePortNumber: b.config.Comm.Port(), SSMAgentEnabled: b.config.SSMAgentEnabled(), + SSHConfig: &b.config.Comm.SSH, }, &awscommon.StepEC2InstanceConnect{ AWSSession: session, diff --git a/builder/ebsvolume/builder.hcl2spec.go b/builder/ebsvolume/builder.hcl2spec.go index 3ce24d775..b2f0fe055 100644 --- a/builder/ebsvolume/builder.hcl2spec.go +++ b/builder/ebsvolume/builder.hcl2spec.go @@ -26,6 +26,7 @@ type FlatBlockDevice struct { Tags map[string]string `mapstructure:"tags" required:"false" cty:"tags" hcl:"tags"` Tag []config.FlatKeyValue `mapstructure:"tag" required:"false" cty:"tag" hcl:"tag"` SnapshotVolume *bool `mapstructure:"snapshot_volume" required:"false" cty:"snapshot_volume" hcl:"snapshot_volume"` + SnapshotDescription *string `mapstructure:"snapshot_description" required:"false" cty:"snapshot_description" hcl:"snapshot_description"` SnapshotTags map[string]string `mapstructure:"snapshot_tags" required:"false" cty:"snapshot_tags" hcl:"snapshot_tags"` SnapshotTag []config.FlatKeyValue `mapstructure:"snapshot_tag" required:"false" cty:"snapshot_tag" hcl:"snapshot_tag"` SnapshotUsers []string `mapstructure:"snapshot_users" required:"false" cty:"snapshot_users" hcl:"snapshot_users"` @@ -58,6 +59,7 @@ func (*FlatBlockDevice) HCL2Spec() map[string]hcldec.Spec { "tags": &hcldec.AttrSpec{Name: "tags", Type: cty.Map(cty.String), Required: false}, "tag": &hcldec.BlockListSpec{TypeName: "tag", Nested: hcldec.ObjectSpec((*config.FlatKeyValue)(nil).HCL2Spec())}, "snapshot_volume": &hcldec.AttrSpec{Name: "snapshot_volume", Type: cty.Bool, Required: false}, + "snapshot_description": &hcldec.AttrSpec{Name: "snapshot_description", Type: cty.String, Required: false}, "snapshot_tags": &hcldec.AttrSpec{Name: "snapshot_tags", Type: cty.Map(cty.String), Required: false}, "snapshot_tag": &hcldec.BlockListSpec{TypeName: "snapshot_tag", Nested: hcldec.ObjectSpec((*config.FlatKeyValue)(nil).HCL2Spec())}, "snapshot_users": &hcldec.AttrSpec{Name: "snapshot_users", Type: cty.List(cty.String), Required: false}, diff --git a/builder/ebsvolume/builder_test.go b/builder/ebsvolume/builder_test.go index 9db0a189b..7350bb9f9 100644 --- a/builder/ebsvolume/builder_test.go +++ b/builder/ebsvolume/builder_test.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package ebsvolume import ( diff --git a/builder/ebsvolume/step_snapshot_ebs_volumes.go b/builder/ebsvolume/step_snapshot_ebs_volumes.go index 80810e573..7d2e17a18 100644 --- a/builder/ebsvolume/step_snapshot_ebs_volumes.go +++ b/builder/ebsvolume/step_snapshot_ebs_volumes.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package ebsvolume import ( @@ -56,6 +59,7 @@ func (s *stepSnapshotEBSVolumes) Run(ctx context.Context, state multistep.StateB input := &ec2.CreateSnapshotInput{ VolumeId: aws.String(*instanceBlockDevice.Ebs.VolumeId), TagSpecifications: []*ec2.TagSpecification{tagSpec}, + Description: aws.String(configVolumeMapping.SnapshotDescription), } //Dont try to set an empty tag spec diff --git a/builder/ebsvolume/step_snapshot_ebs_volumes_test.go b/builder/ebsvolume/step_snapshot_ebs_volumes_test.go index 48d414126..fadcb08a7 100644 --- a/builder/ebsvolume/step_snapshot_ebs_volumes_test.go +++ b/builder/ebsvolume/step_snapshot_ebs_volumes_test.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package ebsvolume import ( diff --git a/builder/ebsvolume/step_tag_ebs_volumes.go b/builder/ebsvolume/step_tag_ebs_volumes.go index a73f89286..78be062b6 100644 --- a/builder/ebsvolume/step_tag_ebs_volumes.go +++ b/builder/ebsvolume/step_tag_ebs_volumes.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package ebsvolume import ( diff --git a/builder/examples/apache_server/packages.sh b/builder/examples/apache_server/packages.sh index 0a6af1d1c..f929c2a94 100644 --- a/builder/examples/apache_server/packages.sh +++ b/builder/examples/apache_server/packages.sh @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + echo "installing apache " sudo apt-get update sudo apt-get install apache2 -y diff --git a/builder/examples/nginx_server/packages.sh b/builder/examples/nginx_server/packages.sh index 3f5973ef0..3ffa39676 100644 --- a/builder/examples/nginx_server/packages.sh +++ b/builder/examples/nginx_server/packages.sh @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + echo "installing nginx " sudo apt-get update sudo apt-get install nginx -y diff --git a/builder/instance/builder.go b/builder/instance/builder.go index e23955cbc..f027f6884 100644 --- a/builder/instance/builder.go +++ b/builder/instance/builder.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + //go:generate packer-sdc struct-markdown //go:generate packer-sdc mapstructure-to-hcl2 -type Config @@ -88,11 +91,10 @@ type Config struct { // okay to create this directory as part of the provisioning process. // Defaults to /tmp. X509UploadPath string `mapstructure:"x509_upload_path" required:"false"` - // Enforce version of the Instance Metadata Service on the built AMI. - // Valid options are unset (legacy) and `v2.0`. See the documentation on - // [IMDS](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html) - // for more information. Defaults to legacy. - IMDSSupport string `mapstructure:"imds_support" required:"false"` + // NitroTPM Support. Valid options are `v2.0`. See the documentation on + // [NitroTPM Support](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enable-nitrotpm-support-on-ami.html) for + // more information. Only enabled if a valid option is provided, otherwise ignored. + TpmSupport string `mapstructure:"tpm_support" required:"false"` ctx interpolate.Context } @@ -238,8 +240,8 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) { "Packer, inclusion of enable_t2_unlimited will error your builds.") } - if b.config.IMDSSupport != "" && b.config.IMDSSupport != ec2.ImdsSupportValuesV20 { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf(`The only valid imds_support values are %q or the empty string`, ec2.ImdsSupportValuesV20)) + if b.config.TpmSupport != "" && b.config.TpmSupport != ec2.TpmSupportValuesV20 { + errs = packersdk.MultiErrorAppend(errs, fmt.Errorf(`The only valid tpm_support value is %q`, ec2.TpmSupportValuesV20)) } if errs != nil && len(errs.Errors) > 0 { @@ -351,13 +353,15 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) AMIVirtType: b.config.AMIVirtType, }, &awscommon.StepNetworkInfo{ - VpcId: b.config.VpcId, - VpcFilter: b.config.VpcFilter, - SecurityGroupIds: b.config.SecurityGroupIds, - SecurityGroupFilter: b.config.SecurityGroupFilter, - SubnetId: b.config.SubnetId, - SubnetFilter: b.config.SubnetFilter, - AvailabilityZone: b.config.AvailabilityZone, + VpcId: b.config.VpcId, + VpcFilter: b.config.VpcFilter, + SecurityGroupIds: b.config.SecurityGroupIds, + SecurityGroupFilter: b.config.SecurityGroupFilter, + SubnetId: b.config.SubnetId, + SubnetFilter: b.config.SubnetFilter, + AvailabilityZone: b.config.AvailabilityZone, + AssociatePublicIpAddress: b.config.AssociatePublicIpAddress, + RequestedMachineType: b.config.InstanceType, }, &awscommon.StepKeyPair{ Debug: b.config.PackerDebug, @@ -379,6 +383,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) Ctx: b.config.ctx, }, &awscommon.StepIamInstanceProfile{ + PollingConfig: b.config.PollingConfig, IamInstanceProfile: b.config.IamInstanceProfile, SkipProfileValidation: b.config.SkipProfileValidation, TemporaryIamInstanceProfilePolicyDocument: b.config.TemporaryIamInstanceProfilePolicyDocument, @@ -397,6 +402,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) LocalPortNumber: b.config.SessionManagerPort, RemotePortNumber: b.config.Comm.Port(), SSMAgentEnabled: b.config.SSMAgentEnabled(), + SSHConfig: &b.config.Comm.SSH, }, &awscommon.StepEC2InstanceConnect{ AWSSession: session, @@ -446,7 +452,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) EnableAMIENASupport: b.config.AMIENASupport, AMISkipBuildRegion: b.config.AMISkipBuildRegion, PollingConfig: b.config.PollingConfig, - IMDSSupport: b.config.IMDSSupport, + TpmSupport: b.config.TpmSupport, }, &awscommon.StepAMIRegionCopy{ AccessConfig: &b.config.AccessConfig, @@ -457,6 +463,10 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) Name: b.config.AMIName, OriginalRegion: *ec2conn.Config.Region, }, + &awscommon.StepEnableDeprecation{ + AccessConfig: &b.config.AccessConfig, + DeprecationTime: b.config.DeprecationTime, + }, &awscommon.StepModifyAMIAttributes{ Description: b.config.AMIDescription, Users: b.config.AMIUsers, @@ -466,6 +476,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) ProductCodes: b.config.AMIProductCodes, SnapshotUsers: b.config.SnapshotUsers, SnapshotGroups: b.config.SnapshotGroups, + IMDSSupport: b.config.AMIIMDSSupport, Ctx: b.config.ctx, GeneratedData: generatedData, }, diff --git a/builder/instance/builder.hcl2spec.go b/builder/instance/builder.hcl2spec.go index b57b96745..9816d1fb4 100644 --- a/builder/instance/builder.hcl2spec.go +++ b/builder/instance/builder.hcl2spec.go @@ -56,6 +56,8 @@ type FlatConfig struct { AMIKmsKeyId *string `mapstructure:"kms_key_id" required:"false" cty:"kms_key_id" hcl:"kms_key_id"` AMIRegionKMSKeyIDs map[string]string `mapstructure:"region_kms_key_ids" required:"false" cty:"region_kms_key_ids" hcl:"region_kms_key_ids"` AMISkipBuildRegion *bool `mapstructure:"skip_save_build_region" cty:"skip_save_build_region" hcl:"skip_save_build_region"` + AMIIMDSSupport *string `mapstructure:"imds_support" required:"false" cty:"imds_support" hcl:"imds_support"` + DeprecationTime *string `mapstructure:"deprecate_at" cty:"deprecate_at" hcl:"deprecate_at"` SnapshotTags map[string]string `mapstructure:"snapshot_tags" required:"false" cty:"snapshot_tags" hcl:"snapshot_tags"` SnapshotTag []config.FlatKeyValue `mapstructure:"snapshot_tag" required:"false" cty:"snapshot_tag" hcl:"snapshot_tag"` SnapshotUsers []string `mapstructure:"snapshot_users" required:"false" cty:"snapshot_users" hcl:"snapshot_users"` @@ -166,7 +168,7 @@ type FlatConfig struct { X509CertPath *string `mapstructure:"x509_cert_path" required:"true" cty:"x509_cert_path" hcl:"x509_cert_path"` X509KeyPath *string `mapstructure:"x509_key_path" required:"true" cty:"x509_key_path" hcl:"x509_key_path"` X509UploadPath *string `mapstructure:"x509_upload_path" required:"false" cty:"x509_upload_path" hcl:"x509_upload_path"` - IMDSSupport *string `mapstructure:"imds_support" required:"false" cty:"imds_support" hcl:"imds_support"` + TpmSupport *string `mapstructure:"tpm_support" required:"false" cty:"tpm_support" hcl:"tpm_support"` } // FlatMapstructure returns a new FlatConfig. @@ -225,6 +227,8 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "kms_key_id": &hcldec.AttrSpec{Name: "kms_key_id", Type: cty.String, Required: false}, "region_kms_key_ids": &hcldec.AttrSpec{Name: "region_kms_key_ids", Type: cty.Map(cty.String), Required: false}, "skip_save_build_region": &hcldec.AttrSpec{Name: "skip_save_build_region", Type: cty.Bool, Required: false}, + "imds_support": &hcldec.AttrSpec{Name: "imds_support", Type: cty.String, Required: false}, + "deprecate_at": &hcldec.AttrSpec{Name: "deprecate_at", Type: cty.String, Required: false}, "snapshot_tags": &hcldec.AttrSpec{Name: "snapshot_tags", Type: cty.Map(cty.String), Required: false}, "snapshot_tag": &hcldec.BlockListSpec{TypeName: "snapshot_tag", Nested: hcldec.ObjectSpec((*config.FlatKeyValue)(nil).HCL2Spec())}, "snapshot_users": &hcldec.AttrSpec{Name: "snapshot_users", Type: cty.List(cty.String), Required: false}, @@ -335,7 +339,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "x509_cert_path": &hcldec.AttrSpec{Name: "x509_cert_path", Type: cty.String, Required: false}, "x509_key_path": &hcldec.AttrSpec{Name: "x509_key_path", Type: cty.String, Required: false}, "x509_upload_path": &hcldec.AttrSpec{Name: "x509_upload_path", Type: cty.String, Required: false}, - "imds_support": &hcldec.AttrSpec{Name: "imds_support", Type: cty.String, Required: false}, + "tpm_support": &hcldec.AttrSpec{Name: "tpm_support", Type: cty.String, Required: false}, } return s } diff --git a/builder/instance/builder_test.go b/builder/instance/builder_test.go index 2929f7aa1..e0b7888bf 100644 --- a/builder/instance/builder_test.go +++ b/builder/instance/builder_test.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package instance import ( @@ -389,3 +392,51 @@ func TestBuilderPrepare_IMDSSupportValue(t *testing.T) { }) } } + +func TestBuilderPrepare_TpmSupportValue(t *testing.T) { + tests := []struct { + name string + optValue string + expectError bool + }{ + { + name: "OK - no value set", + optValue: "", + expectError: false, + }, + { + name: "OK - v2.0", + optValue: "v2.0", + expectError: false, + }, + { + name: "Error - bad value set", + optValue: "v3.0", + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + config, _ := testConfig() + config["ami_name"] = "name" + config["skip_region_validation"] = true + + config["tpm_support"] = tt.optValue + + b := &Builder{} + + _, _, err := b.Prepare(config) + if err != nil && !tt.expectError { + t.Fatalf("got unexpected error: %s", err) + } + if err == nil && tt.expectError { + t.Fatalf("expected an error, got a success instead") + } + + if err != nil { + t.Logf("OK: b.Prepare produced expected error: %s", err) + } + }) + } +} diff --git a/builder/instance/step_bundle_volume.go b/builder/instance/step_bundle_volume.go index efd663f48..a279bd9ba 100644 --- a/builder/instance/step_bundle_volume.go +++ b/builder/instance/step_bundle_volume.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package instance import ( diff --git a/builder/instance/step_register_ami.go b/builder/instance/step_register_ami.go index 02b67dd12..d2334b421 100644 --- a/builder/instance/step_register_ami.go +++ b/builder/instance/step_register_ami.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package instance import ( @@ -18,7 +21,7 @@ type StepRegisterAMI struct { EnableAMIENASupport confighelper.Trilean EnableAMISriovNetSupport bool AMISkipBuildRegion bool - IMDSSupport string + TpmSupport string } func (s *StepRegisterAMI) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { @@ -66,8 +69,8 @@ func (s *StepRegisterAMI) Run(ctx context.Context, state multistep.StateBag) mul // As of February 2017, this applies to C5, I3, P2, R4, X1, and m4.16xlarge registerOpts.EnaSupport = aws.Bool(true) } - if s.IMDSSupport != "" { - registerOpts.ImdsSupport = aws.String(s.IMDSSupport) + if s.TpmSupport != "" { + registerOpts.TpmSupport = aws.String(s.TpmSupport) } registerResp, err := ec2conn.RegisterImage(registerOpts) diff --git a/builder/instance/step_upload_bundle.go b/builder/instance/step_upload_bundle.go index 24412eb45..e7cec69ac 100644 --- a/builder/instance/step_upload_bundle.go +++ b/builder/instance/step_upload_bundle.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package instance import ( diff --git a/builder/instance/step_upload_x509_cert.go b/builder/instance/step_upload_x509_cert.go index 7937023ce..ea70aa0ad 100644 --- a/builder/instance/step_upload_x509_cert.go +++ b/builder/instance/step_upload_x509_cert.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package instance import ( diff --git a/datasource/ami/data.go b/datasource/ami/data.go index 8fbacef0d..c78da2547 100644 --- a/datasource/ami/data.go +++ b/datasource/ami/data.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + //go:generate packer-sdc struct-markdown //go:generate packer-sdc mapstructure-to-hcl2 -type DatasourceOutput,Config package ami diff --git a/datasource/ami/data.hcl2spec.go b/datasource/ami/data.hcl2spec.go index d612da5a2..ab8139ccb 100644 --- a/datasource/ami/data.hcl2spec.go +++ b/datasource/ami/data.hcl2spec.go @@ -38,6 +38,7 @@ type FlatConfig struct { Filters map[string]string `mapstructure:"filters" cty:"filters" hcl:"filters"` Owners []string `mapstructure:"owners" cty:"owners" hcl:"owners"` MostRecent *bool `mapstructure:"most_recent" cty:"most_recent" hcl:"most_recent"` + IncludeDeprecated *bool `mapstructure:"include_deprecated" cty:"include_deprecated" hcl:"include_deprecated"` } // FlatMapstructure returns a new FlatConfig. @@ -79,6 +80,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "filters": &hcldec.AttrSpec{Name: "filters", Type: cty.Map(cty.String), Required: false}, "owners": &hcldec.AttrSpec{Name: "owners", Type: cty.List(cty.String), Required: false}, "most_recent": &hcldec.AttrSpec{Name: "most_recent", Type: cty.Bool, Required: false}, + "include_deprecated": &hcldec.AttrSpec{Name: "include_deprecated", Type: cty.Bool, Required: false}, } return s } diff --git a/datasource/ami/data_acc_test.go b/datasource/ami/data_acc_test.go index c93a588ad..34d15206a 100644 --- a/datasource/ami/data_acc_test.go +++ b/datasource/ami/data_acc_test.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package ami import ( diff --git a/datasource/ami/data_test.go b/datasource/ami/data_test.go index 2c8f47512..5e73ef31c 100644 --- a/datasource/ami/data_test.go +++ b/datasource/ami/data_test.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package ami import ( diff --git a/datasource/ami/test-fixtures/configure-source-ssh.ps1 b/datasource/ami/test-fixtures/configure-source-ssh.ps1 index 7c12dd742..51303ec3e 100644 --- a/datasource/ami/test-fixtures/configure-source-ssh.ps1 +++ b/datasource/ami/test-fixtures/configure-source-ssh.ps1 @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + # Version and download URL $openSSHVersion = "8.1.0.0p1-Beta" diff --git a/datasource/ami/test-fixtures/template.pkr.hcl b/datasource/ami/test-fixtures/template.pkr.hcl index 23369bc86..723b9355d 100644 --- a/datasource/ami/test-fixtures/template.pkr.hcl +++ b/datasource/ami/test-fixtures/template.pkr.hcl @@ -1,6 +1,9 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + data "amazon-ami" "test" { filters = { - name = "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*" + name = "ubuntu/images/*ubuntu-jammy-22.04-amd64-server-*" root-device-type = "ebs" virtualization-type = "hvm" } diff --git a/datasource/parameterstore/data.go b/datasource/parameterstore/data.go index e219b8b81..07a012f80 100644 --- a/datasource/parameterstore/data.go +++ b/datasource/parameterstore/data.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + //go:generate packer-sdc struct-markdown //go:generate packer-sdc mapstructure-to-hcl2 -type DatasourceOutput,Config diff --git a/datasource/parameterstore/data_acc_test.go b/datasource/parameterstore/data_acc_test.go index bb08d3412..db9153e8d 100644 --- a/datasource/parameterstore/data_acc_test.go +++ b/datasource/parameterstore/data_acc_test.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package parameterstore import ( diff --git a/datasource/parameterstore/data_test.go b/datasource/parameterstore/data_test.go index cc5fe1d57..40dcb6be6 100644 --- a/datasource/parameterstore/data_test.go +++ b/datasource/parameterstore/data_test.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package parameterstore import "testing" diff --git a/datasource/parameterstore/test-fixtures/template.pkr.hcl b/datasource/parameterstore/test-fixtures/template.pkr.hcl index 47169ce91..e52a7e51d 100644 --- a/datasource/parameterstore/test-fixtures/template.pkr.hcl +++ b/datasource/parameterstore/test-fixtures/template.pkr.hcl @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + data "amazon-parameterstore" "test" { name = "packer_datasource_parameterstore_test_parameter" with_decryption = false diff --git a/datasource/secretsmanager/data.go b/datasource/secretsmanager/data.go index 1686b7001..7b499ef1e 100644 --- a/datasource/secretsmanager/data.go +++ b/datasource/secretsmanager/data.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + //go:generate packer-sdc struct-markdown //go:generate packer-sdc mapstructure-to-hcl2 -type DatasourceOutput,Config package secretsmanager diff --git a/datasource/secretsmanager/data_acc_test.go b/datasource/secretsmanager/data_acc_test.go index 477ba119a..bef572e5e 100644 --- a/datasource/secretsmanager/data_acc_test.go +++ b/datasource/secretsmanager/data_acc_test.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package secretsmanager import ( diff --git a/datasource/secretsmanager/data_test.go b/datasource/secretsmanager/data_test.go index 5802b3b29..7226ca8ce 100644 --- a/datasource/secretsmanager/data_test.go +++ b/datasource/secretsmanager/data_test.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package secretsmanager import ( diff --git a/datasource/secretsmanager/test-fixtures/template.pkr.hcl b/datasource/secretsmanager/test-fixtures/template.pkr.hcl index a5c024ce7..a23ef487b 100644 --- a/datasource/secretsmanager/test-fixtures/template.pkr.hcl +++ b/datasource/secretsmanager/test-fixtures/template.pkr.hcl @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + data "amazon-secretsmanager" "test" { name = "packer_datasource_secretsmanager_test_secret" key = "packer_test_key" diff --git a/docs-partials/builder/chroot/Config-not-required.mdx b/docs-partials/builder/chroot/Config-not-required.mdx index 76668d5fc..195e62800 100644 --- a/docs-partials/builder/chroot/Config-not-required.mdx +++ b/docs-partials/builder/chroot/Config-not-required.mdx @@ -162,9 +162,8 @@ - `uefi_data` (string) - Base64 representation of the non-volatile UEFI variable store. For more information see [AWS documentation](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/uefi-secure-boot-optionB.html). -- `imds_support` (string) - Enforce version of the Instance Metadata Service on the built AMI. - Valid options are unset (legacy) and `v2.0`. See the documentation on - [IMDS](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html) - for more information. Defaults to legacy. +- `tpm_support` (string) - NitroTPM Support. Valid options are `v2.0`. See the documentation on + [NitroTPM Support](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enable-nitrotpm-support-on-ami.html) for + more information. Only enabled if a valid option is provided, otherwise ignored. diff --git a/docs-partials/builder/common/AMIConfig-not-required.mdx b/docs-partials/builder/common/AMIConfig-not-required.mdx index fa8deeb80..580414c4f 100644 --- a/docs-partials/builder/common/AMIConfig-not-required.mdx +++ b/docs-partials/builder/common/AMIConfig-not-required.mdx @@ -88,8 +88,8 @@ - `kms_key_id` (string) - ID, alias or ARN of the KMS key to use for AMI encryption. This only applies to the main `region` -- any regions the AMI gets copied to - copied will be encrypted by the default EBS KMS key for that region, - unless you set region-specific keys in AMIRegionKMSKeyIDs. + will be encrypted by the default EBS KMS key for that region, + unless you set region-specific keys in `region_kms_key_ids`. Set this value if you select `encrypt_boot`, but don't want to use the region's default KMS key. @@ -128,4 +128,13 @@ the intermediary AMI into any regions provided in `ami_regions`, then delete the intermediary AMI. Default `false`. +- `imds_support` (string) - Enforce version of the Instance Metadata Service on the built AMI. + Valid options are unset (legacy) and `v2.0`. See the documentation on + [IMDS](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html) + for more information. Defaults to legacy. + +- `deprecate_at` (string) - The date and time to deprecate the AMI, in UTC, in the following format: YYYY-MM-DDTHH:MM:SSZ. + If you specify a value for seconds, Amazon EC2 rounds the seconds to the nearest minute. + You can’t specify a date in the past. The upper limit for DeprecateAt is 10 years from now. + diff --git a/docs-partials/builder/common/AWSPollingConfig.mdx b/docs-partials/builder/common/AWSPollingConfig.mdx index 33e9a2fba..b884cc040 100644 --- a/docs-partials/builder/common/AWSPollingConfig.mdx +++ b/docs-partials/builder/common/AWSPollingConfig.mdx @@ -5,18 +5,22 @@ volumes or importing image. HCL2 example: ```hcl -aws_polling { - delay_seconds = 30 - max_attempts = 50 -} + + aws_polling { + delay_seconds = 30 + max_attempts = 50 + } + ``` JSON example: ```json -"aws_polling" : { - "delay_seconds": 30, - "max_attempts": 50 -} + + "aws_polling" : { + "delay_seconds": 30, + "max_attempts": 50 + } + ``` diff --git a/docs-partials/builder/common/AmiFilterOptions-not-required.mdx b/docs-partials/builder/common/AmiFilterOptions-not-required.mdx index 567f61959..283cfdf60 100644 --- a/docs-partials/builder/common/AmiFilterOptions-not-required.mdx +++ b/docs-partials/builder/common/AmiFilterOptions-not-required.mdx @@ -13,4 +13,8 @@ - `most_recent` (bool) - Selects the newest created image when true. This is most useful for selecting a daily distro build. +- `include_deprecated` (bool) - Include deprecated AMIs in the filtered response. Defaults to false. + If you are the AMI owner, deprecated AMIs appear in the response + regardless of what is specified for `include_deprecated`. + diff --git a/docs-partials/builder/common/AssumeRoleConfig.mdx b/docs-partials/builder/common/AssumeRoleConfig.mdx index c6e56e8c5..562bd00ac 100644 --- a/docs-partials/builder/common/AssumeRoleConfig.mdx +++ b/docs-partials/builder/common/AssumeRoleConfig.mdx @@ -8,26 +8,30 @@ Usage example: HCL config example: ```HCL -source "amazon-ebs" "example" { - assume_role { - role_arn = "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME" - session_name = "SESSION_NAME" - external_id = "EXTERNAL_ID" + + source "amazon-ebs" "example" { + assume_role { + role_arn = "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME" + session_name = "SESSION_NAME" + external_id = "EXTERNAL_ID" + } } -} + ``` JSON config example: ```json -builder{ - "type": "amazon-ebs", - "assume_role": { - "role_arn" : "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME", - "session_name": "SESSION_NAME", - "external_id" : "EXTERNAL_ID" + + builder{ + "type": "amazon-ebs", + "assume_role": { + "role_arn" : "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME", + "session_name": "SESSION_NAME", + "external_id" : "EXTERNAL_ID" + } } -} + ``` diff --git a/docs-partials/builder/common/BlockDevice.mdx b/docs-partials/builder/common/BlockDevice.mdx index 4bab0b1bf..640f0158c 100644 --- a/docs-partials/builder/common/BlockDevice.mdx +++ b/docs-partials/builder/common/BlockDevice.mdx @@ -11,21 +11,25 @@ build instance at launch using a specific non-default kms key: HCL2 example: ```hcl -launch_block_device_mappings { - device_name = "/dev/sda1" - encrypted = true - kms_key_id = "1a2b3c4d-5e6f-1a2b-3c4d-5e6f1a2b3c4d" -} + + launch_block_device_mappings { + device_name = "/dev/sda1" + encrypted = true + kms_key_id = "1a2b3c4d-5e6f-1a2b-3c4d-5e6f1a2b3c4d" + } + ``` JSON example: ```json "launch_block_device_mappings": [ - { - "device_name": "/dev/sda1", - "encrypted": true, - "kms_key_id": "1a2b3c4d-5e6f-1a2b-3c4d-5e6f1a2b3c4d" - } + + { + "device_name": "/dev/sda1", + "encrypted": true, + "kms_key_id": "1a2b3c4d-5e6f-1a2b-3c4d-5e6f1a2b3c4d" + } + ] ``` diff --git a/docs-partials/builder/common/Placement-not-required.mdx b/docs-partials/builder/common/Placement-not-required.mdx index f9c31f1f0..b848477cd 100644 --- a/docs-partials/builder/common/Placement-not-required.mdx +++ b/docs-partials/builder/common/Placement-not-required.mdx @@ -2,6 +2,8 @@ - `host_resource_group_arn` (string) - The ARN of the host resource group in which to launch the instances. +- `host_id` (string) - The ID of the host used when Packer launches an EC2 instance. + - `tenancy` (string) - [Tenancy](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/dedicated-instance.html) used when Packer launches the EC2 instance, allowing it to be launched on dedicated hardware. diff --git a/docs-partials/builder/common/RunConfig-not-required.mdx b/docs-partials/builder/common/RunConfig-not-required.mdx index a6faa94b3..2bdcb42fa 100644 --- a/docs-partials/builder/common/RunConfig-not-required.mdx +++ b/docs-partials/builder/common/RunConfig-not-required.mdx @@ -3,6 +3,21 @@ - `associate_public_ip_address` (confighelper.Trilean) - If using a non-default VPC, public IP addresses are not provided by default. If this is true, your new instance will get a Public IP. default: unset + + Note: when specifying this attribute without a `subnet_[id|filter]` or + `vpc_[id|filter]`, we will attempt to infer this information from the + default VPC/Subnet. + This operation may require some extra permissions to the IAM role that + runs the build: + + * ec2:DescribeVpcs + * ec2:DescribeSubnets + + Additionally, since we filter subnets/AZs by their capability to host + an instance of the selected type, you may also want to define the + `ec2:DescribeInstanceTypeOfferings` action to the role running the build. + Otherwise, Packer will pick the most available subnet in the VPC selected, + which may not be able to host the instance type you provided. - `availability_zone` (string) - Destination availability zone to launch instance in. Leave this empty to allow Amazon to auto-assign. @@ -180,7 +195,7 @@ `security_group_ids` take precedence over this. -- `run_tags` (map[string]string) - Key/value pair tags to apply to the generated key-pair, security group, snapshot and instance +- `run_tags` (map[string]string) - Key/value pair tags to apply to the generated key-pair, security group, iam profile and role, snapshot, network interfaces and instance that is *launched* to create the EBS volumes. The resulting AMI will also inherit these tags. This is a [template engine](/packer/docs/templates/legacy_json_templates/engine), see [Build template diff --git a/docs-partials/builder/ebs/Config-not-required.mdx b/docs-partials/builder/ebs/Config-not-required.mdx index a01d357e7..a92a726cc 100644 --- a/docs-partials/builder/ebs/Config-not-required.mdx +++ b/docs-partials/builder/ebs/Config-not-required.mdx @@ -40,8 +40,11 @@ make sure you don't set this for *nix guests; behavior may be unpredictable. -- `deprecate_at` (string) - The date and time to deprecate the AMI, in UTC, in the following format: YYYY-MM-DDTHH:MM:SSZ. - If you specify a value for seconds, Amazon EC2 rounds the seconds to the nearest minute. - You can’t specify a date in the past. The upper limit for DeprecateAt is 10 years from now. +- `fast_launch` (FastLaunchConfig) - The configuration for fast launch support. + + Fast launch is only relevant for Windows AMIs, and should not be used + for other OSes. + See the [Fast Launch Configuration](#fast-launch-config) section for + information on the attributes supported for this block. diff --git a/docs-partials/builder/ebs/FastLaunchConfig-not-required.mdx b/docs-partials/builder/ebs/FastLaunchConfig-not-required.mdx new file mode 100644 index 000000000..974b506c2 --- /dev/null +++ b/docs-partials/builder/ebs/FastLaunchConfig-not-required.mdx @@ -0,0 +1,56 @@ + + +- `enable_fast_launch` (bool) - Configure fast-launch for Windows AMIs + +- `template_id` (string) - The ID of the launch template to use for fast launch for the main AMI. + + This cannot be specified in conjunction with the template name. + + If no template is specified, the default launch template will be used, + as specified in the AWS docs. + + If you copy the AMI to other regions, this option should not + be used, use instead the `fast_launch_template_config` option. + +- `template_name` (string) - The name of the launch template to use for fast launch for the main AMI. + + This cannot be specified in conjunction with the template ID. + + If no template is specified, the default launch template will be used, + as specified in the AWS docs. + + If you copy the AMI to other regions, this option should not + be used, use instead the `fast_launch_template_config` option. + +- `template_version` (int) - The version of the launch template to use for fast launch for the main AMI. + + If unspecified, and a template is referenced, this will default to + the latest version available for the template. + + If you copy the AMI to other regions, this option should not + be used, use instead the `fast_launch_template_config` option. + +- `region_launch_templates` ([]FastLaunchTemplateConfig) - RegionLaunchTemplates is the list of launch templates per region. + + This should be specified if you want to use a custom launch + template for your fast-launched images, and you are copying + the image to other regions. + + All regions don't need a launch template configuration, but for + each that don't have a launch template specified, AWS will pick + a default one for that purpose. + + For information about each entry, refer to the + [Fast Launch Template Config](#fast-launch-template-config) documentation. + +- `max_parallel_launches` (int) - Maximum number of instances to launch for creating pre-provisioned snapshots + + If specified, must be a minimum of `6` + +- `target_resource_count` (int) - The number of snapshots to pre-provision for later launching windows instances + from the resulting fast-launch AMI. + + If unspecified, this will create the default number of snapshots (as of + march 2023, this defaults to 5 on AWS) + + diff --git a/docs-partials/builder/ebs/FastLaunchConfig.mdx b/docs-partials/builder/ebs/FastLaunchConfig.mdx new file mode 100644 index 000000000..e92b2c0ae --- /dev/null +++ b/docs-partials/builder/ebs/FastLaunchConfig.mdx @@ -0,0 +1,9 @@ + + +FastLaunchConfig is the configuration for setting up fast-launch for Windows AMIs + +NOTE: requires the Windows image to be sysprep'd to enable fast-launch. See the +AWS docs for more information: +https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/win-ami-config-fast-launch.html + + diff --git a/docs-partials/builder/ebs/FastLaunchTemplateConfig-not-required.mdx b/docs-partials/builder/ebs/FastLaunchTemplateConfig-not-required.mdx new file mode 100644 index 000000000..b1d1aade2 --- /dev/null +++ b/docs-partials/builder/ebs/FastLaunchTemplateConfig-not-required.mdx @@ -0,0 +1,22 @@ + + +- `template_id` (string) - The ID of the launch template to use for the fast launch + + This cannot be specified in conjunction with the template name. + + If no template is specified, the default launch template will be used, + as specified in the AWS docs. + +- `template_name` (string) - The name of the launch template to use for fast launch + + This cannot be specified in conjunction with the template ID. + + If no template is specified, the default launch template will be used, + as specified in the AWS docs. + +- `template_version` (int) - The version of the launch template to use + + If unspecified, and a template is referenced, this will default to + the latest version available for the template. + + diff --git a/docs-partials/builder/ebs/FastLaunchTemplateConfig-required.mdx b/docs-partials/builder/ebs/FastLaunchTemplateConfig-required.mdx new file mode 100644 index 000000000..a68ccc9dd --- /dev/null +++ b/docs-partials/builder/ebs/FastLaunchTemplateConfig-required.mdx @@ -0,0 +1,5 @@ + + +- `region` (string) - The region in which to find the launch template to use + + diff --git a/docs-partials/builder/ebs/FastLaunchTemplateConfig.mdx b/docs-partials/builder/ebs/FastLaunchTemplateConfig.mdx new file mode 100644 index 000000000..e0a3ed56f --- /dev/null +++ b/docs-partials/builder/ebs/FastLaunchTemplateConfig.mdx @@ -0,0 +1,9 @@ + + +FastLaunchTemplateConfig is the launch template configuration for a region. + +This must be used if the configuration has more than one region specified +in the template, as each fast-launch enablement step occurs after the +copy, and each region may pick their own launch template. + + diff --git a/docs-partials/builder/ebssurrogate/Config-not-required.mdx b/docs-partials/builder/ebssurrogate/Config-not-required.mdx index a5107eac2..77358a1d6 100644 --- a/docs-partials/builder/ebssurrogate/Config-not-required.mdx +++ b/docs-partials/builder/ebssurrogate/Config-not-required.mdx @@ -38,9 +38,17 @@ - `uefi_data` (string) - Base64 representation of the non-volatile UEFI variable store. For more information see [AWS documentation](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/uefi-secure-boot-optionB.html). -- `imds_support` (string) - Enforce version of the Instance Metadata Service on the built AMI. - Valid options are unset (legacy) and `v2.0`. See the documentation on - [IMDS](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html) - for more information. Defaults to legacy. +- `tpm_support` (string) - NitroTPM Support. Valid options are `v2.0`. See the documentation on + [NitroTPM Support](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enable-nitrotpm-support-on-ami.html) for + more information. Only enabled if a valid option is provided, otherwise ignored. + +- `use_create_image` (bool) - Whether to use the CreateImage or RegisterImage API when creating the AMI. + When set to `true`, the CreateImage API is used and will create the image + from the instance itself, and inherit properties from the instance. + When set to `false`, the RegisterImage API is used and the image is created using + a snapshot of the specified EBS volume, and no properties are inherited from the instance. + Defaults to `false`. + Ref: https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateImage.html + https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RegisterImage.html diff --git a/docs-partials/builder/ebsvolume/BlockDevice-not-required.mdx b/docs-partials/builder/ebsvolume/BlockDevice-not-required.mdx index d7a09791c..e683c7330 100644 --- a/docs-partials/builder/ebsvolume/BlockDevice-not-required.mdx +++ b/docs-partials/builder/ebsvolume/BlockDevice-not-required.mdx @@ -11,4 +11,6 @@ - `snapshot_volume` (bool) - Create a Snapshot of this Volume. +- `snapshot_description` (string) - The description for the snapshot. + diff --git a/docs-partials/builder/instance/Config-not-required.mdx b/docs-partials/builder/instance/Config-not-required.mdx index 76550245c..a5a89eddf 100644 --- a/docs-partials/builder/instance/Config-not-required.mdx +++ b/docs-partials/builder/instance/Config-not-required.mdx @@ -37,9 +37,8 @@ okay to create this directory as part of the provisioning process. Defaults to /tmp. -- `imds_support` (string) - Enforce version of the Instance Metadata Service on the built AMI. - Valid options are unset (legacy) and `v2.0`. See the documentation on - [IMDS](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html) - for more information. Defaults to legacy. +- `tpm_support` (string) - NitroTPM Support. Valid options are `v2.0`. See the documentation on + [NitroTPM Support](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enable-nitrotpm-support-on-ami.html) for + more information. Only enabled if a valid option is provided, otherwise ignored. diff --git a/docs-partials/builders/aws-session-manager.mdx b/docs-partials/builders/aws-session-manager.mdx index 732959405..a34524e34 100644 --- a/docs-partials/builders/aws-session-manager.mdx +++ b/docs-partials/builders/aws-session-manager.mdx @@ -57,6 +57,7 @@ build { ``` JSON example: + ```json { "builders": [ @@ -100,3 +101,11 @@ In order for Packer to start and end sessions that connect you to your managed i #### IAM instance profile for Systems Manager By default Systems Manager doesn't have permission to perform actions on created instances so SSM access must be granted by creating an instance profile with the `AmazonSSMManagedInstanceCore` policy. The instance profile can then be attached to any instance you wish to manage via the session-manager-plugin. See [Adding System Manager instance profile](https://docs.aws.amazon.com/systems-manager/latest/userguide/setup-instance-profile.html#instance-profile-add-permissions) for details on creating the required instance profile. + +#### Permissions for Closing the Tunnel + +To close the SSM tunnels created, this plugin relies on being able to call +[DescribeInstanceStatus](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeInstanceStatus.html). +In case this is not possible you might see a `Bad exit status` message in the logs. + +The absence of this permission won't prevent you from building the AMI, and the error only means that packer is not able to close the tunnel gracefully. diff --git a/docs/README.md b/docs/README.md index 80c9b48d2..410e2ce9b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,33 +1,437 @@ -# Amazon Components - -The Amazon plugin is able to create Amazon AMIs through Packer. To achieve this, the plugin comes with +The Amazon plugin can be used with HashiCorp Packer to create custom images on AWS. To achieve this, the plugin comes with multiple builders, data sources, and a post-processor to build the AMI depending on the strategy you want to use. -### Builders: -- [amazon-ebs](/docs/builders/ebs.mdx) - Create EBS-backed AMIs by +### Installation + +To install this plugin, copy and paste this code into your Packer configuration, then run [`packer init`](https://www.packer.io/docs/commands/init). + +```hcl +packer { + required_plugins { + amazon = { + source = "github.com/hashicorp/amazon" + version = "~> 1" + } + } +} +``` + +Alternatively, you can use `packer plugins install` to manage installation of this plugin. + +```sh +$ packer plugins install github.com/hashicorp/amazon +``` + +### Components + +**Don't know which builder to use?** If in doubt, use the [amazon-ebs builder](/packer/plugins/builders/amazon/ebs). +It is much easier to use and Amazon generally recommends EBS-backed images nowadays. + +#### Builders +- [amazon-ebs](/packer/integrations/hashicorp/amazon/latest/components/builder/ebs) - Create EBS-backed AMIs by launching a source AMI and re-packaging it into a new AMI after provisioning. If in doubt, use this builder, which is the easiest to get started with. -- [amazon-instance](/docs/builders/instance.mdx) - Create +- [amazon-instance](/packer/integrations/hashicorp/amazon/latest/components/builder/instance) - Create instance-store AMIs by launching and provisioning a source instance, then rebundling it and uploading it to S3. -- [amazon-chroot](/docs/builders/chroot.mdx) - Create EBS-backed AMIs +- [amazon-chroot](/packer/integrations/hashicorp/amazon/latest/components/builder/chroot) - Create EBS-backed AMIs from an existing EC2 instance by mounting the root device and using a [Chroot](https://en.wikipedia.org/wiki/Chroot) environment to provision that device. This is an **advanced builder and should not be used by newcomers**. However, it is also the fastest way to build an EBS-backed AMI since no new EC2 instance needs to be launched. -- [amazon-ebssurrogate](/docs/builders/ebssurrogate.mdx) - Create EBS +- [amazon-ebssurrogate](/packer/integrations/hashicorp/amazon/latest/components/builder/ebssurrogate) - Create EBS -backed AMIs from scratch. Works similarly to the `chroot` builder but does not require running in AWS. This is an **advanced builder and should not be used by newcomers**. +- [amazon-ebs-volume](/packer/integrations/hashicorp/amazon/latest/components/builder/ebsvolume) - Create prepopulated + EBS volumes by launching an instance and provisioning attached volumes. + This is an **advanced builder and should not be used by newcomers**. -### Data sources: -- [amazon-ami](/docs/datasources/ami.mdx) - Filter and fetch an Amazon AMI to output all the AMI information. -- [amazon-secretsmanager](/docs/datasources/secretsmanager.mdx) - Retrieve information +#### Data sources +- [amazon-ami](/packer/integrations/hashicorp/amazon/latest/components/data-source/ami) - Filter and fetch an Amazon AMI to output all the AMI information. +- [amazon-secretsmanager](/packer/integrations/hashicorp/amazon/latest/components/data-source/secretsmanager) - Retrieve information about a Secrets Manager secret version, including its secret value. -- [amazon-parameterstore](/docs/datasources/parameterstore.mdx) - Retrieve information about a parameter in SSM. +- [amazon-parameterstore](/packer/integrations/hashicorp/amazon/latest/components/data-source/parameterstore) - Retrieve information about a parameter in SSM. + +#### Post-Processors +- [amazon-import](/packer/integrations/hashicorp/amazon/latest/components/post-processor/import) - The Amazon Import post-processor takes an OVA artifact + from various builders and imports it to an AMI available to Amazon Web Services EC2. + +### Authentication + +The AWS provider offers a flexible means of providing credentials for +authentication. The following methods are supported, in this order, and +explained below: + +- Static credentials +- Environment variables +- Shared credentials file +- EC2 Role + +#### Static Credentials + +Static credentials can be provided in the form of an access key id and secret. +These look like: + +```json +"builders": { + "type": "amazon-ebs", + "access_key": "AKIAIOSFODNN7EXAMPLE", + "secret_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "region": "us-east-1", +} +``` + +```hcl +source "amazon-ebs" "basic-example" { + access_key = "AKIAIOSFODNN7EXAMPLE" + secret_key = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" + region = "us-east-1" +} +``` + +If you would like, you may also assume a role using the assume_role +configuration option. You must still have one of the valid credential resources +explained above, and your user must have permission to assume the role in +question. This is a way of running Packer with a more restrictive set of +permissions than your user. + +AssumeRoleConfig lets users set configuration options for assuming a special +role when executing Packer. + +Usage example: + +HCL config example: + +```HCL +source "amazon-ebs" "example" { + assume_role { + role_arn = "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME" + session_name = "SESSION_NAME" + external_id = "EXTERNAL_ID" + } +} +``` + +JSON config example: + +```json +"builders": [{ + "type": "amazon-ebs", + "assume_role": { + "role_arn" : "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME", + "session_name": "SESSION_NAME", + "external_id" : "EXTERNAL_ID" + } +}] +``` + +- `role_arn` (string) - Amazon Resource Name (ARN) of the IAM Role to assume. + +- `duration_seconds` (int) - Number of seconds to restrict the assume role session duration. + +- `external_id` (string) - The external ID to use when assuming the role. If omitted, no external + ID is passed to the AssumeRole call. + +- `policy` (string) - IAM Policy JSON describing further restricting permissions for the IAM + Role being assumed. + +- `policy_arns` ([]string) - Set of Amazon Resource Names (ARNs) of IAM Policies describing further + restricting permissions for the IAM Role being + +- `session_name` (string) - Session name to use when assuming the role. + +- `tags` (map[string]string) - Map of assume role session tags. + +- `transitive_tag_keys` ([]string) - Set of assume role session tag keys to pass to any subsequent sessions. + +#### Environment variables + +You can provide your credentials via the `AWS_ACCESS_KEY_ID` and +`AWS_SECRET_ACCESS_KEY`, environment variables, representing your AWS Access +Key and AWS Secret Key, respectively. Note that setting your AWS credentials +using either these environment variables will override the use of +`AWS_SHARED_CREDENTIALS_FILE` and `AWS_PROFILE`. The `AWS_DEFAULT_REGION` and +`AWS_SESSION_TOKEN` environment variables are also used, if applicable: + +Usage: + + $ export AWS_ACCESS_KEY_ID="anaccesskey" + $ export AWS_SECRET_ACCESS_KEY="asecretkey" + $ export AWS_DEFAULT_REGION="us-west-2" + $ packer build template.pkr.hcl + +#### Shared Credentials file + +You can use an AWS credentials file to specify your credentials. The default +location is `$HOME/.aws/credentials` on Linux and OS X, or +`%USERPROFILE%.aws\credentials` for Windows users. If we fail to detect +credentials inline, or in the environment, the Amazon Plugin will check this location. You +can optionally specify a different location in the configuration by setting the +environment with the `AWS_SHARED_CREDENTIALS_FILE` variable. + +The format for the credentials file is like so + + [default] + aws_access_key_id= + aws_secret_access_key= + +You may also configure the profile to use by setting the `profile` +configuration option, or setting the `AWS_PROFILE` environment variable: + +```json +"builders": { + "type": "amazon-ebs" + "profile": "customprofile", + "region": "us-east-1", +} +``` + +```hcl +source "amazon-ebs" "basic-example" { + profile = "customprofile" + region = "us-east-1" +} +``` + +#### IAM Task or Instance Role + +Finally, the plugin will use credentials provided by the task's or instance's IAM +role, if it has one. + +This is a preferred approach over any other when running in EC2 as you can +avoid hard coding credentials. Instead these are leased on-the-fly by the plugin, +which reduces the chance of leakage. + +The following policy document provides the minimal set permissions necessary +for the Amazon plugin to work: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "ec2:AttachVolume", + "ec2:AuthorizeSecurityGroupIngress", + "ec2:CopyImage", + "ec2:CreateImage", + "ec2:CreateKeyPair", + "ec2:CreateSecurityGroup", + "ec2:CreateSnapshot", + "ec2:CreateTags", + "ec2:CreateVolume", + "ec2:DeleteKeyPair", + "ec2:DeleteSecurityGroup", + "ec2:DeleteSnapshot", + "ec2:DeleteVolume", + "ec2:DeregisterImage", + "ec2:DescribeImageAttribute", + "ec2:DescribeImages", + "ec2:DescribeInstances", + "ec2:DescribeInstanceStatus", + "ec2:DescribeRegions", + "ec2:DescribeSecurityGroups", + "ec2:DescribeSnapshots", + "ec2:DescribeSubnets", + "ec2:DescribeTags", + "ec2:DescribeVolumes", + "ec2:DetachVolume", + "ec2:GetPasswordData", + "ec2:ModifyImageAttribute", + "ec2:ModifyInstanceAttribute", + "ec2:ModifySnapshotAttribute", + "ec2:RegisterImage", + "ec2:RunInstances", + "ec2:StopInstances", + "ec2:TerminateInstances" + ], + "Resource": "*" + } + ] +} +``` + +Note that if you'd like to create a spot instance, you must also add: + + ec2:CreateLaunchTemplate, + ec2:DeleteLaunchTemplate, + ec2:CreateFleet + +If you have the `spot_price` parameter set to `auto`, you must also add: + + ec2:DescribeSpotPriceHistory + +If you are using the `vpc_filter` option, you must also add: + + ec2:DescribeVpcs + +This permission may also be needed by the `associate_public_ip_address` option, if specified without a subnet. +In this case the plugin will invoke `DescribeVpcs` to find information about the default VPC. + +When using `associate_public_ip_address` without a subnet, you will also benefit from having: + + ec2:DescribeInstanceTypeOfferings + +This will ensure that the plugin will pick a subnet/AZ that can host the type of instance +you're requesting in your template. + +If you are using the `deprecate_at` attribute in your templates, you will also need: + + ec2:EnableImageDeprecation + +If you are using SSM to connect to the instance, and are specifying a private key file, you must also add: + + ec2-instance-connect:SendSSHPublicKey + +If you are building a Windows AMI, and want to enable fast-launch, you will also need: + + ec2:EnableFastLaunch + ec2:DescribeLaunchTemplates + ec2:DescribeFastLaunchImages + +### Troubleshooting + +#### Attaching IAM Policies to Roles + +IAM policies can be associated with users or roles. If you use the plugin with IAM +roles, you may encounter an error like this one: + + ==> amazon-ebs: Error launching source instance: You are not authorized to perform this operation. + +You can read more about why this happens on the [Amazon Security +Blog](https://blogs.aws.amazon.com/security/post/Tx3M0IFB5XBOCQX/Granting-Permission-to-Launch-EC2-Instances-with-IAM-Roles-PassRole-Permission). +The example policy below may help the plugin work with IAM roles. Note that this +example provides more than the minimal set of permissions needed for the Amazon plugin to +work, but specifics will depend on your use-case. + +```json +{ + "Sid": "PackerIAMPassRole", + "Effect": "Allow", + "Action": ["iam:PassRole", "iam:GetInstanceProfile"], + "Resource": ["*"] +} +``` + +If using an existing instance profile with spot instances/spot pricing, the `iam:CreateServiceLinkedRole` action is also required: + +```json +{ + "Sid": "PackerIAMPassRole", + "Effect": "Allow", + "Action": ["iam:PassRole", "iam:GetInstanceProfile", "iam:CreateServiceLinkedRole"], + "Resource": ["*"] +} +``` + +In case when you're creating a temporary instance profile you will require to have following +IAM policies. + +```json +{ + "Sid": "PackerIAMCreateRole", + "Effect": "Allow", + "Action": [ + "iam:PassRole", + "iam:CreateInstanceProfile", + "iam:DeleteInstanceProfile", + "iam:GetRole", + "iam:GetInstanceProfile", + "iam:DeleteRolePolicy", + "iam:RemoveRoleFromInstanceProfile", + "iam:CreateRole", + "iam:DeleteRole", + "iam:PutRolePolicy", + "iam:AddRoleToInstanceProfile" + ], + "Resource": "*" +} +``` + +In cases where you are using a KMS key for encryption, your key will need the +following policies at a minimum: + +```json +{ + "Sid": "Allow use of the key", + "Effect": "Allow", + "Action": ["kms:ReEncrypt*", "kms:GenerateDataKey*"], + "Resource": "*" +} +``` + +If you are using a key provided by a different account than the one you are +using to run the Packer build, your key will also need + +```json +("kms:CreateGrant", "kms:DescribeKey") +``` + +#### Check System Time + +Amazon uses the current time as part of the [request signing process](http://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html). If +your system clock is too skewed from the current time, your requests might +fail. If that's the case, you might see an error like this: + + ==> amazon-ebs: Error querying AMI: AuthFailure: AWS was not able to validate the provided access credentials + +If you suspect your system's date is wrong, you can compare it against +`http://www.time.gov/`. On Linux/OS X, you can run the `date` command to get the current time. If you're +on Linux, you can try setting the time with ntp by running `sudo ntpd -q`. + +#### ResourceNotReady Error + +This error generally appears as either `ResourceNotReady: exceeded wait attempts` or `ResourceNotReady: failed waiting for successful resource state`. + +This opaque error gets returned from AWS's API for a number of reasons, +generally during image copy/encryption. Possible reasons for the error include: + +- You aren't waiting long enough. This is where you'll see the `exceeded wait attempts` variety of this error message: + We use the AWS SDK's built-in waiters to wait for longer-running tasks to + complete. These waiters have default delays between queries and maximum + number of queries that don't always work for our users. + + If you find that you are being rate-limited or have exceeded your max wait + attempts, you can override the defaults by setting the following packer + environment variables (note that these will apply to all AWS tasks that we + have to wait for): + + - `AWS_MAX_ATTEMPTS` - This is how many times to re-send a status update + request. Excepting tasks that we know can take an extremely long time, this + defaults to 40 tries. + + - `AWS_POLL_DELAY_SECONDS` - How many seconds to wait in between status update + requests. Generally defaults to 2 or 5 seconds, depending on the task. + + Alternatively, you can configure these settings in source section of the packer + configuration file, for example: + ``` + aws_polling { + delay_seconds = 40 + max_attempts = 5 + } + ``` + +- You are using short-lived credentials that expired during the build. If this + is the problem, you may also see `RequestExpired: Request has expired.` + errors displayed in the Packer output: + + - If you are using STS credentials, make sure that they expire only after the + build has completed + + - If you are chaining roles, make sure your build doesn't last more than an + hour, since when you chain roles the maximum length of time your credentials + will last is an hour: + https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html -### Post-Processors -- [amazon-import](/docs/post-processors/import.mdx) - The Amazon Import post-processor takes an OVA artifact - from various builders and imports it to an AMI available to Amazon Web Services EC2. \ No newline at end of file +- Something is wrong with your KMS key. This is where you'll see the + `ResourceNotReady: failed waiting for successful resource state` variety of + this error message. Issues we've seen include: + - Your KMS key is invalid, possibly because of a typo + - Your KMS key is valid but does not have the necessary permissions (see + above for the necessary key permissions) + - Your KMS key is valid, but not in the region you've told us to use it in. diff --git a/docs/builders/chroot.mdx b/docs/builders/chroot.mdx index 2d32ba61d..97635d76e 100644 --- a/docs/builders/chroot.mdx +++ b/docs/builders/chroot.mdx @@ -35,7 +35,7 @@ builder](/packer/plugins/builders/amazon/ebs), which is much easier to use. The builder does _not_ manage AMIs. Once it creates an AMI and stores it in your account, it is up to you to use, delete, etc., the AMI. -### How Does it Work? +## How Does it Work? This builder works by creating a new EBS volume from an existing source AMI and attaching it into an already-running EC2 instance. Once attached, a @@ -62,11 +62,11 @@ references for [AMI](#ami-configuration), [Access](#access-config-configuration) configuration references, which are necessary for this build to succeed and can be found further down the page. -#### Required: +### Required: @include 'builder/chroot/Config-required.mdx' -#### Optional: +### Optional: @include 'builder/chroot/Config-not-required.mdx' @@ -124,8 +124,7 @@ Block devices can be nested in the Here is a basic example. It is completely valid except for the access keys: - - +**HCL2** ```hcl // To make Packer read these variables from the environment into the var object, @@ -161,8 +160,7 @@ build { } ``` - - +**JSON** ```json { @@ -174,8 +172,6 @@ build { } ``` - - ## Chroot Mounts @@ -194,8 +190,7 @@ defaults. However, if you want to change or add the mount points, you may using the `chroot_mounts` configuration. Here is an example configuration which only mounts `/proc` and `/dev`: - - +**HCL2** ```hcl source "amazon-chroot" "basic-example" { @@ -207,8 +202,7 @@ source "amazon-chroot" "basic-example" { } ``` - - +**JSON** ```json ... @@ -222,8 +216,6 @@ source "amazon-chroot" "basic-example" { }] ``` - - `chroot_mounts` is a list of a 3-tuples of strings. The three components of the 3-tuple, in order, are: @@ -258,8 +250,7 @@ For debian based distributions you can setup a file which will prevent packages installed by your provisioners from starting services: - - +**HCL2** ```hcl // ... @@ -284,8 +275,7 @@ build { } ``` - - +**JSON** ```json "provisioners": [ @@ -304,8 +294,6 @@ build { ] ``` - - ### Ansible provisioner @@ -322,8 +310,7 @@ involving the `nvme_device_path` option above. Read that for more information. A working example for mounting an NVMe device is below: - - +**HCL2** ```hcl // export PKR_VAR_aws_access_key=$YOURKEY @@ -373,8 +360,7 @@ build { } ``` - - +**JSON** ```json { @@ -410,8 +396,6 @@ build { } ``` - - Note that in the `nvme_device_path` you must end with the `p`; if you try to define the partition in this path (e.g. `nvme_device_path`: `/dev/nvme1n1p1`) @@ -426,8 +410,7 @@ The device setup commands partition the device with one partition for use as an HVM image and format it ext4. This builder block should be followed by provisioning commands to install the os and bootloader. - - +**HCL2** ```hcl // This example assumes that AWS_SECRET_ACCESS_KEY and AWS_ACCESS_KEY_ID are @@ -470,8 +453,7 @@ build { } ``` - - +**JSON** ```json { @@ -495,8 +477,6 @@ build { } ``` - - ## Build template data @@ -536,8 +516,7 @@ The generated variables available for this builder are: Usage example: - - +**HCL2** ```hcl // When accessing one of these variables from inside the builder, you need to @@ -567,8 +546,7 @@ post-processor "manifest" { } ``` - - +**JSON** ```json "post-processors": [ @@ -585,5 +563,3 @@ post-processor "manifest" { ] ``` - - diff --git a/docs/builders/ebs.mdx b/docs/builders/ebs.mdx index 2289239eb..78f33a4c1 100644 --- a/docs/builders/ebs.mdx +++ b/docs/builders/ebs.mdx @@ -45,17 +45,17 @@ references for [AMI](#ami-configuration), configuration references, which are necessary for this build to succeed and can be found further down the page. -#### Optional: +**Optional:** @include 'builder/ebs/Config-not-required.mdx' ### AMI Configuration -#### Required: +**Required:** @include 'builder/common/AMIConfig-required.mdx' -#### Optional: +**Optional:** @include 'builder/common/AMIConfig-not-required.mdx' @@ -63,11 +63,11 @@ necessary for this build to succeed and can be found further down the page. ### Access Configuration -#### Required: +**Required:** @include 'builder/common/AccessConfig-required.mdx' -#### Optional: +**Optional:** @include 'builder/common/AccessConfig-not-required.mdx' @@ -85,11 +85,11 @@ necessary for this build to succeed and can be found further down the page. ### Run Configuration -#### Required: +**Required:** @include 'builder/common/RunConfig-required.mdx' -#### Optional: +**Optional:** @include 'builder/common/RunConfig-not-required.mdx' @@ -101,8 +101,7 @@ necessary for this build to succeed and can be found further down the page. Usage Example - - +**HCL2** ```hcl source "amazon-ebs" "basic-example" { @@ -119,8 +118,7 @@ source "amazon-ebs" "basic-example" { } ``` - - +**JSON** ```json { @@ -148,8 +146,29 @@ source "amazon-ebs" "basic-example" { } ``` - - +##### Enforce Instance Metadata Service v2 + +The Amazon builder has support for enforcing metadata service v2 (imdsv2) on a running instance and on the resulting AMI generated from a Packer build. +To enable support for both there are two key attributes that must be defined. + +**HCL2** + +```hcl +source "amazon-ebs" "basic-example" { + region = "us-east-1" + source_ami = "ami-fce3c696" + instance_type = "t2.micro" + ssh_username = "ubuntu" + ami_name = "packer_AWS_example_{{timestamp}}" + # enforces imdsv2 support on the running instance being provisioned by Packer + metadata_options { + http_endpoint = "enabled" + http_tokens = "required" + http_put_response_hop_limit = 1 + } + imds_support = "v2.0" # enforces imdsv2 support on the resulting AMI +} +``` @include 'builders/aws-session-manager.mdx' @@ -161,13 +180,13 @@ Block devices can be nested in the @include 'builder/common/BlockDevice.mdx' -#### Optional: +**Optional:** @include 'builder/common/BlockDevice-not-required.mdx' ### Communicator Configuration -#### Optional: +**Optional:** @include 'packer-plugin-sdk/communicator/Config-not-required.mdx' @@ -187,8 +206,7 @@ Here is a basic example. You will need to provide access keys, and may need to change the AMI IDs according to what images exist at the time the template is run: - - +**HCL2** ```hcl // To make Packer read these variables from the environment into the var object, @@ -227,8 +245,7 @@ build { } ``` - - +**JSON** ```json { @@ -251,8 +268,6 @@ build { } ``` - - -> **Note:** Packer can also read the access key and secret access key directly from environmental variables instead of being set as user variables. See the @@ -265,6 +280,22 @@ Linux](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/finding-an-ami.html) or [for Windows](http://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/finding-an-ami.html). +### Fast Launch Config + +@include 'builder/ebs/FastLaunchConfig.mdx' + +**Optional:** + +@include 'builder/ebs/FastLaunchConfig-not-required.mdx' + +#### Fast Launch Template Config + +@include 'builder/ebs/FastLaunchTemplateConfig-required.mdx' + +**Optional:** + +@include 'builder/ebs/FastLaunchTemplateConfig-not-required.mdx' + ## Accessing the Instance to Debug If you need to access the instance to debug for some reason, run the builder @@ -280,8 +311,7 @@ configuration of `launch_block_device_mappings` will expand the root volume `ami_block_device_mappings` AWS will attach additional volumes `/dev/sdb` and `/dev/sdc` when we boot a new instance of our AMI. - - +**HCL2** ```hcl source "amazon-ebs" "basic-example" { @@ -315,8 +345,7 @@ build { } ``` - - +**JSON** ```json { @@ -351,8 +380,6 @@ build { } ``` - - The above build template is functional assuming you have set the environment variables AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY. @@ -401,8 +428,7 @@ The generated variables available for this builder are: Usage example: - - +**HCL2** ```hcl # When accessing one of these variables from inside the builder, you need to @@ -429,8 +455,7 @@ build { } ``` - - +**JSON** ```json "post-processors": [ @@ -445,8 +470,6 @@ build { ] ``` - - ## Tag Example @@ -455,8 +478,7 @@ Here is an example using the optional AMI tags. This will add the tags provide your access keys, and may need to change the source AMI ID based on what images exist when this template is run: - - +**HCL2** ```hcl source "amazon-ebs" "basic-example" { @@ -480,8 +502,7 @@ build { } ``` - - +**JSON** ```json { @@ -504,8 +525,6 @@ build { } ``` - - ## Connecting to Windows instances using WinRM @@ -573,8 +592,7 @@ You'll notice that this config does not define a user or password; instead, Packer will ask AWS to provide a random password that it generates automatically. The following config will work with the above template: - - +**HCL2** ```hcl # This example uses a amazon-ami data source rather than a specific AMI. @@ -615,8 +633,7 @@ build { } ``` - - +**JSON** ```json { @@ -646,16 +663,13 @@ build { } ``` - - ## Windows 2016 Sysprep Commands - For Amazon Windows AMIs Only For Amazon Windows 2016 AMIs it is necessary to run Sysprep commands which can be easily added to the provisioner section. - - +**HCL2** ```hcl provisioner "powershell" { @@ -666,8 +680,7 @@ provisioner "powershell" { } ``` - - +**JSON** ```json { @@ -679,7 +692,5 @@ provisioner "powershell" { } ``` - - @include 'builders/aws-ssh-differentiation-table.mdx' diff --git a/docs/builders/ebssurrogate.mdx b/docs/builders/ebssurrogate.mdx index c5b8f3fe0..2fff76c42 100644 --- a/docs/builders/ebssurrogate.mdx +++ b/docs/builders/ebssurrogate.mdx @@ -97,8 +97,7 @@ necessary for this build to succeed and can be found further down the page. Usage Example - - +**HCL2** ```hcl source "amazon-ebs" "basic-example" { @@ -115,8 +114,7 @@ source "amazon-ebs" "basic-example" { } ``` - - +**JSON** ```json { @@ -144,8 +142,6 @@ source "amazon-ebs" "basic-example" { } ``` - - @include 'builders/aws-session-manager.mdx' @@ -182,8 +178,7 @@ Block devices can be nested in the ## Basic Example - - +**HCL2** ```hcl source "amazon-ebssurrogate" "basic-example" { @@ -219,8 +214,7 @@ build { } ``` - - +**JSON** ```json { @@ -255,8 +249,6 @@ build { } ``` - - -> **Note:** Packer can also read the access key and secret access key from environmental variables. See the configuration reference in the section above @@ -311,8 +303,7 @@ build { Usage example: - - +**HCL2** ```hcl // When accessing one of these variables from inside the builder, you need to @@ -340,8 +331,7 @@ build { } ``` - - +**JSON** ```json "post-processors": [ @@ -356,8 +346,6 @@ build { ] ``` - - -> **Note:** Packer uses pre-built AMIs as the source for building images. These source AMIs may include volumes that are not flagged to be destroyed on diff --git a/docs/builders/ebsvolume.mdx b/docs/builders/ebsvolume.mdx index 6a57a0395..2a07a2840 100644 --- a/docs/builders/ebsvolume.mdx +++ b/docs/builders/ebsvolume.mdx @@ -102,8 +102,7 @@ Block devices can be nested in the Usage Example - - +**HCL2** ```hcl source "amazon-ebs" "basic-example" { @@ -120,8 +119,7 @@ source "amazon-ebs" "basic-example" { } ``` - - +**JSON** ```json { @@ -149,8 +147,6 @@ source "amazon-ebs" "basic-example" { } ``` - - @include 'builders/aws-session-manager.mdx' @@ -172,8 +168,7 @@ source "amazon-ebs" "basic-example" { ## Basic Example - - +**HCL2** ```hcl source "amazon-ebsvolume" "basic-example" { @@ -221,8 +216,7 @@ build { } ``` - - +**JSON** ```json { @@ -270,8 +264,6 @@ build { } ``` - - -> **Note:** Packer can also read the access key and secret access key from environmental variables. See the configuration reference in the section above @@ -342,8 +334,7 @@ The generated variables available for this builder are: Usage example: - - +**HCL2** ```hcl // When accessing one of these variables from inside the builder, you need to @@ -371,8 +362,7 @@ post-processor "manifest" { } ``` - - +**JSON** ```json "post-processors": [ @@ -387,7 +377,5 @@ post-processor "manifest" { ] ``` - - @include 'builders/aws-ssh-differentiation-table.mdx' diff --git a/docs/builders/instance.mdx b/docs/builders/instance.mdx index 125634e24..a8e6d72ff 100644 --- a/docs/builders/instance.mdx +++ b/docs/builders/instance.mdx @@ -141,8 +141,7 @@ Block devices can be nested in the Here is a basic example. It is completely valid except for the access keys: - - +**HCL2** ```hcl source "amazon-instance" "basic-example" { @@ -165,8 +164,7 @@ build { } ``` - - +**JSON** ```json { @@ -188,8 +186,6 @@ build { } ``` - - -> **Note:** Packer can also read the access key and secret access key from environmental variables. See the configuration reference in the section above @@ -238,8 +234,7 @@ The generated variables available for this builder are: Usage example: - - +**HCL2** ```hcl // When accessing one of these variables from inside the builder, you need to @@ -267,8 +262,7 @@ post-processor "manifest" { } ``` - - +**JSON** ```json "post-processors": [ @@ -283,8 +277,6 @@ post-processor "manifest" { ] ``` - - ## Custom Bundle Commands diff --git a/docs/datasources/index.mdx b/docs/datasources/index.mdx deleted file mode 100644 index 2ce4be122..000000000 --- a/docs/datasources/index.mdx +++ /dev/null @@ -1,36 +0,0 @@ ---- -description: | - The Amazon plugin is able to fetch data from AWS. To achieve this, the plugin comes with - data sources to retrieve AMI and secrets information. -page_title: Amazon - Data Sources -sidebar_title: Overview ---- - -# Amazon Data Sources - -The Amazon plugin is able to fetch data from AWS. To achieve this, the plugin comes with data sources to retrieve AMI and secrets information. -Packer supports the following data sources at the moment: - -- [amazon-ami](/packer/plugins/datasources/amazon/ami) - Filter and fetch an Amazon AMI to output all the AMI information. - -- [amazon-secretsmanager](/packer/plugins/datasources/amazon/secretsmanager) - Retrieve information -about a Secrets Manager secret version, including its secret value. - -- [amazon-parameterstore](/packer/plugins/datasources/amazon/parameterstore) - Retrieve information about a parameter in SSM. - -## How to use this plugin - -From Packer v1.7.0, copy and paste this code into your Packer configuration to install this plugin. -Then, run [`packer init`](/packer/docs/commands/init). - -```hcl -packer { - required_plugins { - amazon = { - version = ">= 1.1.1" - source = "github.com/hashicorp/amazon" - } - } -} -``` - diff --git a/docs/datasources/parameterstore.mdx b/docs/datasources/parameterstore.mdx index 60714973d..0ba5478a8 100644 --- a/docs/datasources/parameterstore.mdx +++ b/docs/datasources/parameterstore.mdx @@ -64,4 +64,4 @@ data "amazon-parameterstore" "basic-example" { external_id = "EXTERNAL_ID" } } -``` \ No newline at end of file +``` diff --git a/docs/datasources/secretsmanager.mdx b/docs/datasources/secretsmanager.mdx index ff8db41e9..1289f2f8f 100644 --- a/docs/datasources/secretsmanager.mdx +++ b/docs/datasources/secretsmanager.mdx @@ -71,4 +71,4 @@ data "amazon-secretsmanager" "basic-example" { external_id = "EXTERNAL_ID" } } -``` \ No newline at end of file +``` diff --git a/docs/post-processors/import.mdx b/docs/post-processors/import.mdx index 05430e067..5133e49ba 100644 --- a/docs/post-processors/import.mdx +++ b/docs/post-processors/import.mdx @@ -38,22 +38,6 @@ Further information about the import process can be found in AWS's [EC2 Import/Export Instance documentation](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instances_of_your_vm.html). -### How to use this plugin - -From Packer v1.7.0, copy and paste this code into your Packer configuration to install this plugin. -Then, run [`packer init`](/packer/docs/commands/init). - -```hcl -packer { - required_plugins { - amazon = { - version = ">= 1.1.1" - source = "github.com/hashicorp/amazon" - } - } -} -``` - ## Configuration There are some configuration options available for the post-processor. They are @@ -119,6 +103,11 @@ Optional: `legacy-bios` or `uefi`. If `architecture` is set to `arm64` then this value must be set to `uefi`. +- `platform` (string) - The operating system of the virtual machine. One of: + `linux` or `windows`. If `boot_mode` is set to `uefi` then this value must be + set to either `windows` or `linux` depending on the operating system of the + virtual machine. + - `custom_endpoint_ec2` (string) - This option is useful if you use a cloud provider whose API is compatible with aws EC2. Specify another endpoint like this `https://ec2.custom.endpoint.com`. diff --git a/example/build.pkr.hcl b/example/build.pkr.hcl index 9d71a194b..8200bf396 100644 --- a/example/build.pkr.hcl +++ b/example/build.pkr.hcl @@ -1,15 +1,18 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + packer { required_plugins { amazon = { version = ">= 1.0.0" - source = "github.com/hashicorp/amazon" + source = "github.com/hashicorp/amazon" } } } -data "amazon-ami" "ubuntu-xenial-1604-amd64" { +data "amazon-ami" "ubuntu-jammy-amd64" { filters = { - name = "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*" + name = "ubuntu/images/*ubuntu-jammy-22.04-amd64-server-*" root-device-type = "ebs" virtualization-type = "hvm" } @@ -23,10 +26,10 @@ source "amazon-ebs" "basic-example" { ami_name = "packer-example-${local.timestamp}" communicator = "ssh" instance_type = "t2.micro" - source_ami = data.amazon-ami.ubuntu-xenial-1604-amd64.id + source_ami = data.amazon-ami.ubuntu-jammy-amd64.id ssh_username = "ubuntu" } build { sources = ["source.amazon-ebs.basic-example"] -} \ No newline at end of file +} diff --git a/example/instance-metadata/ubuntu-imdsv2-enabled.json b/example/instance-metadata/ubuntu-imdsv2-enabled.json new file mode 100644 index 000000000..d5e69f066 --- /dev/null +++ b/example/instance-metadata/ubuntu-imdsv2-enabled.json @@ -0,0 +1,41 @@ +{ + "_comment": "Template used for testing issue 8157", + "variables": { + "region": "us-east-1" + }, + "builders": [ + { + "type": "amazon-ebs", + "ami_name": "packer-example-{{ timestamp }}", + "region": "{{ user `region`}}", + "instance_type": "t2.micro", + "source_ami_filter": { + "filters": { + "virtualization-type": "hvm", + "name": "ubuntu/images/*ubuntu-jammy-22.04-amd64-server-*", + "root-device-type": "ebs" + }, + "owners": [ + "099720109477" + ], + "most_recent": true + }, + "ssh_username": "ubuntu", + "communicator": "ssh", + "metadata_options":{ + "http_endpoint" : "enabled", + "http_tokens": "required", + "http_put_response_hop_limit": 1 + }, + "imds_support":"v2.0" + } + ], + "provisioners": [ + { + "type": "shell", + "inline": [ "TOKEN=`curl -s -X PUT \"http://169.254.169.254/latest/api/token\" -H \"X-aws-ec2-metadata-token-ttl-seconds: 21600\"` && curl -H \"X-aws-ec2-metadata-token: $TOKEN\" -s http://169.254.169.254/latest/meta-data/"] + } + ] + } + + diff --git a/example/instance-metadata/ubuntu-imdsv2-enabled.pkr.hcl b/example/instance-metadata/ubuntu-imdsv2-enabled.pkr.hcl new file mode 100644 index 000000000..ec36ab1cd --- /dev/null +++ b/example/instance-metadata/ubuntu-imdsv2-enabled.pkr.hcl @@ -0,0 +1,45 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +packer { + required_plugins { + amazon = { + version = "~>1" + source = "github.com/hashicorp/amazon" + } + } +} + +data "amazon-ami" "ubuntu-amd64" { + filters = { + name = "ubuntu/images/*ubuntu-jammy-22.04-amd64-server-*" + root-device-type = "ebs" + virtualization-type = "hvm" + } + most_recent = true + owners = ["099720109477"] +} + +locals { timestamp = regex_replace(timestamp(), "[- TZ:]", "") } + +source "amazon-ebs" "imds-example" { + ami_name = "packer-example-${local.timestamp}" + communicator = "ssh" + instance_type = "t2.micro" + source_ami = data.amazon-ami.ubuntu-amd64.id + ssh_username = "ubuntu" + metadata_options { + http_endpoint = "enabled" + http_tokens = "required" + http_put_response_hop_limit = 1 + } + imds_support = "v2.0" + +} + +build { + sources = ["source.amazon-ebs.imds-example"] + provisioner "shell" { + inline = ["TOKEN=`curl -s -X PUT \"http://169.254.169.254/latest/api/token\" -H \"X-aws-ec2-metadata-token-ttl-seconds: 21600\"` && curl -H \"X-aws-ec2-metadata-token: $TOKEN\" -s http://169.254.169.254/latest/meta-data/"] + } +} diff --git a/go.mod b/go.mod index 6f2e3f92f..5cc349f81 100644 --- a/go.mod +++ b/go.mod @@ -1,67 +1,77 @@ module github.com/hashicorp/packer-plugin-amazon -go 1.17 +go 1.21 + +toolchain go1.21.8 require ( - github.com/aws/aws-sdk-go v1.44.110 - github.com/google/go-cmp v0.5.6 + github.com/aws/aws-sdk-go v1.45.6 + github.com/google/go-cmp v0.6.0 github.com/hashicorp/aws-sdk-go-base v0.7.1 github.com/hashicorp/go-cleanhttp v0.5.2 github.com/hashicorp/go-multierror v1.1.1 - github.com/hashicorp/hcl/v2 v2.13.0 - github.com/hashicorp/packer-plugin-sdk v0.3.2 - github.com/hashicorp/vault/api v1.1.1 - github.com/mitchellh/mapstructure v1.4.1 - github.com/stretchr/testify v1.7.0 - github.com/zclconf/go-cty v1.10.0 - golang.org/x/crypto v0.0.0-20220517005047-85d78b3ac167 - golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e + github.com/hashicorp/hcl/v2 v2.19.1 + github.com/hashicorp/packer-plugin-sdk v0.5.2 + github.com/hashicorp/vault/api v1.10.0 + github.com/mitchellh/mapstructure v1.5.0 + github.com/stretchr/testify v1.8.3 + github.com/zclconf/go-cty v1.13.3 + golang.org/x/crypto v0.21.0 + golang.org/x/sys v0.18.0 ) require ( - cloud.google.com/go v0.94.0 // indirect - cloud.google.com/go/storage v1.16.1 // indirect + cloud.google.com/go v0.110.8 // indirect + cloud.google.com/go/compute v1.23.1 // indirect + cloud.google.com/go/compute/metadata v0.2.3 // indirect + cloud.google.com/go/iam v1.1.3 // indirect + cloud.google.com/go/storage v1.35.1 // indirect github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c // indirect github.com/ChrisTrenkamp/goxpath v0.0.0-20210404020558-97928f7e12b6 // indirect github.com/agext/levenshtein v1.2.3 // indirect github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect - github.com/armon/go-metrics v0.3.9 // indirect + github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect + github.com/armon/go-metrics v0.4.1 // indirect github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect github.com/cenkalti/backoff/v3 v3.2.2 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dylanmei/iso8601 v0.1.0 // indirect - github.com/fatih/color v1.12.0 // indirect + github.com/fatih/color v1.14.1 // indirect + github.com/go-jose/go-jose/v3 v3.0.3 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gofrs/uuid v4.0.0+incompatible // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.2 // indirect - github.com/golang/snappy v0.0.4 // indirect - github.com/google/uuid v1.3.0 // indirect - github.com/googleapis/gax-go/v2 v2.1.0 // indirect - github.com/hashicorp/consul/api v1.10.1 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/google/s2a-go v0.1.7 // indirect + github.com/google/uuid v1.4.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect + github.com/googleapis/gax-go/v2 v2.12.0 // indirect + github.com/hashicorp/consul/api v1.25.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect - github.com/hashicorp/go-getter/gcs/v2 v2.1.0 // indirect - github.com/hashicorp/go-getter/s3/v2 v2.1.0 // indirect - github.com/hashicorp/go-getter/v2 v2.1.0 // indirect - github.com/hashicorp/go-hclog v0.16.2 // indirect + github.com/hashicorp/go-getter/gcs/v2 v2.2.2 // indirect + github.com/hashicorp/go-getter/s3/v2 v2.2.2 // indirect + github.com/hashicorp/go-getter/v2 v2.2.2 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-retryablehttp v0.7.0 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect github.com/hashicorp/go-safetemp v1.0.0 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect github.com/hashicorp/go-sockaddr v1.0.2 // indirect - github.com/hashicorp/go-version v1.3.0 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/hashicorp/serf v0.9.5 // indirect - github.com/hashicorp/vault/sdk v0.2.1 // indirect - github.com/hashicorp/yamux v0.0.0-20210826001029-26ff87cf9493 // indirect + github.com/hashicorp/serf v0.10.1 // indirect + github.com/hashicorp/yamux v0.1.1 // indirect github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/klauspost/compress v1.11.2 // indirect github.com/kr/fs v0.1.0 // indirect github.com/masterzen/simplexml v0.0.0-20190410153822-31eea3082786 // indirect github.com/masterzen/winrm v0.0.0-20210623064412-3b76017826b0 // indirect - github.com/mattn/go-colorable v0.1.8 // indirect - github.com/mattn/go-isatty v0.0.13 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect github.com/mitchellh/go-fs v0.0.0-20180402235330-b7b9ca407fff // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect @@ -70,26 +80,31 @@ require ( github.com/mitchellh/reflectwalk v1.0.0 // indirect github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect github.com/packer-community/winrmcp v0.0.0-20180921211025-c76d91c1e7db // indirect - github.com/pierrec/lz4 v2.6.1+incompatible // indirect github.com/pkg/sftp v1.13.2 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect github.com/ugorji/go/codec v1.2.6 // indirect github.com/ulikunitz/xz v0.5.10 // indirect - go.opencensus.io v0.23.0 // indirect - golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect - golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f // indirect - golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect - golang.org/x/text v0.3.7 // indirect - golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect - google.golang.org/api v0.56.0 // indirect + go.opencensus.io v0.24.0 // indirect + golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect + golang.org/x/net v0.23.0 // indirect + golang.org/x/oauth2 v0.13.0 // indirect + golang.org/x/sync v0.5.0 // indirect + golang.org/x/term v0.18.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/time v0.3.0 // indirect + golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect + google.golang.org/api v0.150.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2 // indirect - google.golang.org/grpc v1.40.0 // indirect - google.golang.org/protobuf v1.27.1 // indirect - gopkg.in/square/go-jose.v2 v2.6.0 // indirect + google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 // indirect + google.golang.org/grpc v1.59.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/yaml.v2 v2.3.0 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) -replace github.com/hashicorp/packer-plugin-sdk => github.com/inloco/packer-plugin-sdk v0.3.2-incognia.1 +replace github.com/zclconf/go-cty => github.com/nywilken/go-cty v1.13.3 // added by packer-sdc fix as noted in github.com/hashicorp/packer-plugin-sdk/issues/187 + +replace github.com/hashicorp/packer-plugin-sdk => github.com/inloco/packer-plugin-sdk v0.5.4 diff --git a/go.sum b/go.sum index b3137da93..905449a40 100644 --- a/go.sum +++ b/go.sum @@ -1,283 +1,143 @@ -bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= -cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= -cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= -cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.94.0 h1:QDB2MZHqjTt0hGKnoEWyG/iWykue/lvkLdogLgrg10U= -cloud.google.com/go v0.94.0/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.16.1 h1:sMEIc4wxvoY3NXG7Rn9iP7jb/2buJgWR1vNXCR/UPfs= -cloud.google.com/go/storage v1.16.1/go.mod h1:LaNorbty3ehnU3rEjXSNV/NRgQA0O8Y+uh6bPe5UOk4= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +cloud.google.com/go v0.110.8 h1:tyNdfIxjzaWctIiLYOTalaLKZ17SI44SKFW26QbOhME= +cloud.google.com/go v0.110.8/go.mod h1:Iz8AkXJf1qmxC3Oxoep8R1T36w8B92yU29PcBhHO5fk= +cloud.google.com/go/compute v1.23.1 h1:V97tBoDaZHb6leicZ1G6DLK2BAaZLJ/7+9BB/En3hR0= +cloud.google.com/go/compute v1.23.1/go.mod h1:CqB3xpmPKKt3OJpW2ndFIXnA9A4xAy/F3Xp1ixncW78= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/iam v1.1.3 h1:18tKG7DzydKWUnLjonWcJO6wjSCAtzh4GcRKlH/Hrzc= +cloud.google.com/go/iam v1.1.3/go.mod h1:3khUlaBXfPKKe7huYgEpDn6FtgRyMEqbkvBxrQyY5SE= +cloud.google.com/go/storage v1.35.1 h1:B59ahL//eDfx2IIKFBeT5Atm9wnNmj3+8xG/W4WB//w= +cloud.google.com/go/storage v1.35.1/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8= github.com/Azure/go-ntlmssp v0.0.0-20180810175552-4a21cbd618b4/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c h1:/IBSNwUN8+eKzUzbJPqhK839ygXJ82sde8x3ogr6R28= github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/ChrisTrenkamp/goxpath v0.0.0-20170922090931-c385f95c6022/go.mod h1:nuWgzSkT5PnyOd+272uUmV0dnAnAn42Mk7PiQC5VzN4= github.com/ChrisTrenkamp/goxpath v0.0.0-20210404020558-97928f7e12b6 h1:w0E0fgc1YafGEh5cROhlROMWXiNoZqApk2PDN0M1+Ns= github.com/ChrisTrenkamp/goxpath v0.0.0-20210404020558-97928f7e12b6/go.mod h1:nuWgzSkT5PnyOd+272uUmV0dnAnAn42Mk7PiQC5VzN4= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= -github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= -github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/antchfx/xmlquery v1.3.5 h1:I7TuBRqsnfFuL11ruavGm911Awx9IqSdiU6W/ztSmVw= +github.com/antchfx/xmlquery v1.3.5/go.mod h1:64w0Xesg2sTaawIdNqMB+7qaW/bSqkQm+ssPaCMWNnc= github.com/antchfx/xpath v1.1.11 h1:WOFtK8TVAjLm3lbgqeP0arlHpvCEeTANeWZ/csPpJkQ= github.com/antchfx/xpath v1.1.11/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= -github.com/antchfx/xquery v0.0.0-20180515051857-ad5b8c7a47b0 h1:JaCC8jz0zdMLk2m+qCCVLLLM/PL93p84w4pK3aJWj60= -github.com/antchfx/xquery v0.0.0-20180515051857-ad5b8c7a47b0/go.mod h1:LzD22aAzDP8/dyiCKFp31He4m2GPjl0AFyzDtZzUu9M= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3 h1:ZSTrOEhiM5J5RFxEaFvMZVEAM1KvT1YzbEOwB2EAGjA= github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= -github.com/apparentlymart/go-textseg v1.0.0 h1:rRmlIsPEEhUTIKQb7T++Nz/A5Q6C9IuX2wFoYVvnCs0= -github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk= github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= +github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= +github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-metrics v0.3.0/go.mod h1:zXjbSimjXTd7vOpY8B0/2LpvNvDoXBuplAD+gJD3GYs= -github.com/armon/go-metrics v0.3.3/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= -github.com/armon/go-metrics v0.3.9 h1:O2sNqxBdvq8Eq5xmzljcYzAORli6RWCvEym4cJf9m18= -github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go v1.25.37/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.30.8/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/aws/aws-sdk-go v1.30.27/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/aws/aws-sdk-go v1.31.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/aws/aws-sdk-go v1.40.34/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= -github.com/aws/aws-sdk-go v1.44.110 h1:unno3l2FYQo6p0wYCp9gUk8YNzhOxqSktM0Y1vukl9k= -github.com/aws/aws-sdk-go v1.44.110/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/aws/aws-sdk-go v1.45.6 h1:Y2isQQBZsnO15dzUQo9YQRThtHgrV200XCH05BRHVJI= +github.com/aws/aws-sdk-go v1.45.6/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= -github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= -github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.3.4/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= -github.com/containerd/continuity v0.0.0-20200709052629-daa8e1ccc0bc/go.mod h1:cECdGN1O8G9bgKTlLhuPJimka6Xb/Gg7vYzCTNVxhvo= -github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= -github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= -github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= -github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v1.4.2-0.20200319182547-c7ad2b866182/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dylanmei/iso8601 v0.1.0 h1:812NGQDBcqquTfH5Yeo7lwR0nzx/cKdsmf3qMjPURUI= github.com/dylanmei/iso8601 v0.1.0/go.mod h1:w9KhXSgIyROl1DefbMYIE7UVSIvELTbMrCfx+QkYnoQ= -github.com/dylanmei/winrmtest v0.0.0-20170819153634-c2fbb09e6c08 h1:0bp6/GrNOrTDtSXe9YYGCwf8jp5Fb/b+4a6MTRm4qzY= -github.com/dylanmei/winrmtest v0.0.0-20170819153634-c2fbb09e6c08/go.mod h1:VBVDFSBXCIW8JaHQpI8lldSKfYaLMzP9oyq6IJ4fhzY= +github.com/dylanmei/winrmtest v0.0.0-20210303004826-fbc9ae56efb6 h1:zWydSUQBJApHwpQ4guHi+mGyQN/8yN6xbKWdDtL3ZNM= +github.com/dylanmei/winrmtest v0.0.0-20210303004826-fbc9ae56efb6/go.mod h1:6BLLhzn1VEiJ4veuAGhINBTrBlV889Wd+aU4auxKOww= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc= -github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= -github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= -github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= -github.com/frankban/quicktest v1.10.0 h1:Gfh+GAJZOAoKZsIZeZbdn2JF10kN1XHNvjsvQK8gVkE= -github.com/frankban/quicktest v1.10.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= +github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= +github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= +github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-ldap/ldap/v3 v3.1.3/go.mod h1:3rbOH3jRS2u6jg2rJnKAMLE/xQyCKIveG2Sa/Cohzb8= -github.com/go-ldap/ldap/v3 v3.1.10/go.mod h1:5Zun81jBTabRaI8lzN7E1JjyEl1g6zI6u9pd8luAK4Q= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= -github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.2.1 h1:d8MncMlErDFTwQGBK1xhv026j9kqhvw1Qv9IbWT1VLQ= -github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= +github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.1.0 h1:6DWmvNpomjL1+3liNSZbVns3zsYzzCjm6pRBO1tLeso= -github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= +github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/hashicorp/aws-sdk-go-base v0.7.1 h1:7s/aR3hFn74tYPVihzDyZe7y/+BorN70rr9ZvpV3j3o= github.com/hashicorp/aws-sdk-go-base v0.7.1/go.mod h1:2fRjWDv3jJBeN6mVWFHV6hFTNeFBx2gpDLQaZNxUVAY= -github.com/hashicorp/consul/api v1.10.1 h1:MwZJp86nlnL+6+W1Zly4JUuVn9YHhMggBirMpHGD7kw= -github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= -github.com/hashicorp/consul/sdk v0.8.0 h1:OJtKBtEjboEZvG6AOUdh4Z1Zbyu0WcxQ0qatRrZHTVU= -github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= +github.com/hashicorp/consul/api v1.25.1 h1:CqrdhYzc8XZuPnhIYZWH45toM0LB9ZeYr/gvpLVI3PE= +github.com/hashicorp/consul/api v1.25.1/go.mod h1:iiLVwR/htV7mas/sy0O+XSuEnrdBUUydemjxcUrAt4g= +github.com/hashicorp/consul/sdk v0.14.1 h1:ZiwE2bKb+zro68sWzZ1SgHF3kRMBZ94TwOCFRF4ylPs= +github.com/hashicorp/consul/sdk v0.14.1/go.mod h1:vFt03juSzocLRFo59NkeQHHmQa6+g7oU0pfzdI1mUhg= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -285,24 +145,18 @@ github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-getter/gcs/v2 v2.1.0 h1:1S1hvWgHrhUihP/Y4FVbjCWwE7EwxpksKoRcC7g+Hgs= -github.com/hashicorp/go-getter/gcs/v2 v2.1.0/go.mod h1:dVyTnX1BynHAjbumB4Pk14GoJ+v3VbDUJtbI7G0oOlU= -github.com/hashicorp/go-getter/s3/v2 v2.1.0 h1:8uwuP97zEQ7y7H4bLzRqiN4T8vmpXeJthigqSEjX+08= -github.com/hashicorp/go-getter/s3/v2 v2.1.0/go.mod h1:rwzJPQaBuc5riYOucPx84DOE74xIhKENOWgBjK3XVEs= -github.com/hashicorp/go-getter/v2 v2.1.0 h1:MsLbi7yFKGFPVmpK+un4/k5HFry0tqvo9JppsCmIutU= -github.com/hashicorp/go-getter/v2 v2.1.0/go.mod h1:w65fE5glbccYjndAuj1kA5lnVBGZYEaH0e5qA1kpIks= -github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= +github.com/hashicorp/go-getter/gcs/v2 v2.2.2 h1:KDbsz44Clh+qpsskK9EnlhWki8NMH18jlAjEseJXIco= +github.com/hashicorp/go-getter/gcs/v2 v2.2.2/go.mod h1:reRiCTBtE1ANT92nMmjwbDzoB6KMJ5azAoMOvQRGGH0= +github.com/hashicorp/go-getter/s3/v2 v2.2.2 h1:ProI1SMBNRt17gC3I8XCMdh35sXN68IUieYnWXwfwew= +github.com/hashicorp/go-getter/s3/v2 v2.2.2/go.mod h1:5MRjeGjI4DqzkRYa+g6OuNJDR0MamdE5VqDPdI42+vQ= +github.com/hashicorp/go-getter/v2 v2.2.2 h1:Al5bzCNW5DrlZMK6TumGrSue7Xz8beyLcen+4N4erwo= +github.com/hashicorp/go-getter/v2 v2.2.2/go.mod h1:hp5Yy0GMQvwWVUmwLs3ygivz1JSLI323hdIE9J9m7TY= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-hclog v0.16.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-hclog v0.16.2 h1:K4ev2ib4LdQETX5cSZBG0DVLk1jwGqSPXBjdah3veNs= -github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-immutable-radix v1.1.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-kms-wrapping/entropy v0.1.0/go.mod h1:d1g9WGtAunDNpek8jUIEJnBlbgKS1N2Q61QkHiZyR1g= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= @@ -310,65 +164,49 @@ github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHh github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-retryablehttp v0.6.2/go.mod h1:gEx6HMUGxYYhJScX7W1Il64m6cc2C1mDaW3NQ9sY1FY= -github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-retryablehttp v0.7.0 h1:eu1EI/mbirUgP5C8hVsTNaGZreBDlYiwC1FZWkvQPQ4= github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= -github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 h1:om4Al8Oy7kCm/B86rLCLah4Dt5Aa0Fr5rYBG60OzwHQ= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= -github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go-version v1.3.0 h1:McDWVJIU/y+u1BRV06dPaLfLCaT7fUTJLp5r04x7iNw= -github.com/hashicorp/go-version v1.3.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/hcl/v2 v2.13.0 h1:0Apadu1w6M11dyGFxWnmhhcMjkbAiKCv7G1r/2QgCNc= -github.com/hashicorp/hcl/v2 v2.13.0/go.mod h1:e4z5nxYlWNPdDSNYX+ph14EvWYMFm3eP0zIUqPc2jr0= +github.com/hashicorp/hcl/v2 v2.19.1 h1://i05Jqznmb2EXqa39Nsvyan2o5XyMowW5fnCKW5RPI= +github.com/hashicorp/hcl/v2 v2.19.1/go.mod h1:ThLC89FV4p9MPW804KVbe/cEXoQ8NZEh+JtMeeGErHE= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= -github.com/hashicorp/memberlist v0.2.2 h1:5+RffWKwqJ71YPu9mWsF7ZOscZmwfasdA8kbdC7AO2g= -github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= -github.com/hashicorp/serf v0.9.5 h1:EBWvyu9tcRszt3Bxp3KNssBMP1KuHWyO51lz9+786iM= -github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= -github.com/hashicorp/vault/api v1.0.5-0.20200519221902-385fac77e20f/go.mod h1:euTFbi2YJgwcju3imEt919lhJKF68nN1cQPq3aA+kBE= -github.com/hashicorp/vault/api v1.1.1 h1:907ld+Z9cALyvbZK2qUX9cLwvSaEQsMVQB3x2KE8+AI= -github.com/hashicorp/vault/api v1.1.1/go.mod h1:29UXcn/1cLOPHQNMWA7bCz2By4PSd0VKPAydKXS5yN0= -github.com/hashicorp/vault/sdk v0.1.14-0.20200519221530-14615acda45f/go.mod h1:WX57W2PwkrOPQ6rVQk+dy5/htHIaB4aBM70EwKThu10= -github.com/hashicorp/vault/sdk v0.2.1 h1:S4O6Iv/dyKlE9AUTXGa7VOvZmsCvg36toPKgV4f2P4M= -github.com/hashicorp/vault/sdk v0.2.1/go.mod h1:WfUiO1vYzfBkz1TmoE4ZGU7HD0T0Cl/rZwaxjBkgN4U= -github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= -github.com/hashicorp/yamux v0.0.0-20210826001029-26ff87cf9493 h1:brI5vBRUlAlM34VFmnLPwjnCL/FxAJp9XvOdX6Zt+XE= -github.com/hashicorp/yamux v0.0.0-20210826001029-26ff87cf9493/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/inloco/packer-plugin-sdk v0.3.2-incognia.1 h1:gkC1f9NdVqjmJMm5sUqcNoXWQ6Do4NPoge/V6PAWV9Q= -github.com/inloco/packer-plugin-sdk v0.3.2-incognia.1/go.mod h1:XZRvL9kRqJJtB6rf9Lu2zWLJbf2/4ImWXDjp9O9UQGE= +github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= +github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM= +github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0= +github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= +github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= +github.com/hashicorp/vault/api v1.10.0 h1:/US7sIjWN6Imp4o/Rj1Ce2Nr5bki/AXi9vAW3p2tOJQ= +github.com/hashicorp/vault/api v1.10.0/go.mod h1:jo5Y/ET+hNyz+JnKDt8XLAdKs+AM0G5W0Vp1IrFI8N8= +github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= +github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/inloco/packer-plugin-sdk v0.5.4 h1:q8AIkPujK4Ccl0qL/MCisY5HVb2c0aucaKCyChOtMPk= +github.com/inloco/packer-plugin-sdk v0.5.4/go.mod h1:DH6SOIAdO3t0IXS5tgiJwfPi+ougQgZA5pkJUPdMSSw= github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 h1:IPJ3dvxmJ4uczJe5YQdrYB16oTJlGSC/OyZDqUk9xX4= github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869/go.mod h1:cJ6Cj7dQo+O6GJNiMx+Pa94qKj+TG8ONdKHgMNIyyag= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= @@ -376,12 +214,9 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGw github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.11.2 h1:MiK62aErc3gIiVEtyzKfeOHgW7atJb5g/KNX5m3c2nQ= +github.com/klauspost/compress v1.11.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= @@ -393,7 +228,6 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/masterzen/simplexml v0.0.0-20160608183007-4572e39b1ab9/go.mod h1:kCEbxUJlNDEBNbdQMkPSp6yaKcRXVI6f4ddk8Riv4bc= github.com/masterzen/simplexml v0.0.0-20190410153822-31eea3082786 h1:2ZKn+w/BJeL43sCxI2jhPLRv73oVVOjEKZjKkflyqxg= github.com/masterzen/simplexml v0.0.0-20190410153822-31eea3082786/go.mod h1:kCEbxUJlNDEBNbdQMkPSp6yaKcRXVI6f4ddk8Riv4bc= @@ -402,568 +236,252 @@ github.com/masterzen/winrm v0.0.0-20210623064412-3b76017826b0/go.mod h1:l31LCh9V github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= -github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA= -github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.26 h1:gPxPSwALAeHJSjarOs00QjVdV9QoBvc1D2ujQUr5BzU= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= -github.com/mitchellh/cli v1.1.2/go.mod h1:6iaV0fGdElS6dPBx0EApTxHrcWvmJphyh2n8YBLPPZ4= -github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/go-fs v0.0.0-20180402235330-b7b9ca407fff h1:bFJ74ac7ZK/jyislqiWdzrnENesFt43sNEBRh1xk/+g= github.com/mitchellh/go-fs v0.0.0-20180402235330-b7b9ca407fff/go.mod h1:g7SZj7ABpStq3tM4zqHiVEG5un/DZ1+qJJKO7qx1EvU= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= -github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/mitchellh/iochan v1.0.0 h1:C+X3KsSTLFVBr/tK1eYN/vs4rJcvsiLU338UhYPJWeY= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= -github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= -github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= -github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/nywilken/go-cty v1.13.3 h1:03U99oXf3j3g9xgqAE3YGpixCjM8Mg09KZ0Ji9LzX0o= +github.com/nywilken/go-cty v1.13.3/go.mod h1:YKQzy/7pZ7iq2jNFzy5go57xdxdWoLLpaEp4u238AE0= github.com/packer-community/winrmcp v0.0.0-20180921211025-c76d91c1e7db h1:9uViuKtx1jrlXLBW/pMnhOfzn3iSEdLase/But/IZRU= github.com/packer-community/winrmcp v0.0.0-20180921211025-c76d91c1e7db/go.mod h1:f6Izs6JvFTdnRbziASagjZ2vmf55NSIkC/weStxCHqk= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pierrec/lz4 v2.5.2+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= -github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.13.2 h1:taJnKntsWgU+qae21Rx52lIwndAdKrj0mfUNQsz1z4Q= github.com/pkg/sftp v1.13.2/go.mod h1:LzqnAvaD5TWeNBsZpfKxSYn1MbjWwOsCIAFFJbpIsK8= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= -github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= -github.com/ugorji/go v1.2.6 h1:tGiWC9HENWE2tqYycIqFTNorMmFRVhNwCpDOpWqnk8E= github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0= github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ= github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw= -github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8= github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= -github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= -github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= -github.com/zclconf/go-cty v1.8.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= -github.com/zclconf/go-cty v1.10.0 h1:mp9ZXQeIcN8kAwuqorjH+Q+njbJKjLrvB2yIh4q7U+0= -github.com/zclconf/go-cty v1.10.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b h1:FosyBZYxY34Wul7O/MSKey3txpPYyCqVO5ZyceuQJEI= github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190222235706-ffb98f73852f/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220517005047-85d78b3ac167 h1:O8uGbHCqlTp2P6QJSLmCojM4mN6UemYv8K+dCnmHmu0= -golang.org/x/crypto v0.0.0-20220517005047-85d78b3ac167/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= +golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mobile v0.0.0-20210901025245-1fde1d6c3ca1/go.mod h1:jFTmtFYCV0MFtXBU+J5V/+5AUeVS0ON/0WkE/KSrl6E= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f h1:Qmd2pbz05z7z6lm0DrgQVVPuBm92jqujBKMHMOlOQEw= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= +golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= -golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.21.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= -google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= -google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= -google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= -google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.56.0 h1:08F9XVYTLOGeSQb3xI9C0gXMuQanhdGed0cWFhDozbI= -google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +google.golang.org/api v0.150.0 h1:Z9k22qD289SZ8gCJrk4DrWXkNjtfvKAUo/l1ma8eBYE= +google.golang.org/api v0.150.0/go.mod h1:ccy+MJ6nrYFgE3WgRx/AMXOxOmU8Q4hSa+jjibzhxcg= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= -google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210825212027-de86158e7fda/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2 h1:NHN4wOCScVzKhPenJ2dt+BTs3X/XkBVI/Rh4iDt55T8= -google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b h1:+YaDE2r2OG8t/z5qmsh7Y+XXwCbvadxxZ0YY6mTdrVA= +google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:CgAqfJo+Xmu0GwA0411Ht3OU3OntXwsGmrmjI8ioGXI= +google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b h1:CIC2YMXmIhYw6evmhPxBKJ4fmLbOFtXQN/GV3XOZR8k= +google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 h1:AB/lmRny7e2pLhFEYIbl5qkDAUt2h0ZRO4wGPhZf+ik= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405/go.mod h1:67X1fPuzjcrkymZzZV1vvkFeTn2Rvc6lYF9MYFGCcwE= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -972,46 +490,25 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= -gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= -gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= -gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/main.go b/main.go index 21d6a04a8..9359e8f58 100644 --- a/main.go +++ b/main.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package main import ( diff --git a/post-processor/import/post-processor.go b/post-processor/import/post-processor.go index 5b130472c..dc696dfcc 100644 --- a/post-processor/import/post-processor.go +++ b/post-processor/import/post-processor.go @@ -1,3 +1,6 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + //go:generate packer-sdc mapstructure-to-hcl2 -type Config package amazonimport @@ -50,6 +53,7 @@ type Config struct { Format string `mapstructure:"format"` Architecture string `mapstructure:"architecture"` BootMode string `mapstructure:"boot_mode"` + Platform string `mapstructure:"platform"` ctx interpolate.Context } @@ -89,6 +93,8 @@ func (p *PostProcessor) Configure(raws ...interface{}) error { p.config.Architecture = "x86_64" } + errs := new(packersdk.MultiError) + if p.config.BootMode == "" { // Graviton instance types run uefi by default if p.config.Architecture == "arm64" { @@ -96,10 +102,13 @@ func (p *PostProcessor) Configure(raws ...interface{}) error { } else { p.config.BootMode = "legacy-bios" } + } else { + err := awscommon.IsValidBootMode(p.config.BootMode) + if err != nil { + errs = packersdk.MultiErrorAppend(errs, err) + } } - errs := new(packersdk.MultiError) - // Check and render s3_key_name if err = interpolate.Validate(p.config.S3Key, &p.config.ctx); err != nil { errs = packersdk.MultiErrorAppend( @@ -128,6 +137,17 @@ func (p *PostProcessor) Configure(raws ...interface{}) error { errs, fmt.Errorf("invalid format '%s'. Only 'ova', 'raw', 'vhd', 'vhdx', or 'vmdk' are allowed", p.config.Format)) } + switch p.config.Platform { + case "windows", "linux": + case "": + if p.config.BootMode == "uefi" { + errs = packersdk.MultiErrorAppend( + errs, fmt.Errorf("invalid platform '%s', 'platform' must be set for 'uefi' image imports", p.config.Platform)) + } + default: + errs = packersdk.MultiErrorAppend(errs, fmt.Errorf( + "invalid platform '%s'. Only 'linux' and 'windows' are allowed", p.config.Platform)) + } if p.config.S3Encryption != "" && p.config.S3Encryption != "AES256" && p.config.S3Encryption != "aws:kms" { errs = packersdk.MultiErrorAppend( errs, fmt.Errorf("invalid s3 encryption format '%s'. Only 'AES256' and 'aws:kms' are allowed", p.config.S3Encryption)) @@ -251,6 +271,7 @@ func (p *PostProcessor) PostProcess(ctx context.Context, ui packersdk.Ui, artifa }, Architecture: &p.config.Architecture, BootMode: &p.config.BootMode, + Platform: &p.config.Platform, } if p.config.Encrypt && p.config.KMSKey != "" { diff --git a/post-processor/import/post-processor.hcl2spec.go b/post-processor/import/post-processor.hcl2spec.go index 943b1d8be..f7e11d82b 100644 --- a/post-processor/import/post-processor.hcl2spec.go +++ b/post-processor/import/post-processor.hcl2spec.go @@ -54,6 +54,7 @@ type FlatConfig struct { Format *string `mapstructure:"format" cty:"format" hcl:"format"` Architecture *string `mapstructure:"architecture" cty:"architecture" hcl:"architecture"` BootMode *string `mapstructure:"boot_mode" cty:"boot_mode" hcl:"boot_mode"` + Platform *string `mapstructure:"platform" cty:"platform" hcl:"platform"` } // FlatMapstructure returns a new FlatConfig. @@ -111,6 +112,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { "format": &hcldec.AttrSpec{Name: "format", Type: cty.String, Required: false}, "architecture": &hcldec.AttrSpec{Name: "architecture", Type: cty.String, Required: false}, "boot_mode": &hcldec.AttrSpec{Name: "boot_mode", Type: cty.String, Required: false}, + "platform": &hcldec.AttrSpec{Name: "platform", Type: cty.String, Required: false}, } return s } diff --git a/version/version.go b/version/version.go index 7bf6c6ae6..6ed559842 100644 --- a/version/version.go +++ b/version/version.go @@ -1,10 +1,13 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + package version import "github.com/hashicorp/packer-plugin-sdk/version" var ( // Version is the main version number that is being run at the moment. - Version = "1.1.6" + Version = "1.3.3" // VersionPrerelease is A pre-release marker for the Version. If this is "" // (empty string) then it means that it is a final release. Otherwise, this