From 58ac9a8f4bbb3c39236afb9c22729ae74fc8eba5 Mon Sep 17 00:00:00 2001 From: mbothe Date: Tue, 17 Sep 2024 09:08:24 -0400 Subject: [PATCH 1/6] added terraform --- my-infra/deploy/.terraform.lock.hcl | 25 ++++++++++++++ my-infra/deploy/main.tf | 35 ++++++++++++++++++++ my-infra/deploy/variables.tf | 51 +++++++++++++++++++++++++++++ my-infra/docker-compose.yml | 17 ++++++++++ my-infra/setup/.terraform.lock.hcl | 25 ++++++++++++++ my-infra/setup/ecr.tf | 0 my-infra/setup/iam.tf | 0 my-infra/setup/main.tf | 29 ++++++++++++++++ my-infra/setup/outputs.tf | 0 my-infra/setup/variables.tf | 19 +++++++++++ 10 files changed, 201 insertions(+) create mode 100644 my-infra/deploy/.terraform.lock.hcl create mode 100644 my-infra/deploy/main.tf create mode 100644 my-infra/deploy/variables.tf create mode 100644 my-infra/docker-compose.yml create mode 100644 my-infra/setup/.terraform.lock.hcl create mode 100644 my-infra/setup/ecr.tf create mode 100644 my-infra/setup/iam.tf create mode 100644 my-infra/setup/main.tf create mode 100644 my-infra/setup/outputs.tf create mode 100644 my-infra/setup/variables.tf diff --git a/my-infra/deploy/.terraform.lock.hcl b/my-infra/deploy/.terraform.lock.hcl new file mode 100644 index 00000000..2ffb9a9b --- /dev/null +++ b/my-infra/deploy/.terraform.lock.hcl @@ -0,0 +1,25 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/aws" { + version = "5.23.0" + constraints = "5.23.0" + hashes = [ + "h1:AwjyBYctD8UKCXcm+kLJfRjYdUYzG0hetStKrw8UL9M=", + "zh:100966f25b1878b7c4ee250dcbaf09e5a2dad4bcebba2482d77c4cc4e48957da", + "zh:57ed5e66949568d25788ebcd170abf5961f81bb141f69d3acca9a7454994d0c5", + "zh:5acf55f8901d5443b6994463d7b2dcbb137a242486f47963e0f33c4cce30171a", + "zh:7036770df1223d15e0982be39bedf32b2e2cae1eabac717138cbc90bbf94e30e", + "zh:79f3f151984a97a7dee14e74ca9d9926b2add30982fe44a450645b89a6da6e00", + "zh:8a1b0bc5e237609fc1ad7af17e15a95f93a56c3403c0d022d94163ac1989507c", + "zh:94f3baf6a3ba728e31844d6786dae9aa505323389c6323e2eb820a3c81e82229", + "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", + "zh:ac4059a4f45c77432897605efb3642451c125ddddabe14d36a4a85dad13ae6cb", + "zh:d2a8d1c9a9100ae3fec34f119d3a90faefb89bf93780fc6934898533c6900cba", + "zh:de647167adb585a54cfbfc4c5d204c5d0a444624d386a773eae75789aa75f363", + "zh:edb533b3df81f2d1ef7387380cab843877f3f3c756f7a87cbba1961b3f01e4a2", + "zh:f56491ecb31b1ebde35cbfe8261e3c82c983b3039837f8756834cf27018bd93a", + "zh:fba46b50c35e40ea27947f4305320aaa61cdc22812b138571841e9bf8c7f5db9", + "zh:fcb92b5c6fbb70ae9137291ffc8ef06c48daec9cf0fafb980d178fe925658160", + ] +} diff --git a/my-infra/deploy/main.tf b/my-infra/deploy/main.tf new file mode 100644 index 00000000..618244a6 --- /dev/null +++ b/my-infra/deploy/main.tf @@ -0,0 +1,35 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "5.23.0" + } + } + + backend "s3" { + bucket = "thim-terraform" + key = "tf-state-deploy" + workspace_key_prefix = "tf-state-deploy-env" + region = "us-east-1" + encrypt = true + dynamodb_table = "devops-recipe-api-lock" + } +} + +provider "aws" { + region = "us-east-1" + default_tags { + tags = { + Environment = terraform.workspace + Project = var.project + Contact = var.contact + ManageBy = "Terraform/deploy" + } + } +} + +locals { + prefix = "${var.prefix}-${terraform.workspace}" +} + +data "aws_region" "current" {} diff --git a/my-infra/deploy/variables.tf b/my-infra/deploy/variables.tf new file mode 100644 index 00000000..29bc74ee --- /dev/null +++ b/my-infra/deploy/variables.tf @@ -0,0 +1,51 @@ +variable "prefix" { + description = "Prefix for resources in AWS" + default = "raa" +} + +variable "project" { + description = "Project name for tagging resources" + default = "recipe-app-api" +} + +variable "contact" { + description = "Contact email for tagging resources" + default = "mark@example.com" +} + +variable "db_username" { + description = "Username for the recipe app api database" + default = "recipeapp" +} + +variable "db_password" { + description = "Password for the Terraform database" +} + +variable "ecr_proxy_image" { + description = "Path to the ECR repo with the proxy image" +} + +variable "ecr_app_image" { + description = "Path to the ECR repo with the API image" +} + +variable "django_secret_key" { + description = "Secret key for Django" +} + +variable "dns_zone_name" { + description = "Domain name" + default = "londonappdev.net" +} + +variable "subdomain" { + description = "Subdomain for each environment" + type = map(string) + + default = { + prod = "api" + staging = "api.staging" + dev = "api.dev" + } +} diff --git a/my-infra/docker-compose.yml b/my-infra/docker-compose.yml new file mode 100644 index 00000000..3e241659 --- /dev/null +++ b/my-infra/docker-compose.yml @@ -0,0 +1,17 @@ +services: + terraform: + image: hashicorp/terraform:1.6.2 + volumes: + - ./setup:/tf/setup + - ./deploy:/tf/deploy + working_dir: /tf + environment: + - AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} + - AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} + - AWS_SESSION_TOKEN=${AWS_SESSION_TOKEN} + - AWS_DEFAULT_REGION=us-east-1 + - TF_WORKSPACE=${TF_WORKSPACE} + - TF_VAR_db_password=${TF_VAR_db_password} + - TF_VAR_django_secret_key=${TF_VAR_django_secret_key} + - TF_VAR_ecr_proxy_image=${TF_VAR_ecr_proxy_image} + - TF_VAR_ecr_app_image=${TF_VAR_ecr_app_image} diff --git a/my-infra/setup/.terraform.lock.hcl b/my-infra/setup/.terraform.lock.hcl new file mode 100644 index 00000000..2ffb9a9b --- /dev/null +++ b/my-infra/setup/.terraform.lock.hcl @@ -0,0 +1,25 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/aws" { + version = "5.23.0" + constraints = "5.23.0" + hashes = [ + "h1:AwjyBYctD8UKCXcm+kLJfRjYdUYzG0hetStKrw8UL9M=", + "zh:100966f25b1878b7c4ee250dcbaf09e5a2dad4bcebba2482d77c4cc4e48957da", + "zh:57ed5e66949568d25788ebcd170abf5961f81bb141f69d3acca9a7454994d0c5", + "zh:5acf55f8901d5443b6994463d7b2dcbb137a242486f47963e0f33c4cce30171a", + "zh:7036770df1223d15e0982be39bedf32b2e2cae1eabac717138cbc90bbf94e30e", + "zh:79f3f151984a97a7dee14e74ca9d9926b2add30982fe44a450645b89a6da6e00", + "zh:8a1b0bc5e237609fc1ad7af17e15a95f93a56c3403c0d022d94163ac1989507c", + "zh:94f3baf6a3ba728e31844d6786dae9aa505323389c6323e2eb820a3c81e82229", + "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", + "zh:ac4059a4f45c77432897605efb3642451c125ddddabe14d36a4a85dad13ae6cb", + "zh:d2a8d1c9a9100ae3fec34f119d3a90faefb89bf93780fc6934898533c6900cba", + "zh:de647167adb585a54cfbfc4c5d204c5d0a444624d386a773eae75789aa75f363", + "zh:edb533b3df81f2d1ef7387380cab843877f3f3c756f7a87cbba1961b3f01e4a2", + "zh:f56491ecb31b1ebde35cbfe8261e3c82c983b3039837f8756834cf27018bd93a", + "zh:fba46b50c35e40ea27947f4305320aaa61cdc22812b138571841e9bf8c7f5db9", + "zh:fcb92b5c6fbb70ae9137291ffc8ef06c48daec9cf0fafb980d178fe925658160", + ] +} diff --git a/my-infra/setup/ecr.tf b/my-infra/setup/ecr.tf new file mode 100644 index 00000000..e69de29b diff --git a/my-infra/setup/iam.tf b/my-infra/setup/iam.tf new file mode 100644 index 00000000..e69de29b diff --git a/my-infra/setup/main.tf b/my-infra/setup/main.tf new file mode 100644 index 00000000..46104785 --- /dev/null +++ b/my-infra/setup/main.tf @@ -0,0 +1,29 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "5.23.0" + } + } + + backend "s3" { + bucket = "thim-terraform" + key = "tf-state-setup" + region = "us-east-1" + encrypt = true + dynamodb_table = "devops-recipe-api-lock" + } +} + +provider "aws" { + region = "us-east-1" + + default_tags { + tags = { + Environment = terraform.workspace + Project = var.project + Contact = var.contact + ManageBy = "Terraform/setup" + } + } +} diff --git a/my-infra/setup/outputs.tf b/my-infra/setup/outputs.tf new file mode 100644 index 00000000..e69de29b diff --git a/my-infra/setup/variables.tf b/my-infra/setup/variables.tf new file mode 100644 index 00000000..621ca339 --- /dev/null +++ b/my-infra/setup/variables.tf @@ -0,0 +1,19 @@ +variable "tf_state_bucket" { + description = "Name of S3 bucket in AWS for storing TF state" + default = "thim-terraform" +} + +variable "tf_state_lock_table" { + description = "Name of DynamoDB table for TF state locking" + default = "devops-recipe-api-lock" +} + +variable "project" { + description = "Project name for tagging resources" + default = "recipe-app-api" +} + +variable "contact" { + description = "Contact name for tagging resources" + default = "mark@example.com" +} From 9d878c4fcc43d9bda9c0d79729e101016438d2cf Mon Sep 17 00:00:00 2001 From: mbothe Date: Tue, 17 Sep 2024 12:08:29 -0400 Subject: [PATCH 2/6] added iam user for cicd --- my-infra/deploy/iam.tf | 0 my-infra/setup/iam.tf | 72 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 my-infra/deploy/iam.tf diff --git a/my-infra/deploy/iam.tf b/my-infra/deploy/iam.tf new file mode 100644 index 00000000..e69de29b diff --git a/my-infra/setup/iam.tf b/my-infra/setup/iam.tf index e69de29b..a30de56b 100644 --- a/my-infra/setup/iam.tf +++ b/my-infra/setup/iam.tf @@ -0,0 +1,72 @@ +####################################################################### +# Create IAM user and policies for Continuous Deployment (CD) account # +####################################################################### + +resource "aws_iam_user" "cd" { + name = "recipe-app-api-cd" +} + +resource "aws_iam_access_key" "cd" { + user = aws_iam_user.cd.name +} + +######################################################### +# Policy for Teraform backend to S3 and DynamoDB access # +######################################################### + +data "aws_iam_policy_document" "tf_backend" { + statement { + effect = "Allow" + actions = ["s3:ListBucket"] + resources = ["arn:aws:s3:::${var.tf_state_bucket}"] + } + + statement { + effect = "Allow" + actions = ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"] + resources = [ + "arn:aws:s3:::${var.tf_state_bucket}/tf-state-deploy/*", + "arn:aws:s3:::${var.tf_state_bucket}/tf-state-deploy-env/*" + ] + } + statement { + effect = "Allow" + actions = [ + "dynamodb:DescribeTable", + "dynamodb:GetItem", + "dynamodb:PutItem", + "dynamodb:DeleteItem" + ] + resources = ["arn:aws:dynamodb:*:*:table/${var.tf_state_lock_table}"] + } +} +resource "aws_iam_policy" "tf_backend" { + name = "${aws_iam_user.cd.name}-tf-s3-dynamodb" + description = "Allow user to use S3 and DynamoDB for TF backend resources" + policy = data.aws_iam_policy_document.tf_backend.json +} + +resource "aws_iam_user_policy_attachment" "tf_backend" { + user = aws_iam_user.cd.name + policy_arn = aws_iam_policy.tf_backend.arn +} + + +######################### +# Policy for ECR access # +######################### + +data "aws_iam_policy_document" "ecr" { + +} + +output "cd_user_access_key_id" { + description = "AWS Key ID for CD user" + value = aws_iam_access_key.cd.id +} + +output "cd_user_access_key_secret" { + description = "Access Key for CD user" + value = aws_iam_access_key.cd.secret + sensitive = true +} From fd17751173b4e6be7e27941d43e30f5e817a34e7 Mon Sep 17 00:00:00 2001 From: mbothe Date: Tue, 17 Sep 2024 12:28:38 -0400 Subject: [PATCH 3/6] added ecr policy --- my-infra/setup/ecr.tf | 23 +++++++++++++++++++++++ my-infra/setup/iam.tf | 32 +++++++++++++++++++++++--------- my-infra/setup/outputs.tf | 20 ++++++++++++++++++++ 3 files changed, 66 insertions(+), 9 deletions(-) diff --git a/my-infra/setup/ecr.tf b/my-infra/setup/ecr.tf index e69de29b..adeef4b5 100644 --- a/my-infra/setup/ecr.tf +++ b/my-infra/setup/ecr.tf @@ -0,0 +1,23 @@ +############################################## +# Create ECR repos for storing Docker images # +############################################## + +resource "aws_ecr_repository" "app" { + name = "recipe-app-api-app" + image_tag_mutability = "MUTABLE" + force_delete = true + + image_scanning_configuration { + scan_on_push = false + } +} + + +resource "aws_ecr_repository" "proxy" { + name = "recipe-app-api-proxy" + image_tag_mutability = "MUTABLE" + force_delete = true + image_scanning_configuration { + scan_on_push = false + } +} diff --git a/my-infra/setup/iam.tf b/my-infra/setup/iam.tf index a30de56b..68c7e9d5 100644 --- a/my-infra/setup/iam.tf +++ b/my-infra/setup/iam.tf @@ -57,16 +57,30 @@ resource "aws_iam_user_policy_attachment" "tf_backend" { ######################### data "aws_iam_policy_document" "ecr" { + statement { + effect = "Allow" + actions = ["ecr:GetAuthorizationToken"] + resources = ["*"] + } + statement { + effect = "Allow" + actions = [ + "ecr:CompleteLayerUpload", + "ecr:UploadLayerPart", + "ecr:InitiateLayerUpload", + "ecr:BatchCheckLayerAvailability", + "ecr:PutImage" + ] + resources = [ + aws_ecr_repository.app.arn, + aws_ecr_repository.proxy.arn, + ] + } } -output "cd_user_access_key_id" { - description = "AWS Key ID for CD user" - value = aws_iam_access_key.cd.id -} - -output "cd_user_access_key_secret" { - description = "Access Key for CD user" - value = aws_iam_access_key.cd.secret - sensitive = true +resource "aws_iam_policy" "ecr" { + name = "${aws_iam_user.cd.name}-ecr" + description = "Allow user to manage ECR resources" + policy = data.aws_iam_policy_document.ecr.json } diff --git a/my-infra/setup/outputs.tf b/my-infra/setup/outputs.tf index e69de29b..8d528ab7 100644 --- a/my-infra/setup/outputs.tf +++ b/my-infra/setup/outputs.tf @@ -0,0 +1,20 @@ +output "cd_user_access_key_id" { + description = "Access key ID for CD user" + value = aws_iam_access_key.cd.id +} + +output "cd_user_access_key_secret" { + description = "Access key secret for CD user" + value = aws_iam_access_key.cd.secret + sensitive = true +} + +output "ecr_repo_app" { + description = "ECR repository URL for app image" + value = aws_ecr_repository.app.repository_url +} + +output "ecr_repo_proxy" { + description = "ECR repository URL for the proxy image" + value = aws_ecr_repository.proxy.repository_url +} From ee23aad625f665e9fad7faecbd55d0774b37913e Mon Sep 17 00:00:00 2001 From: mbothe Date: Tue, 17 Sep 2024 15:55:23 -0400 Subject: [PATCH 4/6] added Readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 5681a219..e0b102e3 100644 --- a/README.md +++ b/README.md @@ -209,3 +209,5 @@ Or find them below: - [Build a Backend REST API with Python & Django REST Framework - Beginner](https://londonapp.dev/c1) - [Build a Backend REST API with Python & Django REST Framework - Advanced](https://londonapp.dev/c2) - [Deploy a Serverless Django App on Google App Engine](https://londonapp.dev/c5) + +hello123 From 83e9904e83a947574c240f96a1374080310eac6f Mon Sep 17 00:00:00 2001 From: mbothe Date: Tue, 17 Sep 2024 16:39:11 -0400 Subject: [PATCH 5/6] removed Readme --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index e0b102e3..5681a219 100644 --- a/README.md +++ b/README.md @@ -209,5 +209,3 @@ Or find them below: - [Build a Backend REST API with Python & Django REST Framework - Beginner](https://londonapp.dev/c1) - [Build a Backend REST API with Python & Django REST Framework - Advanced](https://londonapp.dev/c2) - [Deploy a Serverless Django App on Google App Engine](https://londonapp.dev/c5) - -hello123 From 9d126528abf485067f8d54e5faa33b4c5b3d21c3 Mon Sep 17 00:00:00 2001 From: mbothe Date: Tue, 17 Sep 2024 17:09:29 -0400 Subject: [PATCH 6/6] original commit --- devops-recipe-test | 1 + testfile | 1 + 2 files changed, 2 insertions(+) create mode 160000 devops-recipe-test create mode 100644 testfile diff --git a/devops-recipe-test b/devops-recipe-test new file mode 160000 index 00000000..9535f553 --- /dev/null +++ b/devops-recipe-test @@ -0,0 +1 @@ +Subproject commit 9535f553cd98616c48ddf886f1ae004edcead4ae diff --git a/testfile b/testfile new file mode 100644 index 00000000..882ca730 --- /dev/null +++ b/testfile @@ -0,0 +1 @@ +mytest