You will need to checkout the code for your app(s) using Git. For this tutorial, we are going to checkout
sample-app-frontend-multi-account-acme, which is a sample app that's handy for
demonstrating all the key concepts in this tutorial.
Note that sample-app-frontend-multi-account-acme depends on another sample app called sample-app-backend-multi-account-acme,
so you may want to checkout that app too:
sample-app-frontend-multi-account-acme is packaged as a Docker container so that it runs the same way in all
environments, including on your computer. Moreover, we've used Docker Compose to
configure all the Docker containers you need to run your entire tech stack (i.e., all apps, databases, etc) in the
docker-compose.yml file, so you can fire everything up with a single command:
cdsample-app-frontend-multi-account-acme
docker-compose up
Your entire stack will boot up in a few seconds and you should be able to test it by going to
http://localhost:3000/sample-app-frontend-multi-account-acme.
The app that's running is a simple Node.js app, but the ideas demonstrated work more or less
the same way in any language. Take a look at app/index.js to see the code. You should also see other endpoints in
that file that you can try.
Make a service call
One of the other endpoints you can try is http://localhost:3000/sample-app-frontend-multi-account-acme/service.
This demonstrates how sample-app-frontend-multi-account-acme can make a service call to sample-app-backend-multi-account-acme. How does this work?
If you dig through the code in app/server.js, you'll see that sample-app-frontend-multi-account-acme is getting the IP address of
sample-app-backend-multi-account-acme from an environment variable called BACKEND_URL and falling back to the value backend if that
environment variable is not set. Here's how this works:
In dev, Docker Compose Networking sets up a single network where each
service xxx is accessible at the hostname xxx. Since our service is called backend, it is accessible at
http(s)://backend.
In other environments (e.g. stage, prod) we configure Terraform to set the BACKEND_URL environment variable for
your Docker containers, except we point the variable to an internal Application Load Balancer (see
Architecture overview), which is configured to route traffic to sample-app-backend-multi-account-acme.
We use a similar approach to allow the app to talk to all of its other dependencies too (e.g., the database, cache,
etc), with slightly different service names and environment variables for each one.
Change the code
Make a change to the app code, such as modifying app/index.js or app/index.html.
Refresh the page in your browser and you should see your changes immediately! Here's how that works:
In docker-compose.yml, we configure Docker to mount
the code from your host OS into the Docker container (look for the volumes settings in docker-compose.yml). That
way, every time you make a change on your host OS, it's reflected immediately in the Docker container.
The Docker container uses nodemon in dev mode, so the Node app restarts
automatically with every change.
This setup allows you to iterate rapidly!
Update the application configuration
sample-app-frontend-multi-account-acme stores most of its configuration settings in files. The advantage of this is that the files are
checked into version control (so you have a history of config changes) and are versioned and deployed with the app code
itself (so you don't get a mismatch between app and config).
The files live in the config directory.
The names use the format example-config-<environment>.json, where environment is an environment name, such as
development, stage, or prod. Note that the same basic config approach shown here works with any file format and
naming convention; we only use JSON because it's easy to use with the sample Node.js app.
In app/server.js, the app loads the proper config file for the current environment based on the environment
variable VPC_NAME.
In dev, the VPC_NAME environment variable is configured in docker-compose.yml.
In other environments (e.g., stage, prod) the VPC_NAME environment variable is set by Terraform.
Encrypt a secret
Occasionally, you may need to encrypt some secret data. For example, you may want to store the password to your
database in your app's configuration. Storing secrets in plain text anywhere, including version control, is a major
security risk and should be avoided (see Gruntwork Security Best Practices
for more info). A better way to handle this is to encrypt the secrets before putting them in version control and to
have your app decrypt those secrets before it boots.
Create "master key" in KMS using the kms-master-key
module. Note that we've already
created one master key in each environment, so for most use cases, you should use those and not create any new ones.
You can see all available master keys in the Encryption Keys page in
IAM.
Use the master key, along with gruntkms, to encrypt and decrypt secrets
with a single CLI command.
For example, you could run gruntkms on your computer to encrypt a database password:
You can now safely check the kmscrypt::... ciphertext into version control.
You can then give your apps access to the same KMS key via IAM permissions and configure your apps to decrypt the
ciphertext using gruntkms just before booting:
# An app decrypts the ciphertext before booting
echo "kmscrypt::AQICAHhQYFj4xrlpRdnui/MrOlrIt+gSSrFxZay4ZMDMofceSwEXSzGkmBBWbG6==" | gruntkms decrypt --aws-region "us-east-1""super secret database password"
Make sure to read through the gruntkms docs to learn how how the kmscrypt::
prefix works and how to decrypt all secrets in a config file in a single command (see bin/run-app.sh in the sample
apps for an example).
Apply schema migrations
sample-app-backend-multi-account-acme contains example code of how to talk to a relational database. It also contains an example of how
to apply schema migrations to your database before the app boots. The idea is to version and package the schema
migration code with the app code so that whenever you deploy a new version of the app, it always ensures the schema it
depends on is in place before booting.
Under the hood, the example code manages the schema migrations using simple .sql files (see the sql folder) and
uses Flyway to apply those migrations (see bin/run-app.sh). The same basic approach should
work with any other schema migration tool (e.g., Luiqibase,
ActiveRecord) as long as that tool obtains a lock
before applying schema changes (to ensure you only apply the schema changes once even if multiple copies of the app
boot up at the same time).
Commit your changes
If you've made any changes to the code during this tutorial, it's time to commit them back to Git!
{"treedata":{"name":"root","toggled":true,"children":[{"name":".gitignore","path":".gitignore","sha":"1c27fc6013cba46cd301a7c8bf951694670153a3"},{"name":"CODEOWNERS","path":"CODEOWNERS","sha":"00570abefb91e715366015f8b5acf32631336d52"},{"name":"README.md","path":"README.md","sha":"45d75f99aefaa9a2d008b223da04bc26453ef651"},{"name":"_docs","children":[{"name":"01-architecture-overview.md","path":"_docs/01-architecture-overview.md","sha":"115a05d08f3a431a19e5aa2596c079619ae66dab"},{"name":"02-whats-deployed.md","path":"_docs/02-whats-deployed.md","sha":"9dc8a401caf24896ce00a8087bfe32c7af99d2d2"},{"name":"03-security-compliance-compatibility.md","path":"_docs/03-security-compliance-compatibility.md","sha":"9342617f42adb28e440cc2161f3fee56205c150e"},{"name":"04-how-code-is-organized.md","path":"_docs/04-how-code-is-organized.md","sha":"3b340de506525633e1f7333a1e9ac9a5565a88e3"},{"name":"05-dev-environment.md","path":"_docs/05-dev-environment.md","sha":"c8b494aed802b623f7891047b6cba633d8ab5fa7","toggled":true},{"name":"06-ci-cd.md","path":"_docs/06-ci-cd.md","sha":"b6c2a7d7cde7471fb08bff5dcf68c40156db68d5"},{"name":"07-monitoring-alerting-logging.md","path":"_docs/07-monitoring-alerting-logging.md","sha":"619c810c6e60418b3a46fa3d903bc76dc6d48e41"},{"name":"08-ssh-vpn.md","path":"_docs/08-ssh-vpn.md","sha":"9fe83afbd3d6116a4f3faff8923a81cd37ff91c7"},{"name":"09-accounts-and-auth.md","path":"_docs/09-accounts-and-auth.md","sha":"6b0472241644ffc79556e60d582ff1edb80f0554"},{"name":"10-gruntwork-tools.md","path":"_docs/10-gruntwork-tools.md","sha":"0ef0415847d1202ef8843dada867d018d653de6e"},{"name":"11-deploying-a-docker-service.md","path":"_docs/11-deploying-a-docker-service.md","sha":"c735be4ee94e76cc55b48a21039dfec44e6a5d51"},{"name":"12-migration.md","path":"_docs/12-migration.md","sha":"464cadf6e05d5ffd44e569c0d866b5c2cf5f42e9"},{"name":"13-deploying-the-reference-architecture-from-scratch.md","path":"_docs/13-deploying-the-reference-architecture-from-scratch.md","sha":"2176ccd41cf80dd7409e7f0df0ba13146f0b0378"},{"name":"14-undeploying-the-reference-architecture.md","path":"_docs/14-undeploying-the-reference-architecture.md","sha":"c6dcaae7266ead56d539b1816a5cfe2988412fe1"},{"name":"15-adding-new-environments-regions-and-accounts.md","path":"_docs/15-adding-new-environments-regions-and-accounts.md","sha":"c01188a1539e93ed2773a1b799b3b0f8e7b2045e"},{"name":"README.md","path":"_docs/README.md","sha":"ddb9fe83eb2fcad91e82771ad276dd0bdba40cb2"},{"name":"_images","children":[{"name":"cw-logs-1.png","path":"_docs/_images/cw-logs-1.png","sha":"84c86f014751844fbd777b5139ed61f749b5ed32"},{"name":"cw-logs-2.png","path":"_docs/_images/cw-logs-2.png","sha":"9a0a80b20490fdc1b9014040cc0bbc87c9cf6f68"},{"name":"cw-logs-3.png","path":"_docs/_images/cw-logs-3.png","sha":"bda49dc4e947658e0ceb9ba592b4e314d9db61e9"},{"name":"cw-logs-4.png","path":"_docs/_images/cw-logs-4.png","sha":"54bcc44c4b0701620b7f20c4e6fc0a9fd8f38049"},{"name":"ecs-console-1.png","path":"_docs/_images/ecs-console-1.png","sha":"afe452278d5f107e6ec225a235c587de7cb53510"},{"name":"ecs-console-2.png","path":"_docs/_images/ecs-console-2.png","sha":"40609b98015d781b9e1de801c131fadc323337ae"},{"name":"ecs-console-3.png","path":"_docs/_images/ecs-console-3.png","sha":"87ad40d291b7e9e6f6caa0389b846392bdb93ee0"},{"name":"ref-arch-full.png","path":"_docs/_images/ref-arch-full.png","sha":"8c17eef52be06757553a1f3ee4e387e6dc820016"},{"name":"ref-arch-icon.png","path":"_docs/_images/ref-arch-icon.png","sha":"05876962e6877df911674237ca1b793d9f4f04b3"},{"name":"terraform-code-provenance.png","path":"_docs/_images/terraform-code-provenance.png","sha":"e2a9d6bfbd8b963b057d4341dd0ec93e3823d834"}]}],"toggled":true},{"name":"dev","children":[{"name":"_global","children":[{"name":"README.md","path":"dev/_global/README.md","sha":"d1b8a96c00211751f079fa13cac1b3417d29bf09"},{"name":"cloudtrail","children":[{"name":"README.md","path":"dev/_global/cloudtrail/README.md","sha":"e6781286118d8ac86fe60cda1057595644d851da"},{"name":"terragrunt.hcl","path":"dev/_global/cloudtrail/terragrunt.hcl","sha":"fb19b4438de2ba919d17f3e4a6ccb3c9f2517f26"}]},{"name":"iam-cross-account","children":[{"name":"README.md","path":"dev/_global/iam-cross-account/README.md","sha":"d33fb4cd9ef7b20250205797177184bf1828f966"},{"name":"terragrunt.hcl","path":"dev/_global/iam-cross-account/terragrunt.hcl","sha":"ef9dd9c28172500be3ffd79646dff2e0c4981f70"}]},{"name":"iam-user-password-policy","children":[{"name":"README.md","path":"dev/_global/iam-user-password-policy/README.md","sha":"b47d1c6602f3f4ea02fabd247f12c9ee3520be56"},{"name":"terragrunt.hcl","path":"dev/_global/iam-user-password-policy/terragrunt.hcl","sha":"47b669ba52099812a6d52ed4fcdad48c5e32e91e"}]},{"name":"region.yaml","path":"dev/_global/region.yaml","sha":"18b7823ed017b97431d58da7bcb9a4e31299272a"},{"name":"route53-public","children":[{"name":"README.md","path":"dev/_global/route53-public/README.md","sha":"03c91d97d2da5dea0f5dfa34a3004cc54118e60c"},{"name":"terragrunt.hcl","path":"dev/_global/route53-public/terragrunt.hcl","sha":"68ed9958a62546160f9007660857c5baa95ce12b"}]}]},{"name":"empty.yaml","path":"dev/empty.yaml","sha":"5aa66daa40faeaef37eccb7b4b0fcc792233cd7b"},{"name":"terragrunt.hcl","path":"dev/terragrunt.hcl","sha":"35ddfe3ed25d8ce7f35d20f1ea7a59dd1ccf4450"},{"name":"us-east-1","children":[{"name":"_global","children":[{"name":"README.md","path":"dev/us-east-1/_global/README.md","sha":"37b828b038945a50e2e571ef1e755c4f9170e7cf"},{"name":"kms-master-key","children":[{"name":"README.md","path":"dev/us-east-1/_global/kms-master-key/README.md","sha":"d348d763df093b315e6a8810250a01d8a5301051"},{"name":"terragrunt.hcl","path":"dev/us-east-1/_global/kms-master-key/terragrunt.hcl","sha":"d5c556e7eb743da62e0191243a2d4ee9ec2cf828"}]},{"name":"sns-topics","children":[{"name":"README.md","path":"dev/us-east-1/_global/sns-topics/README.md","sha":"ae3e2f9522b38fa85eff3c962e4c3d40c6724e17"},{"name":"terragrunt.hcl","path":"dev/us-east-1/_global/sns-topics/terragrunt.hcl","sha":"225cf4b3fe49af57c85a1e25b7942c72cf9e6853"}]}]},{"name":"dev","children":[{"name":"README.md","path":"dev/us-east-1/dev/README.md","sha":"30eef7620895f3ad23174f5f2c8772ab7f8880a8"},{"name":"cloudwatch-dashboard","children":[{"name":"README.md","path":"dev/us-east-1/dev/cloudwatch-dashboard/README.md","sha":"aa1cfea49f1679e79991f9cf80c12a5b41943a1d"},{"name":"terragrunt.hcl","path":"dev/us-east-1/dev/cloudwatch-dashboard/terragrunt.hcl","sha":"f3533abbe42145ab1b29f235701892621c9d63d3"}]},{"name":"data-stores","children":[{"name":"elk-single-cluster","children":[{"name":"README.md","path":"dev/us-east-1/dev/data-stores/elk-single-cluster/README.md","sha":"9a1cb70a6f6b1b3ac81b2c7c5b17d902328db1e0"},{"name":"terragrunt.hcl","path":"dev/us-east-1/dev/data-stores/elk-single-cluster/terragrunt.hcl","sha":"97fc6b6c810137e559da50b3684a5f6383c77c72"}]},{"name":"kafka","children":[{"name":"README.md","path":"dev/us-east-1/dev/data-stores/kafka/README.md","sha":"8bfe6579bd97e0148c3baa24e1215abce8cf312b"},{"name":"terragrunt.hcl","path":"dev/us-east-1/dev/data-stores/kafka/terragrunt.hcl","sha":"1c40ceaf50ae178033dda665553598a3f7548cd1"}]},{"name":"mysql","children":[{"name":"README.md","path":"dev/us-east-1/dev/data-stores/mysql/README.md","sha":"df149a836e3a0f3e082cb98f3679e48e0cf6fe4b"},{"name":"terragrunt.hcl","path":"dev/us-east-1/dev/data-stores/mysql/terragrunt.hcl","sha":"40313bc9ada285fe59d77067728f6cf208b04668"}]},{"name":"redis","children":[{"name":"README.md","path":"dev/us-east-1/dev/data-stores/redis/README.md","sha":"a305dff8ab1fd409e94cb7b9bf8d3a78ef84c689"},{"name":"terragrunt.hcl","path":"dev/us-east-1/dev/data-stores/redis/terragrunt.hcl","sha":"bfa22ef95f443e06ccf0624c414d6f9f6bde5b88"}]},{"name":"zookeeper","children":[{"name":"README.md","path":"dev/us-east-1/dev/data-stores/zookeeper/README.md","sha":"451ce7cb440aa724bf4dc8a35726e2bda7e071a2"},{"name":"terragrunt.hcl","path":"dev/us-east-1/dev/data-stores/zookeeper/terragrunt.hcl","sha":"76af3451b7a52fd7d59cd8744ff3836da3c1826d"}]}]},{"name":"env.yaml","path":"dev/us-east-1/dev/env.yaml","sha":"c38dd83256fc4206be3afc24972cd7f3b6712b19"},{"name":"lambda","children":[{"name":"long-running-scheduled","children":[{"name":"README.md","path":"dev/us-east-1/dev/lambda/long-running-scheduled/README.md","sha":"af7b8b9950d620577e1db104d0140a478e5f46fd"},{"name":"terragrunt.hcl","path":"dev/us-east-1/dev/lambda/long-running-scheduled/terragrunt.hcl","sha":"72518b7089bd107c05c281372f3cccd6d7a6a628"}]},{"name":"s3-image-processing","children":[{"name":"README.md","path":"dev/us-east-1/dev/lambda/s3-image-processing/README.md","sha":"236ef4197db71e6e121e3ca7182e556fa9ecaa60"},{"name":"terragrunt.hcl","path":"dev/us-east-1/dev/lambda/s3-image-processing/terragrunt.hcl","sha":"9be5024cab87f495dd8ac275b9807d086b971da5"}]}]},{"name":"networking","children":[{"name":"alb-internal","children":[{"name":"README.md","path":"dev/us-east-1/dev/networking/alb-internal/README.md","sha":"62a1d20d3b1b638b435dc3f72b900dad211d7e50"},{"name":"terragrunt.hcl","path":"dev/us-east-1/dev/networking/alb-internal/terragrunt.hcl","sha":"3226f2f8cc966d88abe6ffe7b1d912735a638b80"}]},{"name":"alb-public","children":[{"name":"README.md","path":"dev/us-east-1/dev/networking/alb-public/README.md","sha":"62a1d20d3b1b638b435dc3f72b900dad211d7e50"},{"name":"terragrunt.hcl","path":"dev/us-east-1/dev/networking/alb-public/terragrunt.hcl","sha":"039a02514db5e62d5ec21d3131579c821dcb6283"}]},{"name":"route53-private","children":[{"name":"README.md","path":"dev/us-east-1/dev/networking/route53-private/README.md","sha":"2f6db22493297bf5ae1c98149b9a7c9c896c3c7f"},{"name":"terragrunt.hcl","path":"dev/us-east-1/dev/networking/route53-private/terragrunt.hcl","sha":"f7e7c4b437c11b0340c682314deb9b08aca3a854"}]}]},{"name":"services","children":[{"name":"ecs-cluster","children":[{"name":"README.md","path":"dev/us-east-1/dev/services/ecs-cluster/README.md","sha":"408361ee7f158cd1ff3d61aface9d1d1e38de478"},{"name":"terragrunt.hcl","path":"dev/us-east-1/dev/services/ecs-cluster/terragrunt.hcl","sha":"64c60f67c5ce0a965a2e636015dcb9ff4e22344a"}]},{"name":"eks-cluster","children":[{"name":"README.md","path":"dev/us-east-1/dev/services/eks-cluster/README.md","sha":"74ede9bb3693e3e380ee157dc3fb806f7d0d3371"},{"name":"terragrunt.hcl","path":"dev/us-east-1/dev/services/eks-cluster/terragrunt.hcl","sha":"791a66ce8376fbec9a019d0cab0ac0ead3aac1ac"}]},{"name":"eks-core-services","children":[{"name":"README.md","path":"dev/us-east-1/dev/services/eks-core-services/README.md","sha":"b7fae44415a060b53046b876f0740cc35d6c8301"},{"name":"terragrunt.hcl","path":"dev/us-east-1/dev/services/eks-core-services/terragrunt.hcl","sha":"b9a002b3992e384e57015587693b3e7fe8eddc48"}]},{"name":"k8s-applications-namespace","children":[{"name":"README.md","path":"dev/us-east-1/dev/services/k8s-applications-namespace/README.md","sha":"7cd7fd44a26d97c8be91434fb23c1a8cf5564f61"},{"name":"terragrunt.hcl","path":"dev/us-east-1/dev/services/k8s-applications-namespace/terragrunt.hcl","sha":"dd0fbec59f588fe88fc6c7f59382c0ab6d20ff9c"}]},{"name":"k8s-sample-app-backend-multi-account-acme","children":[{"name":"README.md","path":"dev/us-east-1/dev/services/k8s-sample-app-backend-multi-account-acme/README.md","sha":"be9775b3967cebddddd703b156bb11a43ed60504"},{"name":"terragrunt.hcl","path":"dev/us-east-1/dev/services/k8s-sample-app-backend-multi-account-acme/terragrunt.hcl","sha":"953bef0317447c080e801343e586b0d1b3cbfbfa"}]},{"name":"k8s-sample-app-frontend-multi-account-acme","children":[{"name":"README.md","path":"dev/us-east-1/dev/services/k8s-sample-app-frontend-multi-account-acme/README.md","sha":"ab557b031a3224f14132dc6c49301a8b4462d96f"},{"name":"terragrunt.hcl","path":"dev/us-east-1/dev/services/k8s-sample-app-frontend-multi-account-acme/terragrunt.hcl","sha":"40060b5d96f21608eb30d259cef65289f6169a6f"}]},{"name":"sample-app-backend-multi-account-acme-asg","children":[{"name":"README.md","path":"dev/us-east-1/dev/services/sample-app-backend-multi-account-acme-asg/README.md","sha":"685cf659d427612df857de9d87b412194c4cab6b"},{"name":"terragrunt.hcl","path":"dev/us-east-1/dev/services/sample-app-backend-multi-account-acme-asg/terragrunt.hcl","sha":"cf84fcfa70c6d966803b70e29f549f3bd057f206"}]},{"name":"sample-app-backend-multi-account-acme","children":[{"name":"README.md","path":"dev/us-east-1/dev/services/sample-app-backend-multi-account-acme/README.md","sha":"dff94c5b1e4eb6f3d5f4692b8c6631def939d5b0"},{"name":"terragrunt.hcl","path":"dev/us-east-1/dev/services/sample-app-backend-multi-account-acme/terragrunt.hcl","sha":"c88b0d61edddbf9337c414cfae2d970735be2b6f"}]},{"name":"sample-app-beanstalk","children":[{"name":"README.md","path":"dev/us-east-1/dev/services/sample-app-beanstalk/README.md","sha":"690d80935b99167035ee0222aa6ab67d6ab6ca92"},{"name":"terragrunt.hcl","path":"dev/us-east-1/dev/services/sample-app-beanstalk/terragrunt.hcl","sha":"77ac87dca4c64fbf5108231a6faf807fca3d1fee"}]},{"name":"sample-app-frontend-multi-account-acme-asg","children":[{"name":"README.md","path":"dev/us-east-1/dev/services/sample-app-frontend-multi-account-acme-asg/README.md","sha":"f79d423702bf789228ed180ac6364329cfbc15d2"},{"name":"terragrunt.hcl","path":"dev/us-east-1/dev/services/sample-app-frontend-multi-account-acme-asg/terragrunt.hcl","sha":"17d10295d106fbde6b0de3bf6c5d3badc97c0ecd"}]},{"name":"sample-app-frontend-multi-account-acme","children":[{"name":"README.md","path":"dev/us-east-1/dev/services/sample-app-frontend-multi-account-acme/README.md","sha":"a646dd069176d91bdd8bb6d330e6e66c61a7b5e8"},{"name":"terragrunt.hcl","path":"dev/us-east-1/dev/services/sample-app-frontend-multi-account-acme/terragrunt.hcl","sha":"c423cc7a2fe3630db7c75a72ef212ba186ab3739"}]},{"name":"static-website","children":[{"name":"README.md","path":"dev/us-east-1/dev/services/static-website/README.md","sha":"bd02d2c0be6895e1154a84f183684889e0c9549a"},{"name":"terragrunt.hcl","path":"dev/us-east-1/dev/services/static-website/terragrunt.hcl","sha":"3329db273624fe437ef031ee4e42583aa13c2312"}]}]},{"name":"vpc","children":[{"name":"README.md","path":"dev/us-east-1/dev/vpc/README.md","sha":"280e9664161d12f19141baa007a5c7d3d6e4f4a8"},{"name":"terragrunt.hcl","path":"dev/us-east-1/dev/vpc/terragrunt.hcl","sha":"aea95690d1f2f5d37e6781f718f4b132c7f509b1"}]}]},{"name":"mgmt","children":[{"name":"README.md","path":"dev/us-east-1/mgmt/README.md","sha":"8a131a11632b97fec18a5e344d5c721fce24b652"},{"name":"env.yaml","path":"dev/us-east-1/mgmt/env.yaml","sha":"b514ab3187ebfb5bf467c632f27a21f5a9611bfc"},{"name":"openvpn-server","children":[{"name":"README.md","path":"dev/us-east-1/mgmt/openvpn-server/README.md","sha":"c11261ef74ec62c04f96717ddf94544c1649125b"},{"name":"terragrunt.hcl","path":"dev/us-east-1/mgmt/openvpn-server/terragrunt.hcl","sha":"2541766dcbbcd6165dc0f661144f6f09be56ce1b"}]},{"name":"vpc","children":[{"name":"README.md","path":"dev/us-east-1/mgmt/vpc/README.md","sha":"73452d7db6e78079df0ee0854e9ae80645fce937"},{"name":"terragrunt.hcl","path":"dev/us-east-1/mgmt/vpc/terragrunt.hcl","sha":"20f97f225446751b79f2283837d0d9d225ea3833"}]}]},{"name":"region.yaml","path":"dev/us-east-1/region.yaml","sha":"d56afa3d82e6cea0d792e84748de56dafb0bad70"}]}]},{"name":"master","children":[{"name":"_global","children":[{"name":"README.md","path":"master/_global/README.md","sha":"d1b8a96c00211751f079fa13cac1b3417d29bf09"},{"name":"cloudtrail","children":[{"name":"README.md","path":"master/_global/cloudtrail/README.md","sha":"e6781286118d8ac86fe60cda1057595644d851da"},{"name":"terragrunt.hcl","path":"master/_global/cloudtrail/terragrunt.hcl","sha":"fb19b4438de2ba919d17f3e4a6ccb3c9f2517f26"}]},{"name":"iam-cross-account","children":[{"name":"README.md","path":"master/_global/iam-cross-account/README.md","sha":"d33fb4cd9ef7b20250205797177184bf1828f966"},{"name":"terragrunt.hcl","path":"master/_global/iam-cross-account/terragrunt.hcl","sha":"4b7fbf5498b4a1f2958a81a253faf5fc0e261b37"}]},{"name":"iam-user-password-policy","children":[{"name":"README.md","path":"master/_global/iam-user-password-policy/README.md","sha":"b47d1c6602f3f4ea02fabd247f12c9ee3520be56"},{"name":"terragrunt.hcl","path":"master/_global/iam-user-password-policy/terragrunt.hcl","sha":"47b669ba52099812a6d52ed4fcdad48c5e32e91e"}]},{"name":"region.yaml","path":"master/_global/region.yaml","sha":"18b7823ed017b97431d58da7bcb9a4e31299272a"}]},{"name":"empty.yaml","path":"master/empty.yaml","sha":"5aa66daa40faeaef37eccb7b4b0fcc792233cd7b"},{"name":"terragrunt.hcl","path":"master/terragrunt.hcl","sha":"450cb535222a9ba6e246c8c70ba8b4b6b76e2f18"},{"name":"us-east-1","children":[{"name":"_global","children":[{"name":"README.md","path":"master/us-east-1/_global/README.md","sha":"37b828b038945a50e2e571ef1e755c4f9170e7cf"}]},{"name":"region.yaml","path":"master/us-east-1/region.yaml","sha":"d56afa3d82e6cea0d792e84748de56dafb0bad70"}]}]},{"name":"prod","children":[{"name":"_global","children":[{"name":"README.md","path":"prod/_global/README.md","sha":"d1b8a96c00211751f079fa13cac1b3417d29bf09"},{"name":"cloudtrail","children":[{"name":"README.md","path":"prod/_global/cloudtrail/README.md","sha":"e6781286118d8ac86fe60cda1057595644d851da"},{"name":"terragrunt.hcl","path":"prod/_global/cloudtrail/terragrunt.hcl","sha":"fb19b4438de2ba919d17f3e4a6ccb3c9f2517f26"}]},{"name":"iam-cross-account","children":[{"name":"README.md","path":"prod/_global/iam-cross-account/README.md","sha":"d33fb4cd9ef7b20250205797177184bf1828f966"},{"name":"terragrunt.hcl","path":"prod/_global/iam-cross-account/terragrunt.hcl","sha":"ef9dd9c28172500be3ffd79646dff2e0c4981f70"}]},{"name":"iam-user-password-policy","children":[{"name":"README.md","path":"prod/_global/iam-user-password-policy/README.md","sha":"b47d1c6602f3f4ea02fabd247f12c9ee3520be56"},{"name":"terragrunt.hcl","path":"prod/_global/iam-user-password-policy/terragrunt.hcl","sha":"47b669ba52099812a6d52ed4fcdad48c5e32e91e"}]},{"name":"region.yaml","path":"prod/_global/region.yaml","sha":"18b7823ed017b97431d58da7bcb9a4e31299272a"},{"name":"route53-public","children":[{"name":"README.md","path":"prod/_global/route53-public/README.md","sha":"03c91d97d2da5dea0f5dfa34a3004cc54118e60c"},{"name":"terragrunt.hcl","path":"prod/_global/route53-public/terragrunt.hcl","sha":"68ed9958a62546160f9007660857c5baa95ce12b"}]}]},{"name":"empty.yaml","path":"prod/empty.yaml","sha":"5aa66daa40faeaef37eccb7b4b0fcc792233cd7b"},{"name":"terragrunt.hcl","path":"prod/terragrunt.hcl","sha":"9cc4740794cee1af908f0a90a7b24541a0e2757c"},{"name":"us-east-1","children":[{"name":"_global","children":[{"name":"README.md","path":"prod/us-east-1/_global/README.md","sha":"37b828b038945a50e2e571ef1e755c4f9170e7cf"},{"name":"kms-master-key","children":[{"name":"README.md","path":"prod/us-east-1/_global/kms-master-key/README.md","sha":"0739299135b88bf5259961de35eb374566a33d3c"},{"name":"terragrunt.hcl","path":"prod/us-east-1/_global/kms-master-key/terragrunt.hcl","sha":"5e19caaa42e506f2797048979d773f2fac5bce8a"}]},{"name":"sns-topics","children":[{"name":"README.md","path":"prod/us-east-1/_global/sns-topics/README.md","sha":"ae3e2f9522b38fa85eff3c962e4c3d40c6724e17"},{"name":"terragrunt.hcl","path":"prod/us-east-1/_global/sns-topics/terragrunt.hcl","sha":"225cf4b3fe49af57c85a1e25b7942c72cf9e6853"}]}]},{"name":"mgmt","children":[{"name":"README.md","path":"prod/us-east-1/mgmt/README.md","sha":"8a131a11632b97fec18a5e344d5c721fce24b652"},{"name":"env.yaml","path":"prod/us-east-1/mgmt/env.yaml","sha":"b514ab3187ebfb5bf467c632f27a21f5a9611bfc"},{"name":"openvpn-server","children":[{"name":"README.md","path":"prod/us-east-1/mgmt/openvpn-server/README.md","sha":"5aafd75eed0aa4f50d12b041bfad085f9f8f8bc7"},{"name":"terragrunt.hcl","path":"prod/us-east-1/mgmt/openvpn-server/terragrunt.hcl","sha":"7d032d739e1742ccab6be199d60da7680d3d5681"}]},{"name":"vpc","children":[{"name":"README.md","path":"prod/us-east-1/mgmt/vpc/README.md","sha":"73452d7db6e78079df0ee0854e9ae80645fce937"},{"name":"terragrunt.hcl","path":"prod/us-east-1/mgmt/vpc/terragrunt.hcl","sha":"a3dbfb5bb3b55e6fcf452338c69e2fdab5aa6204"}]}]},{"name":"prod","children":[{"name":"README.md","path":"prod/us-east-1/prod/README.md","sha":"f15da18661ef3624d5f63deb288bad072e93df57"},{"name":"cloudwatch-dashboard","children":[{"name":"README.md","path":"prod/us-east-1/prod/cloudwatch-dashboard/README.md","sha":"aa1cfea49f1679e79991f9cf80c12a5b41943a1d"},{"name":"terragrunt.hcl","path":"prod/us-east-1/prod/cloudwatch-dashboard/terragrunt.hcl","sha":"fe0a59a0885dd19898acfd6b65b290e5b6bf279c"}]},{"name":"data-stores","children":[{"name":"elk-multi-cluster","children":[{"name":"README.md","path":"prod/us-east-1/prod/data-stores/elk-multi-cluster/README.md","sha":"111f8a7f2339e9f329920b92c275eb9fcf6c18dc"},{"name":"terragrunt.hcl","path":"prod/us-east-1/prod/data-stores/elk-multi-cluster/terragrunt.hcl","sha":"ad3c96134476a81696c73807021c875283c3dfd1"}]},{"name":"kafka","children":[{"name":"README.md","path":"prod/us-east-1/prod/data-stores/kafka/README.md","sha":"8bfe6579bd97e0148c3baa24e1215abce8cf312b"},{"name":"terragrunt.hcl","path":"prod/us-east-1/prod/data-stores/kafka/terragrunt.hcl","sha":"c9e85c9678126c48a4cd6fc16cc55d523194b4d8"}]},{"name":"mysql","children":[{"name":"README.md","path":"prod/us-east-1/prod/data-stores/mysql/README.md","sha":"df149a836e3a0f3e082cb98f3679e48e0cf6fe4b"},{"name":"terragrunt.hcl","path":"prod/us-east-1/prod/data-stores/mysql/terragrunt.hcl","sha":"e88eea81774f2ff43c6ba0f4929593b2adf80e20"}]},{"name":"redis","children":[{"name":"README.md","path":"prod/us-east-1/prod/data-stores/redis/README.md","sha":"a305dff8ab1fd409e94cb7b9bf8d3a78ef84c689"},{"name":"terragrunt.hcl","path":"prod/us-east-1/prod/data-stores/redis/terragrunt.hcl","sha":"2ab5abad0edb89d10ffebb7c279a94b5e344bce6"}]},{"name":"zookeeper","children":[{"name":"README.md","path":"prod/us-east-1/prod/data-stores/zookeeper/README.md","sha":"451ce7cb440aa724bf4dc8a35726e2bda7e071a2"},{"name":"terragrunt.hcl","path":"prod/us-east-1/prod/data-stores/zookeeper/terragrunt.hcl","sha":"e04f530614ac4913a702c2a18e38b4fa5a1f7848"}]}]},{"name":"env.yaml","path":"prod/us-east-1/prod/env.yaml","sha":"90e2d18e481b6e35ddc57391f752874ffc0058cf"},{"name":"lambda","children":[{"name":"long-running-scheduled","children":[{"name":"README.md","path":"prod/us-east-1/prod/lambda/long-running-scheduled/README.md","sha":"af7b8b9950d620577e1db104d0140a478e5f46fd"},{"name":"terragrunt.hcl","path":"prod/us-east-1/prod/lambda/long-running-scheduled/terragrunt.hcl","sha":"72518b7089bd107c05c281372f3cccd6d7a6a628"}]},{"name":"s3-image-processing","children":[{"name":"README.md","path":"prod/us-east-1/prod/lambda/s3-image-processing/README.md","sha":"236ef4197db71e6e121e3ca7182e556fa9ecaa60"},{"name":"terragrunt.hcl","path":"prod/us-east-1/prod/lambda/s3-image-processing/terragrunt.hcl","sha":"87d070e374ab2b7a6860167650e26c0fc73b486a"}]}]},{"name":"networking","children":[{"name":"alb-internal","children":[{"name":"README.md","path":"prod/us-east-1/prod/networking/alb-internal/README.md","sha":"c2a9ab57e03ddedf51dad9c4b375336aabc0e44b"},{"name":"terragrunt.hcl","path":"prod/us-east-1/prod/networking/alb-internal/terragrunt.hcl","sha":"cc5feacf99eebd2cd695507d9169037599c763e5"}]},{"name":"alb-public","children":[{"name":"README.md","path":"prod/us-east-1/prod/networking/alb-public/README.md","sha":"c2a9ab57e03ddedf51dad9c4b375336aabc0e44b"},{"name":"terragrunt.hcl","path":"prod/us-east-1/prod/networking/alb-public/terragrunt.hcl","sha":"03af1d8d3f8a860dc443addbf610f5934f7869eb"}]},{"name":"route53-private","children":[{"name":"README.md","path":"prod/us-east-1/prod/networking/route53-private/README.md","sha":"2f6db22493297bf5ae1c98149b9a7c9c896c3c7f"},{"name":"terragrunt.hcl","path":"prod/us-east-1/prod/networking/route53-private/terragrunt.hcl","sha":"f7e7c4b437c11b0340c682314deb9b08aca3a854"}]}]},{"name":"services","children":[{"name":"ecs-cluster","children":[{"name":"README.md","path":"prod/us-east-1/prod/services/ecs-cluster/README.md","sha":"d990f5a959ffd98ad6c341e3c5a006edae894e1e"},{"name":"terragrunt.hcl","path":"prod/us-east-1/prod/services/ecs-cluster/terragrunt.hcl","sha":"b0eef93fabce97dfe098d6e18677fd3b1839d009"}]},{"name":"eks-cluster","children":[{"name":"README.md","path":"prod/us-east-1/prod/services/eks-cluster/README.md","sha":"09f1c5d37ab965b3330d0c4baa15a4bdabe3f4f7"},{"name":"terragrunt.hcl","path":"prod/us-east-1/prod/services/eks-cluster/terragrunt.hcl","sha":"6cd702f65352efa6710f63842666cd214b9e4109"}]},{"name":"eks-core-services","children":[{"name":"README.md","path":"prod/us-east-1/prod/services/eks-core-services/README.md","sha":"8d2479fb8630467588cadb041607244739ce235d"},{"name":"terragrunt.hcl","path":"prod/us-east-1/prod/services/eks-core-services/terragrunt.hcl","sha":"3ba3473cbb4c7cd83fb23f3fa18ca624bc9de5aa"}]},{"name":"k8s-applications-namespace","children":[{"name":"README.md","path":"prod/us-east-1/prod/services/k8s-applications-namespace/README.md","sha":"6f4aedb903ed85b60b35faf831a926ad6765ea9d"},{"name":"terragrunt.hcl","path":"prod/us-east-1/prod/services/k8s-applications-namespace/terragrunt.hcl","sha":"c9d638ac7e6367e974db2dbdf2ffc8f17473fb91"}]},{"name":"k8s-sample-app-backend-multi-account-acme","children":[{"name":"README.md","path":"prod/us-east-1/prod/services/k8s-sample-app-backend-multi-account-acme/README.md","sha":"a95e230a5fc692c4bf8ee19ee444b66405e08eab"},{"name":"terragrunt.hcl","path":"prod/us-east-1/prod/services/k8s-sample-app-backend-multi-account-acme/terragrunt.hcl","sha":"e8b8df48ed310a08be55d5d3d07af9dc20fe7c12"}]},{"name":"k8s-sample-app-frontend-multi-account-acme","children":[{"name":"README.md","path":"prod/us-east-1/prod/services/k8s-sample-app-frontend-multi-account-acme/README.md","sha":"9a2e1ef3ca5487142225c9c02b25132049d884d9"},{"name":"terragrunt.hcl","path":"prod/us-east-1/prod/services/k8s-sample-app-frontend-multi-account-acme/terragrunt.hcl","sha":"cab54c75aa28d2d0a1df465e3e4272fc7a154adb"}]},{"name":"sample-app-backend-multi-account-acme-asg","children":[{"name":"README.md","path":"prod/us-east-1/prod/services/sample-app-backend-multi-account-acme-asg/README.md","sha":"3df2251cd06cfde9b6d113329d050669284204fb"},{"name":"terragrunt.hcl","path":"prod/us-east-1/prod/services/sample-app-backend-multi-account-acme-asg/terragrunt.hcl","sha":"3bc70a7302b813667b0d9b9a19d888ce7a53e711"}]},{"name":"sample-app-backend-multi-account-acme","children":[{"name":"README.md","path":"prod/us-east-1/prod/services/sample-app-backend-multi-account-acme/README.md","sha":"5fb21249645ccc5db9f8cf7ac93b70bbda0cc7c5"},{"name":"terragrunt.hcl","path":"prod/us-east-1/prod/services/sample-app-backend-multi-account-acme/terragrunt.hcl","sha":"f6f9ecf019df9635b4a68f42816d37f1ef4722c3"}]},{"name":"sample-app-beanstalk","children":[{"name":"README.md","path":"prod/us-east-1/prod/services/sample-app-beanstalk/README.md","sha":"8e099f7d34b7bb62d26960c43a07220617c97e04"},{"name":"terragrunt.hcl","path":"prod/us-east-1/prod/services/sample-app-beanstalk/terragrunt.hcl","sha":"aa974300d961214d4a76f729b87e3d6d1dc90107"}]},{"name":"sample-app-frontend-multi-account-acme-asg","children":[{"name":"README.md","path":"prod/us-east-1/prod/services/sample-app-frontend-multi-account-acme-asg/README.md","sha":"39739d90168866c8293a4ebe1be5665997327f56"},{"name":"terragrunt.hcl","path":"prod/us-east-1/prod/services/sample-app-frontend-multi-account-acme-asg/terragrunt.hcl","sha":"c7cdbcf4cc8effe73a0130cf07a7f5da8cca0f23"}]},{"name":"sample-app-frontend-multi-account-acme","children":[{"name":"README.md","path":"prod/us-east-1/prod/services/sample-app-frontend-multi-account-acme/README.md","sha":"3345f973994d2480a8d60e12da68523275656d95"},{"name":"terragrunt.hcl","path":"prod/us-east-1/prod/services/sample-app-frontend-multi-account-acme/terragrunt.hcl","sha":"f0137a766733b3575863a74230dfc92ec0c94cd0"}]},{"name":"static-website","children":[{"name":"README.md","path":"prod/us-east-1/prod/services/static-website/README.md","sha":"bd02d2c0be6895e1154a84f183684889e0c9549a"},{"name":"terragrunt.hcl","path":"prod/us-east-1/prod/services/static-website/terragrunt.hcl","sha":"d5879453a53db71287dad837ed32e7d9b59d120e"}]}]},{"name":"vpc","children":[{"name":"README.md","path":"prod/us-east-1/prod/vpc/README.md","sha":"fc9ad2ee05250c2e2134884feb49c142bc948897"},{"name":"terragrunt.hcl","path":"prod/us-east-1/prod/vpc/terragrunt.hcl","sha":"521968dd6fb563a01f26d8b4662fbf4624cd21a0"}]}]},{"name":"region.yaml","path":"prod/us-east-1/region.yaml","sha":"d56afa3d82e6cea0d792e84748de56dafb0bad70"}]}]},{"name":"security","children":[{"name":"_global","children":[{"name":"README.md","path":"security/_global/README.md","sha":"d1b8a96c00211751f079fa13cac1b3417d29bf09"},{"name":"cloudtrail","children":[{"name":"README.md","path":"security/_global/cloudtrail/README.md","sha":"e6781286118d8ac86fe60cda1057595644d851da"},{"name":"terragrunt.hcl","path":"security/_global/cloudtrail/terragrunt.hcl","sha":"880d875fa813a2ec594b9a8ef15eb431bf540fa4"}]},{"name":"iam-cross-account","children":[{"name":"README.md","path":"security/_global/iam-cross-account/README.md","sha":"d33fb4cd9ef7b20250205797177184bf1828f966"},{"name":"terragrunt.hcl","path":"security/_global/iam-cross-account/terragrunt.hcl","sha":"fcb656ee6ce7d78ed479bbe98f7dec361cc8f8ba"}]},{"name":"iam-groups","children":[{"name":"README.md","path":"security/_global/iam-groups/README.md","sha":"4f322b55501dba80060a90fa9b7355e6034cac45"},{"name":"terragrunt.hcl","path":"security/_global/iam-groups/terragrunt.hcl","sha":"3d8532178660f931753089c2ed3dd3c3a0634965"}]},{"name":"iam-user-password-policy","children":[{"name":"README.md","path":"security/_global/iam-user-password-policy/README.md","sha":"b47d1c6602f3f4ea02fabd247f12c9ee3520be56"},{"name":"terragrunt.hcl","path":"security/_global/iam-user-password-policy/terragrunt.hcl","sha":"47b669ba52099812a6d52ed4fcdad48c5e32e91e"}]},{"name":"region.yaml","path":"security/_global/region.yaml","sha":"18b7823ed017b97431d58da7bcb9a4e31299272a"}]},{"name":"empty.yaml","path":"security/empty.yaml","sha":"5aa66daa40faeaef37eccb7b4b0fcc792233cd7b"},{"name":"terragrunt.hcl","path":"security/terragrunt.hcl","sha":"bcb0251ac68b2a7bb1acab94808083bc52b4dcf3"}]},{"name":"shared-services","children":[{"name":"_global","children":[{"name":"README.md","path":"shared-services/_global/README.md","sha":"d1b8a96c00211751f079fa13cac1b3417d29bf09"},{"name":"cloudtrail","children":[{"name":"README.md","path":"shared-services/_global/cloudtrail/README.md","sha":"e6781286118d8ac86fe60cda1057595644d851da"},{"name":"terragrunt.hcl","path":"shared-services/_global/cloudtrail/terragrunt.hcl","sha":"fb19b4438de2ba919d17f3e4a6ccb3c9f2517f26"}]},{"name":"iam-cross-account","children":[{"name":"README.md","path":"shared-services/_global/iam-cross-account/README.md","sha":"d33fb4cd9ef7b20250205797177184bf1828f966"},{"name":"terragrunt.hcl","path":"shared-services/_global/iam-cross-account/terragrunt.hcl","sha":"4b7fbf5498b4a1f2958a81a253faf5fc0e261b37"}]},{"name":"iam-user-password-policy","children":[{"name":"README.md","path":"shared-services/_global/iam-user-password-policy/README.md","sha":"b47d1c6602f3f4ea02fabd247f12c9ee3520be56"},{"name":"terragrunt.hcl","path":"shared-services/_global/iam-user-password-policy/terragrunt.hcl","sha":"47b669ba52099812a6d52ed4fcdad48c5e32e91e"}]},{"name":"region.yaml","path":"shared-services/_global/region.yaml","sha":"18b7823ed017b97431d58da7bcb9a4e31299272a"},{"name":"route53-public","children":[{"name":"README.md","path":"shared-services/_global/route53-public/README.md","sha":"03c91d97d2da5dea0f5dfa34a3004cc54118e60c"},{"name":"terragrunt.hcl","path":"shared-services/_global/route53-public/terragrunt.hcl","sha":"68ed9958a62546160f9007660857c5baa95ce12b"}]}]},{"name":"empty.yaml","path":"shared-services/empty.yaml","sha":"5aa66daa40faeaef37eccb7b4b0fcc792233cd7b"},{"name":"terragrunt.hcl","path":"shared-services/terragrunt.hcl","sha":"97348cf7336b2508647742881b377b1ba714e9c0"},{"name":"us-east-1","children":[{"name":"_global","children":[{"name":"README.md","path":"shared-services/us-east-1/_global/README.md","sha":"37b828b038945a50e2e571ef1e755c4f9170e7cf"},{"name":"ecr-repos","children":[{"name":"README.md","path":"shared-services/us-east-1/_global/ecr-repos/README.md","sha":"def6523ffcf755613e462937e89f88063379d54b"},{"name":"terragrunt.hcl","path":"shared-services/us-east-1/_global/ecr-repos/terragrunt.hcl","sha":"0aebd1fe76c536af522f7af783dae529637f5a2b"}]},{"name":"kms-master-key","children":[{"name":"README.md","path":"shared-services/us-east-1/_global/kms-master-key/README.md","sha":"e5bbe0789e554212ffe2c605b9a301ebce202947"},{"name":"terragrunt.hcl","path":"shared-services/us-east-1/_global/kms-master-key/terragrunt.hcl","sha":"e3d3456c830e33007018dfa0444e1bb20950e327"}]},{"name":"sns-topics","children":[{"name":"README.md","path":"shared-services/us-east-1/_global/sns-topics/README.md","sha":"ae3e2f9522b38fa85eff3c962e4c3d40c6724e17"},{"name":"terragrunt.hcl","path":"shared-services/us-east-1/_global/sns-topics/terragrunt.hcl","sha":"225cf4b3fe49af57c85a1e25b7942c72cf9e6853"}]}]},{"name":"mgmt","children":[{"name":"README.md","path":"shared-services/us-east-1/mgmt/README.md","sha":"8a131a11632b97fec18a5e344d5c721fce24b652"},{"name":"env.yaml","path":"shared-services/us-east-1/mgmt/env.yaml","sha":"b514ab3187ebfb5bf467c632f27a21f5a9611bfc"},{"name":"jenkins","children":[{"name":"README.md","path":"shared-services/us-east-1/mgmt/jenkins/README.md","sha":"9401dae6add177f3f045f0f2e368076a7fc9a42e"},{"name":"terragrunt.hcl","path":"shared-services/us-east-1/mgmt/jenkins/terragrunt.hcl","sha":"2697d39997ae18103e586008388a3e79dfcabbed"}]},{"name":"openvpn-server","children":[{"name":"README.md","path":"shared-services/us-east-1/mgmt/openvpn-server/README.md","sha":"d0faac5567ed30af350e6b9181e0a9282ef88ac9"},{"name":"terragrunt.hcl","path":"shared-services/us-east-1/mgmt/openvpn-server/terragrunt.hcl","sha":"94491e691a4819cf78eefe98a69c818573c61b48"}]},{"name":"vpc","children":[{"name":"README.md","path":"shared-services/us-east-1/mgmt/vpc/README.md","sha":"73452d7db6e78079df0ee0854e9ae80645fce937"},{"name":"terragrunt.hcl","path":"shared-services/us-east-1/mgmt/vpc/terragrunt.hcl","sha":"29ff68537a532e119786f868bb2a709839792e90"}]}]},{"name":"region.yaml","path":"shared-services/us-east-1/region.yaml","sha":"d56afa3d82e6cea0d792e84748de56dafb0bad70"}]}]},{"name":"stage","children":[{"name":"_global","children":[{"name":"README.md","path":"stage/_global/README.md","sha":"d1b8a96c00211751f079fa13cac1b3417d29bf09"},{"name":"cloudtrail","children":[{"name":"README.md","path":"stage/_global/cloudtrail/README.md","sha":"e6781286118d8ac86fe60cda1057595644d851da"},{"name":"terragrunt.hcl","path":"stage/_global/cloudtrail/terragrunt.hcl","sha":"fb19b4438de2ba919d17f3e4a6ccb3c9f2517f26"}]},{"name":"iam-cross-account","children":[{"name":"README.md","path":"stage/_global/iam-cross-account/README.md","sha":"d33fb4cd9ef7b20250205797177184bf1828f966"},{"name":"terragrunt.hcl","path":"stage/_global/iam-cross-account/terragrunt.hcl","sha":"ef9dd9c28172500be3ffd79646dff2e0c4981f70"}]},{"name":"iam-user-password-policy","children":[{"name":"README.md","path":"stage/_global/iam-user-password-policy/README.md","sha":"b47d1c6602f3f4ea02fabd247f12c9ee3520be56"},{"name":"terragrunt.hcl","path":"stage/_global/iam-user-password-policy/terragrunt.hcl","sha":"47b669ba52099812a6d52ed4fcdad48c5e32e91e"}]},{"name":"region.yaml","path":"stage/_global/region.yaml","sha":"18b7823ed017b97431d58da7bcb9a4e31299272a"},{"name":"route53-public","children":[{"name":"README.md","path":"stage/_global/route53-public/README.md","sha":"03c91d97d2da5dea0f5dfa34a3004cc54118e60c"},{"name":"terragrunt.hcl","path":"stage/_global/route53-public/terragrunt.hcl","sha":"68ed9958a62546160f9007660857c5baa95ce12b"}]}]},{"name":"empty.yaml","path":"stage/empty.yaml","sha":"5aa66daa40faeaef37eccb7b4b0fcc792233cd7b"},{"name":"terragrunt.hcl","path":"stage/terragrunt.hcl","sha":"25ec25b2a01b51434679521aecb7a6f4a0bbb2d8"},{"name":"us-east-1","children":[{"name":"_global","children":[{"name":"README.md","path":"stage/us-east-1/_global/README.md","sha":"37b828b038945a50e2e571ef1e755c4f9170e7cf"},{"name":"kms-master-key","children":[{"name":"README.md","path":"stage/us-east-1/_global/kms-master-key/README.md","sha":"e6a201af63351f171403b62a0b41866e2cb13476"},{"name":"terragrunt.hcl","path":"stage/us-east-1/_global/kms-master-key/terragrunt.hcl","sha":"c0c2f65c3cf60fc59e6646347d4458001a116e6b"}]},{"name":"sns-topics","children":[{"name":"README.md","path":"stage/us-east-1/_global/sns-topics/README.md","sha":"ae3e2f9522b38fa85eff3c962e4c3d40c6724e17"},{"name":"terragrunt.hcl","path":"stage/us-east-1/_global/sns-topics/terragrunt.hcl","sha":"225cf4b3fe49af57c85a1e25b7942c72cf9e6853"}]}]},{"name":"mgmt","children":[{"name":"README.md","path":"stage/us-east-1/mgmt/README.md","sha":"8a131a11632b97fec18a5e344d5c721fce24b652"},{"name":"env.yaml","path":"stage/us-east-1/mgmt/env.yaml","sha":"b514ab3187ebfb5bf467c632f27a21f5a9611bfc"},{"name":"openvpn-server","children":[{"name":"README.md","path":"stage/us-east-1/mgmt/openvpn-server/README.md","sha":"2b17dbeb74071ffd9f1a359989d6041acadf69b4"},{"name":"terragrunt.hcl","path":"stage/us-east-1/mgmt/openvpn-server/terragrunt.hcl","sha":"2264e52073f6eff6db62cf871eb558a06216515c"}]},{"name":"vpc","children":[{"name":"README.md","path":"stage/us-east-1/mgmt/vpc/README.md","sha":"73452d7db6e78079df0ee0854e9ae80645fce937"},{"name":"terragrunt.hcl","path":"stage/us-east-1/mgmt/vpc/terragrunt.hcl","sha":"b2016650621679f7b9f99b93806cc0b8efb149ac"}]}]},{"name":"region.yaml","path":"stage/us-east-1/region.yaml","sha":"d56afa3d82e6cea0d792e84748de56dafb0bad70"},{"name":"stage","children":[{"name":"README.md","path":"stage/us-east-1/stage/README.md","sha":"b24ba21bf01baf19ff84a2de457697a757d905c5"},{"name":"cloudwatch-dashboard","children":[{"name":"README.md","path":"stage/us-east-1/stage/cloudwatch-dashboard/README.md","sha":"aa1cfea49f1679e79991f9cf80c12a5b41943a1d"},{"name":"terragrunt.hcl","path":"stage/us-east-1/stage/cloudwatch-dashboard/terragrunt.hcl","sha":"01ed95b4b404eda346293dbe5eb78b9a74f2f5bb"}]},{"name":"data-stores","children":[{"name":"elk-single-cluster","children":[{"name":"README.md","path":"stage/us-east-1/stage/data-stores/elk-single-cluster/README.md","sha":"9a1cb70a6f6b1b3ac81b2c7c5b17d902328db1e0"},{"name":"terragrunt.hcl","path":"stage/us-east-1/stage/data-stores/elk-single-cluster/terragrunt.hcl","sha":"7818782091e335360279369b391a3401703ddedd"}]},{"name":"kafka","children":[{"name":"README.md","path":"stage/us-east-1/stage/data-stores/kafka/README.md","sha":"8bfe6579bd97e0148c3baa24e1215abce8cf312b"},{"name":"terragrunt.hcl","path":"stage/us-east-1/stage/data-stores/kafka/terragrunt.hcl","sha":"26d778dddca07ead27d37e481a897659d7cec7d2"}]},{"name":"mysql","children":[{"name":"README.md","path":"stage/us-east-1/stage/data-stores/mysql/README.md","sha":"df149a836e3a0f3e082cb98f3679e48e0cf6fe4b"},{"name":"terragrunt.hcl","path":"stage/us-east-1/stage/data-stores/mysql/terragrunt.hcl","sha":"35991621a16fb4cc8443fdf2695c23d3e658c5ac"}]},{"name":"redis","children":[{"name":"README.md","path":"stage/us-east-1/stage/data-stores/redis/README.md","sha":"a305dff8ab1fd409e94cb7b9bf8d3a78ef84c689"},{"name":"terragrunt.hcl","path":"stage/us-east-1/stage/data-stores/redis/terragrunt.hcl","sha":"79ef1e07fde2d0dcb9673d653089da8fb3fa449a"}]},{"name":"zookeeper","children":[{"name":"README.md","path":"stage/us-east-1/stage/data-stores/zookeeper/README.md","sha":"451ce7cb440aa724bf4dc8a35726e2bda7e071a2"},{"name":"terragrunt.hcl","path":"stage/us-east-1/stage/data-stores/zookeeper/terragrunt.hcl","sha":"045e1d8802b8b1dc93070a80d98da5b917dec655"}]}]},{"name":"env.yaml","path":"stage/us-east-1/stage/env.yaml","sha":"5767506e27e978f52524dadbbd8fb9f8ad115599"},{"name":"lambda","children":[{"name":"long-running-scheduled","children":[{"name":"README.md","path":"stage/us-east-1/stage/lambda/long-running-scheduled/README.md","sha":"af7b8b9950d620577e1db104d0140a478e5f46fd"},{"name":"terragrunt.hcl","path":"stage/us-east-1/stage/lambda/long-running-scheduled/terragrunt.hcl","sha":"72518b7089bd107c05c281372f3cccd6d7a6a628"}]},{"name":"s3-image-processing","children":[{"name":"README.md","path":"stage/us-east-1/stage/lambda/s3-image-processing/README.md","sha":"236ef4197db71e6e121e3ca7182e556fa9ecaa60"},{"name":"terragrunt.hcl","path":"stage/us-east-1/stage/lambda/s3-image-processing/terragrunt.hcl","sha":"02a23cc6f220d8301d40f7616d1e17f9e17448a5"}]}]},{"name":"networking","children":[{"name":"alb-internal","children":[{"name":"README.md","path":"stage/us-east-1/stage/networking/alb-internal/README.md","sha":"7a0ead86441c133aa09441613d4c1d8d7e630166"},{"name":"terragrunt.hcl","path":"stage/us-east-1/stage/networking/alb-internal/terragrunt.hcl","sha":"9537dc7cb6dc7c9eb929a0b97a6f89025e042e57"}]},{"name":"alb-public","children":[{"name":"README.md","path":"stage/us-east-1/stage/networking/alb-public/README.md","sha":"7a0ead86441c133aa09441613d4c1d8d7e630166"},{"name":"terragrunt.hcl","path":"stage/us-east-1/stage/networking/alb-public/terragrunt.hcl","sha":"8ea93d9b8dafad1fc2044a677dd9d0db8d768a55"}]},{"name":"route53-private","children":[{"name":"README.md","path":"stage/us-east-1/stage/networking/route53-private/README.md","sha":"2f6db22493297bf5ae1c98149b9a7c9c896c3c7f"},{"name":"terragrunt.hcl","path":"stage/us-east-1/stage/networking/route53-private/terragrunt.hcl","sha":"f7e7c4b437c11b0340c682314deb9b08aca3a854"}]}]},{"name":"services","children":[{"name":"ecs-cluster","children":[{"name":"README.md","path":"stage/us-east-1/stage/services/ecs-cluster/README.md","sha":"69133a6a78eabd9f9cedbbb52144f0b3f8a72421"},{"name":"terragrunt.hcl","path":"stage/us-east-1/stage/services/ecs-cluster/terragrunt.hcl","sha":"a42cc57f67f8a9ee2bf5bfce1fb58ea96f5e48f5"}]},{"name":"eks-cluster","children":[{"name":"README.md","path":"stage/us-east-1/stage/services/eks-cluster/README.md","sha":"67f4e452bf104a0b6329d3147e7158058e5df135"},{"name":"terragrunt.hcl","path":"stage/us-east-1/stage/services/eks-cluster/terragrunt.hcl","sha":"ec2a56580f4fbe9d5ea53b4a7bc0768a7ae90029"}]},{"name":"eks-core-services","children":[{"name":"README.md","path":"stage/us-east-1/stage/services/eks-core-services/README.md","sha":"9a346101188e4590ca4f5e963ae9f0418a5b736b"},{"name":"terragrunt.hcl","path":"stage/us-east-1/stage/services/eks-core-services/terragrunt.hcl","sha":"4c1aecc3ec52837b98978ec6fc1cd8d5564763ae"}]},{"name":"k8s-applications-namespace","children":[{"name":"README.md","path":"stage/us-east-1/stage/services/k8s-applications-namespace/README.md","sha":"99acc7283fb7bd8ebddd652eb40f00ffdae7c212"},{"name":"terragrunt.hcl","path":"stage/us-east-1/stage/services/k8s-applications-namespace/terragrunt.hcl","sha":"3665bac8be17e73ab034e2f32017c69ef209b2af"}]},{"name":"k8s-sample-app-backend-multi-account-acme","children":[{"name":"README.md","path":"stage/us-east-1/stage/services/k8s-sample-app-backend-multi-account-acme/README.md","sha":"8a53ab896e3502a85f8d96f694c4ba807ee33282"},{"name":"terragrunt.hcl","path":"stage/us-east-1/stage/services/k8s-sample-app-backend-multi-account-acme/terragrunt.hcl","sha":"9ea86835ea625bbc341b4d8cbfbcd9b954c4feb5"}]},{"name":"k8s-sample-app-frontend-multi-account-acme","children":[{"name":"README.md","path":"stage/us-east-1/stage/services/k8s-sample-app-frontend-multi-account-acme/README.md","sha":"bbaed0680673b0973880a98f90a7d321125975d9"},{"name":"terragrunt.hcl","path":"stage/us-east-1/stage/services/k8s-sample-app-frontend-multi-account-acme/terragrunt.hcl","sha":"b53766ca7b1cf18f27c115d086e3aebf697ee5f3"}]},{"name":"sample-app-backend-multi-account-acme-asg","children":[{"name":"README.md","path":"stage/us-east-1/stage/services/sample-app-backend-multi-account-acme-asg/README.md","sha":"d435c50c5f02f91388927d6fde51f8220dc3b0ae"},{"name":"terragrunt.hcl","path":"stage/us-east-1/stage/services/sample-app-backend-multi-account-acme-asg/terragrunt.hcl","sha":"2b1ddfe35699ecff6ee4e8c164ad4c9e00d224da"}]},{"name":"sample-app-backend-multi-account-acme","children":[{"name":"README.md","path":"stage/us-east-1/stage/services/sample-app-backend-multi-account-acme/README.md","sha":"5e3bb4688968e356ff649f88b28edfc72c0d03c0"},{"name":"terragrunt.hcl","path":"stage/us-east-1/stage/services/sample-app-backend-multi-account-acme/terragrunt.hcl","sha":"1dd22075941f49b593bc9bfb03f616ac8004a06d"}]},{"name":"sample-app-beanstalk","children":[{"name":"README.md","path":"stage/us-east-1/stage/services/sample-app-beanstalk/README.md","sha":"3b5e260db76305505ad5e2c5d581040abbda1f9f"},{"name":"terragrunt.hcl","path":"stage/us-east-1/stage/services/sample-app-beanstalk/terragrunt.hcl","sha":"4360debb24de5f877a88782858260326f9d72dbd"}]},{"name":"sample-app-frontend-multi-account-acme-asg","children":[{"name":"README.md","path":"stage/us-east-1/stage/services/sample-app-frontend-multi-account-acme-asg/README.md","sha":"1941c9a22b6d3b7316ad2260b2b774f12e877961"},{"name":"terragrunt.hcl","path":"stage/us-east-1/stage/services/sample-app-frontend-multi-account-acme-asg/terragrunt.hcl","sha":"e0efa40fe276041d8bea4a543144a5591cfcead5"}]},{"name":"sample-app-frontend-multi-account-acme","children":[{"name":"README.md","path":"stage/us-east-1/stage/services/sample-app-frontend-multi-account-acme/README.md","sha":"9516c852664f8d68f3f7dd47cc974061cb733077"},{"name":"terragrunt.hcl","path":"stage/us-east-1/stage/services/sample-app-frontend-multi-account-acme/terragrunt.hcl","sha":"2507d6e2e44be9e18a120c45b083b901f98a4cf9"}]},{"name":"static-website","children":[{"name":"README.md","path":"stage/us-east-1/stage/services/static-website/README.md","sha":"bd02d2c0be6895e1154a84f183684889e0c9549a"},{"name":"terragrunt.hcl","path":"stage/us-east-1/stage/services/static-website/terragrunt.hcl","sha":"5dcb8cc0d74456bfa9756c29cbc70118b7c894ed"}]}]},{"name":"vpc","children":[{"name":"README.md","path":"stage/us-east-1/stage/vpc/README.md","sha":"b1272af31abdcc984831e69017e53de0c28ef71b"},{"name":"terragrunt.hcl","path":"stage/us-east-1/stage/vpc/terragrunt.hcl","sha":"96c7ebd950aea8d3e7d6767609e9419ef407db4f"}]}]}]}]}]},"detailsContent":"<h1 class=\"preview__body--title\" id=\"running-an-app-in-the-dev-environment\">Running An App in the Dev Environment</h1><div class=\"preview__body--border\"></div><p>Now that you have an idea of <a href=\"/repos/v0.0.1-20210527/infrastructure-live-multi-account-acme/_docs/01-architecture-overview.md\" class=\"preview__body--description--blue\">what the architecture looks like</a>, <a href=\"/repos/v0.0.1-20210527/infrastructure-live-multi-account-acme/_docs/02-whats-deployed.md\" class=\"preview__body--description--blue\">what's\ndeployed</a>, <a href=\"/repos/v0.0.1-20210527/infrastructure-live-multi-account-acme/_docs/03-security-compliance-compatibility.md\" class=\"preview__body--description--blue\">security compliance</a>, and <a href=\"/repos/v0.0.1-20210527/infrastructure-live-multi-account-acme/_docs/04-how-code-is-organized.md\" class=\"preview__body--description--blue\">how the code is\norganized</a>, it's time to start running some of that code on your own computer!</p>\n<p>Here's what we'll cover:</p>\n<ul>\n<li><a href=\"#prerequisites\" class=\"preview__body--description--blue\">Prerequisites</a></li>\n<li><a href=\"#checkout-the-code\" class=\"preview__body--description--blue\">Checkout the code</a></li>\n<li><a href=\"#run-the-app\" class=\"preview__body--description--blue\">Run the app</a></li>\n<li><a href=\"#make-a-service-call\" class=\"preview__body--description--blue\">Make a service call</a></li>\n<li><a href=\"#change-the-code\" class=\"preview__body--description--blue\">Change the code</a></li>\n<li><a href=\"#update-the-application-configuration\" class=\"preview__body--description--blue\">Update the application configuration</a></li>\n<li><a href=\"#encrypt-a-secret\" class=\"preview__body--description--blue\">Encrypt a secret</a></li>\n<li><a href=\"#apply-schema-migrations\" class=\"preview__body--description--blue\">Apply schema migrations</a></li>\n<li><a href=\"#commit-your-changes\" class=\"preview__body--description--blue\">Commit your changes</a></li>\n</ul>\n<h2 class=\"preview__body--subtitle\" id=\"prerequisites\">Prerequisites</h2>\n<p>You will need to install the following software on your computer:</p>\n<ul>\n<li><a href=\"https://git-scm.com/\" class=\"preview__body--description--blue\" target=\"_blank\">Git</a>: Used for version control.</li>\n<li><a href=\"http://docker.com/\" class=\"preview__body--description--blue\" target=\"_blank\">Docker</a>: Used to package apps so they run the same way in all environments, including your dev\nenvironment.</li>\n<li><a href=\"https://www.terraform.io/\" class=\"preview__body--description--blue\" target=\"_blank\">Terraform</a>: Used to provision and manage infrastructure as code.</li>\n<li><a href=\"/repos/terragrunt\" class=\"preview__body--description--blue\">Terragrunt</a>: A thin wrapper for Terraform that provides extra tools for\nworking with multiple Terraform modules.</li>\n<li><a href=\"https://www.packer.io/\" class=\"preview__body--description--blue\" target=\"_blank\">Packer</a>: Used to package apps as Amazon Machine Images.</li>\n<li><a href=\"/repos/gruntkms\" class=\"preview__body--description--blue\">GruntKMS</a>: Used to encrypt and decrypt secrets.</li>\n</ul>\n<h2 class=\"preview__body--subtitle\" id=\"checkout-the-code\">Checkout the code</h2>\n<p>You will need to checkout the code for your app(s) using Git. For this tutorial, we are going to checkout\n<a href=\"/repos/sample-app-frontend-multi-account-acme\" class=\"preview__body--description--blue\">sample-app-frontend-multi-account-acme</a>, which is a sample app that's handy for\ndemonstrating all the key concepts in this tutorial.</p>\n<p>To check this app out onto your computer, run:</p>\n<pre>git <span class=\"hljs-keyword\">clone</span> <span class=\"hljs-title\">git</span>@github.com:gruntwork-io/sample-app-frontend-multi-account-acme.git\n</pre>\n<p>Note that sample-app-frontend-multi-account-acme depends on another sample app called <a href=\"/repos/sample-app-backend-multi-account-acme\" class=\"preview__body--description--blue\">sample-app-backend-multi-account-acme</a>,\nso you may want to checkout that app too:</p>\n<pre>git <span class=\"hljs-keyword\">clone</span> <span class=\"hljs-title\">git</span>@github.com:gruntwork-io/sample-app-backend-multi-account-acme.git\n</pre>\n<h2 class=\"preview__body--subtitle\" id=\"run-the-app\">Run the app</h2>\n<p>sample-app-frontend-multi-account-acme is packaged as a <a href=\"http://docker.com/\" class=\"preview__body--description--blue\" target=\"_blank\">Docker</a> container so that it runs the same way in all\nenvironments, including on your computer. Moreover, we've used <a href=\"https://docs.docker.com/compose/\" class=\"preview__body--description--blue\" target=\"_blank\">Docker Compose</a> to\nconfigure all the Docker containers you need to run your entire tech stack (i.e., all apps, databases, etc) in the\n<code>docker-compose.yml</code> file, so you can fire everything up with a single command:</p>\n<pre><span class=\"hljs-keyword\">cd</span> <span class=\"hljs-keyword\">sample</span>-<span class=\"hljs-keyword\">app</span>-frontend-multi-account-acme\ndocker-compose up\n</pre>\n<p>Your entire stack will boot up in a few seconds and you should be able to test it by going to\nhttp://localhost:3000/sample-app-frontend-multi-account-acme.</p>\n<p>The app that's running is a simple <a href=\"https://nodejs.org/en/\" class=\"preview__body--description--blue\" target=\"_blank\">Node.js</a> app, but the ideas demonstrated work more or less\nthe same way in any language. Take a look at <code>app/index.js</code> to see the code. You should also see other endpoints in\nthat file that you can try.</p>\n<h2 class=\"preview__body--subtitle\" id=\"make-a-service-call\">Make a service call</h2>\n<p>One of the other endpoints you can try is http://localhost:3000/sample-app-frontend-multi-account-acme/service.\nThis demonstrates how sample-app-frontend-multi-account-acme can make a service call to sample-app-backend-multi-account-acme. How does this work?</p>\n<p>If you dig through the code in <code>app/server.js</code>, you'll see that sample-app-frontend-multi-account-acme is getting the IP address of\nsample-app-backend-multi-account-acme from an environment variable called <code>BACKEND_URL</code> and falling back to the value <code>backend</code> if that\nenvironment variable is not set. Here's how this works:</p>\n<ul>\n<li>\n<p>In dev, <a href=\"https://docs.docker.com/compose/networking/\" class=\"preview__body--description--blue\" target=\"_blank\">Docker Compose Networking</a> sets up a single network where each\nservice <code>xxx</code> is accessible at the hostname <code>xxx</code>. Since our service is called <code>backend</code>, it is accessible at\n<code>http(s)://backend</code>.</p>\n</li>\n<li>\n<p>In other environments (e.g. stage, prod) we configure Terraform to set the <code>BACKEND_URL</code> environment variable for\nyour Docker containers, except we point the variable to an internal Application Load Balancer (see\n<a href=\"/repos/v0.0.1-20210527/infrastructure-live-multi-account-acme/_docs/01-architecture-overview.md\" class=\"preview__body--description--blue\">Architecture overview</a>), which is configured to route traffic to sample-app-backend-multi-account-acme.</p>\n</li>\n</ul>\n<p>We use a similar approach to allow the app to talk to all of its other dependencies too (e.g., the database, cache,\netc), with slightly different service names and environment variables for each one.</p>\n<h2 class=\"preview__body--subtitle\" id=\"change-the-code\">Change the code</h2>\n<p>Make a change to the app code, such as modifying <code>app/index.js</code> or <code>app/index.html</code>.\nRefresh the page in your browser and you should see your changes immediately! Here's how that works:</p>\n<ul>\n<li>\n<p>In <code>docker-compose.yml</code>, we configure Docker to <a href=\"https://docs.docker.com/engine/tutorials/dockervolumes/#mount-a-host-directory-as-a-data-volume\" class=\"preview__body--description--blue\" target=\"_blank\">mount</a>\nthe code from your host OS into the Docker container (look for the <code>volumes</code> settings in <code>docker-compose.yml</code>). That\nway, every time you make a change on your host OS, it's reflected immediately in the Docker container.</p>\n</li>\n<li>\n<p>The Docker container uses <a href=\"https://github.com/remy/nodemon\" class=\"preview__body--description--blue\" target=\"_blank\">nodemon</a> in dev mode, so the Node app restarts\nautomatically with every change.</p>\n</li>\n</ul>\n<p>This setup allows you to iterate rapidly!</p>\n<h2 class=\"preview__body--subtitle\" id=\"update-the-application-configuration\">Update the application configuration</h2>\n<p>sample-app-frontend-multi-account-acme stores most of its configuration settings in files. The advantage of this is that the files are\nchecked into version control (so you have a history of config changes) and are versioned and deployed with the app code\nitself (so you don't get a mismatch between app and config).</p>\n<ul>\n<li>\n<p>The files live in the <code>config</code> directory.</p>\n</li>\n<li>\n<p>The names use the format <code>example-config-<environment>.json</code>, where <code>environment</code> is an environment name, such as\ndevelopment, stage, or prod. Note that the same basic config approach shown here works with any file format and\nnaming convention; we only use JSON because it's easy to use with the sample Node.js app.</p>\n</li>\n<li>\n<p>In <code>app/server.js</code>, the app loads the proper config file for the current environment based on the environment\nvariable <code>VPC_NAME</code>.</p>\n</li>\n<li>\n<p>In dev, the <code>VPC_NAME</code> environment variable is configured in <code>docker-compose.yml</code>.</p>\n</li>\n<li>\n<p>In other environments (e.g., stage, prod) the <code>VPC_NAME</code> environment variable is set by Terraform.</p>\n</li>\n</ul>\n<h2 class=\"preview__body--subtitle\" id=\"encrypt-a-secret\">Encrypt a secret</h2>\n<p>Occasionally, you may need to encrypt some secret data. For example, you may want to store the password to your\ndatabase in your app's configuration. Storing secrets in plain text anywhere, including version control, is a major\nsecurity risk and should be avoided (see <a href=\"https://docs.google.com/document/d/e/2PACX-1vTikva7hXPd2h1SSglJWhlW8W6qhMlZUxl0qQ9rUJ0OX22CQNeM-91w4lStRk9u2zQIn6lPejUbe-dl/pub\" class=\"preview__body--description--blue\" target=\"_blank\">Gruntwork Security Best Practices</a>\nfor more info). A better way to handle this is to encrypt the secrets before putting them in version control and to\nhave your app decrypt those secrets before it boots.</p>\n<p>Managing encryption keys securely is very tricky, so we strongly recommend using <a href=\"https://aws.amazon.com/kms/\" class=\"preview__body--description--blue\" target=\"_blank\">Amazon's Key Management Service\n(KMS)</a>:</p>\n<ol>\n<li>\n<p>Create "master key" in KMS using the <a href=\"/repos/module-security/modules/kms-master-key\" class=\"preview__body--description--blue\">kms-master-key\nmodule</a>. Note that we've already\ncreated one master key in each environment, so for most use cases, you should use those and not create any new ones.\nYou can see all available master keys in the <a href=\"https://console.aws.amazon.com/iam/home?region=us-east-1#/encryptionKeys/us-east-1\" class=\"preview__body--description--blue\" target=\"_blank\">Encryption Keys page in\nIAM</a>.</p>\n</li>\n<li>\n<p>Use the master key, along with <a href=\"/repos/gruntkms\" class=\"preview__body--description--blue\">gruntkms</a>, to encrypt and decrypt secrets\nwith a single CLI command.</p>\n</li>\n</ol>\n<p>For example, you could run <code>gruntkms</code> on your computer to encrypt a database password:</p>\n<pre><span class=\"hljs-comment\"># A developer encrypts a plaintext secret</span>\n$ echo <span class=\"hljs-string\">\"super secret database password\"</span> | gruntkms encrypt --key-id <span class=\"hljs-string\">\"alias/cmk-stage\"</span> --aws-region <span class=\"hljs-string\">\"us-east-1\"</span>\nkmscrypt::AQICAHhQYFj4xrlpRdnui/MrOlrIt+gSSrFxZay4ZMDMofceSwEXSzGkmBBWbG6==\n</pre>\n<p>You can now safely check the <code>kmscrypt::...</code> ciphertext into version control.</p>\n<p>You can then give your apps access to the same KMS key via IAM permissions and configure your apps to decrypt the\nciphertext using <code>gruntkms</code> just before booting:</p>\n<pre><span class=\"hljs-comment\"># An app decrypts the ciphertext before booting</span>\necho <span class=\"hljs-string\">\"kmscrypt::AQICAHhQYFj4xrlpRdnui/MrOlrIt+gSSrFxZay4ZMDMofceSwEXSzGkmBBWbG6==\"</span> | gruntkms decrypt --aws-region <span class=\"hljs-string\">\"us-east-1\"</span>\n<span class=\"hljs-string\">\"super secret database password\"</span> \n</pre>\n<p>Make sure to read through the <a href=\"/repos/gruntkms\" class=\"preview__body--description--blue\">gruntkms docs</a> to learn how how the <code>kmscrypt::</code>\nprefix works and how to decrypt all secrets in a config file in a single command (see <code>bin/run-app.sh</code> in the sample\napps for an example).</p>\n<h2 class=\"preview__body--subtitle\" id=\"apply-schema-migrations\">Apply schema migrations</h2>\n<p>sample-app-backend-multi-account-acme contains example code of how to talk to a relational database. It also contains an example of how\nto apply schema migrations to your database before the app boots. The idea is to version and package the schema\nmigration code with the app code so that whenever you deploy a new version of the app, it always ensures the schema it\ndepends on is in place before booting.</p>\n<p>Under the hood, the example code manages the schema migrations using simple <code>.sql</code> files (see the <code>sql</code> folder) and\nuses <a href=\"https://flywaydb.org/\" class=\"preview__body--description--blue\" target=\"_blank\">Flyway</a> to apply those migrations (see <code>bin/run-app.sh</code>). The same basic approach should\nwork with any other schema migration tool (e.g., <a href=\"http://www.liquibase.org/\" class=\"preview__body--description--blue\" target=\"_blank\">Luiqibase</a>,\n<a href=\"http://edgeguides.rubyonrails.org/active_record_migrations.html\" class=\"preview__body--description--blue\" target=\"_blank\">ActiveRecord</a>) as long as that tool obtains a lock\nbefore applying schema changes (to ensure you only apply the schema changes once even if multiple copies of the app\nboot up at the same time).</p>\n<h2 class=\"preview__body--subtitle\" id=\"commit-your-changes\">Commit your changes</h2>\n<p>If you've made any changes to the code during this tutorial, it's time to commit them back to Git!</p>\n<pre><span class=\"hljs-symbol\">git</span> <span class=\"hljs-keyword\">add </span><files_you_modified>\n<span class=\"hljs-symbol\">git</span> commit -m <span class=\"hljs-string\">\"<commit message>\"</span>\n<span class=\"hljs-symbol\">git</span> <span class=\"hljs-keyword\">push </span>origin master\n</pre>\n<h2 class=\"preview__body--subtitle\" id=\"next-steps\">Next steps</h2>\n<p>Now that you've committed some code, it's time to learn how the automated <a href=\"/repos/v0.0.1-20210527/infrastructure-live-multi-account-acme/_docs/06-ci-cd.md\" class=\"preview__body--description--blue\">Build, test, and deployment\n(CI/CD)</a> process works.</p>\n","repoName":"infrastructure-live-multi-account-acme","repoRef":"v0.0.1-06082020","serviceDescriptor":{"serviceName":"Multi-account Reference Architecture","serviceRepoName":"infrastructure-live-multi-account-acme","serviceRepoOrg":"gruntwork-io","cloudProviders":["aws"],"description":"End-to-end tech stack designed to deploy into multiple AWS accounts. Includes VPCs, EKS, ALBs, CI / CD, monitoring, alerting, VPN, DNS, and more.","imageUrl":"grunt.png","licenseType":"subscriber","technologies":["Terraform","Go","Bash","Python"],"compliance":[],"tags":[""]},"serviceCategoryName":"Reference Architecture","fileName":"05-dev-environment.md","filePath":"/_docs/05-dev-environment.md","title":"Repo Browser: Multi-account Reference Architecture","description":"Browse the repos in the Gruntwork Infrastructure as Code Library."}