This module can be used to set up a secure CI/CD pipeline for your infrastructure code
(Terraform, Terragrunt, Packer,
Docker, etc). You can use this in combination with existing CI servers (e.g Jenkins, CircleCI,
Gitlab) to set up workflows that:
Run plan and apply with approval stages
Build docker images for every PR
Build VM images (e.g., AMIs) for every PR
Automatically update infrastructure code and commit and push the changes to Git
These workflows can be implemented without directly running the steps from your CI servers. Instead, the CI server can coordinate the CI / CD flow, and for anything that requires sensitive / powerful IAM permissions, it can trigger pre-defined, locked-down jobs in an isolated ECS task, and stream the logs from that task as if it’s running locally.
Overview: An overview of the architecture deployed by in this module, including how
to implement a CI/CD pipeline for infrastructure code.
Threat model of the deploy runner: An overview of the threat
model used to design the security features of the solution, including a description of the potential attack vectors
that are mitigated by the solution, and those attacks that require policy and behavioral changes to mitigate.
If you need help with this repo or anything else related to infrastructure or DevOps, Gruntwork offers Commercial Support via Slack, email, and phone/video. If you’re already a Gruntwork customer, hop on Slack and ask away! If not, subscribe now. If you’re not sure, feel free to email us at support@gruntwork.io.
Contributions to this repo are very welcome and appreciated! If you find a bug or want to add a new feature or even contribute an entirely new module, we are very happy to accept pull requests, provide feedback, and run your changes through our automated test suite.
{"treedata":{"name":"root","toggled":true,"children":[{"name":".circleci","children":[{"name":"config.yml","path":".circleci/config.yml","sha":"39a21f4f15394416888317f9eb003e5e9760176d"}]},{"name":".gitignore","path":".gitignore","sha":"1cd2e7ca72e5102b6b85a0c1de82d28c99d4287e"},{"name":".pre-commit-config.yaml","path":".pre-commit-config.yaml","sha":"47826a6fca6c68c6e0f0e9ac88988c2830ed4ef1"},{"name":"CODEOWNERS","path":"CODEOWNERS","sha":"a834dbe979d6fb551a71156abfb7e22771115e48"},{"name":"LICENSE.txt","path":"LICENSE.txt","sha":"f4e3d9bd4717a044ed31ad847a300eee74371a78"},{"name":"README-CircleCI.adoc","path":"README-CircleCI.adoc","sha":"046b030ed6e15023530d4a29a3dcf60ac7982d27"},{"name":"README-Jenkins.adoc","path":"README-Jenkins.adoc","sha":"2587e3b59001ed39eaac88468202afdcbc2332af"},{"name":"README-Terraform-Terragrunt-Pipeline.adoc","path":"README-Terraform-Terragrunt-Pipeline.adoc","sha":"1ad99530c6cf984aa638e7c2fcd0bf4d4987ce12"},{"name":"README-TravisCI.adoc","path":"README-TravisCI.adoc","sha":"45e0d32aae5d971ee7e7670dc0da94d364c14457"},{"name":"README.adoc","path":"README.adoc","sha":"47cb10253af3b2e514678434a61ad681c02a88f2"},{"name":"_ci","children":[{"name":"output-debug-values.sh","path":"_ci/output-debug-values.sh","sha":"fa613638c76c2031b1427c2daa1d66f71fedad68"}]},{"name":"_docs","children":[{"name":"circleci-cicd-architecture.png","path":"_docs/circleci-cicd-architecture.png","sha":"06f8a55b7c123b6e589333a1ff1c3d90c43222d6"},{"name":"circleci-icon.png","path":"_docs/circleci-icon.png","sha":"d4e8df17858e6f230ff9e8d90ea388b3ff340b79"},{"name":"jenkins-architecture.png","path":"_docs/jenkins-architecture.png","sha":"a35a534eb7f13547e232635262d6b1c1506e9230"},{"name":"jenkins-icon.png","path":"_docs/jenkins-icon.png","sha":"cfb474486acb167b655c22a400fe5cc999959164"},{"name":"terraform-icon.png","path":"_docs/terraform-icon.png","sha":"85602f11c76fd989788112ba40c08d979ddb1164"},{"name":"tftg-pipeline-architecture.png","path":"_docs/tftg-pipeline-architecture.png","sha":"c016f9263be935e933db832e6e5047d6d656339c"},{"name":"travisci-cicd-architecture.png","path":"_docs/travisci-cicd-architecture.png","sha":"c7da609e901de1baba84918893af9016c3da78ed"},{"name":"travisci-icon.png","path":"_docs/travisci-icon.png","sha":"57116e900f797c8f35399929fb3a24b2cf0e7181"}]},{"name":"examples","children":[{"name":"ecs-deploy-runner","children":[{"name":"README.md","path":"examples/ecs-deploy-runner/README.md","sha":"f7dbc2c05f78cdeaff779eecfef93594f7a9c175"},{"name":"main.tf","path":"examples/ecs-deploy-runner/main.tf","sha":"ba5f23421fb1e4da5a44f12ba3b750ea56ac56e1"},{"name":"outputs.tf","path":"examples/ecs-deploy-runner/outputs.tf","sha":"0d39cc204673e2e92f0b6e32464ac8080fda59c2"},{"name":"variables.tf","path":"examples/ecs-deploy-runner/variables.tf","sha":"569c2a38d743951b63d72e61caeac4071d7bbd92"}]},{"name":"iam-policies","children":[{"name":"README.md","path":"examples/iam-policies/README.md","sha":"4eaf42cd7b4bc254ac9aabfaa8d6c1b4b8cc4281"},{"name":"main.tf","path":"examples/iam-policies/main.tf","sha":"29ed07d00498d2964f2850a49cb9b28cce541333"},{"name":"vars.tf","path":"examples/iam-policies/vars.tf","sha":"ffd4eed9234a389e6809cbb1c149efdbe778578e"}]},{"name":"jenkins","children":[{"name":"README.md","path":"examples/jenkins/README.md","sha":"5c76af2853297fa24f0ab44dc1cdcdf6ba8e1a55"},{"name":"docker-compose.yml","path":"examples/jenkins/docker-compose.yml","sha":"cdbb01e4c39d6ad67656d7997355b03027f2358e"},{"name":"main.tf","path":"examples/jenkins/main.tf","sha":"1881a2126a139b44718e4fd54aaa8a087206b8da"},{"name":"mock","children":[{"name":"mock-user-data.sh","path":"examples/jenkins/mock/mock-user-data.sh","sha":"610ba8091622d0bbec4301093b63c4263b5939ae"},{"name":"mount-ebs-volume","path":"examples/jenkins/mock/mount-ebs-volume","sha":"faa2394ad8a7a35657fb7f34b2014c7f05224e56"},{"name":"systemctl","path":"examples/jenkins/mock/systemctl","sha":"c656c65a7fd2b411548adb7865bc9c065333ad2e"}]},{"name":"outputs.tf","path":"examples/jenkins/outputs.tf","sha":"0be347ef2da711389da6e9ab98e7717e3dfa1a02"},{"name":"packer","children":[{"name":"jenkins.json","path":"examples/jenkins/packer/jenkins.json","sha":"d35f1c232b6d5cc2f35b37eb4bac1409a4c4c391"}]},{"name":"user-data","children":[{"name":"user-data.sh","path":"examples/jenkins/user-data/user-data.sh","sha":"19a4ccc9a1f8cb264d6995473ece0c2b02a0091a"}]},{"name":"vars.tf","path":"examples/jenkins/vars.tf","sha":"880057af01bab8502d9c786cf2827b3f8134cc69"}]}]},{"name":"modules","children":[{"name":"aws-helpers","children":[{"name":"README.md","path":"modules/aws-helpers/README.md","sha":"2fc74c09e7880238a4c049022f455809549d2ee1"},{"name":"bin","children":[{"name":"publish-ami","path":"modules/aws-helpers/bin/publish-ami","sha":"1d5697d411cbeed05734fb356ffbf598f7e4eeeb"}]},{"name":"install.sh","path":"modules/aws-helpers/install.sh","sha":"2700711d6a80c6f6c218e4b3d5b1b0cfe4d7609b"}]},{"name":"build-helpers","children":[{"name":"README.md","path":"modules/build-helpers/README.md","sha":"6816ecb1ffd0810892df24343366667a2a4ba66a"},{"name":"bin","children":[{"name":"build-docker-image","path":"modules/build-helpers/bin/build-docker-image","sha":"0fde55c7e1985925fe00d2d399b190ae6b2edd26"},{"name":"build-packer-artifact","path":"modules/build-helpers/bin/build-packer-artifact","sha":"70f860fd8dab2178c9a89a2ced7c548d1cc5d562"}]},{"name":"install.sh","path":"modules/build-helpers/install.sh","sha":"a132488127b88ef8268399a0b3852aa5e0967a20"}]},{"name":"check-url","children":[{"name":"README.md","path":"modules/check-url/README.md","sha":"070d26ac5f4cf136fc28a69d97df6710a341cf24"},{"name":"bin","children":[{"name":"check-url","path":"modules/check-url/bin/check-url","sha":"4e6c57dd70e0a385fb23814619dc917b7c527e57"}]},{"name":"install.sh","path":"modules/check-url/install.sh","sha":"488fad728f75e4ffb6d7156b7cc9ee9682d60183"}]},{"name":"circleci-helpers","children":[{"name":"README.md","path":"modules/circleci-helpers/README.md","sha":"3e58d0856dd6ae04bbd22814d6243b0225a689d9"},{"name":"bin","children":[{"name":"install-go-version","path":"modules/circleci-helpers/bin/install-go-version","sha":"8a0121205f24358a00af129e729795013ebf7edb"},{"name":"place-repo-in-gopath","path":"modules/circleci-helpers/bin/place-repo-in-gopath","sha":"ac7085bb304a2004050e676bea658f039493fdcc"}]},{"name":"install.sh","path":"modules/circleci-helpers/install.sh","sha":"313288f93c55678a883f53106471a21f8ebbb2fa"}]},{"name":"ec2-backup","children":[{"name":"README.md","path":"modules/ec2-backup/README.md","sha":"d9ef51b6b9a83f8e5bf15a582d5b18d48091f3de"},{"name":"backup-lambda-function","children":[{"name":"ec2-snapper_linux_amd64-v0.5.2","path":"modules/ec2-backup/backup-lambda-function/ec2-snapper_linux_amd64-v0.5.2","sha":"11f872d3dde35b44c160eccf3f0adf49cc5bd72f"},{"name":"index.js","path":"modules/ec2-backup/backup-lambda-function/index.js","sha":"555ea9666346d7d57588452a5a9642ff73bcf25e"}]},{"name":"main.tf","path":"modules/ec2-backup/main.tf","sha":"78ed3754120c76cb150f6b858bc7cfdbddaa1466"},{"name":"outputs.tf","path":"modules/ec2-backup/outputs.tf","sha":"770744637fcd7cafd98991397b26a82d01524192"},{"name":"vars.tf","path":"modules/ec2-backup/vars.tf","sha":"dd8d61875d9f68596d05bf677a51119750f512e8"}]},{"name":"ecs-deploy-runner-invoke-iam-policy","children":[{"name":"README.md","path":"modules/ecs-deploy-runner-invoke-iam-policy/README.md","sha":"66152227a29ea201358ced76a359bb5f2cfd7c9d"},{"name":"main.tf","path":"modules/ecs-deploy-runner-invoke-iam-policy/main.tf","sha":"42b23973668008665974e714e1ca077ea96a9b9d"},{"name":"outputs.tf","path":"modules/ecs-deploy-runner-invoke-iam-policy/outputs.tf","sha":"8703d962acdf4584375558aa59831c1c873fe606"},{"name":"variables.tf","path":"modules/ecs-deploy-runner-invoke-iam-policy/variables.tf","sha":"566d414f7ef8621e8c7613847d92b77c3e08cbb6"}]},{"name":"ecs-deploy-runner-standard-configuration","children":[{"name":"README.md","path":"modules/ecs-deploy-runner-standard-configuration/README.md","sha":"f4c49c30bd8f1675ac907077b2e59a946ee96315"},{"name":"main.tf","path":"modules/ecs-deploy-runner-standard-configuration/main.tf","sha":"000a97b59512ee87ae1afea3e091723b262befdc"},{"name":"outputs.tf","path":"modules/ecs-deploy-runner-standard-configuration/outputs.tf","sha":"8a49694a66a0914299b1fb73e4b9576d32ec001e"},{"name":"variables.tf","path":"modules/ecs-deploy-runner-standard-configuration/variables.tf","sha":"f1475315eae8b7b3954400cf5abaa60855d1ee45"}]},{"name":"ecs-deploy-runner","children":[{"name":"README.adoc","path":"modules/ecs-deploy-runner/README.adoc","sha":"1857addf7729b043a1353863402b12b8cfb7ee4a","toggled":true},{"name":"_docs","children":[{"name":"images","children":[{"name":"sequence-diagram.png","path":"modules/ecs-deploy-runner/_docs/images/sequence-diagram.png","sha":"15c9ea45ff27d20fdc23cf918f8c9ba64c0601a3"}]}]},{"name":"core-concepts.md","path":"modules/ecs-deploy-runner/core-concepts.md","sha":"849b1db4b083d1ba6a9f4d009ae767ad4651d458"},{"name":"docker","children":[{"name":"deploy-runner","children":[{"name":"Dockerfile","path":"modules/ecs-deploy-runner/docker/deploy-runner/Dockerfile","sha":"54f947afbeeda22d76ba630f4ecd84065468764e"},{"name":"known_hosts","path":"modules/ecs-deploy-runner/docker/deploy-runner/known_hosts","sha":"0dd0a16cd905887f363c0ba4effb5e88a8c4afac"}]},{"name":"kaniko","children":[{"name":"Dockerfile","path":"modules/ecs-deploy-runner/docker/kaniko/Dockerfile","sha":"d613a7380265e94d592ec61b9935bfede120fde7"},{"name":"build_docker_image.go","path":"modules/ecs-deploy-runner/docker/kaniko/build_docker_image.go","sha":"8051d59a7a8cc839a61f860d38a68c34957feafb"},{"name":"config.json","path":"modules/ecs-deploy-runner/docker/kaniko/config.json","sha":"34798d807bda1825a3285dd3ac4436eab0905d9d"},{"name":"go.mod","path":"modules/ecs-deploy-runner/docker/kaniko/go.mod","sha":"2915250c36924f1bbfb58a7485d58e3ce386efed"},{"name":"go.sum","path":"modules/ecs-deploy-runner/docker/kaniko/go.sum","sha":"cd278d67681ad9401f9de5d3ac258b9df24ed173"}]}]},{"name":"entrypoint","children":[{"name":"deploy_runner_entrypoint.go","path":"modules/ecs-deploy-runner/entrypoint/deploy_runner_entrypoint.go","sha":"f71a662ec5653f4c3f569d0606e05058c6130cd9"},{"name":"go.mod","path":"modules/ecs-deploy-runner/entrypoint/go.mod","sha":"eeca92d303d02287f5d4b1db8e0c10e5afa7e54f"},{"name":"go.sum","path":"modules/ecs-deploy-runner/entrypoint/go.sum","sha":"a114c9668062acd899c6a833fd7c09ebd4563146"},{"name":"install.sh","path":"modules/ecs-deploy-runner/entrypoint/install.sh","sha":"08c92e1e908e330112adff47b4da225658f4369e"}]},{"name":"invoker-lambda","children":[{"name":"dev_requirements.txt","path":"modules/ecs-deploy-runner/invoker-lambda/dev_requirements.txt","sha":"e5c3080c5b1785d0bcbb0a0c0751ae3adef55c54"},{"name":"invoker","children":[{"name":"__init__.py","path":"modules/ecs-deploy-runner/invoker-lambda/invoker/__init__.py","sha":"e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"},{"name":"assertions.py","path":"modules/ecs-deploy-runner/invoker-lambda/invoker/assertions.py","sha":"53d74960da2cd9088992f4d1e8d62297709e4e3c"},{"name":"exceptions.py","path":"modules/ecs-deploy-runner/invoker-lambda/invoker/exceptions.py","sha":"bd0ae2c664b6242323c4f19e2bf4ebdd64262009"},{"name":"index.py","path":"modules/ecs-deploy-runner/invoker-lambda/invoker/index.py","sha":"fc432c8beacbb0275e0dda086781e5eda24ee266"},{"name":"project_logging.py","path":"modules/ecs-deploy-runner/invoker-lambda/invoker/project_logging.py","sha":"7073c22d7c70ee8940a3ab194a2edc3aef554055"},{"name":"types.py","path":"modules/ecs-deploy-runner/invoker-lambda/invoker/types.py","sha":"75f4262982bfbd5f751654b35e903be5279b7d98"}]},{"name":"test","children":[{"name":"test_assertions.py","path":"modules/ecs-deploy-runner/invoker-lambda/test/test_assertions.py","sha":"8f52d353ab727bd0e34922cfac7e98924302af65"},{"name":"test_invoker.py","path":"modules/ecs-deploy-runner/invoker-lambda/test/test_invoker.py","sha":"e99f8ee3c1314716100a1378b0d50c58c83988f3"}]}]},{"name":"main.tf","path":"modules/ecs-deploy-runner/main.tf","sha":"8af4dc91ff4e02ec58d0d7980f5a79f51542dca7"},{"name":"main_ecs.tf","path":"modules/ecs-deploy-runner/main_ecs.tf","sha":"9b3702c41b5194cd75b8b5764be111efbcc844bc"},{"name":"main_lambda.tf","path":"modules/ecs-deploy-runner/main_lambda.tf","sha":"d6d9836f72482c041841667465a3cd09e328b888"},{"name":"outputs.tf","path":"modules/ecs-deploy-runner/outputs.tf","sha":"a78322a16476d579a9f1d92846cd252a6eb8755a"},{"name":"variables.tf","path":"modules/ecs-deploy-runner/variables.tf","sha":"374b3cbcd42da8b5ed1a10e189567451ca035241"}],"toggled":true},{"name":"git-helpers","children":[{"name":"README.md","path":"modules/git-helpers/README.md","sha":"86803f51a9bdcca05dfd13756fe16088a6363ff4"},{"name":"bin","children":[{"name":"git-add-commit-push","path":"modules/git-helpers/bin/git-add-commit-push","sha":"f270bc4da9ee46bc7754c0ce8bf8f5a6c6c38c0a"},{"name":"git-rebase","path":"modules/git-helpers/bin/git-rebase","sha":"887dd90ba36adc5c0362cbadca79707756535b24"}]},{"name":"install.sh","path":"modules/git-helpers/install.sh","sha":"f22ede2f2f085af0a065dd43ed1279c69dd5a00b"}]},{"name":"gruntwork-module-circleci-helpers","children":[{"name":"README.md","path":"modules/gruntwork-module-circleci-helpers/README.md","sha":"074bc610447d27206bc50ba1a7b06fc95226d369"},{"name":"bin","children":[{"name":"build-go-binaries","path":"modules/gruntwork-module-circleci-helpers/bin/build-go-binaries","sha":"8aca966ed857b2d6d50a7c72c09e9181ae125e3c"},{"name":"configure-environment-for-gruntwork-module","path":"modules/gruntwork-module-circleci-helpers/bin/configure-environment-for-gruntwork-module","sha":"66538721d100ad93eac0784ab0603ddf508c6265"},{"name":"run-go-tests","path":"modules/gruntwork-module-circleci-helpers/bin/run-go-tests","sha":"d5406bdd61dae657ded161cf6f2ca66b17cd5b81"},{"name":"upload-github-release-assets","path":"modules/gruntwork-module-circleci-helpers/bin/upload-github-release-assets","sha":"b86a2f1049b1be58179569ea7fed641d960d1f05"}]},{"name":"install.sh","path":"modules/gruntwork-module-circleci-helpers/install.sh","sha":"a9cc16c05a73cf6c40097608838758a8de64daab"}]},{"name":"iam-policies","children":[{"name":"README.md","path":"modules/iam-policies/README.md","sha":"da28056c8749bc2c46dc99ed16286e14b7c55511"},{"name":"ecr-docker-push","children":[{"name":"README.md","path":"modules/iam-policies/ecr-docker-push/README.md","sha":"6a0a84157fe573f2c7ac1e0bd6e2169b2814f1c0"},{"name":"main.tf","path":"modules/iam-policies/ecr-docker-push/main.tf","sha":"f42bf07dbc968788e3afca42528ebf5f581ac7c8"},{"name":"outputs.tf","path":"modules/iam-policies/ecr-docker-push/outputs.tf","sha":"ba3177631efce4651f499e457cc9aa0b1afb338d"},{"name":"vars.tf","path":"modules/iam-policies/ecr-docker-push/vars.tf","sha":"d8aaeae6205750961e3deaba741ee68180a32ca7"}]},{"name":"ecs-service-deployment","children":[{"name":"README.md","path":"modules/iam-policies/ecs-service-deployment/README.md","sha":"77bb1df6db0d7cd886ee665f1d6566944521b00c"},{"name":"main.tf","path":"modules/iam-policies/ecs-service-deployment/main.tf","sha":"01c7f850e862dc36c1930b8deb767388c631eda7"},{"name":"outputs.tf","path":"modules/iam-policies/ecs-service-deployment/outputs.tf","sha":"4bf7dcb16326113889318ee8da63dadfc1ce35e9"},{"name":"vars.tf","path":"modules/iam-policies/ecs-service-deployment/vars.tf","sha":"78c2705c906b853f0e4b18b6c8f2c05e164109bf"}]},{"name":"terraform-remote-state-s3","children":[{"name":"README.md","path":"modules/iam-policies/terraform-remote-state-s3/README.md","sha":"b7892fd6dabecb66909706dbb8941e63e2c56954"},{"name":"main.tf","path":"modules/iam-policies/terraform-remote-state-s3/main.tf","sha":"76eb7e37989dc731b4e304303d2a46f9f17e2779"},{"name":"outputs.tf","path":"modules/iam-policies/terraform-remote-state-s3/outputs.tf","sha":"07cabd2ad56a78ea31e2bf59f1cb938fdf3b9664"},{"name":"vars.tf","path":"modules/iam-policies/terraform-remote-state-s3/vars.tf","sha":"720084fa0f9cf944b19ba30f59e78efc2e7b96b9"}]},{"name":"terragrunt","children":[{"name":"README.md","path":"modules/iam-policies/terragrunt/README.md","sha":"eccacc553810fa838b23d24718ffb8f70a9a39e5"},{"name":"main.tf","path":"modules/iam-policies/terragrunt/main.tf","sha":"e479890f7c37ce794c61022ab08e3febb91441ef"},{"name":"outputs.tf","path":"modules/iam-policies/terragrunt/outputs.tf","sha":"2b948005b8a1322f408e999226ac7b66629759cd"},{"name":"vars.tf","path":"modules/iam-policies/terragrunt/vars.tf","sha":"52f0480b69a57d0ff43e76ae26cb17d77dab5069"}]}]},{"name":"infrastructure-deploy-script","children":[{"name":"README.adoc","path":"modules/infrastructure-deploy-script/README.adoc","sha":"28e1366b934ff07de913455a42ca96555f6a8165"},{"name":"core-concepts.md","path":"modules/infrastructure-deploy-script/core-concepts.md","sha":"e617d3dd528507993c8162811cb6de16328e9ed3"},{"name":"dev_requirements.txt","path":"modules/infrastructure-deploy-script/dev_requirements.txt","sha":"6059bddb829b89421c7e1fba8a6e330de33e1a75"},{"name":"infrastructure_deploy_script","children":[{"name":"__init__.py","path":"modules/infrastructure-deploy-script/infrastructure_deploy_script/__init__.py","sha":"e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"},{"name":"deploy.py","path":"modules/infrastructure-deploy-script/infrastructure_deploy_script/deploy.py","sha":"1f204faa3579919b19067c7face5af56a2aa3785"},{"name":"exceptions.py","path":"modules/infrastructure-deploy-script/infrastructure_deploy_script/exceptions.py","sha":"087c7ad70e8077121d24d775af578aa238995dca"},{"name":"git.py","path":"modules/infrastructure-deploy-script/infrastructure_deploy_script/git.py","sha":"749ace8d9812e8a906eba2d14b6eef4f90c97e02"},{"name":"project_logging.py","path":"modules/infrastructure-deploy-script/infrastructure_deploy_script/project_logging.py","sha":"a72c2a19962838f3375390380dcf444b73e1fcef"},{"name":"py.typed","path":"modules/infrastructure-deploy-script/infrastructure_deploy_script/py.typed","sha":"e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"},{"name":"shell.py","path":"modules/infrastructure-deploy-script/infrastructure_deploy_script/shell.py","sha":"f9b98a99686b214a68c8c99d23fd8019a9f68213"},{"name":"ssh.py","path":"modules/infrastructure-deploy-script/infrastructure_deploy_script/ssh.py","sha":"3db8994be058bfa590bbbbdd0476128c44ad5979"},{"name":"terra.py","path":"modules/infrastructure-deploy-script/infrastructure_deploy_script/terra.py","sha":"67b1bc0f598d253e9b9ba13f54b9ca875f23f84f"}]},{"name":"install.sh","path":"modules/infrastructure-deploy-script/install.sh","sha":"c958f1065315b16e9f0474ee39728a4556c18247"},{"name":"requirements.txt","path":"modules/infrastructure-deploy-script/requirements.txt","sha":"ebe0f49e006828d7147c8ee540a278142e44e618"},{"name":"scripts","children":[{"name":"infrastructure-deploy-script","path":"modules/infrastructure-deploy-script/scripts/infrastructure-deploy-script","sha":"9f6b9fd7774de6892e9fdbb77f3200c1b1d698ae"}]},{"name":"setup.py","path":"modules/infrastructure-deploy-script/setup.py","sha":"0885421ba85af260d5e2d97ebc75e26c76fb25da"},{"name":"test","children":[{"name":"conftest.py","path":"modules/infrastructure-deploy-script/test/conftest.py","sha":"ebae81d85a6ce4997c9d6f4a3d833c617822a0a0"},{"name":"fixtures","children":[{"name":"terraform-with-inputs","children":[{"name":"input.tfvars","path":"modules/infrastructure-deploy-script/test/fixtures/terraform-with-inputs/input.tfvars","sha":"68468ad2c7a8319c2674d572eec058660cddfdfb"},{"name":"main.tf","path":"modules/infrastructure-deploy-script/test/fixtures/terraform-with-inputs/main.tf","sha":"de3e20f9744dc757b7ea2620ebdbc2e8aa7a3ec1"},{"name":"terragrunt.hcl","path":"modules/infrastructure-deploy-script/test/fixtures/terraform-with-inputs/terragrunt.hcl","sha":"e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"}]},{"name":"terraform","children":[{"name":"main.tf","path":"modules/infrastructure-deploy-script/test/fixtures/terraform/main.tf","sha":"362851fda16747e2a39abba071646933e51fbbdf"}]},{"name":"terragrunt","children":[{"name":"terragrunt.hcl","path":"modules/infrastructure-deploy-script/test/fixtures/terragrunt/terragrunt.hcl","sha":"2359b15bc6a698e481a8e99fdb352e174203b925"}]}]},{"name":"test_deploy.py","path":"modules/infrastructure-deploy-script/test/test_deploy.py","sha":"f41e53648f0c9df3c55692380ab02133f5bcde12"},{"name":"test_git.py","path":"modules/infrastructure-deploy-script/test/test_git.py","sha":"862852a92b7a7edb7276cdd3cf212e500ca3c8d9"},{"name":"test_shell.py","path":"modules/infrastructure-deploy-script/test/test_shell.py","sha":"fa0f984c4ce6218303d7f9c38c4c20d018411318"}]}]},{"name":"infrastructure-deployer","children":[{"name":"README.adoc","path":"modules/infrastructure-deployer/README.adoc","sha":"ccb8ddacbca1f403e2f7487fee8da11adfff0e03"},{"name":"core-concepts.md","path":"modules/infrastructure-deployer/core-concepts.md","sha":"8b4f541bbb9986cd1ad3b27fb6896dff0f4a3b90"},{"name":"deploy","children":[{"name":"aws.go","path":"modules/infrastructure-deployer/deploy/aws.go","sha":"935179ae7f0a82af9600d2552e9c43ee48dedc77"},{"name":"aws_ecs.go","path":"modules/infrastructure-deployer/deploy/aws_ecs.go","sha":"267b65065c505ea0649a29d49f14152729258c74"},{"name":"deploy.go","path":"modules/infrastructure-deployer/deploy/deploy.go","sha":"f85db6e4e21c77103925dea13c202c2d76770d40"},{"name":"errors.go","path":"modules/infrastructure-deployer/deploy/errors.go","sha":"74d73d20144cbbac68ebe4a7c50a53b204151fb4"}]},{"name":"go.mod","path":"modules/infrastructure-deployer/go.mod","sha":"6235897ee1c45ed4259089ae217684c91946adf5"},{"name":"go.sum","path":"modules/infrastructure-deployer/go.sum","sha":"803f46872f55922e3c888dd4aff5236717352ddc"},{"name":"logging","children":[{"name":"logging.go","path":"modules/infrastructure-deployer/logging/logging.go","sha":"9a7a2aa73ff0dc233bdb5b48ddfdf1d14423f011"}]},{"name":"main.go","path":"modules/infrastructure-deployer/main.go","sha":"72ee953990c0a57554312feac5b3b733b2c03b5c"},{"name":"revshlex","children":[{"name":"revshlex.go","path":"modules/infrastructure-deployer/revshlex/revshlex.go","sha":"965c2960b0d9a0ba56e7b1868def546556167c3b"},{"name":"revshlex_test.go","path":"modules/infrastructure-deployer/revshlex/revshlex_test.go","sha":"f25d5a84e38fb4fb44930477ad999431f323f5d7"}]}]},{"name":"install-jenkins","children":[{"name":"README.md","path":"modules/install-jenkins/README.md","sha":"f3c33b9c09257522281a7be9687a53b343bc1fd8"},{"name":"install.sh","path":"modules/install-jenkins/install.sh","sha":"e9ccf35e247fc5de353f0a02e187c35246ec5655"},{"name":"run-jenkins","path":"modules/install-jenkins/run-jenkins","sha":"4f66dcc9b68b4623231de09d87c76cce40fc914e"}]},{"name":"jenkins-server","children":[{"name":"README.md","path":"modules/jenkins-server/README.md","sha":"49ecb595ff9883d9a77ddfebe1369e25f1692890"},{"name":"main.tf","path":"modules/jenkins-server/main.tf","sha":"cbecb0617d71fa5905a0fafbdf0e88892185bb35"},{"name":"outputs.tf","path":"modules/jenkins-server/outputs.tf","sha":"5670bd47368b97e5eeedcca805a28a337230e9e2"},{"name":"vars.tf","path":"modules/jenkins-server/vars.tf","sha":"c1f7433e5d2422435c256d9927eacc81db405fa3"}]},{"name":"kubernetes-circleci-helpers","children":[{"name":"README.md","path":"modules/kubernetes-circleci-helpers/README.md","sha":"833fef8b04c17c43b10c680fad7db3aa7da2e8ad"},{"name":"bin","children":[{"name":"setup-minikube","path":"modules/kubernetes-circleci-helpers/bin/setup-minikube","sha":"9a6dd7b530cdb65c314b7ca5f60c656ee6b4bbc8"}]},{"name":"install.sh","path":"modules/kubernetes-circleci-helpers/install.sh","sha":"2ae8670872407ceb2c434dc5b117ae14073af9a2"}]},{"name":"terraform-helpers","children":[{"name":"README.md","path":"modules/terraform-helpers/README.md","sha":"d6004df66f3b9684ea901f0d41592fca2aceb874"},{"name":"bin","children":[{"name":"git-updated-folders","path":"modules/terraform-helpers/bin/git-updated-folders","sha":"d1325e85a5922d482dc8a4474fe8ef547bf51589"},{"name":"terraform-update-variable","path":"modules/terraform-helpers/bin/terraform-update-variable","sha":"44fb722fa9745668b343ca85329b003a24f650f6"}]},{"name":"install.sh","path":"modules/terraform-helpers/install.sh","sha":"6b7e40c382ec391f64e54efab3367d202b123883"}]}],"toggled":true},{"name":"setup.cfg","path":"setup.cfg","sha":"dbcd773df9356e74782ad58e0a2255ffa188df49"},{"name":"test","children":[{"name":"README.md","path":"test/README.md","sha":"a5996d6e678f1d454c380b7c1722843886028589"},{"name":"build_docker_image_test.go","path":"test/build_docker_image_test.go","sha":"1c3c70c8e7ae97c05acb50fdfda9c14a2762392e"},{"name":"build_helpers.go","path":"test/build_helpers.go","sha":"0e77ed869d6406431209fdbf405745dce7a7cc26"},{"name":"build_packer_artifact_test.go","path":"test/build_packer_artifact_test.go","sha":"e5a185070f7249f7ab84367f68a9af016b2b892c"},{"name":"build_packer_artifact_unit_test.go","path":"test/build_packer_artifact_unit_test.go","sha":"ae89bece3fa432e3b5e9c4c917bdf00a6f358c15"},{"name":"check_url_test.go","path":"test/check_url_test.go","sha":"bd3419bcb07624923777c14619eba17c7edc8c64"},{"name":"ecs_deploy_runner_docker_test.go","path":"test/ecs_deploy_runner_docker_test.go","sha":"be41be9e908257499a9b0487a8cec36c1a98b923"},{"name":"ecs_deploy_runner_ec2_test.go","path":"test/ecs_deploy_runner_ec2_test.go","sha":"99b17f4a1c69cdc25165b18e29497f04afde237d"},{"name":"ecs_deploy_runner_kaniko_test.go","path":"test/ecs_deploy_runner_kaniko_test.go","sha":"383e5c3ed6eda4fc3a1169f2f66b29baac4de516"},{"name":"ecs_deploy_runner_security_test.go","path":"test/ecs_deploy_runner_security_test.go","sha":"9ae42634a2bd561004d393fd969f2aad07454c2f"},{"name":"ecs_deploy_runner_standard_configuration_test.go","path":"test/ecs_deploy_runner_standard_configuration_test.go","sha":"b1ae7b1b051397409d6a54e72049c21fc78d7678"},{"name":"ecs_deploy_runner_test.go","path":"test/ecs_deploy_runner_test.go","sha":"d8feacfc2ed21631b470bd6660fe4191b1997f66"},{"name":"ecs_deploy_runner_test_helpers.go","path":"test/ecs_deploy_runner_test_helpers.go","sha":"e5b0b03e0db4ee754aeee0e5cf5f32b74ac1481a"},{"name":"ecs_deploy_runner_workflow_test.go","path":"test/ecs_deploy_runner_workflow_test.go","sha":"122bb8888a3364dd34c87e6aaf8aff4c93c8b3f2"},{"name":"edrhelpers","children":[{"name":"edrhelpers.go","path":"test/edrhelpers/edrhelpers.go","sha":"d07d2f6de7ef7eaecba18bae75ffa92751abdb9a"},{"name":"edrhelpers_test.go","path":"test/edrhelpers/edrhelpers_test.go","sha":"5b34ed2f7d5ea1f8290b354b045554db143069f9"},{"name":"fixtures","children":[{"name":"docker","children":[{"name":"Dockerfile","path":"test/edrhelpers/fixtures/docker/Dockerfile","sha":"09bd120286de9d94d1340b658e66088f6f8ae28b"}]}]},{"name":"go.mod","path":"test/edrhelpers/go.mod","sha":"dbd47ade4dfa1a18d5e97992f373775e7b62d2a8"},{"name":"go.sum","path":"test/edrhelpers/go.sum","sha":"5c7ba66f33aa2c50f25dc66c190ed7fc9aa0e892"}]},{"name":"fixtures","children":[{"name":"build-packer-image-unit","children":[{"name":"ami-name","children":[{"name":"clean-resource-name.json","path":"test/fixtures/build-packer-image-unit/ami-name/clean-resource-name.json","sha":"2601caa0afd10705ba4c023f31dd03c1b2c10417"},{"name":"isotime-ami-name.json","path":"test/fixtures/build-packer-image-unit/ami-name/isotime-ami-name.json","sha":"29fa01b7f32d374cca8549b2bda8b18b69953373"},{"name":"multiple.json","path":"test/fixtures/build-packer-image-unit/ami-name/multiple.json","sha":"436b13dd54866f8926ce24c7766a043ff6d1e223"},{"name":"timestamp-ami-name.json","path":"test/fixtures/build-packer-image-unit/ami-name/timestamp-ami-name.json","sha":"17bb05e841d46f41900e3f647acaec28c58a34cc"},{"name":"uuid-ami-name.json","path":"test/fixtures/build-packer-image-unit/ami-name/uuid-ami-name.json","sha":"834762f57e84d3a3b62ae2afb04ac56aa145ad00"},{"name":"variables.json","path":"test/fixtures/build-packer-image-unit/ami-name/variables.json","sha":"5743df9f17cf8056f9c553196dc49afac1dbb59d"},{"name":"whitespace.json","path":"test/fixtures/build-packer-image-unit/ami-name/whitespace.json","sha":"35cfd5200bbd124689868f115cb1b5498a8dfbbe"}]},{"name":"ami-region","children":[{"name":"variable.json","path":"test/fixtures/build-packer-image-unit/ami-region/variable.json","sha":"2601caa0afd10705ba4c023f31dd03c1b2c10417"}]},{"name":"ami-tags","children":[{"name":"multiple-tags-variable.json","path":"test/fixtures/build-packer-image-unit/ami-tags/multiple-tags-variable.json","sha":"a546cb645b151da0156251a2e40c0599945f605b"},{"name":"no-tags.json","path":"test/fixtures/build-packer-image-unit/ami-tags/no-tags.json","sha":"d160046152b90e840fe08650cb9fb4ae8273ab40"},{"name":"single-tag.json","path":"test/fixtures/build-packer-image-unit/ami-tags/single-tag.json","sha":"c2770e7139805962dfa1eab83e5d02dde42a7b95"}]},{"name":"assert-build-amazon","children":[{"name":"amazon-ebs.json","path":"test/fixtures/build-packer-image-unit/assert-build-amazon/amazon-ebs.json","sha":"d160046152b90e840fe08650cb9fb4ae8273ab40"},{"name":"ambiguous.json","path":"test/fixtures/build-packer-image-unit/assert-build-amazon/ambiguous.json","sha":"b516d4fd64b4fae25af1582d2a9236266740333c"},{"name":"docker.json","path":"test/fixtures/build-packer-image-unit/assert-build-amazon/docker.json","sha":"65adc353ebf9bda1f6821d42ec0b2f6f8d5fc125"}]},{"name":"scripts","children":[{"name":"ami-name-test.sh","path":"test/fixtures/build-packer-image-unit/scripts/ami-name-test.sh","sha":"07137cff13ec18cc3bb6c3b31e706f8a0b754882"},{"name":"ami-region-test.sh","path":"test/fixtures/build-packer-image-unit/scripts/ami-region-test.sh","sha":"7211f8d2e27f00395b2355eed780aa7e0c245196"},{"name":"ami-tags-test.sh","path":"test/fixtures/build-packer-image-unit/scripts/ami-tags-test.sh","sha":"2848b4aa11df09e8aed559a9e0b9119cdee10468"},{"name":"assert-builder-amazon-test.sh","path":"test/fixtures/build-packer-image-unit/scripts/assert-builder-amazon-test.sh","sha":"ff33aabd963e7971017901988f408c628c0dabb9"}]}]},{"name":"git-add-commit-push","children":[{"name":"auto-committed.txt","path":"test/fixtures/git-add-commit-push/auto-committed.txt","sha":"5a1b0487943a6bb6645e502dc2c550c3c043f52a"}]},{"name":"hello-world-go-app","children":[{"name":"main.go","path":"test/fixtures/hello-world-go-app/main.go","sha":"3e0c7643f51386747f1b85656a0c797f282aed04"}]},{"name":"infra-pipeline-workflow","children":[{"name":"deploy-ami","children":[{"name":"main.tf","path":"test/fixtures/infra-pipeline-workflow/deploy-ami/main.tf","sha":"ce71c0fc94842687489f9423d9983cd831c79751"},{"name":"terragrunt.hcl","path":"test/fixtures/infra-pipeline-workflow/deploy-ami/terragrunt.hcl","sha":"726d218ced39781cf10699baf05283fbfcfb22df"}]},{"name":"deploy-docker","children":[{"name":"main.tf","path":"test/fixtures/infra-pipeline-workflow/deploy-docker/main.tf","sha":"4c5b2f8e767ab37cdedc43910ee91c6e181feb6b"},{"name":"terragrunt.hcl","path":"test/fixtures/infra-pipeline-workflow/deploy-docker/terragrunt.hcl","sha":"6d6be2748d15d39b736ebdf7b9621ed001b1da09"}]}]},{"name":"test-docker-image","children":[{"name":"Dockerfile","path":"test/fixtures/test-docker-image/Dockerfile","sha":"5de35bbecce145045ae22fbc5fb97c133568a1ff"},{"name":"test.sh","path":"test/fixtures/test-docker-image/test.sh","sha":"ef3083cf7f3436ac7d01acfa33e4dab143fbcafd"}]},{"name":"test-go-test-files","children":[{"name":"simple_test.go","path":"test/fixtures/test-go-test-files/simple_test.go","sha":"53007ca88996e540ddfc503ce42982bdd5e785d2"},{"name":"test.sh","path":"test/fixtures/test-go-test-files/test.sh","sha":"25b8ef156d589c8d088d026b422e3b9c751c4b53"}]},{"name":"test-packer-image","children":[{"name":"hello-world-multiple-builders.json","path":"test/fixtures/test-packer-image/hello-world-multiple-builders.json","sha":"1c3e101f8965041b7aef0f5c4cddb14e1011d520"},{"name":"hello-world-no-tags-builder.json","path":"test/fixtures/test-packer-image/hello-world-no-tags-builder.json","sha":"d160046152b90e840fe08650cb9fb4ae8273ab40"},{"name":"hello-world-one-builder.json","path":"test/fixtures/test-packer-image/hello-world-one-builder.json","sha":"44a88c43721e45e9f5d921d8c04d08fa62c26748"}]},{"name":"test-tfvars-files","children":[{"name":"multiple-similar-variables.tfvars","path":"test/fixtures/test-tfvars-files/multiple-similar-variables.tfvars","sha":"8147977dee3d9a196177c575cd664354c601e68f"},{"name":"multiple-variables-and-comments.tfvars","path":"test/fixtures/test-tfvars-files/multiple-variables-and-comments.tfvars","sha":"8b757cfa5ed1d5049c478ed9180b9e9a5743335e"},{"name":"one-variable-extra-whitespace.tfvars","path":"test/fixtures/test-tfvars-files/one-variable-extra-whitespace.tfvars","sha":"743b02f7015bd51232f9c40564c654f424cbb523"},{"name":"one-variable-no-whitespace.tfvars","path":"test/fixtures/test-tfvars-files/one-variable-no-whitespace.tfvars","sha":"39ddb49aa78f683e3e45384d2440a904d0ad7ec9"},{"name":"one-variable.tfvars","path":"test/fixtures/test-tfvars-files/one-variable.tfvars","sha":"82a0cea8ac06d9534dd2549c73ae70afd47336bb"}]},{"name":"test-tghcl-files","children":[{"name":"multiple-similar-variables.hcl","path":"test/fixtures/test-tghcl-files/multiple-similar-variables.hcl","sha":"8224297de9667b6887136c897b473977f7013fc0"},{"name":"multiple-variables-and-comments.hcl","path":"test/fixtures/test-tghcl-files/multiple-variables-and-comments.hcl","sha":"1905719b9208e53d78a9bced9792194f6955f928"},{"name":"one-variable-extra-whitespace.hcl","path":"test/fixtures/test-tghcl-files/one-variable-extra-whitespace.hcl","sha":"aa09bc5beacd10b66660e71173d16f3b093e9415"},{"name":"one-variable-no-whitespace.hcl","path":"test/fixtures/test-tghcl-files/one-variable-no-whitespace.hcl","sha":"8e77e4baf099fdb7f1e1d1571725c835ac92093a"},{"name":"one-variable.hcl","path":"test/fixtures/test-tghcl-files/one-variable.hcl","sha":"0afe11b72b3635feb75d71d7aff4cc28806a7f67"}]},{"name":"tfpipeline","children":[{"name":"failure","children":[{"name":"terraform","children":[{"name":"main.tf","path":"test/fixtures/tfpipeline/failure/terraform/main.tf","sha":"5488bde3fbd03a58398aeeb904cfef74d7200aae"}]},{"name":"terragrunt","children":[{"name":"terragrunt.hcl","path":"test/fixtures/tfpipeline/failure/terragrunt/terragrunt.hcl","sha":"2359b15bc6a698e481a8e99fdb352e174203b925"}]}]},{"name":"nested","children":[{"name":"terraform","children":[{"name":"main.tf","path":"test/fixtures/tfpipeline/nested/terraform/main.tf","sha":"19538a8d8cb3820ffc99138ecf3b19004e7afa8f"}]},{"name":"terragrunt","children":[{"name":"terragrunt.hcl","path":"test/fixtures/tfpipeline/nested/terragrunt/terragrunt.hcl","sha":"2359b15bc6a698e481a8e99fdb352e174203b925"}]}]},{"name":"root","children":[{"name":"terraform","children":[{"name":"main.tf","path":"test/fixtures/tfpipeline/root/terraform/main.tf","sha":"4c38ad94d4d10a46cb1acd012f9b3e5513757ac2"}]},{"name":"terragrunt","children":[{"name":"terragrunt.hcl","path":"test/fixtures/tfpipeline/root/terragrunt/terragrunt.hcl","sha":"2359b15bc6a698e481a8e99fdb352e174203b925"}]}]}]}]},{"name":"git_updated_folders_test.go","path":"test/git_updated_folders_test.go","sha":"365224f7ed12aa3ccf6df765af3669d844274726"},{"name":"github_helpers.go","path":"test/github_helpers.go","sha":"56e54040790227aab12ae1b2f43991b9f00f87f6"},{"name":"go.mod","path":"test/go.mod","sha":"5cba1f1d742d8e433c44a513d43f79c06ae36126"},{"name":"go.sum","path":"test/go.sum","sha":"eeeb026c64c831e119900a51d8d12d3d9a96c455"},{"name":"gruntwork_module_circleci_helpers_integration_test.go","path":"test/gruntwork_module_circleci_helpers_integration_test.go","sha":"b6962168427fd2bae16cd6b5cca6f27afd9a0808"},{"name":"iam_policies_test.go","path":"test/iam_policies_test.go","sha":"75daff44988b41977dcfd064c868f038f77ffbb0"},{"name":"infrastructure_deploy_script_test.go","path":"test/infrastructure_deploy_script_test.go","sha":"1f4c3698ade167ba793813c2326e8aa7eb04ee6a"},{"name":"jenkins_test.go","path":"test/jenkins_test.go","sha":"d2cdf692eec0d4344ea052028d9a80155b1f9bcd"},{"name":"kubernetes_circleci_helpers_test.go","path":"test/kubernetes_circleci_helpers_test.go","sha":"76a87d2854c2c7cf0a57c56582796b9cdb533c1b"},{"name":"publish_ami_test.go","path":"test/publish_ami_test.go","sha":"04f7667c39445fe5d6a336641c110e2c6c1744a3"},{"name":"terraform_update_variable_unit_test.go","path":"test/terraform_update_variable_unit_test.go","sha":"5b405d87a457c0983d1bc804d1b78bc86c6e82f3"},{"name":"terragrunt_update_variable_unit_test.go","path":"test/terragrunt_update_variable_unit_test.go","sha":"69aee2044f92db0a42acde9d9f8ee5217a840796"},{"name":"test-git-add-commit-push.sh","path":"test/test-git-add-commit-push.sh","sha":"95fd142ed3d26e85c2873ee55c0e2718f0927ffd"},{"name":"test_helpers.go","path":"test/test_helpers.go","sha":"d4eb5b752450f221e5d615ffd1e470edbf7adfa0"}]},{"name":"testdep","children":[{"name":"Gopkg.lock","path":"testdep/Gopkg.lock","sha":"f12dfa4652085a0043d69d1b3bff7cc16b64551f"},{"name":"Gopkg.toml","path":"testdep/Gopkg.toml","sha":"092de38583d1bb2aff2b194753b7cc18aecddd87"},{"name":"dep_test.go","path":"testdep/dep_test.go","sha":"b87facc135093c5258a5f2da43e5f9177bc008b7"},{"name":"fixtures","children":[{"name":"hello-world-godep-app","children":[{"name":"Gopkg.lock","path":"testdep/fixtures/hello-world-godep-app/Gopkg.lock","sha":"623c785ee006b1ff3c524d18935ebdeb45395d55"},{"name":"Gopkg.toml","path":"testdep/fixtures/hello-world-godep-app/Gopkg.toml","sha":"26f5a8f783bb942cf6fba93c10b6a09017329526"},{"name":"main.go","path":"testdep/fixtures/hello-world-godep-app/main.go","sha":"0a09ad54ada955edd8e8ae731e0c113cc708766c"}]}]}]}]},"detailsContent":"<div id=\"preamble\">\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p><span class=\"image\"><a class=\"image\" href=\"https://gruntwork.io/?ref=repo_aws_eks\" target=\"_blank\"><img src=\"https://img.shields.io/badge/maintained%20by-gruntwork.io-%235849a6.svg\" alt=\"maintained%20by gruntwork.io %235849a6\" class=\"preview__body--diagram\"></a></span>\n<span class=\"image\"><img src=\"https://img.shields.io/badge/tf-%3E%3D0.12.0-blue.svg\" alt=\"Terraform version\" class=\"preview__body--diagram\"></span></p>\n</div>\n<div class=\"paragraph\">\n<p>This module can be used to set up a secure CI/CD pipeline for your infrastructure code\n(<a href=\"https://www.terraform.io\" target=\"_blank\">Terraform</a>, <a href=\"https://terragrunt.gruntwork.io\" target=\"_blank\">Terragrunt</a>, <a href=\"https://www.packer.io/\" target=\"_blank\">Packer</a>,\n<a href=\"https://www.docker.com/\" target=\"_blank\">Docker</a>, etc). You can use this in combination with existing CI servers (e.g Jenkins, CircleCI,\nGitlab) to set up workflows that:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p>Run <code>plan</code> and <code>apply</code> with approval stages</p>\n</li>\n<li>\n<p>Build docker images for every PR</p>\n</li>\n<li>\n<p>Build VM images (e.g., AMIs) for every PR</p>\n</li>\n<li>\n<p>Automatically update infrastructure code and commit and push the changes to Git</p>\n</li>\n</ul>\n</div>\n<div class=\"paragraph\">\n<p>These workflows can be implemented without directly running the steps from your CI servers. Instead, the CI server can coordinate the CI / CD flow, and for anything that requires sensitive / powerful IAM permissions, it can trigger pre-defined, locked-down jobs in an isolated ECS task, and stream the logs from that task as if it’s running locally.</p>\n</div>\n<div class=\"paragraph\">\n<p>Refer to the <a href=\"/repos/v0.29.12/module-ci/modules/infrastructure-deployer\">infrastructure-deployer CLI</a> to integrate this with existing CI\nservers. You can also refer to the <a href=\"/repos/v0.29.12/module-ci/modules/infrastructure-deploy-script\">infrastructure-deploy-script module</a> for\nmore information on the underlying deployment scripts.</p>\n</div>\n<div class=\"imageblock\">\n<div class=\"content\">\n<img src=\"/repos/images/v0.29.12/module-ci/_docs/tftg-pipeline-architecture.png?raw=true\" alt=\"Terraform and Terragrunt CI/CD architecture\" class=\"preview__body--diagram\">\n</div>\n</div>\n<div id=\"toc\" class=\"toc\">\n<div id=\"toctitle\" class=\"title\"></div>\n<ul class=\"sectlevel1\">\n<li><a href=\"#_features\">Features</a></li>\n<li><a href=\"#_learn\">Learn</a>\n<ul class=\"sectlevel2\">\n<li><a href=\"#_core_concepts\">Core concepts</a></li>\n<li><a href=\"#_repo_organization\">Repo organization</a></li>\n</ul>\n</li>\n<li><a href=\"#_deploy\">Deploy</a>\n<ul class=\"sectlevel2\">\n<li><a href=\"#_non_production_deployment_quick_start_for_learning\">Non-production deployment (quick start for learning)</a></li>\n</ul>\n</li>\n<li><a href=\"#_manage\">Manage</a></li>\n<li><a href=\"#_support\">Support</a></li>\n<li><a href=\"#_contributions\">Contributions</a></li>\n<li><a href=\"#_license\">License</a></li>\n</ul>\n</div>\n</div>\n</div>\n<div class=\"sect1\">\n<h2 id=\"_features\"><a class=\"anchor\" href=\"#_features\"></a><a class=\"link\" href=\"#_features\">Features</a></h2>\n<div class=\"sectionbody\">\n<div class=\"ulist\">\n<ul>\n<li>\n<p>Set up an automated CI / CD pipeline for your infrastructure code (Terraform / Terragrunt / Packer / Docker)</p>\n</li>\n<li>\n<p>Supports approval work flows: see plan first and approve it in your CI / CD system before running apply</p>\n</li>\n<li>\n<p>Build AMIs and Docker images</p>\n</li>\n<li>\n<p>Isolated runtime environment in AWS using AWS Lambda and ECS Fargate/EC2</p>\n</li>\n<li>\n<p>Deploy any reference (commit sha, tag, or branch) from any git repository</p>\n</li>\n</ul>\n</div>\n</div>\n</div>\n<div class=\"sect1\">\n<h2 id=\"_learn\"><a class=\"anchor\" href=\"#_learn\"></a><a class=\"link\" href=\"#_learn\">Learn</a></h2>\n<div class=\"sectionbody\">\n<div class=\"admonitionblock note\">\n<table>\n<tr>\n<td class=\"icon\">\n<div class=\"title\">Note</div>\n</td>\n<td class=\"content\">\nThis repo is a part of <a href=\"https://gruntwork.io/infrastructure-as-code-library/\" target=\"_blank\">the Gruntwork Infrastructure as Code\nLibrary</a>, a collection of reusable, battle-tested, production ready infrastructure code. If you’ve never used the Infrastructure as Code Library before, make sure to read <a href=\"https://gruntwork.io/guides/foundations/how-to-use-gruntwork-infrastructure-as-code-library/\" target=\"_blank\">How to use the Gruntwork Infrastructure as Code Library</a>!\n</td>\n</tr>\n</table>\n</div>\n<div class=\"sect2\">\n<h3 id=\"_core_concepts\"><a class=\"anchor\" href=\"#_core_concepts\"></a><a class=\"link\" href=\"#_core_concepts\">Core concepts</a></h3>\n<div class=\"ulist\">\n<ul>\n<li>\n<p><a href=\"/repos/v0.29.12/module-ci/modules/ecs-deploy-runner/core-concepts.md#overview\">Overview</a>: An overview of the architecture deployed by in this module, including how\nto implement a CI/CD pipeline for infrastructure code.</p>\n</li>\n<li>\n<p><a href=\"/repos/v0.29.12/module-ci/modules/ecs-deploy-runner/core-concepts.md#threat-model-of-the-deploy-runner\">Threat model of the deploy runner</a>: An overview of the threat\nmodel used to design the security features of the solution, including a description of the potential attack vectors\nthat are mitigated by the solution, and those attacks that require policy and behavioral changes to mitigate.</p>\n</li>\n</ul>\n</div>\n</div>\n<div class=\"sect2\">\n<h3 id=\"_repo_organization\"><a class=\"anchor\" href=\"#_repo_organization\"></a><a class=\"link\" href=\"#_repo_organization\">Repo organization</a></h3>\n<div class=\"ulist\">\n<ul>\n<li>\n<p><a href=\"/repos/v0.29.12/module-ci/modules\">modules</a>: the main implementation code for this repo, broken down into multiple standalone, orthogonal submodules.</p>\n</li>\n<li>\n<p><a href=\"/repos/v0.29.12/module-ci/examples\">examples</a>: This folder contains working examples of how to use the submodules.</p>\n</li>\n<li>\n<p><a href=\"/repos/v0.29.12/module-ci/test\">test</a>: Automated tests for the modules and examples.</p>\n</li>\n</ul>\n</div>\n</div>\n</div>\n</div>\n<div class=\"sect1\">\n<h2 id=\"_deploy\"><a class=\"anchor\" href=\"#_deploy\"></a><a class=\"link\" href=\"#_deploy\">Deploy</a></h2>\n<div class=\"sectionbody\">\n<div class=\"sect2\">\n<h3 id=\"_non_production_deployment_quick_start_for_learning\"><a class=\"anchor\" href=\"#_non_production_deployment_quick_start_for_learning\"></a><a class=\"link\" href=\"#_non_production_deployment_quick_start_for_learning\">Non-production deployment (quick start for learning)</a></h3>\n<div class=\"paragraph\">\n<p>If you just want to try this repo out for experimenting and learning, check out the following resources:</p>\n</div>\n<div class=\"ulist\">\n<ul>\n<li>\n<p><a href=\"/repos/v0.29.12/module-ci/examples\">examples folder</a>: The <code>examples</code> folder contains sample code optimized for learning, experimenting, and testing (but not production usage).</p>\n</li>\n</ul>\n</div>\n</div>\n</div>\n</div>\n<div class=\"sect1\">\n<h2 id=\"_manage\"><a class=\"anchor\" href=\"#_manage\"></a><a class=\"link\" href=\"#_manage\">Manage</a></h2>\n<div class=\"sectionbody\">\n<div class=\"ulist\">\n<ul>\n<li>\n<p><a href=\"/repos/v0.29.12/module-ci/modules/ecs-deploy-runner/core-concepts.md#what-configuration-is-recommended-for-container_images\">What configuration is recommended for container_images?</a></p>\n</li>\n<li>\n<p><a href=\"/repos/v0.29.12/module-ci/modules/ecs-deploy-runner/core-concepts.md#how-do-i-restrict-what-args-can-be-passed-into-the-scripts\">How do I restrict what args can be passed into the scripts?</a></p>\n</li>\n<li>\n<p><a href=\"/repos/v0.29.12/module-ci/modules/ecs-deploy-runner/core-concepts.md#how-do-i-trigger-a-deployment\">How do I trigger a deployment?</a></p>\n</li>\n<li>\n<p><a href=\"/repos/v0.29.12/module-ci/modules/ecs-deploy-runner/core-concepts.md#how-do-i-trigger-a-deployment-from-ci\">How do I trigger a deployment from CI?</a></p>\n</li>\n<li>\n<p><a href=\"/repos/v0.29.12/module-ci/modules/ecs-deploy-runner/core-concepts.md#what-container-is-used-for-the-deploy-task\">How do I customize the deployment task runtime\nenvironment?</a></p>\n</li>\n<li>\n<p><a href=\"/repos/v0.29.12/module-ci/modules/ecs-deploy-runner/core-concepts.md#how-do-i-use-the-ecs-deploy-runner-with-a-private-vcs-system-such-as-github-enterprise\">How do I\nuse the deployment task container with a private VCS system such as GitHub Enterprise?</a></p>\n</li>\n<li>\n<p><a href=\"/repos/v0.29.12/module-ci/modules/ecs-deploy-runner/core-concepts.md#how-do-i-stream-logs-from-the-deployment-task\">How do I stream logs from the deployment task?</a></p>\n</li>\n<li>\n<p><a href=\"/repos/v0.29.12/module-ci/modules/ecs-deploy-runner/core-concepts.md#what-are-the-iam-permissions-necessary-to-trigger-a-deployment\">What are the IAM permissions\nnecessary to trigger a deployment?</a></p>\n</li>\n</ul>\n</div>\n</div>\n</div>\n<div class=\"sect1\">\n<h2 id=\"_support\"><a class=\"anchor\" href=\"#_support\"></a><a class=\"link\" href=\"#_support\">Support</a></h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>If you need help with this repo or anything else related to infrastructure or DevOps, Gruntwork offers <a href=\"https://gruntwork.io/support/\" target=\"_blank\">Commercial Support</a> via Slack, email, and phone/video. If you’re already a Gruntwork customer, hop on Slack and ask away! If not, <a href=\"https://www.gruntwork.io/pricing/\" target=\"_blank\">subscribe now</a>. If you’re not sure, feel free to email us at <a href=\"mailto:support@gruntwork.io\" target=\"_blank\">support@gruntwork.io</a>.</p>\n</div>\n</div>\n</div>\n<div class=\"sect1\">\n<h2 id=\"_contributions\"><a class=\"anchor\" href=\"#_contributions\"></a><a class=\"link\" href=\"#_contributions\">Contributions</a></h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Contributions to this repo are very welcome and appreciated! If you find a bug or want to add a new feature or even contribute an entirely new module, we are very happy to accept pull requests, provide feedback, and run your changes through our automated test suite.</p>\n</div>\n<div class=\"paragraph\">\n<p>Please see <a href=\"https://gruntwork.io/guides/foundations/how-to-use-gruntwork-infrastructure-as-code-library/#contributing-to-the-gruntwork-infrastructure-as-code-library\" target=\"_blank\">Contributing to the Gruntwork Infrastructure as Code Library</a> for instructions.</p>\n</div>\n</div>\n</div>\n<div class=\"sect1\">\n<h2 id=\"_license\"><a class=\"anchor\" href=\"#_license\"></a><a class=\"link\" href=\"#_license\">License</a></h2>\n<div class=\"sectionbody\">\n<div class=\"paragraph\">\n<p>Please see <a href=\"/repos/v0.29.12/module-ci/LICENSE.txt\">LICENSE.txt</a> for details on how the code in this repo is licensed.</p>\n</div>\n</div>\n</div>","repoName":"module-ci","repoRef":"v0.29.2","serviceDescriptor":{"serviceName":"EC2 backup","serviceRepoName":"module-ci","serviceRepoOrg":"gruntwork-io","serviceMainReadmePath":"/modules/ec2-backup","cloudProviders":["aws"],"description":"Snapshot your EC2 instances on a scheduled basis.","imageUrl":"grunt.png","licenseType":"subscriber","technologies":["Terraform","JavaScript","Lambda"],"compliance":[],"tags":[""]},"serviceCategoryName":"Backup & recovery","fileName":"README.adoc","filePath":"/modules/ecs-deploy-runner","title":"Repo Browser: EC2 backup","description":"Browse the repos in the Gruntwork Infrastructure as Code Library."}