diff --git a/.aws/task-definition.json b/.aws/task-definition.json deleted file mode 100644 index 72a9fc211..000000000 --- a/.aws/task-definition.json +++ /dev/null @@ -1,195 +0,0 @@ -{ - "taskDefinitionArn": "arn:aws:ecs:us-east-1:768512802988:task-definition/appointments-definition:24", - "containerDefinitions": [ - { - "name": "backend", - "image": "backend-latest", - "cpu": 0, - "portMappings": [ - { - "name": "backend-5000-tcp", - "containerPort": 5000, - "hostPort": 5000, - "protocol": "tcp", - "appProtocol": "http" - } - ], - "essential": true, - "environment": [ - { - "name": "FRONTEND_URL", - "value": "https://stage.appointment.day" - }, - { - "name": "SHORT_BASE_URL", - "value": "https://stage.apmt.day" - }, - { - "name": "TIER_BASIC_CALENDAR_LIMIT", - "value": "3" - }, - { - "name": "TIER_PLUS_CALENDAR_LIMIT", - "value": "5" - }, - { - "name": "TIER_PRO_CALENDAR_LIMIT", - "value": "10" - }, - { - "name": "LOG_USE_STREAM", - "value": "True" - }, - { - "name": "LOG_LEVEL", - "value": "INFO" - }, - { - "name": "APP_ENV", - "value": "stage" - }, - { - "name": "SENTRY_DSN", - "value": "https://5dddca3ecc964284bb8008bc2beef808@o4505428107853824.ingest.sentry.io/4505428124827648" - }, - { - "name": "ZOOM_API_ENABLED", - "value": "True" - }, - { - "name": "ZOOM_AUTH_CALLBACK", - "value": "https://stage.appointment.day/api/v1/zoom/callback" - }, - { - "name": "SERVICE_EMAIL", - "value": "no-reply@appointment.day" - }, - { - "name": "AUTH_SCHEME", - "value": "fxa" - }, - { - "name": "JWT_ALGO", - "value": "HS256" - }, - { - "name": "JWT_EXPIRE_IN_MINS", - "value": "10000" - } - ], - "secrets": [ - { - "name": "DATABASE_SECRETS", - "valueFrom": "arn:aws:secretsmanager:us-east-1:768512802988:secret:staging/appointment/db-mysql-Ixf6qD" - }, - { - "name": "DB_ENC_SECRET", - "valueFrom": "arn:aws:secretsmanager:us-east-1:768512802988:secret:staging/appointment/db-secret-CYKglI" - }, - { - "name": "SMTP_SECRETS", - "valueFrom": "arn:aws:secretsmanager:us-east-1:768512802988:secret:staging/appointment/socketlabs-UYmjaC" - }, - { - "name": "GOOGLE_OAUTH_SECRETS", - "valueFrom": "arn:aws:secretsmanager:us-east-1:768512802988:secret:staging/appointment/google-cal-oauth-VevaSo" - }, - { - "name": "ZOOM_SECRETS", - "valueFrom": "arn:aws:secretsmanager:us-east-1:768512802988:secret:staging/appointment/zoom-S862zi" - }, - { - "name": "FXA_SECRETS", - "valueFrom": "arn:aws:secretsmanager:us-east-1:768512802988:secret:staging/appointment/fxa-7koQF0" - } - ], - "mountPoints": [], - "volumesFrom": [], - "logConfiguration": { - "logDriver": "awslogs", - "options": { - "awslogs-create-group": "true", - "awslogs-group": "/ecs/appointments-definition", - "awslogs-region": "us-east-1", - "awslogs-stream-prefix": "ecs" - } - } - }, - { - "name": "frontend", - "image": "frontend-latest", - "cpu": 0, - "portMappings": [ - { - "name": "frontend-80-tcp", - "containerPort": 80, - "hostPort": 80, - "protocol": "tcp", - "appProtocol": "http" - } - ], - "essential": true, - "environment": [], - "mountPoints": [], - "volumesFrom": [], - "logConfiguration": { - "logDriver": "awslogs", - "options": { - "awslogs-create-group": "true", - "awslogs-group": "/ecs/appointments-definition", - "awslogs-region": "us-east-1", - "awslogs-stream-prefix": "ecs" - } - } - } - ], - "family": "appointments-definition", - "executionRoleArn": "arn:aws:iam::768512802988:role/apointments-ci-role", - "networkMode": "awsvpc", - "revision": 24, - "volumes": [], - "status": "ACTIVE", - "requiresAttributes": [ - { - "name": "com.amazonaws.ecs.capability.logging-driver.awslogs" - }, - { - "name": "ecs.capability.execution-role-awslogs" - }, - { - "name": "com.amazonaws.ecs.capability.ecr-auth" - }, - { - "name": "com.amazonaws.ecs.capability.docker-remote-api.1.19" - }, - { - "name": "ecs.capability.execution-role-ecr-pull" - }, - { - "name": "com.amazonaws.ecs.capability.docker-remote-api.1.18" - }, - { - "name": "ecs.capability.task-eni" - }, - { - "name": "com.amazonaws.ecs.capability.docker-remote-api.1.29" - } - ], - "placementConstraints": [], - "compatibilities": [ - "EC2", - "FARGATE" - ], - "requiresCompatibilities": [ - "FARGATE" - ], - "cpu": "512", - "memory": "1024", - "runtimePlatform": { - "cpuArchitecture": "X86_64", - "operatingSystemFamily": "LINUX" - }, - "registeredAt": "2023-03-15T22:19:59.642Z", - "registeredBy": "arn:aws:iam::768512802988:user/melissa", - "tags": [] -} diff --git a/.github/workflows/aws.yml b/.github/workflows/aws.yml deleted file mode 100644 index 1ef62f5a3..000000000 --- a/.github/workflows/aws.yml +++ /dev/null @@ -1,102 +0,0 @@ -# This workflow will build and push a new container image to Amazon ECR, -# and then will deploy a new task definition to Amazon ECS, when there is a push to the "staging" branch. - -name: Deploy to Stage Environment - -# Stop any pending jobs -concurrency: - group: staging - cancel-in-progress: true - -on: - push: - branches: [ "stage" ] - -env: - AWS_REGION: us-east-1 - ECR_REPOSITORY: appointments - ECS_SERVICE: appointments-service - ECS_CLUSTER: appointments - ECS_TASK_DEFINITION: .aws/task-definition.json - - CONTAINER_FRONTEND: frontend - CONTAINER_BACKEND: backend - -permissions: - contents: read - -jobs: - deploy: - name: Build & Deploy - runs-on: ubuntu-latest - environment: - name: staging - url: https://stage.appointment.day - - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v1 - with: - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - aws-region: ${{ env.AWS_REGION }} - - - name: Login to Amazon ECR - id: login-ecr - uses: aws-actions/amazon-ecr-login@v2 - with: - mask-password: 'true' - - - name: Build, tag, and push backend to Amazon ECR - id: build-backend - env: - ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} - IMAGE_TAG: backend-${{ github.sha }} - run: | - # Build a docker container and - # push it to ECR so that it can - # be deployed to ECS. - docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG ./backend -f ./backend/deploy.dockerfile - docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG - echo "image_backend=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT - - - name: Build, tag, and push frontend to Amazon ECR - id: build-frontend - env: - ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} - IMAGE_TAG: frontend-${{ github.sha }} - run: | - # Build a docker container and - # push it to ECR so that it can - # be deployed to ECS. - docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG ./frontend -f ./frontend/deploy.dockerfile - docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG - echo "image_frontend=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT - - - name: Fill in the new backend image ID in the Amazon ECS task definition - id: task-def-backend - uses: aws-actions/amazon-ecs-render-task-definition@v1 - with: - task-definition: ${{ env.ECS_TASK_DEFINITION }} - container-name: ${{ env.CONTAINER_BACKEND }} - image: ${{ steps.build-backend.outputs.image_backend }} - environment-variables: "RELEASE_VERSION=${{ github.sha }}" - - - name: Fill in the new frontend image ID in the Amazon ECS task definition - id: task-def-frontend - uses: aws-actions/amazon-ecs-render-task-definition@v1 - with: - task-definition: ${{ steps.task-def-backend.outputs.task-definition }} - container-name: ${{ env.CONTAINER_FRONTEND }} - image: ${{ steps.build-frontend.outputs.image_frontend }} - - - name: Deploy Amazon ECS task definition - uses: aws-actions/amazon-ecs-deploy-task-definition@v1 - with: - task-definition: ${{ steps.task-def-frontend.outputs.task-definition }} - service: ${{ env.ECS_SERVICE }} - cluster: ${{ env.ECS_CLUSTER }} - wait-for-service-stability: true diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml deleted file mode 100644 index 89cd424ab..000000000 --- a/.github/workflows/ci-tests.yml +++ /dev/null @@ -1,49 +0,0 @@ -# This workflow will install backend's requirements and run tests - -name: Run Tests - -on: - push: - branches: [main] - pull_request: - branches: [main] - -permissions: - contents: read - -jobs: - pytest: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: '3.11' - cache: 'pip' - - name: Install dependencies - run: | - cd ./backend - python -m pip install --upgrade pip - python -m pip install .'[test]' - - name: Test with pytest - run: | - cd ./backend && python -m pytest - vitest: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: 18 - cache: 'yarn' - cache-dependency-path: 'frontend/yarn.lock' - - name: Install dependencies - run: | - cd ./frontend - yarn install - - name: Test with vitest - run: | - cd ./frontend && yarn test --run diff --git a/.github/workflows/deploy-production.yml b/.github/workflows/deploy-production.yml new file mode 100644 index 000000000..979798911 --- /dev/null +++ b/.github/workflows/deploy-production.yml @@ -0,0 +1,166 @@ +name: deploy-production + +concurrency: + group: deploy-production + cancel-in-progress: true + +on: + release: + types: [published] + +permissions: + id-token: write # This is required for requesting the JWT + contents: read # This is required for actions/checkout + +jobs: + deploy-iac: + environment: production + runs-on: ubuntu-latest + outputs: + bucket: ${{ steps.output-bucket-name.outputs.bucket }} + cloudfront_id: ${{ steps.output-cloudfront-distro.outputs.cloudfront_id }} +# env: +# TF_VAR_region: ${{ vars.AWS_REGION }} +# TF_VAR_environment: ${{ vars.ENV_SHORT_NAME }} +# TF_VAR_name_prefix: "tb-${{ vars.PROJECT_SHORT_NAME }}-${{ vars.ENV_SHORT_NAME }}" +# TF_VAR_app_env: ${{ vars.APP_ENV }} +# TF_VAR_db_enc_secret: ${{ vars.DB_ENCRYPTED_SECRET }} +# TF_VAR_frontend_url: ${{ vars.FRONTEND_URL }} +# TF_VAR_fxa_secret: ${{ vars.FXA_SECRET }} +# TF_VAR_google_oauth_secret: ${{ vars.GOOGLE_OAUTH_SECRET }} +# TF_VAR_log_level: ${{ vars.LOG_LEVEL }} +# TF_VAR_short_base_url: ${{ vars.SHORT_BASE_URL }} +# TF_VAR_smtp_secret: ${{ vars.SMTP_SECRET }} +# TF_VAR_zoom_callback: ${{ vars.ZOOM_CALLBACK }} +# TF_VAR_zoom_secret: ${{ vars.zoom_secret }} +# TF_VAR_sentry_dsn: ${{ vars.SENTRY_DSN }} + steps: + - uses: actions/checkout@v4 + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.IAM_ROLE }} + role-session-name: Appointment_GitHub_to_AWS_via_FederatedOIDC + aws-region: ${{ vars.AWS_REGION }} + + - name: install opentofu + uses: opentofu/setup-opentofu@v1 + with: + tofu_version: ${{ vars.TF_VERSION }} + tofu_wrapper: false + + - name: install terragrunt + run: | + sudo wget -q -O /bin/terragrunt "https://github.com/gruntwork-io/terragrunt/releases/download/v${{ vars.TG_VERSION }}/terragrunt_linux_amd64" + sudo chmod +x /bin/terragrunt + terragrunt -v + + - name: vpc + working-directory: ./tofu/environments/stage/network/vpc + run: | + terragrunt init -upgrade + terragrunt validate + terragrunt plan -out tfplan +# terragrunt apply tfplan # will be re-enabled once release workflow is tested + + - name: backend-infra + working-directory: ./tofu/environments/stage/services/backend-infra + run: | + terragrunt init -upgrade + terragrunt validate + terragrunt plan -out tfplan +# terragrunt apply tfplan # will be re-enabled once release workflow is tested + + - name: cache + working-directory: ./tofu/environments/stage/data-store/cache + run: | + terragrunt init -upgrade + terragrunt validate + terragrunt plan -out tfplan +# terragrunt apply tfplan # will be re-enabled once release workflow is tested + + - name: database + working-directory: ./tofu/environments/stage/data-store/database + run: | + terragrunt init -upgrade + terragrunt validate + terragrunt plan -out tfplan +# terragrunt apply tfplan # will be re-enabled once release workflow is tested + + - name: frontend-infra + working-directory: ./tofu/environments/stage/services/frontend-infra + run: | + terragrunt init -upgrade + terragrunt validate + terragrunt plan -out tfplan +# terragrunt apply tfplan # will be re-enabled once release workflow is tested + + - name: output-bucket-name + id: output-bucket-name + working-directory: ./tofu/environments/stage/services/frontend-infra + run: | + output=$(terragrunt output bucket_name | tr -d '"') + echo bucket=$output >> $GITHUB_OUTPUT + + - name: output-cloudfront-distro + id: output-cloudfront-distro + working-directory: ./tofu/environments/stage/services/frontend-infra + run: | + output=$(terragrunt output cloudfront_id) + echo cloudfront_id=$output >> $GITHUB_OUTPUT + + release-production: + name: Release to Production + needs: deploy-iac + if: startsWith(github.ref_name, 'r-') # the prefix we have added to the tag + environment: production + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + + steps: + - name: Get Artifact from Release + uses: dsaltares/fetch-gh-release-asset@master + with: + version: ${{ github.event.release.id }} + file: frontend.zip + + - name: Unzip Artifact + run: unzip frontend.zip + + - name: Get ECR tag from Release + id: get_ecr_tag + uses: dsaltares/fetch-gh-release-asset@master + with: + version: ${{ github.event.release.id }} + file: ecr_tag.txt + target: ./tofu/environments/stage/services/backend-service + + - name: Unzip ECR tag + working-directory: ./tofu/environments/stage/services/backend-service + run: unzip ecr_tag.zip + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.IAM_ROLE }} + role-session-name: Appointment_GitHub_to_AWS_via_FederatedOIDC + aws-region: ${{ vars.AWS_REGION }} + + - name: Deploy Backend + working-directory: ./tofu/environments/stage/services/backend-service + run: | + terragrunt init -upgrade + terragrunt validate + terragrunt plan -var "image=$(cat steps.get_ecr_tag.outputs.*)" -out tfplan + cat tfplan +# terragrunt apply tfplan # will be re-enabled once release workflow is tested + +# will be re-enabled once release workflow is tested +# - name: Deploy frontend to S3 +# run: aws s3 sync ./frontend/frontend/dist "s3://${{ needs.deploy-iac.outputs.bucket }}" + + - name: Invalidate Cloudfront cache + run: aws cloudfront create-invalidation --distribution-id ${{ needs.deploy-iac.outputs.cloudfront_id }} --paths "/*" \ No newline at end of file diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml new file mode 100644 index 000000000..46982c571 --- /dev/null +++ b/.github/workflows/deploy-staging.yml @@ -0,0 +1,310 @@ +name: deploy-staging + +concurrency: + group: deploy-staging + cancel-in-progress: true + +on: + push: + branches: + - main + +permissions: + id-token: write # This is required for requesting the JWT + contents: write # This is required to create a release + +jobs: + detect-changes: + runs-on: ubuntu-latest + environment: staging + outputs: + deploy-iac: ${{ steps.check.outputs.deploy-iac }} + deploy-app: ${{ steps.check.outputs.deploy-app }} + steps: + - uses: actions/checkout@v4 + + - uses: dorny/paths-filter@v3 + id: check + with: + filters: | + deploy-iac: + - 'tofu/modules/**' + - 'tofu/environments/stage/**' + - '.github/workflows/deploy-staging.yml' + deploy-app: + - 'backend/**' + - 'tofu/modules/services/backend-service/**' + - 'tofu/environments/stage/services/backend-service/**' + - 'frontend/**' + - 'tofu/modules/services/frontend-infra/**' + - 'tofu/environments/stage/services/frontend-infra/**' + - '.github/workflows/deploy-staging.yml' + + deploy-iac: + needs: detect-changes + if: needs.detect-changes.outputs.deploy-iac == 'true' + environment: staging + runs-on: ubuntu-latest + outputs: + bucket: ${{ steps.output-bucket-name.outputs.bucket }} + cloudfront_id: ${{ steps.output-cloudfront-distro.outputs.cloudfront_id }} + env: + TF_VAR_region: ${{ vars.AWS_REGION }} + TF_VAR_environment: ${{ vars.ENV_SHORT_NAME }} + TF_VAR_name_prefix: "tb-${{ vars.PROJECT_SHORT_NAME }}-${{ vars.ENV_SHORT_NAME }}" + TF_VAR_app_env: ${{ vars.APP_ENV }} + TF_VAR_db_enc_secret: ${{ vars.DB_ENCRYPTED_SECRET }} + TF_VAR_frontend_url: ${{ vars.FRONTEND_URL }} + TF_VAR_fxa_secret: ${{ vars.FXA_SECRET }} + TF_VAR_google_oauth_secret: ${{ vars.GOOGLE_OAUTH_SECRET }} + TF_VAR_log_level: ${{ vars.LOG_LEVEL }} + TF_VAR_short_base_url: ${{ vars.SHORT_BASE_URL }} + TF_VAR_smtp_secret: ${{ vars.SMTP_SECRET }} + TF_VAR_zoom_callback: ${{ vars.ZOOM_CALLBACK }} + TF_VAR_zoom_secret: ${{ vars.zoom_secret }} + TF_VAR_sentry_dsn: ${{ vars.SENTRY_DSN }} + steps: + - uses: actions/checkout@v4 + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.IAM_ROLE }} + role-session-name: Appointment_GitHub_to_AWS_via_FederatedOIDC + aws-region: ${{ vars.AWS_REGION }} + + - name: install opentofu + uses: opentofu/setup-opentofu@v1 + with: + tofu_version: ${{ vars.TF_VERSION }} + tofu_wrapper: false + + - name: install terragrunt + run: | + sudo wget -q -O /bin/terragrunt "https://github.com/gruntwork-io/terragrunt/releases/download/v${{ vars.TG_VERSION }}/terragrunt_linux_amd64" + sudo chmod +x /bin/terragrunt + terragrunt -v + + - name: vpc + working-directory: ./tofu/environments/stage/network/vpc + run: | + terragrunt init -upgrade + terragrunt validate + terragrunt plan -out tfplan + terragrunt apply tfplan + + - name: backend-infra + working-directory: ./tofu/environments/stage/services/backend-infra + run: | + terragrunt init -upgrade + terragrunt validate + terragrunt plan -out tfplan + terragrunt apply tfplan + + - name: cache + working-directory: ./tofu/environments/stage/data-store/cache + run: | + terragrunt init -upgrade + terragrunt validate + terragrunt plan -out tfplan + terragrunt apply tfplan + + - name: database + working-directory: ./tofu/environments/stage/data-store/database + run: | + terragrunt init -upgrade + terragrunt validate + terragrunt plan -out tfplan + terragrunt apply tfplan + + - name: frontend-infra + working-directory: ./tofu/environments/stage/services/frontend-infra + run: | + terragrunt init -upgrade + terragrunt validate + terragrunt plan -out tfplan + terragrunt apply tfplan + + - name: output-bucket-name + id: output-bucket-name + working-directory: ./tofu/environments/stage/services/frontend-infra + run: | + output=$(terragrunt output bucket_name | tr -d '"') + echo bucket=$output >> $GITHUB_OUTPUT + + - name: output-cloudfront-distro + id: output-cloudfront-distro + working-directory: ./tofu/environments/stage/services/frontend-infra + run: | + output=$(terragrunt output cloudfront_id) + echo cloudfront_id=$output >> $GITHUB_OUTPUT + + deploy-frontend: + needs: + - detect-changes + - deploy-iac + if: needs.detect-changes.outputs.deploy-app == 'true' + environment: staging + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup NPM + uses: actions/setup-node@v4 + with: + node-version: '18.x' + + - name: Install dependencies + run: cd frontend && yarn install + + - name: Build project + run: | + cp frontend/.env.stage.example frontend/.env.stage + cd frontend && yarn build --mode ${{ vars.APP_ENV }} + + - name: Install AWS CLI + uses: unfor19/install-aws-cli-action@v1 + with: + version: 2 + arch: amd64 + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.IAM_ROLE }} + role-session-name: Appointment_GitHub_to_AWS_via_FederatedOIDC + aws-region: ${{ vars.AWS_REGION }} + + - name: Invalidate Cloudfront cache + run: aws cloudfront create-invalidation --distribution-id ${{ needs.deploy-iac.outputs.cloudfront_id }} --paths "/*" + + - name: Archive Frontend + uses: actions/upload-artifact@v4 + with: + name: frontend + path: frontend/dist + + - name: Deploy frontend to S3 + run: aws s3 sync frontend/dist "s3://${{ needs.deploy-iac.outputs.bucket }}" + + + + deploy-backend: + needs: + - detect-changes + - deploy-iac + if: needs.detect-changes.outputs.deploy-app == 'true' + environment: staging + runs-on: ubuntu-latest + env: + TF_VAR_region: ${{ vars.AWS_REGION }} + TF_VAR_environment: ${{ vars.ENV_SHORT_NAME }} + TF_VAR_name_prefix: "tb-${{ vars.PROJECT_SHORT_NAME }}-${{ vars.ENV_SHORT_NAME }}" + TF_VAR_app_env: ${{ vars.APP_ENV }} + TF_VAR_db_enc_secret: ${{ vars.DB_ENCRYPTED_SECRET }} + TF_VAR_frontend_url: ${{ vars.FRONTEND_URL }} + TF_VAR_fxa_secret: ${{ vars.FXA_SECRET }} + TF_VAR_google_oauth_secret: ${{ vars.GOOGLE_OAUTH_SECRET }} + TF_VAR_log_level: ${{ vars.LOG_LEVEL }} + TF_VAR_short_base_url: ${{ vars.SHORT_BASE_URL }} + TF_VAR_smtp_secret: ${{ vars.SMTP_SECRET }} + TF_VAR_zoom_callback: ${{ vars.ZOOM_CALLBACK }} + TF_VAR_zoom_secret: ${{ vars.ZOOM_SECRET }} + TF_VAR_sentry_dsn: ${{ vars.SENTRY_DSN }} + steps: + - uses: actions/checkout@v4 + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.IAM_ROLE }} + role-session-name: Appointment_GitHub_to_AWS_via_FederatedOIDC + aws-region: ${{ vars.AWS_REGION }} + + - name: install opentofu + uses: opentofu/setup-opentofu@v1 + with: + tofu_version: ${{ vars.TF_VERSION }} + tofu_wrapper: false + + - name: install terragrunt + run: | + sudo wget -q -O /bin/terragrunt "https://github.com/gruntwork-io/terragrunt/releases/download/v${{ vars.TG_VERSION }}/terragrunt_linux_amd64" + sudo chmod +x /bin/terragrunt + terragrunt -v + + - name: Login to Amazon ECR + id: login-ecr + uses: aws-actions/amazon-ecr-login@v2 + with: + mask-password: 'true' + + - name: Build, tag, and push backend image to Amazon ECR + id: build-backend + env: + ECR_TAG: '${{ steps.login-ecr.outputs.registry }}/${{ vars.PROJECT }}:backend-${{ github.sha }}' + run: | + # Build a docker container and + # push it to ECR so that it can + # be deployed to ECS. + docker build -t $ECR_TAG ./backend -f ./backend/deploy.dockerfile + docker push $ECR_TAG + echo "image_backend=$ECR_TAG" >> $GITHUB_OUTPUT + echo $ECR_TAG > ecr_tag.txt + + - name: Archive ECR tag + uses: actions/upload-artifact@v4 + with: + name: ecr_tag + path: ecr_tag.txt + + - name: deploy backend-service + working-directory: ./tofu/environments/stage/services/backend-service + run: | + terragrunt init -upgrade + terragrunt validate + terragrunt plan -var 'image=${{ steps.build-backend.outputs.image_backend }}' -out tfplan + terragrunt apply tfplan + + create-release: + needs: + - detect-changes + - deploy-backend + - deploy-frontend + if: needs.detect-changes.outputs.deploy-app == 'true' + environment: staging + runs-on: ubuntu-latest + steps: + - name: download artifact + uses: actions/download-artifact@v4 + with: + name: + frontend + + - name: download ecr tag + uses: actions/download-artifact@v4 + with: + name: + ecr_tag + + - name: create release tag + id: create-release-tag + run: echo "tag_name=r-$(printf %04d $GITHUB_RUN_NUMBER)" >> $GITHUB_OUTPUT + + - name: create draft release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ steps.create-release-tag.outputs.tag_name }} + name: Release ${{ steps.create-release-tag.outputs.tag_name }} + body: | + ## Info + Commit ${{ github.sha }} was deployed to `stage`. [See code diff](${{ github.event.compare }}). + + It was initialized by [${{ github.event.sender.login }}](${{ github.event.sender.html_url }}). + + ## How to Promote? + In order to promote this to prod, edit the draft and press **"Publish release"**. + draft: true + files: | + frontend.zip + ecr_tag.zip diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml new file mode 100644 index 000000000..c18171a91 --- /dev/null +++ b/.github/workflows/validate.yml @@ -0,0 +1,171 @@ +name: validate + +concurrency: + group: validate + cancel-in-progress: true + +on: + push: + branches: + - '**' + - '!main' + +permissions: + id-token: write # This is required for requesting the JWT + contents: read # This is required for actions/checkout + +jobs: + detect-changes: + runs-on: ubuntu-latest + environment: staging + outputs: + validate-iac: ${{ steps.check.outputs.validate-iac }} + validate-backend: ${{ steps.check.outputs.validate-backend }} + validate-frontend: ${{ steps.check.outputs.validate-frontend }} + steps: + - uses: actions/checkout@v4 + + - uses: dorny/paths-filter@v3 + id: check + with: + filters: | + validate-iac: + - 'tofu/**' + - '.github/workflows/validate.yml' + validate-backend: + - 'backend/**' + - '.github/workflows/validate.yml' + validate-frontend: + - 'frontend/**' + - '.github/workflows/validate.yml' + + validate-iac: + needs: detect-changes + runs-on: ubuntu-latest + environment: staging + if: needs.detect-changes.outputs.validate-iac == 'true' + env: + TF_VAR_region: ${{ vars.AWS_REGION }} + TF_VAR_environment: ${{ vars.ENV_SHORT_NAME }} + TF_VAR_name_prefix: "tb-${{ vars.PROJECT_SHORT_NAME }}-${{ vars.ENV_SHORT_NAME }}" + TF_VAR_app_env: ${{ vars.APP_ENV }} + TF_VAR_db_enc_secret: ${{ vars.DB_ENCRYPTED_SECRET }} + TF_VAR_frontend_url: ${{ vars.FRONTEND_URL }} + TF_VAR_fxa_secret: ${{ vars.FXA_SECRET }} + TF_VAR_google_oauth_secret: ${{ vars.GOOGLE_OAUTH_SECRET }} + TF_VAR_log_level: ${{ vars.LOG_LEVEL }} + TF_VAR_short_base_url: ${{ vars.SHORT_BASE_URL }} + TF_VAR_smtp_secret: ${{ vars.SMTP_SECRET }} + TF_VAR_zoom_callback: ${{ vars.ZOOM_CALLBACK }} + TF_VAR_zoom_secret: ${{ vars.zoom_secret }} + TF_VAR_sentry_dsn: ${{ vars.SENTRY_DSN }} + steps: + - uses: actions/checkout@v4 + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.IAM_ROLE }} + role-session-name: GitHub_to_AWS_via_FederatedOIDC + aws-region: ${{ vars.AWS_REGION }} + + - name: install opentofu + uses: opentofu/setup-opentofu@v1 + with: + tofu_version: ${{ vars.TF_VERSION }} + tofu_wrapper: false + + - name: install terragrunt + run: | + sudo wget -q -O /bin/terragrunt "https://github.com/gruntwork-io/terragrunt/releases/download/v${{ vars.TG_VERSION }}/terragrunt_linux_amd64" + sudo chmod +x /bin/terragrunt + terragrunt -v + + - name: vpc + working-directory: ./tofu/environments/stage/network/vpc + continue-on-error: true + run: | + terragrunt init -upgrade + terragrunt validate + + - name: backend-infra + working-directory: ./tofu/environments/stage/services/backend-infra + continue-on-error: true + run: | + terragrunt init -upgrade + terragrunt validate + + - name: cache + working-directory: ./tofu/environments/stage/data-store/cache + continue-on-error: true + run: | + terragrunt init -upgrade + terragrunt validate + + - name: database + working-directory: ./tofu/environments/stage/data-store/database + continue-on-error: true + run: | + terragrunt init -upgrade + terragrunt validate + + - name: frontend-infra + working-directory: ./tofu/environments/stage/services/frontend-infra + continue-on-error: true + run: | + terragrunt init -upgrade + terragrunt validate + + - name: backend-service + working-directory: ./tofu/environments/stage/services/backend-service + run: | + terragrunt init -upgrade + terragrunt validate + + validate-backend: + needs: detect-changes + runs-on: ubuntu-latest + environment: staging + if: needs.detect-changes.outputs.validate-backend == 'true' + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + cache: 'pip' + + - name: Install dependencies + run: | + cd ./backend + python -m pip install --upgrade pip + python -m pip install .'[test]' + + - name: Test with pytest + run: | + cd ./backend && python -m pytest + + validate-frontend: + needs: detect-changes + runs-on: ubuntu-latest + environment: staging + if: needs.detect-changes.outputs.validate-frontend == 'true' + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 18 + cache: 'yarn' + cache-dependency-path: 'frontend/yarn.lock' + + - name: Install dependencies + run: | + cd ./frontend + yarn install + + - name: Test with vitest + run: | + cd ./frontend && yarn test --run diff --git a/.gitignore b/.gitignore index 28b32f1c3..c5fdbdc42 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,44 @@ venv .coverage htmlcov caldav + +# Mac noise +**/.DS_Store + +# Terragrunt +**/.terragrunt-cache + +# Local .terraform directories +**/.terraform/* + +# .tfstate files +*.tfstate +*.tfstate.* + +# Crash log files +crash.log +crash.*.log + +# Exclude all .tfvars files, which are likely to contain sensitive data, such as +# password, private keys, and other secrets. These should not be part of version +# control as they are data points which are potentially sensitive and subject +# to change depending on the environment. +*.tfvars +*.tfvars.json + +# Ignore override files as they are usually used to override resources locally and so +# are not checked in +override.tf +override.tf.json +*_override.tf +*_override.tf.json + +# Include override files you do wish to add to version control using negated pattern +# !example_override.tf + +# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan +# example: *tfplan* + +# Ignore CLI configuration files +.terraformrc +terraform.rc \ No newline at end of file diff --git a/frontend/.env.staging.example b/frontend/.env.stage.example similarity index 100% rename from frontend/.env.staging.example rename to frontend/.env.stage.example diff --git a/frontend/deploy.dockerfile b/frontend/deploy.dockerfile index 8aa183c14..10f573074 100644 --- a/frontend/deploy.dockerfile +++ b/frontend/deploy.dockerfile @@ -3,8 +3,8 @@ FROM nginx:stable # Copy over files COPY . /build/frontend -# Copy over the staging config -RUN mv /build/frontend/.env.staging.example /build/frontend/.env.staging +# Copy over the stage config +RUN mv /build/frontend/.env.stage.example /build/frontend/.env.stage # Add Node 18 support RUN apt-get update @@ -19,7 +19,7 @@ RUN npm install --global yarn # Build site RUN cd /build/frontend && yarn install -RUN cd /build/frontend && yarn build --mode staging +RUN cd /build/frontend && yarn build --mode stage # Use our custom nginx config RUN rm /etc/nginx/conf.d/default.conf diff --git a/frontend/index.html b/frontend/index.html index 5578045d1..a37594f83 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -27,4 +27,5 @@
+ diff --git a/tofu/README.md b/tofu/README.md new file mode 100644 index 000000000..aa1711a20 --- /dev/null +++ b/tofu/README.md @@ -0,0 +1,116 @@ +# Tooling + +Code was written and tested with the following (these versions are enforced in code as minimums): + +- OpenTofu v1.6.2 +- Terragrunt 0.55.15 +- hashicorp/aws v5.46.0 +- hashicorp/random v3.6.1 + +**Note:** All code should be run through Terragrunt, which will then execute the required Tofu commands + +## Modules + +### tfbackend + +Contains the remote state resources: + +- S3 bucket - state +- DynamoDB - locks + +### vpc + +Contains the VPC and all core network resources and supporting security groups etc...including: + +- subnets +- vpc endpoints +- IGW +- NAT gateways + +### backend-infra + +Contains the ECS cluster & Application Load Balancer for the backend & supporting resources + +### cache + +Contains the Elasticache redis cluster and supporting resources + +### database + +Contains the RDS database instance and supporting resources + +### frontend + +Contains the Cloudfront CDN distribution, frontend S3 bucket and supporting resources. WHile the bucket contents will change with frontend code changes the infrastructure defined here will remain static + +### backend-service + +Contains the backend ECS service and task definitions. This will be redeployed whenever the backend code is updated + +## Deployment Order + +All infrastructure should be deployed via terragrunt commands from the appropriate 'environments' folder. Tofu should never be executed directly from the 'modules' folders + +### Remote State + +This is deployed individually before any other stacks and generally should not change with application or infrastructure deployments + +1. tofu/environments/\/terraform/tfbackend + 1. `cd tofu/environments//terraform/tfbackend` + 2. `terragrunt init` + 3. `terragrunt validate` + 4. `terragrunt plan -out tfplan` + 5. `terragrunt apply tfplan` + +### Infrastructure Stacks + +These should be deployed in the following order and generally will only be updated with infrastructure changes while remaining static for code changes + +1. tofu/environments/\/network/vpc + 1. `cd tofu/environments//network/vpc` + 2. `terragrunt init` + 3. `terragrunt validate` + 4. `terragrunt plan -out tfplan` + 5. `terragrunt apply tfplan` +2. tofu/environments/\/services/backend-infra + 1. `cd tofu/environments//services/backend-infra` + 2. `terragrunt init` + 3. `terragrunt validate` + 4. `terragrunt plan -out tfplan` + 5. `terragrunt apply tfplan` +3. tofu/environments/\/data-store/cache + 1. `cd tofu/environments//datastore/cache` + 2. `terragrunt init` + 3. `terragrunt validate` + 4. `terragrunt plan -out tfplan` + 5. `terragrunt apply tfplan` +4. tofu/environments/\/data-store/database + 1. `cd tofu/environments//data-store/database` + 2. `terragrunt init` + 3. `terragrunt validate` + 4. `terragrunt plan -out tfplan` + 5. `terragrunt apply tfplan` +5. tofu/environments/\/services/frontend + 1. `cd tofu/environments//services/frontend` + 2. `terragrunt init` + 3. `terragrunt validate` + 4. `terragrunt plan -out tfplan` + 5. `terragrunt apply tfplan` + +### Application Stacks + +1. tofu/environments/\/services/backend-service + 1. `cd tofu/environments//services/backend-service` + 2. `terragrunt init` + 3. `terragrunt validate` + 4. `terragrunt plan -out tfplan` + 5. `terragrunt apply tfplan` + +### Application Stacks + +1. tofu/environments/\/services/backend-service + 1. `cd tofu/environments//services/backend-service` + 2. `terragrunt init` + 3. `terragrunt validate` + 4. `terragrunt plan -out tfplan` + 5. `terragrunt apply tfplan` diff --git a/tofu/environments/prod/data-store/cache/.terraform.lock.hcl b/tofu/environments/prod/data-store/cache/.terraform.lock.hcl new file mode 100644 index 000000000..b88b3b5eb --- /dev/null +++ b/tofu/environments/prod/data-store/cache/.terraform.lock.hcl @@ -0,0 +1,19 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/hashicorp/aws" { + version = "5.41.0" + hashes = [ + "h1:Fx+3haIzgp5zo3zVxJDMpTUQcZ8z0g8eQLFud0hA0xc=", + "zh:28fda8bbfe6bdba53aa8a7ce1005e7d686bce1d604c6e0b58e32735162afc667", + "zh:3961d01ce92bc6fcb1cc0e267d6fc4270adf010d93e7890460c566b2f5761670", + "zh:85cf587abfdf6f306dc593232abb91cf5090296decaf6e84669dd92662f2f856", + "zh:9f9d2e81f493c0daba943211c8146100d4a90f7f09fd831f4e8dde2c5f8ab34a", + "zh:c7444bd54437f4e044dbe71353a5fc54fae5b96673c80ec42f3823e8890c5cd3", + "zh:d041d2a83a80a2be85297cff467ef3c0ae2887789f88197bda190e6d2b64399e", + "zh:db02a4756318595de2d72cad69c25bd29b61940ad3c91ddf06c32437170f9d56", + "zh:dd90187b8382e28347ca08f4642a405edbb50c27c94405367f55f8fafd6b42ad", + "zh:e8c47d26c221d6975d9905b4ffd4dc713fbafb60db2e740b974da7ff5b500a86", + "zh:f222038c55866e5121d24290824f56c76afff2562bdd47624e42a44d1c7c2002", + ] +} diff --git a/tofu/environments/prod/data-store/cache/terragrunt.hcl b/tofu/environments/prod/data-store/cache/terragrunt.hcl new file mode 100644 index 000000000..9011c853d --- /dev/null +++ b/tofu/environments/prod/data-store/cache/terragrunt.hcl @@ -0,0 +1,53 @@ +include "root" { + path = find_in_parent_folders() + expose = true +} + +include "environment" { + path = find_in_parent_folders("environment.hcl") + expose = true +} + +terraform { + source = "../../../../modules/data-store/cache" +} + +dependency "vpc" { + config_path = "../../network/vpc" + + mock_outputs_allowed_terraform_commands = ["init", "validate", "plan"] + mock_outputs = { + vpc_id = "mock_vpc_id" + subnets = ["subnet-mocksubnet1234567"] + database_subnet_cidrs = ["subnet-mocksubnet1234567"] + source_security_groups = ["sg-mocksecuritygroup"] + } +} + +dependency "backend" { + config_path = "../../services/backend-infra" + + mock_outputs_allowed_terraform_commands = ["init", "validate", "plan", "destroy"] + mock_outputs = { + security_group_id = "mock_sg_id" + } +} + +locals { + environment = get_env("TF_VAR_environment") + name_prefix = get_env("TF_VAR_name_prefix") + region = get_env("TF_VAR_region") + + project_tags = include.root.locals.tags + environment_tags = include.environment.locals.tags + tags = "${merge(local.project_tags, local.environment_tags)}" +} + +inputs = { + name_prefix = local.name_prefix + vpc = dependency.vpc.outputs.vpc_id + subnets = dependency.vpc.outputs.database_subnets + source_security_groups = [dependency.backend.outputs.security_group_id] + database_subnet_cidrs = dependency.vpc.outputs.database_subnet_cidrs + tags = local.tags +} \ No newline at end of file diff --git a/tofu/environments/prod/data-store/database/.terraform.lock.hcl b/tofu/environments/prod/data-store/database/.terraform.lock.hcl new file mode 100644 index 000000000..520f9bfec --- /dev/null +++ b/tofu/environments/prod/data-store/database/.terraform.lock.hcl @@ -0,0 +1,38 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/hashicorp/aws" { + version = "5.41.0" + constraints = ">= 5.36.0" + hashes = [ + "h1:Fx+3haIzgp5zo3zVxJDMpTUQcZ8z0g8eQLFud0hA0xc=", + "zh:28fda8bbfe6bdba53aa8a7ce1005e7d686bce1d604c6e0b58e32735162afc667", + "zh:3961d01ce92bc6fcb1cc0e267d6fc4270adf010d93e7890460c566b2f5761670", + "zh:85cf587abfdf6f306dc593232abb91cf5090296decaf6e84669dd92662f2f856", + "zh:9f9d2e81f493c0daba943211c8146100d4a90f7f09fd831f4e8dde2c5f8ab34a", + "zh:c7444bd54437f4e044dbe71353a5fc54fae5b96673c80ec42f3823e8890c5cd3", + "zh:d041d2a83a80a2be85297cff467ef3c0ae2887789f88197bda190e6d2b64399e", + "zh:db02a4756318595de2d72cad69c25bd29b61940ad3c91ddf06c32437170f9d56", + "zh:dd90187b8382e28347ca08f4642a405edbb50c27c94405367f55f8fafd6b42ad", + "zh:e8c47d26c221d6975d9905b4ffd4dc713fbafb60db2e740b974da7ff5b500a86", + "zh:f222038c55866e5121d24290824f56c76afff2562bdd47624e42a44d1c7c2002", + ] +} + +provider "registry.opentofu.org/hashicorp/random" { + version = "3.6.0" + constraints = ">= 3.1.0" + hashes = [ + "h1:6QMZ6JACl+V2t8daN5GTlw22EtG7nhc3BbkbJDw2a5M=", + "zh:486a1c921eab5c51a480f2eb0ad85173f207c9b7bb215f3893e58bc38d3b7c75", + "zh:6901b3afa4607d1e31934ba91ed2625215ada42b3518c3a9adeeac7a5f656dc3", + "zh:7e93752c9de710e417191353ad1a41b5a60432ab7ef4f8b556bf248297ec5e23", + "zh:c795d3d319e8ee7be972746b935963b7e772a6a14080261a35c03915c1f9ccb2", + "zh:cd4f8bcaf332828d1736c73874549c25e427737f136173c7b61e2df3db50e5d9", + "zh:e0103eb2e280989c3d9ffda5d6b413e8f583be21bc1d5754c6e9ca87ecc1c44a", + "zh:f4fbec2510322d5b7ad584a92436b5dbd0f2e897a3ec538932af59e245a4c8e4", + "zh:f5418842afd4aa7676e2456e425e8f573cb2b9bffd29bd7de09d91845644ab24", + "zh:f572a26f93d00ec42461ce478678366e570fa4497e2273f9d47f24cdfc4b42b4", + "zh:ff1f07c561a3f7f219b6fee1647a559933b5dd6181753e164c3978fd47a11685", + ] +} diff --git a/tofu/environments/prod/data-store/database/terragrunt.hcl b/tofu/environments/prod/data-store/database/terragrunt.hcl new file mode 100644 index 000000000..77a7ac842 --- /dev/null +++ b/tofu/environments/prod/data-store/database/terragrunt.hcl @@ -0,0 +1,62 @@ +include "root" { + path = find_in_parent_folders() + expose = true +} + +include "environment" { + path = find_in_parent_folders("environment.hcl") + expose = true +} + +terraform { + source = "../../../../modules/data-store/database" +} + +dependency "vpc" { + config_path = "../../network/vpc" + + mock_outputs_allowed_terraform_commands = ["init", "validate", "plan"] + mock_outputs = { + vpc_id = "mock_vpc_id" + database_subnet_group = "mock_subnet_group" + } +} + +dependency "cache" { + config_path = "../cache" + + mock_outputs_allowed_terraform_commands = ["init", "validate", "plan"] + mock_outputs = { + security_group_id = "mock_sg_id" + } +} + +dependency "backend" { + config_path = "../../services/backend-infra" + + mock_outputs_allowed_terraform_commands = ["init", "validate", "plan", "destroy"] + mock_outputs = { + security_group_id = "sg-mocksecuritygroup" + } +} + +locals { + environment = get_env("TF_VAR_environment") + name_prefix = get_env("TF_VAR_name_prefix") + region = get_env("TF_VAR_region") + + project_tags = include.root.locals.tags + environment_tags = include.environment.locals.tags + tags = "${merge(local.project_tags, local.environment_tags)}" +} + +inputs = { + environment = local.environment + name_prefix = local.name_prefix + region = local.region + vpc = dependency.vpc.outputs.vpc_id + subnet_group = dependency.vpc.outputs.database_subnet_group + elasticache_security_group = dependency.cache.outputs.security_group_id + backend_security_group = dependency.backend.outputs.security_group_id + tags = local.tags +} \ No newline at end of file diff --git a/tofu/environments/prod/environment.hcl b/tofu/environments/prod/environment.hcl new file mode 100644 index 000000000..6aa839efa --- /dev/null +++ b/tofu/environments/prod/environment.hcl @@ -0,0 +1,10 @@ +locals { + environment_vars = yamldecode(file("environment_vars.yaml")) + + environment = local.environment_vars.environment + region = local.environment_vars.region + + tags = { + environment = local.environment + } +} \ No newline at end of file diff --git a/tofu/environments/prod/environment_vars.yaml b/tofu/environments/prod/environment_vars.yaml new file mode 100644 index 000000000..fb2734aec --- /dev/null +++ b/tofu/environments/prod/environment_vars.yaml @@ -0,0 +1,4 @@ +--- +environment: prod +region: us-east-1 +... \ No newline at end of file diff --git a/tofu/environments/prod/network/vpc/.terraform.lock.hcl b/tofu/environments/prod/network/vpc/.terraform.lock.hcl new file mode 100644 index 000000000..14c6af9ab --- /dev/null +++ b/tofu/environments/prod/network/vpc/.terraform.lock.hcl @@ -0,0 +1,20 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/hashicorp/aws" { + version = "5.46.0" + constraints = ">= 4.0.0, >= 5.30.0" + hashes = [ + "h1:/vOvEEgnd+OY/Bbz6uwwEW1EnlgWQWJsXw5NnwHQOUY=", + "zh:151d35ab9d67f39ab568f5713dd74f0856a7d7b59a8c9557d05eaf0fa305426f", + "zh:2ff7031712d6fca0fc826ca6f1749244cc9aee5141b75ec9aea084a2907d6c40", + "zh:4c7d81be3b3dbb0f46f4a2074c17c72fe4c0a768b92b0882ffff39fdbe6ba310", + "zh:5313b02b5a1d9ece5302f075975a5ac9ba143bb32a457952885ecaa6a44fc232", + "zh:676a050266346d0b07d188c70377d8fb3c85a7a4c605a3ed4f9c6fcfc0537c7f", + "zh:6a02981bff4bd3d00d260e4ce72e5d6e54a7c6ea038cfb664b7cae13cef59b9f", + "zh:8c2a218e7e8969080eb400dd3e6b4707c74e4b0ccad07baaf410efec959162e4", + "zh:d2ea4316ed8f0b92eb62f1c676f7304081730a5cefbd5b36dae0f7bb91305016", + "zh:e310721c4d275a2e0cd222bdbac08676f62153d55c7dd0fbcbbcc2e919e3557f", + "zh:f52ed32e0393840c059fcfdac8022b50a58cffb0e3eff1fda21a58fc68562fe0", + ] +} diff --git a/tofu/environments/prod/network/vpc/terragrunt.hcl b/tofu/environments/prod/network/vpc/terragrunt.hcl new file mode 100644 index 000000000..f3bac5f91 --- /dev/null +++ b/tofu/environments/prod/network/vpc/terragrunt.hcl @@ -0,0 +1,31 @@ +include "root" { + path = find_in_parent_folders() + expose = true +} + +include "environment" { + path = find_in_parent_folders("environment.hcl") + expose = true +} + +terraform { + source = "../../../../modules/network/vpc" +} + +locals { + environment = get_env("TF_VAR_environment") + name_prefix = get_env("TF_VAR_name_prefix") + region = get_env("TF_VAR_region") + + project_tags = include.root.locals.tags + environment_tags = include.environment.locals.tags + tags = "${merge(local.project_tags, local.environment_tags)}" +} + +inputs = { + environment = local.environment + name_prefix = local.name_prefix + region = local.region + vpc_cidr = "10.0.0.0/16" + tags = local.tags +} \ No newline at end of file diff --git a/tofu/environments/prod/services/backend-infra/.terraform.lock.hcl b/tofu/environments/prod/services/backend-infra/.terraform.lock.hcl new file mode 100644 index 000000000..8d87a3f64 --- /dev/null +++ b/tofu/environments/prod/services/backend-infra/.terraform.lock.hcl @@ -0,0 +1,37 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/hashicorp/aws" { + version = "5.46.0" + constraints = ">= 4.66.1, >= 5.46.0" + hashes = [ + "h1:/vOvEEgnd+OY/Bbz6uwwEW1EnlgWQWJsXw5NnwHQOUY=", + "zh:151d35ab9d67f39ab568f5713dd74f0856a7d7b59a8c9557d05eaf0fa305426f", + "zh:2ff7031712d6fca0fc826ca6f1749244cc9aee5141b75ec9aea084a2907d6c40", + "zh:4c7d81be3b3dbb0f46f4a2074c17c72fe4c0a768b92b0882ffff39fdbe6ba310", + "zh:5313b02b5a1d9ece5302f075975a5ac9ba143bb32a457952885ecaa6a44fc232", + "zh:676a050266346d0b07d188c70377d8fb3c85a7a4c605a3ed4f9c6fcfc0537c7f", + "zh:6a02981bff4bd3d00d260e4ce72e5d6e54a7c6ea038cfb664b7cae13cef59b9f", + "zh:8c2a218e7e8969080eb400dd3e6b4707c74e4b0ccad07baaf410efec959162e4", + "zh:d2ea4316ed8f0b92eb62f1c676f7304081730a5cefbd5b36dae0f7bb91305016", + "zh:e310721c4d275a2e0cd222bdbac08676f62153d55c7dd0fbcbbcc2e919e3557f", + "zh:f52ed32e0393840c059fcfdac8022b50a58cffb0e3eff1fda21a58fc68562fe0", + ] +} + +provider "registry.opentofu.org/hashicorp/random" { + version = "3.6.1" + hashes = [ + "h1:egGGMQ18ihxoFBTgL/6aRL2N5/0bTI738Mg+TTsvBHA=", + "zh:1208af24d1f66e858740812dd5da12e8951b1ca75cc6edb1975ba22bfdeefb1b", + "zh:19137e9b4d3c15e1d99d2352888b98ec0e69bd5b2e89049150379d7bbd115063", + "zh:26613834a1a8ac60390c7a4cbd4cb794b01dfe237d2b0c10f132f3e434a21e03", + "zh:2cbe4425918f3f401609d89e6381f7d120493d637a3d103d827f0c0fd00b1600", + "zh:44ef27a972540435efa88f323280f96d6ac77934079225e7fcc3560cc28aae59", + "zh:8c5d4ca7d1ce007f7c055807cde77aad4685eb807ff802c93ffbec8589068f17", + "zh:9a4fa908d6af48805c862cd4f3a1031d552b96d863a94263e390ac92915d74a9", + "zh:ba396849f0f6d488784f6039095634e1c84e67e31375f3d17218fcf8ce952cb8", + "zh:cb695db8798957bd64ce411f061307e39cb2baa69668b4d42ccf010db47d2e39", + "zh:d02704bf99a93dc0b1ca00bd6051df9c431fbe17cd662a1ab58db1b96264a26f", + ] +} diff --git a/tofu/environments/prod/services/backend-infra/terragrunt.hcl b/tofu/environments/prod/services/backend-infra/terragrunt.hcl new file mode 100644 index 000000000..4b1289993 --- /dev/null +++ b/tofu/environments/prod/services/backend-infra/terragrunt.hcl @@ -0,0 +1,52 @@ +include "root" { + path = find_in_parent_folders() + expose = true +} + +include "environment" { + path = find_in_parent_folders("environment.hcl") + expose = true +} + +terraform { + source = "../../../../modules/services/backend-infra" +} + +dependency "vpc" { + config_path = "../../network/vpc" + + mock_outputs_allowed_terraform_commands = ["init", "validate", "plan"] + mock_outputs = { + vpc_id = "mock_vpc_id" + subnets = [] + private_subnets = [] + ecr_endpoint_security_group = "mock_sg" + secrets_endpoint_security_group = "mock_sg" + logs_endpoint_security_group = "mock_sg" + database_subnet_cidrs = ["10.0.1.0/24", "10.0.2.0/24"] + } +} + +locals { + environment = get_env("TF_VAR_environment") + name_prefix = get_env("TF_VAR_name_prefix") + region = get_env("TF_VAR_region") + + project_tags = include.root.locals.tags + environment_tags = include.environment.locals.tags + tags = "${merge(local.project_tags, local.environment_tags)}" +} + +inputs = { + environment = local.environment + name_prefix = local.name_prefix + region = local.region + vpc = dependency.vpc.outputs.vpc_id + subnets = dependency.vpc.outputs.public_subnets + ecr_endpoint_security_group = dependency.vpc.outputs.ecr_endpoint_security_group + secrets_endpoint_security_group = dependency.vpc.outputs.secrets_endpoint_security_group + logs_endpoint_security_group = dependency.vpc.outputs.logs_endpoint_security_group + database_subnet_cidrs = dependency.vpc.outputs.database_subnet_cidrs + ssl_cert = "arn:aws:acm:us-east-1:768512802988:certificate/4a53e27b-0cd3-4855-a13f-5bac50015e43" + tags = local.tags +} \ No newline at end of file diff --git a/tofu/environments/prod/services/backend-service/.terraform.lock.hcl b/tofu/environments/prod/services/backend-service/.terraform.lock.hcl new file mode 100644 index 000000000..839b3300a --- /dev/null +++ b/tofu/environments/prod/services/backend-service/.terraform.lock.hcl @@ -0,0 +1,19 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/hashicorp/aws" { + version = "5.46.0" + hashes = [ + "h1:/vOvEEgnd+OY/Bbz6uwwEW1EnlgWQWJsXw5NnwHQOUY=", + "zh:151d35ab9d67f39ab568f5713dd74f0856a7d7b59a8c9557d05eaf0fa305426f", + "zh:2ff7031712d6fca0fc826ca6f1749244cc9aee5141b75ec9aea084a2907d6c40", + "zh:4c7d81be3b3dbb0f46f4a2074c17c72fe4c0a768b92b0882ffff39fdbe6ba310", + "zh:5313b02b5a1d9ece5302f075975a5ac9ba143bb32a457952885ecaa6a44fc232", + "zh:676a050266346d0b07d188c70377d8fb3c85a7a4c605a3ed4f9c6fcfc0537c7f", + "zh:6a02981bff4bd3d00d260e4ce72e5d6e54a7c6ea038cfb664b7cae13cef59b9f", + "zh:8c2a218e7e8969080eb400dd3e6b4707c74e4b0ccad07baaf410efec959162e4", + "zh:d2ea4316ed8f0b92eb62f1c676f7304081730a5cefbd5b36dae0f7bb91305016", + "zh:e310721c4d275a2e0cd222bdbac08676f62153d55c7dd0fbcbbcc2e919e3557f", + "zh:f52ed32e0393840c059fcfdac8022b50a58cffb0e3eff1fda21a58fc68562fe0", + ] +} diff --git a/tofu/environments/prod/services/backend-service/terragrunt.hcl b/tofu/environments/prod/services/backend-service/terragrunt.hcl new file mode 100644 index 000000000..f66551520 --- /dev/null +++ b/tofu/environments/prod/services/backend-service/terragrunt.hcl @@ -0,0 +1,89 @@ +include "root" { + path = find_in_parent_folders() + expose = true +} + +include "env" { + path = find_in_parent_folders("environment.hcl") + expose = true +} + +terraform { + source = "../../../../modules/services/backend-service" +} + +dependency "vpc" { + config_path = "../../network/vpc" + + mock_outputs_allowed_terraform_commands = ["init", "validate", "plan"] + mock_outputs = { + private_subnets = ["subnet-mocksubnet1234567"] + ecs_execution_role = "arn:aws:iam::768512802988:role/mockrolearn" + } +} + +dependency "backend-infra" { + config_path = "../backend-infra" + + mock_outputs_allowed_terraform_commands = ["init", "validate", "plan"] + mock_outputs = { + target_group_arn = "arn:aws:elasticloadbalancing:us-east-1:768512802988:targetgroup/mocktg/12345678901234" + log_group = "MOCK_LOGS" + cluster_id = "MOCK_CLUSTER_ID" + security_group_id = "MOCK_SG" + } +} + +dependency "database" { + config_path = "../../data-store/database" + + mock_outputs_allowed_terraform_commands = ["init", "validate", "plan"] + mock_outputs = { + db_secret = "arn:aws:secretsmanager:us-east-1:768512802988:secret:mocksecretarn" + } +} + +dependency "cache" { + config_path = "../../data-store/cache" + + mock_outputs_allowed_terraform_commands = ["init", "validate", "plan"] + mock_outputs = { + redis_endpoint = "mockcache.serverless.use1.cache.amazonaws.com" + } +} + +locals { + environment = get_env("TF_VAR_environment") + name_prefix = get_env("TF_VAR_name_prefix") + region = get_env("TF_VAR_region") + short_name = include.root.locals.short_name + project_tags = include.root.locals.tags + environment_tags = include.env.locals.tags + tags = "${merge(local.project_tags, local.environment_tags)}" +} + +inputs = { + name_prefix = local.name_prefix + region = local.region + subnets = dependency.vpc.outputs.private_subnets + log_group = dependency.backend-infra.outputs.log_group + target_group_arn = dependency.backend-infra.outputs.target_group_arn + security_group = dependency.backend-infra.outputs.security_group_id + ecs_cluster = dependency.backend-infra.outputs.cluster_id + task_execution_role = dependency.vpc.outputs.ecs_execution_role + frontend_url = get_env("TF_VAR_frontend_url") + short_base_url = get_env("TF_VAR_short_base_url") + app_env = get_env("TF_VAR_app_env") + sentry_dsn = get_env("TF_VAR_sentry_dsn") + zoom_auth_callback = get_env("TF_VAR_zoom_callback") + short_name = local.short_name + database_secret = dependency.database.outputs.db_secret + db_enc_secret = get_env("TF_VAR_db_enc_secret") + smtp_secret = get_env("TF_VAR_smtp_secret") + google_oauth_secret = get_env("TF_VAR_google_oauth_secret") + zoom_secret = get_env("TF_VAR_zoom_secret") + fxa_secret = get_env("TF_VAR_fxa_secret") + redis_endpoint = dependency.cache.outputs.endpoint + log_level = get_env("TF_VAR_log_level") + tags = local.tags +} \ No newline at end of file diff --git a/tofu/environments/prod/services/frontend-infra/.terraform.lock.hcl b/tofu/environments/prod/services/frontend-infra/.terraform.lock.hcl new file mode 100644 index 000000000..839b3300a --- /dev/null +++ b/tofu/environments/prod/services/frontend-infra/.terraform.lock.hcl @@ -0,0 +1,19 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/hashicorp/aws" { + version = "5.46.0" + hashes = [ + "h1:/vOvEEgnd+OY/Bbz6uwwEW1EnlgWQWJsXw5NnwHQOUY=", + "zh:151d35ab9d67f39ab568f5713dd74f0856a7d7b59a8c9557d05eaf0fa305426f", + "zh:2ff7031712d6fca0fc826ca6f1749244cc9aee5141b75ec9aea084a2907d6c40", + "zh:4c7d81be3b3dbb0f46f4a2074c17c72fe4c0a768b92b0882ffff39fdbe6ba310", + "zh:5313b02b5a1d9ece5302f075975a5ac9ba143bb32a457952885ecaa6a44fc232", + "zh:676a050266346d0b07d188c70377d8fb3c85a7a4c605a3ed4f9c6fcfc0537c7f", + "zh:6a02981bff4bd3d00d260e4ce72e5d6e54a7c6ea038cfb664b7cae13cef59b9f", + "zh:8c2a218e7e8969080eb400dd3e6b4707c74e4b0ccad07baaf410efec959162e4", + "zh:d2ea4316ed8f0b92eb62f1c676f7304081730a5cefbd5b36dae0f7bb91305016", + "zh:e310721c4d275a2e0cd222bdbac08676f62153d55c7dd0fbcbbcc2e919e3557f", + "zh:f52ed32e0393840c059fcfdac8022b50a58cffb0e3eff1fda21a58fc68562fe0", + ] +} diff --git a/tofu/environments/prod/services/frontend-infra/terragrunt.hcl b/tofu/environments/prod/services/frontend-infra/terragrunt.hcl new file mode 100644 index 000000000..ed8608d7b --- /dev/null +++ b/tofu/environments/prod/services/frontend-infra/terragrunt.hcl @@ -0,0 +1,48 @@ +include "root" { + path = find_in_parent_folders() + expose = true +} + +include "environment" { + path = find_in_parent_folders("environment.hcl") + expose = true +} + +terraform { + source = "../../../../modules/services/frontend-infra" +} + +dependency "backend" { + config_path = "../../services/backend-infra" + + mock_outputs_allowed_terraform_commands = ["init", "validate", "plan", "destroy"] + mock_outputs = { + alb_id = "mock_alb_id" + dns_name = "mock_dns_name" + x_allow_secret = "mock_secret" + } +} + +locals { + environment = get_env("TF_VAR_environment") + name_prefix = get_env("TF_VAR_name_prefix") + region = get_env("TF_VAR_region") + + project_tags = include.root.locals.tags + environment_tags = include.environment.locals.tags + tags = "${merge(local.project_tags, local.environment_tags)}" + + + ssl_cert = "arn:aws:acm:us-east-1:768512802988:certificate/4a53e27b-0cd3-4855-a13f-5bac50015e43" +} + +inputs = { + environment = local.environment + name_prefix = local.name_prefix + region = local.region + tags = local.tags + ssl_cert = local.ssl_cert + backend_id = dependency.backend.outputs.alb_id + backend_dns_name = dependency.backend.outputs.dns_name + x_allow_secret = dependency.backend.outputs.x_allow_secret +} \ No newline at end of file diff --git a/tofu/environments/prod/terraform/tfbackend/.terraform.lock.hcl b/tofu/environments/prod/terraform/tfbackend/.terraform.lock.hcl new file mode 100644 index 000000000..839b3300a --- /dev/null +++ b/tofu/environments/prod/terraform/tfbackend/.terraform.lock.hcl @@ -0,0 +1,19 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/hashicorp/aws" { + version = "5.46.0" + hashes = [ + "h1:/vOvEEgnd+OY/Bbz6uwwEW1EnlgWQWJsXw5NnwHQOUY=", + "zh:151d35ab9d67f39ab568f5713dd74f0856a7d7b59a8c9557d05eaf0fa305426f", + "zh:2ff7031712d6fca0fc826ca6f1749244cc9aee5141b75ec9aea084a2907d6c40", + "zh:4c7d81be3b3dbb0f46f4a2074c17c72fe4c0a768b92b0882ffff39fdbe6ba310", + "zh:5313b02b5a1d9ece5302f075975a5ac9ba143bb32a457952885ecaa6a44fc232", + "zh:676a050266346d0b07d188c70377d8fb3c85a7a4c605a3ed4f9c6fcfc0537c7f", + "zh:6a02981bff4bd3d00d260e4ce72e5d6e54a7c6ea038cfb664b7cae13cef59b9f", + "zh:8c2a218e7e8969080eb400dd3e6b4707c74e4b0ccad07baaf410efec959162e4", + "zh:d2ea4316ed8f0b92eb62f1c676f7304081730a5cefbd5b36dae0f7bb91305016", + "zh:e310721c4d275a2e0cd222bdbac08676f62153d55c7dd0fbcbbcc2e919e3557f", + "zh:f52ed32e0393840c059fcfdac8022b50a58cffb0e3eff1fda21a58fc68562fe0", + ] +} diff --git a/tofu/environments/prod/terraform/tfbackend/terragrunt.hcl b/tofu/environments/prod/terraform/tfbackend/terragrunt.hcl new file mode 100644 index 000000000..74efdd318 --- /dev/null +++ b/tofu/environments/prod/terraform/tfbackend/terragrunt.hcl @@ -0,0 +1,28 @@ +include "root" { + path = find_in_parent_folders() + expose = true +} + +include "environment" { + path = find_in_parent_folders("environment.hcl") + expose = true +} + +terraform { + source = "../../../../modules/terraform/tfbackend" +} + +locals { + bucket_name = "tb-${include.root.locals.short_name}-${include.environment.locals.environment}-state" + table_name = "tb-${include.root.locals.short_name}-${include.environment.locals.environment}-locks" + + project_tags = include.root.locals.tags + environment_tags = include.environment.locals.tags + tags = "${merge(local.project_tags, local.environment_tags)}" +} + +inputs = { + bucket_name = local.bucket_name + table_name = local.table_name + tags = local.tags +} \ No newline at end of file diff --git a/tofu/environments/production/data-store/cache/.terraform.lock.hcl b/tofu/environments/production/data-store/cache/.terraform.lock.hcl new file mode 100644 index 000000000..b88b3b5eb --- /dev/null +++ b/tofu/environments/production/data-store/cache/.terraform.lock.hcl @@ -0,0 +1,19 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/hashicorp/aws" { + version = "5.41.0" + hashes = [ + "h1:Fx+3haIzgp5zo3zVxJDMpTUQcZ8z0g8eQLFud0hA0xc=", + "zh:28fda8bbfe6bdba53aa8a7ce1005e7d686bce1d604c6e0b58e32735162afc667", + "zh:3961d01ce92bc6fcb1cc0e267d6fc4270adf010d93e7890460c566b2f5761670", + "zh:85cf587abfdf6f306dc593232abb91cf5090296decaf6e84669dd92662f2f856", + "zh:9f9d2e81f493c0daba943211c8146100d4a90f7f09fd831f4e8dde2c5f8ab34a", + "zh:c7444bd54437f4e044dbe71353a5fc54fae5b96673c80ec42f3823e8890c5cd3", + "zh:d041d2a83a80a2be85297cff467ef3c0ae2887789f88197bda190e6d2b64399e", + "zh:db02a4756318595de2d72cad69c25bd29b61940ad3c91ddf06c32437170f9d56", + "zh:dd90187b8382e28347ca08f4642a405edbb50c27c94405367f55f8fafd6b42ad", + "zh:e8c47d26c221d6975d9905b4ffd4dc713fbafb60db2e740b974da7ff5b500a86", + "zh:f222038c55866e5121d24290824f56c76afff2562bdd47624e42a44d1c7c2002", + ] +} diff --git a/tofu/environments/production/data-store/cache/terragrunt.hcl b/tofu/environments/production/data-store/cache/terragrunt.hcl new file mode 100644 index 000000000..9b6781d48 --- /dev/null +++ b/tofu/environments/production/data-store/cache/terragrunt.hcl @@ -0,0 +1,51 @@ +include "root" { + path = find_in_parent_folders() + expose = true +} + +include "environment" { + path = find_in_parent_folders("environment.hcl") + expose = true +} + +terraform { + source = "../../../../modules/data-store/cache" +} + +dependency "vpc" { + config_path = "../../network/vpc" + + mock_outputs_allowed_terraform_commands = ["init", "validate", "plan"] + mock_outputs = { + vpc_id = "mock_vpc_id" + database_subnets = [] + source_security_groups = [] + } +} + +dependency "backend" { + config_path = "../../services/backend-infra" + + mock_outputs_allowed_terraform_commands = ["init", "validate", "plan", "destroy"] + mock_outputs = { + security_group_id = "mock_sg_id" + } +} + +locals { + environment = include.environment.locals.environment + name_prefix = "tb-${include.root.locals.short_name}-${include.environment.locals.environment}" + region = include.environment.locals.region + + project_tags = include.root.locals.tags + environment_tags = include.environment.locals.tags + tags = "${merge(local.project_tags, local.environment_tags)}" +} + +inputs = { + name_prefix = local.name_prefix + vpc = dependency.vpc.outputs.vpc_id + subnets = dependency.vpc.outputs.database_subnets + source_security_groups = [dependency.backend.outputs.security_group_id] + tags = local.tags +} \ No newline at end of file diff --git a/tofu/environments/production/data-store/database/.terraform.lock.hcl b/tofu/environments/production/data-store/database/.terraform.lock.hcl new file mode 100644 index 000000000..520f9bfec --- /dev/null +++ b/tofu/environments/production/data-store/database/.terraform.lock.hcl @@ -0,0 +1,38 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/hashicorp/aws" { + version = "5.41.0" + constraints = ">= 5.36.0" + hashes = [ + "h1:Fx+3haIzgp5zo3zVxJDMpTUQcZ8z0g8eQLFud0hA0xc=", + "zh:28fda8bbfe6bdba53aa8a7ce1005e7d686bce1d604c6e0b58e32735162afc667", + "zh:3961d01ce92bc6fcb1cc0e267d6fc4270adf010d93e7890460c566b2f5761670", + "zh:85cf587abfdf6f306dc593232abb91cf5090296decaf6e84669dd92662f2f856", + "zh:9f9d2e81f493c0daba943211c8146100d4a90f7f09fd831f4e8dde2c5f8ab34a", + "zh:c7444bd54437f4e044dbe71353a5fc54fae5b96673c80ec42f3823e8890c5cd3", + "zh:d041d2a83a80a2be85297cff467ef3c0ae2887789f88197bda190e6d2b64399e", + "zh:db02a4756318595de2d72cad69c25bd29b61940ad3c91ddf06c32437170f9d56", + "zh:dd90187b8382e28347ca08f4642a405edbb50c27c94405367f55f8fafd6b42ad", + "zh:e8c47d26c221d6975d9905b4ffd4dc713fbafb60db2e740b974da7ff5b500a86", + "zh:f222038c55866e5121d24290824f56c76afff2562bdd47624e42a44d1c7c2002", + ] +} + +provider "registry.opentofu.org/hashicorp/random" { + version = "3.6.0" + constraints = ">= 3.1.0" + hashes = [ + "h1:6QMZ6JACl+V2t8daN5GTlw22EtG7nhc3BbkbJDw2a5M=", + "zh:486a1c921eab5c51a480f2eb0ad85173f207c9b7bb215f3893e58bc38d3b7c75", + "zh:6901b3afa4607d1e31934ba91ed2625215ada42b3518c3a9adeeac7a5f656dc3", + "zh:7e93752c9de710e417191353ad1a41b5a60432ab7ef4f8b556bf248297ec5e23", + "zh:c795d3d319e8ee7be972746b935963b7e772a6a14080261a35c03915c1f9ccb2", + "zh:cd4f8bcaf332828d1736c73874549c25e427737f136173c7b61e2df3db50e5d9", + "zh:e0103eb2e280989c3d9ffda5d6b413e8f583be21bc1d5754c6e9ca87ecc1c44a", + "zh:f4fbec2510322d5b7ad584a92436b5dbd0f2e897a3ec538932af59e245a4c8e4", + "zh:f5418842afd4aa7676e2456e425e8f573cb2b9bffd29bd7de09d91845644ab24", + "zh:f572a26f93d00ec42461ce478678366e570fa4497e2273f9d47f24cdfc4b42b4", + "zh:ff1f07c561a3f7f219b6fee1647a559933b5dd6181753e164c3978fd47a11685", + ] +} diff --git a/tofu/environments/production/data-store/database/terragrunt.hcl b/tofu/environments/production/data-store/database/terragrunt.hcl new file mode 100644 index 000000000..6a8a0a46a --- /dev/null +++ b/tofu/environments/production/data-store/database/terragrunt.hcl @@ -0,0 +1,62 @@ +include "root" { + path = find_in_parent_folders() + expose = true +} + +include "environment" { + path = find_in_parent_folders("environment.hcl") + expose = true +} + +terraform { + source = "../../../../modules/data-store/database" +} + +dependency "vpc" { + config_path = "../../network/vpc" + + mock_outputs_allowed_terraform_commands = ["init", "validate", "plan"] + mock_outputs = { + vpc_id = "mock_vpc_id" + database_subnet_group = "mock_subnet_group" + } +} + +dependency "cache" { + config_path = "../cache" + + mock_outputs_allowed_terraform_commands = ["init", "validate", "plan"] + mock_outputs = { + security_group_id = "mock_sg_id" + } +} + +dependency "backend" { + config_path = "../../services/backend-infra" + + mock_outputs_allowed_terraform_commands = ["init", "validate", "plan", "destroy"] + mock_outputs = { + security_group_id = "sg-mocksecuritygroup" + } +} + +locals { + environment = include.environment.locals.environment + name_prefix = "tb-${include.root.locals.short_name}-${include.environment.locals.environment}" + region = include.environment.locals.region + + project_tags = include.root.locals.tags + environment_tags = include.environment.locals.tags + tags = "${merge(local.project_tags, local.environment_tags)}" +} + +inputs = { + environment = local.environment + name_prefix = local.name_prefix + region = local.region + vpc = dependency.vpc.outputs.vpc_id + subnet_group = dependency.vpc.outputs.database_subnet_group + elasticache_security_group = dependency.cache.outputs.security_group_id + backend_security_group = dependency.backend.outputs.security_group_id + tags = local.tags +} \ No newline at end of file diff --git a/tofu/environments/production/environment.hcl b/tofu/environments/production/environment.hcl new file mode 100644 index 000000000..6aa839efa --- /dev/null +++ b/tofu/environments/production/environment.hcl @@ -0,0 +1,10 @@ +locals { + environment_vars = yamldecode(file("environment_vars.yaml")) + + environment = local.environment_vars.environment + region = local.environment_vars.region + + tags = { + environment = local.environment + } +} \ No newline at end of file diff --git a/tofu/environments/production/environment_vars.yaml b/tofu/environments/production/environment_vars.yaml new file mode 100644 index 000000000..e415a0ef9 --- /dev/null +++ b/tofu/environments/production/environment_vars.yaml @@ -0,0 +1,4 @@ +--- +environment: production +region: us-east-1 +... \ No newline at end of file diff --git a/tofu/environments/production/network/vpc/.terraform.lock.hcl b/tofu/environments/production/network/vpc/.terraform.lock.hcl new file mode 100644 index 000000000..c8048244a --- /dev/null +++ b/tofu/environments/production/network/vpc/.terraform.lock.hcl @@ -0,0 +1,20 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/hashicorp/aws" { + version = "5.41.0" + constraints = ">= 4.0.0, >= 5.30.0" + hashes = [ + "h1:Fx+3haIzgp5zo3zVxJDMpTUQcZ8z0g8eQLFud0hA0xc=", + "zh:28fda8bbfe6bdba53aa8a7ce1005e7d686bce1d604c6e0b58e32735162afc667", + "zh:3961d01ce92bc6fcb1cc0e267d6fc4270adf010d93e7890460c566b2f5761670", + "zh:85cf587abfdf6f306dc593232abb91cf5090296decaf6e84669dd92662f2f856", + "zh:9f9d2e81f493c0daba943211c8146100d4a90f7f09fd831f4e8dde2c5f8ab34a", + "zh:c7444bd54437f4e044dbe71353a5fc54fae5b96673c80ec42f3823e8890c5cd3", + "zh:d041d2a83a80a2be85297cff467ef3c0ae2887789f88197bda190e6d2b64399e", + "zh:db02a4756318595de2d72cad69c25bd29b61940ad3c91ddf06c32437170f9d56", + "zh:dd90187b8382e28347ca08f4642a405edbb50c27c94405367f55f8fafd6b42ad", + "zh:e8c47d26c221d6975d9905b4ffd4dc713fbafb60db2e740b974da7ff5b500a86", + "zh:f222038c55866e5121d24290824f56c76afff2562bdd47624e42a44d1c7c2002", + ] +} diff --git a/tofu/environments/production/network/vpc/terragrunt.hcl b/tofu/environments/production/network/vpc/terragrunt.hcl new file mode 100644 index 000000000..edae031a7 --- /dev/null +++ b/tofu/environments/production/network/vpc/terragrunt.hcl @@ -0,0 +1,31 @@ +include "root" { + path = find_in_parent_folders() + expose = true +} + +include "environment" { + path = find_in_parent_folders("environment.hcl") + expose = true +} + +terraform { + source = "../../../../modules/network/vpc" +} + +locals { + environment = include.environment.locals.environment + name_prefix = "tb-${include.root.locals.short_name}-${include.environment.locals.environment}" + region = include.environment.locals.region + + project_tags = include.root.locals.tags + environment_tags = include.environment.locals.tags + tags = "${merge(local.project_tags, local.environment_tags)}" +} + +inputs = { + environment = local.environment + name_prefix = local.name_prefix + region = local.region + vpc_cidr = "10.0.0.0/16" + tags = local.tags +} \ No newline at end of file diff --git a/tofu/environments/production/services/backend-infra/.terraform.lock.hcl b/tofu/environments/production/services/backend-infra/.terraform.lock.hcl new file mode 100644 index 000000000..16bf2d314 --- /dev/null +++ b/tofu/environments/production/services/backend-infra/.terraform.lock.hcl @@ -0,0 +1,20 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/hashicorp/aws" { + version = "5.41.0" + constraints = ">= 4.66.1, >= 5.33.0" + hashes = [ + "h1:Fx+3haIzgp5zo3zVxJDMpTUQcZ8z0g8eQLFud0hA0xc=", + "zh:28fda8bbfe6bdba53aa8a7ce1005e7d686bce1d604c6e0b58e32735162afc667", + "zh:3961d01ce92bc6fcb1cc0e267d6fc4270adf010d93e7890460c566b2f5761670", + "zh:85cf587abfdf6f306dc593232abb91cf5090296decaf6e84669dd92662f2f856", + "zh:9f9d2e81f493c0daba943211c8146100d4a90f7f09fd831f4e8dde2c5f8ab34a", + "zh:c7444bd54437f4e044dbe71353a5fc54fae5b96673c80ec42f3823e8890c5cd3", + "zh:d041d2a83a80a2be85297cff467ef3c0ae2887789f88197bda190e6d2b64399e", + "zh:db02a4756318595de2d72cad69c25bd29b61940ad3c91ddf06c32437170f9d56", + "zh:dd90187b8382e28347ca08f4642a405edbb50c27c94405367f55f8fafd6b42ad", + "zh:e8c47d26c221d6975d9905b4ffd4dc713fbafb60db2e740b974da7ff5b500a86", + "zh:f222038c55866e5121d24290824f56c76afff2562bdd47624e42a44d1c7c2002", + ] +} diff --git a/tofu/environments/production/services/backend-infra/terragrunt.hcl b/tofu/environments/production/services/backend-infra/terragrunt.hcl new file mode 100644 index 000000000..93beded47 --- /dev/null +++ b/tofu/environments/production/services/backend-infra/terragrunt.hcl @@ -0,0 +1,52 @@ +include "root" { + path = find_in_parent_folders() + expose = true +} + +include "environment" { + path = find_in_parent_folders("environment.hcl") + expose = true +} + +terraform { + source = "../../../../modules/services/backend-infra" +} + +dependency "vpc" { + config_path = "../../network/vpc" + + mock_outputs_allowed_terraform_commands = ["init", "validate", "plan"] + mock_outputs = { + vpc_id = "mock_vpc_id" + subnets = [] + private_subnets = [] + ecr_endpoint_security_group = "mock_sg" + secrets_endpoint_security_group = "mock_sg" + logs_endpoint_security_group = "mock_sg" + database_subnet_cidrs = ["10.0.1.0/24", "10.0.2.0/24"] + } +} + +locals { + environment = include.environment.locals.environment + name_prefix = "tb-${include.root.locals.short_name}-${include.environment.locals.environment}" + region = include.environment.locals.region + + project_tags = include.root.locals.tags + environment_tags = include.environment.locals.tags + tags = "${merge(local.project_tags, local.environment_tags)}" +} + +inputs = { + environment = local.environment + name_prefix = local.name_prefix + region = local.region + vpc = dependency.vpc.outputs.vpc_id + subnets = dependency.vpc.outputs.private_subnets + ecr_endpoint_security_group = dependency.vpc.outputs.ecr_endpoint_security_group + secrets_endpoint_security_group = dependency.vpc.outputs.secrets_endpoint_security_group + logs_endpoint_security_group = dependency.vpc.outputs.logs_endpoint_security_group + database_subnet_cidrs = dependency.vpc.outputs.database_subnet_cidrs + ssl_cert = "arn:aws:acm:us-east-1:768512802988:certificate/4a53e27b-0cd3-4855-a13f-5bac50015e43" + tags = local.tags +} \ No newline at end of file diff --git a/tofu/environments/production/services/backend-service/terragrunt.hcl b/tofu/environments/production/services/backend-service/terragrunt.hcl new file mode 100644 index 000000000..2a2243204 --- /dev/null +++ b/tofu/environments/production/services/backend-service/terragrunt.hcl @@ -0,0 +1,90 @@ +include "root" { + path = find_in_parent_folders() + expose = true +} + +include "env" { + path = find_in_parent_folders("environment.hcl") + expose = true +} + +terraform { + source = "../../../../modules/services/backend-service" +} + +dependency "vpc" { + config_path = "../../network/vpc" + + mock_outputs_allowed_terraform_commands = ["init", "validate", "plan"] + mock_outputs = { + private_subnets = ["subnet-mocksubnet1234567"] + ecs_execution_role = "arn:aws:iam::768512802988:role/mockrolearn" + } +} + +dependency "backend-infra" { + config_path = "../backend-infra" + + mock_outputs_allowed_terraform_commands = ["init", "validate", "plan"] + mock_outputs = { + target_group_arn = "arn:aws:elasticloadbalancing:us-east-1:768512802988:targetgroup/mocktg/12345678901234" + log_group = "MOCK_LOGS" + cluster_id = "MOCK_CLUSTER_ID" + security_group_id = "MOCK_SG" + } +} + +dependency "database" { + config_path = "../../data-store/database" + + mock_outputs_allowed_terraform_commands = ["init", "validate", "plan"] + mock_outputs = { + db_secret = "arn:aws:secretsmanager:us-east-1:768512802988:secret:mocksecretarn" + } +} + +dependency "cache" { + config_path = "../../data-store/cache" + + mock_outputs_allowed_terraform_commands = ["init", "validate", "plan"] + mock_outputs = { + redis_endpoint = "mockcache.serverless.use1.cache.amazonaws.com" + } +} + +locals { + environment = get_env("TF_VAR_environment") + name_prefix = get_env("TF_VAR_name_prefix") + region = get_env("TF_VAR_region") + project = include.root.locals.project + short_name = include.root.locals.short_name + project_tags = include.root.locals.tags + environment_tags = include.env.locals.tags + tags = "${merge(local.project_tags, local.environment_tags)}" +} + +inputs = { + name_prefix = local.name_prefix + region = local.region + subnets = dependency.vpc.outputs.private_subnets + log_group = dependency.backend-infra.outputs.log_group + target_group_arn = dependency.backend-infra.outputs.target_group_arn + security_group = dependency.backend-infra.outputs.security_group_id + ecs_cluster = dependency.backend-infra.outputs.cluster_id + task_execution_role = dependency.vpc.outputs.ecs_execution_role + frontend_url = get_env("TF_VAR_frontend_url") + short_base_url = get_env("TF_VAR_short_base_url") + app_env = get_env("TF_VAR_app_env") + sentry_dsn = get_env("TF_VAR_sentry_dsn") + zoom_auth_callback = get_env("TF_VAR_zoom_callback") + short_name = local.short_name + database_secret = dependency.database.outputs.db_secret + db_enc_secret = get_env("TF_VAR_db_enc_secret") + smtp_secret = get_env("TF_VAR_smtp_secret") + google_oauth_secret = get_env("TF_VAR_google_oauth_secret") + zoom_secret = get_env("TF_VAR_zoom_secret") + fxa_secret = get_env("TF_VAR_fxa_secret") + log_level = get_env("TF_VAR_log_level") + redis_endpoint = dependency.cache.outputs.endpoint + tags = local.tags +} \ No newline at end of file diff --git a/tofu/environments/production/services/frontend/.terraform.lock.hcl b/tofu/environments/production/services/frontend/.terraform.lock.hcl new file mode 100644 index 000000000..b88b3b5eb --- /dev/null +++ b/tofu/environments/production/services/frontend/.terraform.lock.hcl @@ -0,0 +1,19 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/hashicorp/aws" { + version = "5.41.0" + hashes = [ + "h1:Fx+3haIzgp5zo3zVxJDMpTUQcZ8z0g8eQLFud0hA0xc=", + "zh:28fda8bbfe6bdba53aa8a7ce1005e7d686bce1d604c6e0b58e32735162afc667", + "zh:3961d01ce92bc6fcb1cc0e267d6fc4270adf010d93e7890460c566b2f5761670", + "zh:85cf587abfdf6f306dc593232abb91cf5090296decaf6e84669dd92662f2f856", + "zh:9f9d2e81f493c0daba943211c8146100d4a90f7f09fd831f4e8dde2c5f8ab34a", + "zh:c7444bd54437f4e044dbe71353a5fc54fae5b96673c80ec42f3823e8890c5cd3", + "zh:d041d2a83a80a2be85297cff467ef3c0ae2887789f88197bda190e6d2b64399e", + "zh:db02a4756318595de2d72cad69c25bd29b61940ad3c91ddf06c32437170f9d56", + "zh:dd90187b8382e28347ca08f4642a405edbb50c27c94405367f55f8fafd6b42ad", + "zh:e8c47d26c221d6975d9905b4ffd4dc713fbafb60db2e740b974da7ff5b500a86", + "zh:f222038c55866e5121d24290824f56c76afff2562bdd47624e42a44d1c7c2002", + ] +} diff --git a/tofu/environments/production/services/frontend/terragrunt.hcl b/tofu/environments/production/services/frontend/terragrunt.hcl new file mode 100644 index 000000000..5e4c5e5c6 --- /dev/null +++ b/tofu/environments/production/services/frontend/terragrunt.hcl @@ -0,0 +1,48 @@ +include "root" { + path = find_in_parent_folders() + expose = true +} + +include "environment" { + path = find_in_parent_folders("environment.hcl") + expose = true +} + +terraform { + source = "../../../../modules/services/frontend" +} + +dependency "backend" { + config_path = "../../services/backend" + + mock_outputs_allowed_terraform_commands = ["init", "validate", "plan", "destroy"] + mock_outputs = { + alb_id = "mock_alb_id" + dns_name = "mock_dns_name" + x_allow_secret = "mock_secret" + } +} + +locals { + environment = include.environment.locals.environment + name_prefix = "tb-${include.root.locals.short_name}-${include.environment.locals.environment}" + region = include.environment.locals.region + + project_tags = include.root.locals.tags + environment_tags = include.environment.locals.tags + tags = "${merge(local.project_tags, local.environment_tags)}" + + + ssl_cert = "arn:aws:acm:us-east-1:768512802988:certificate/4a53e27b-0cd3-4855-a13f-5bac50015e43" +} + +inputs = { + environment = local.environment + name_prefix = local.name_prefix + region = local.region + tags = local.tags + ssl_cert = local.ssl_cert + backend_id = dependency.backend.outputs.alb_id + backend_dns_name = dependency.backend.outputs.dns_name + x_allow_secret = dependency.backend.outputs.x_allow_secret +} \ No newline at end of file diff --git a/tofu/environments/production/terraform/tfbackend/.terraform.lock.hcl b/tofu/environments/production/terraform/tfbackend/.terraform.lock.hcl new file mode 100644 index 000000000..b88b3b5eb --- /dev/null +++ b/tofu/environments/production/terraform/tfbackend/.terraform.lock.hcl @@ -0,0 +1,19 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/hashicorp/aws" { + version = "5.41.0" + hashes = [ + "h1:Fx+3haIzgp5zo3zVxJDMpTUQcZ8z0g8eQLFud0hA0xc=", + "zh:28fda8bbfe6bdba53aa8a7ce1005e7d686bce1d604c6e0b58e32735162afc667", + "zh:3961d01ce92bc6fcb1cc0e267d6fc4270adf010d93e7890460c566b2f5761670", + "zh:85cf587abfdf6f306dc593232abb91cf5090296decaf6e84669dd92662f2f856", + "zh:9f9d2e81f493c0daba943211c8146100d4a90f7f09fd831f4e8dde2c5f8ab34a", + "zh:c7444bd54437f4e044dbe71353a5fc54fae5b96673c80ec42f3823e8890c5cd3", + "zh:d041d2a83a80a2be85297cff467ef3c0ae2887789f88197bda190e6d2b64399e", + "zh:db02a4756318595de2d72cad69c25bd29b61940ad3c91ddf06c32437170f9d56", + "zh:dd90187b8382e28347ca08f4642a405edbb50c27c94405367f55f8fafd6b42ad", + "zh:e8c47d26c221d6975d9905b4ffd4dc713fbafb60db2e740b974da7ff5b500a86", + "zh:f222038c55866e5121d24290824f56c76afff2562bdd47624e42a44d1c7c2002", + ] +} diff --git a/tofu/environments/production/terraform/tfbackend/terragrunt.hcl b/tofu/environments/production/terraform/tfbackend/terragrunt.hcl new file mode 100644 index 000000000..74efdd318 --- /dev/null +++ b/tofu/environments/production/terraform/tfbackend/terragrunt.hcl @@ -0,0 +1,28 @@ +include "root" { + path = find_in_parent_folders() + expose = true +} + +include "environment" { + path = find_in_parent_folders("environment.hcl") + expose = true +} + +terraform { + source = "../../../../modules/terraform/tfbackend" +} + +locals { + bucket_name = "tb-${include.root.locals.short_name}-${include.environment.locals.environment}-state" + table_name = "tb-${include.root.locals.short_name}-${include.environment.locals.environment}-locks" + + project_tags = include.root.locals.tags + environment_tags = include.environment.locals.tags + tags = "${merge(local.project_tags, local.environment_tags)}" +} + +inputs = { + bucket_name = local.bucket_name + table_name = local.table_name + tags = local.tags +} \ No newline at end of file diff --git a/tofu/environments/project_vars.yaml b/tofu/environments/project_vars.yaml new file mode 100644 index 000000000..02925aa85 --- /dev/null +++ b/tofu/environments/project_vars.yaml @@ -0,0 +1,4 @@ +--- +project: appointment +short_name: apmt +... \ No newline at end of file diff --git a/tofu/environments/stage/data-store/cache/.terraform.lock.hcl b/tofu/environments/stage/data-store/cache/.terraform.lock.hcl new file mode 100644 index 000000000..69708e2d9 --- /dev/null +++ b/tofu/environments/stage/data-store/cache/.terraform.lock.hcl @@ -0,0 +1,38 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/hashicorp/aws" { + version = "5.50.0" + constraints = ">= 5.46.0" + hashes = [ + "h1:ZN7MLKklx+LTYZvRerNw5O2qHA913Xg9eQW99uqfbI8=", + "zh:17345c5dee93b49009c7941b1e47bb6fe94376e2d0ffc83bfd80f75c9857e2cd", + "zh:2ed80ee2aa5db4fe29700e5488cd67409331a5a586102511a512c34e0f31bc38", + "zh:30cbf46810151a2f587bbeb4172e3534186e4cfae03d4d91a90dc4d3b304acb4", + "zh:449b4562b8530e2d3e7555d3ed9bc0a5a9ead1067784e86572b26b98f87a073f", + "zh:7a853b8ae08304c8d4e8d37a607e21d1a06e0956b3aef9e52b569dc556438d90", + "zh:8a6923372241b0b4aa58631e5a9487b6c8eebd456d001422f0b05f707ec29744", + "zh:90e1b8c7a51a97d2cae255b225f9260bf75bff72c13b791453fbed8f2d2ac729", + "zh:a0b4f62de237913e22387630668a79754fb23c231ea8629615722287cf5e58c5", + "zh:c4632d2dad5ec905f625b75b80d996047967c1d2105c11daad8cbc69972fdeda", + "zh:ce8866ce789f27e97b890dd8a82dea101deb66daf2e651ed387584aecc51d8b4", + ] +} + +provider "registry.opentofu.org/hashicorp/random" { + version = "3.6.1" + constraints = ">= 3.6.1" + hashes = [ + "h1:egGGMQ18ihxoFBTgL/6aRL2N5/0bTI738Mg+TTsvBHA=", + "zh:1208af24d1f66e858740812dd5da12e8951b1ca75cc6edb1975ba22bfdeefb1b", + "zh:19137e9b4d3c15e1d99d2352888b98ec0e69bd5b2e89049150379d7bbd115063", + "zh:26613834a1a8ac60390c7a4cbd4cb794b01dfe237d2b0c10f132f3e434a21e03", + "zh:2cbe4425918f3f401609d89e6381f7d120493d637a3d103d827f0c0fd00b1600", + "zh:44ef27a972540435efa88f323280f96d6ac77934079225e7fcc3560cc28aae59", + "zh:8c5d4ca7d1ce007f7c055807cde77aad4685eb807ff802c93ffbec8589068f17", + "zh:9a4fa908d6af48805c862cd4f3a1031d552b96d863a94263e390ac92915d74a9", + "zh:ba396849f0f6d488784f6039095634e1c84e67e31375f3d17218fcf8ce952cb8", + "zh:cb695db8798957bd64ce411f061307e39cb2baa69668b4d42ccf010db47d2e39", + "zh:d02704bf99a93dc0b1ca00bd6051df9c431fbe17cd662a1ab58db1b96264a26f", + ] +} diff --git a/tofu/environments/stage/data-store/cache/terragrunt.hcl b/tofu/environments/stage/data-store/cache/terragrunt.hcl new file mode 100644 index 000000000..9011c853d --- /dev/null +++ b/tofu/environments/stage/data-store/cache/terragrunt.hcl @@ -0,0 +1,53 @@ +include "root" { + path = find_in_parent_folders() + expose = true +} + +include "environment" { + path = find_in_parent_folders("environment.hcl") + expose = true +} + +terraform { + source = "../../../../modules/data-store/cache" +} + +dependency "vpc" { + config_path = "../../network/vpc" + + mock_outputs_allowed_terraform_commands = ["init", "validate", "plan"] + mock_outputs = { + vpc_id = "mock_vpc_id" + subnets = ["subnet-mocksubnet1234567"] + database_subnet_cidrs = ["subnet-mocksubnet1234567"] + source_security_groups = ["sg-mocksecuritygroup"] + } +} + +dependency "backend" { + config_path = "../../services/backend-infra" + + mock_outputs_allowed_terraform_commands = ["init", "validate", "plan", "destroy"] + mock_outputs = { + security_group_id = "mock_sg_id" + } +} + +locals { + environment = get_env("TF_VAR_environment") + name_prefix = get_env("TF_VAR_name_prefix") + region = get_env("TF_VAR_region") + + project_tags = include.root.locals.tags + environment_tags = include.environment.locals.tags + tags = "${merge(local.project_tags, local.environment_tags)}" +} + +inputs = { + name_prefix = local.name_prefix + vpc = dependency.vpc.outputs.vpc_id + subnets = dependency.vpc.outputs.database_subnets + source_security_groups = [dependency.backend.outputs.security_group_id] + database_subnet_cidrs = dependency.vpc.outputs.database_subnet_cidrs + tags = local.tags +} \ No newline at end of file diff --git a/tofu/environments/stage/data-store/database/.terraform.lock.hcl b/tofu/environments/stage/data-store/database/.terraform.lock.hcl new file mode 100644 index 000000000..9cf40ccc0 --- /dev/null +++ b/tofu/environments/stage/data-store/database/.terraform.lock.hcl @@ -0,0 +1,38 @@ +# This file is maintained automatically by "tofu init". +# Manual edits may be lost in future updates. + +provider "registry.opentofu.org/hashicorp/aws" { + version = "5.50.0" + constraints = ">= 5.46.0, >= 5.47.0" + hashes = [ + "h1:ZN7MLKklx+LTYZvRerNw5O2qHA913Xg9eQW99uqfbI8=", + "zh:17345c5dee93b49009c7941b1e47bb6fe94376e2d0ffc83bfd80f75c9857e2cd", + "zh:2ed80ee2aa5db4fe29700e5488cd67409331a5a586102511a512c34e0f31bc38", + "zh:30cbf46810151a2f587bbeb4172e3534186e4cfae03d4d91a90dc4d3b304acb4", + "zh:449b4562b8530e2d3e7555d3ed9bc0a5a9ead1067784e86572b26b98f87a073f", + "zh:7a853b8ae08304c8d4e8d37a607e21d1a06e0956b3aef9e52b569dc556438d90", + "zh:8a6923372241b0b4aa58631e5a9487b6c8eebd456d001422f0b05f707ec29744", + "zh:90e1b8c7a51a97d2cae255b225f9260bf75bff72c13b791453fbed8f2d2ac729", + "zh:a0b4f62de237913e22387630668a79754fb23c231ea8629615722287cf5e58c5", + "zh:c4632d2dad5ec905f625b75b80d996047967c1d2105c11daad8cbc69972fdeda", + "zh:ce8866ce789f27e97b890dd8a82dea101deb66daf2e651ed387584aecc51d8b4", + ] +} + +provider "registry.opentofu.org/hashicorp/random" { + version = "3.6.1" + constraints = ">= 3.1.0, >= 3.6.1" + hashes = [ + "h1:egGGMQ18ihxoFBTgL/6aRL2N5/0bTI738Mg+TTsvBHA=", + "zh:1208af24d1f66e858740812dd5da12e8951b1ca75cc6edb1975ba22bfdeefb1b", + "zh:19137e9b4d3c15e1d99d2352888b98ec0e69bd5b2e89049150379d7bbd115063", + "zh:26613834a1a8ac60390c7a4cbd4cb794b01dfe237d2b0c10f132f3e434a21e03", + "zh:2cbe4425918f3f401609d89e6381f7d120493d637a3d103d827f0c0fd00b1600", + "zh:44ef27a972540435efa88f323280f96d6ac77934079225e7fcc3560cc28aae59", + "zh:8c5d4ca7d1ce007f7c055807cde77aad4685eb807ff802c93ffbec8589068f17", + "zh:9a4fa908d6af48805c862cd4f3a1031d552b96d863a94263e390ac92915d74a9", + "zh:ba396849f0f6d488784f6039095634e1c84e67e31375f3d17218fcf8ce952cb8", + "zh:cb695db8798957bd64ce411f061307e39cb2baa69668b4d42ccf010db47d2e39", + "zh:d02704bf99a93dc0b1ca00bd6051df9c431fbe17cd662a1ab58db1b96264a26f", + ] +} diff --git a/tofu/environments/stage/data-store/database/terragrunt.hcl b/tofu/environments/stage/data-store/database/terragrunt.hcl new file mode 100644 index 000000000..474f1c1ca --- /dev/null +++ b/tofu/environments/stage/data-store/database/terragrunt.hcl @@ -0,0 +1,66 @@ +include "root" { + path = find_in_parent_folders() + expose = true +} + +include "environment" { + path = find_in_parent_folders("environment.hcl") + expose = true +} + +terraform { + source = "../../../../modules/data-store/database" +} + +dependency "vpc" { + config_path = "../../network/vpc" + + mock_outputs_allowed_terraform_commands = ["init", "validate", "plan"] + mock_outputs = { + vpc_id = "mock_vpc_id" + database_subnet_group = "mock_subnet_group" + database_subnets = [] + + } +} + +dependency "cache" { + config_path = "../cache" + + mock_outputs_allowed_terraform_commands = ["init", "validate", "plan"] + mock_outputs = { + security_group_id = "mock_sg_id" + } +} + +dependency "backend" { + config_path = "../../services/backend-infra" + + mock_outputs_allowed_terraform_commands = ["init", "validate", "plan", "destroy"] + mock_outputs = { + security_group_id = "sg-mocksecuritygroup" + } +} + +locals { + environment = get_env("TF_VAR_environment") + name_prefix = get_env("TF_VAR_name_prefix") + region = get_env("TF_VAR_region") + + project_tags = include.root.locals.tags + environment_tags = include.environment.locals.tags + tags = "${merge(local.project_tags, local.environment_tags)}" +} + +inputs = { + environment = local.environment + name_prefix = local.name_prefix + region = local.region + vpc = dependency.vpc.outputs.vpc_id + subnet_group = local.name_prefix //dependency.vpc.outputs.database_subnet_group + database_subnets = dependency.vpc.outputs.database_subnets + elasticache_security_group = dependency.cache.outputs.security_group_id + backend_security_group = dependency.backend.outputs.security_group_id + database_secret = "arn:aws:secretsmanager:us-east-1:768512802988:secret:tb-apmt-stage-db-secret-V0syHj" + tags = local.tags +} \ No newline at end of file diff --git a/tofu/environments/stage/environment.hcl b/tofu/environments/stage/environment.hcl new file mode 100644 index 000000000..13b0a99d8 --- /dev/null +++ b/tofu/environments/stage/environment.hcl @@ -0,0 +1,29 @@ +locals { + environment_vars = yamldecode(file("environment_vars.yaml")) + + environment = local.environment_vars.environment + region = local.environment_vars.region + + tags = { + environment = local.environment + } +} + +generate "versions" { + path = "versions_override.tf" + if_exists = "overwrite_terragrunt" + contents = <.*?)/.*", get_terragrunt_dir()) + env = local.parsed.env +} + +generate "backend" { + path = "backend.tf" + if_exists = "overwrite_terragrunt" + contents = < request.uri.startsWith(path); + + // If our api path is the first thing that's found in the uri then remove it from the uri. + if (request.uri.indexOf(apiPath) === 0) { + request.uri = request.uri.replace(apiPath, ""); + } else if (!ignorePaths.some(pathCheckFn)) { + // If we're not in one of the ignorePaths then force them to /index.html + request.uri = '/index.html'; + } + // else carry on like normal. + return request; + } + EOT +} + +resource "aws_s3_bucket" "request_logs" { + bucket = local.log_bucket + force_destroy = true + + tags = merge(var.tags, { + Name = "${local.bucket}-request-logs" + }) +} + +resource "aws_s3_bucket_versioning" "request_logs" { + bucket = aws_s3_bucket.request_logs.bucket + versioning_configuration { + status = "Enabled" + } +} + +resource "aws_s3_bucket_server_side_encryption_configuration" "request_logs" { + bucket = aws_s3_bucket.request_logs.bucket + + rule { + apply_server_side_encryption_by_default { + sse_algorithm = "AES256" + } + } +} + +resource "aws_s3_bucket_public_access_block" "request_logs" { + bucket = aws_s3_bucket.request_logs.bucket + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true +} + +resource "aws_s3_bucket_ownership_controls" "request_logs" { + bucket = aws_s3_bucket.request_logs.id + rule { + object_ownership = "BucketOwnerPreferred" + } +} + +resource "aws_s3_bucket_acl" "request_logs" { + depends_on = [aws_s3_bucket_ownership_controls.request_logs] + bucket = aws_s3_bucket.request_logs.id + acl = "private" +} \ No newline at end of file diff --git a/tofu/modules/services/frontend-infra/outputs.tf b/tofu/modules/services/frontend-infra/outputs.tf new file mode 100644 index 000000000..a64278fd5 --- /dev/null +++ b/tofu/modules/services/frontend-infra/outputs.tf @@ -0,0 +1,15 @@ +output "bucket" { + value = aws_s3_bucket.frontend.bucket_domain_name +} + +output "bucket_name" { + value = aws_s3_bucket.frontend.id +} + +output "cloudfront_arn" { + value = aws_cloudfront_distribution.appointment.arn +} + +output "cloudfront_id" { + value = aws_cloudfront_distribution.appointment.id +} \ No newline at end of file diff --git a/tofu/modules/services/frontend-infra/variables.tf b/tofu/modules/services/frontend-infra/variables.tf new file mode 100644 index 000000000..3f218240f --- /dev/null +++ b/tofu/modules/services/frontend-infra/variables.tf @@ -0,0 +1,44 @@ +variable "environment" { + description = "Application environment ie. staging, production, etc..." + type = string +} + +variable "name_prefix" { + description = "Prefix to be used with all resource names" + type = string +} + +variable "tags" { + description = "Common tags" + type = map(string) +} + +variable "region" { + description = "AWS deployment region" + type = string +} + +variable "ssl_cert" { + description = "SSL certificate ARN in AWS Certificate Manager" + type = string +} + +/*variable "urls" { + description = "Site URLs" + type = list(any) +}*/ + +variable "backend_id" { + description = "Backend id" + type = string +} + +variable "backend_dns_name" { + description = "Backend DNS name" + type = string +} + +variable "x_allow_secret" { + description = "X-Allow header secret" + type = string +} \ No newline at end of file diff --git a/tofu/modules/terraform/tfbackend/main.tf b/tofu/modules/terraform/tfbackend/main.tf new file mode 100644 index 000000000..ac454d4c8 --- /dev/null +++ b/tofu/modules/terraform/tfbackend/main.tf @@ -0,0 +1,47 @@ +resource "aws_s3_bucket" "terraform_state" { + bucket = var.bucket_name + + # Prevent accidental deletion of this S3 bucket + lifecycle { + prevent_destroy = false + } + tags = var.tags +} + +resource "aws_s3_bucket_versioning" "enabled" { + bucket = aws_s3_bucket.terraform_state.id + versioning_configuration { + status = "Enabled" + } +} + +resource "aws_s3_bucket_server_side_encryption_configuration" "default" { + bucket = aws_s3_bucket.terraform_state.id + + rule { + apply_server_side_encryption_by_default { + sse_algorithm = "AES256" + } + } +} + +resource "aws_s3_bucket_public_access_block" "public_access" { + bucket = aws_s3_bucket.terraform_state.id + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true +} + +resource "aws_dynamodb_table" "terraform_locks" { + name = var.table_name + billing_mode = "PAY_PER_REQUEST" + hash_key = "LockID" + + attribute { + name = "LockID" + type = "S" + } + + tags = var.tags +} diff --git a/tofu/modules/terraform/tfbackend/variables.tf b/tofu/modules/terraform/tfbackend/variables.tf new file mode 100644 index 000000000..477c5530c --- /dev/null +++ b/tofu/modules/terraform/tfbackend/variables.tf @@ -0,0 +1,15 @@ +variable "bucket_name" { + description = "TF state S3 bucket name" + type = string +} + +variable "table_name" { + description = "TF locks Dynamodb table name" + type = string +} + +variable "tags" { + description = "Common tags" + type = map(string) +} +