├── CODEOWNERS ├── .github ├── FUNDING.yml ├── renovate │ ├── actions.json5 │ ├── devcontainers.json5 │ ├── labels.json5 │ ├── terraform.json5 │ └── semanticCommits.json5 ├── workflows │ ├── dependency-review.yml │ ├── lint-pr.yml │ ├── terraform-lint.yml │ ├── scorecard.yml │ ├── devcontainer-smoke.yml │ ├── stale.yml │ └── release.yml ├── PULL_REQUEST_TEMPLATE.md ├── renovate.json5 ├── ISSUE_TEMPLATE │ ├── enhancement.yml │ └── bug.yml └── cliff.toml ├── .gitattributes ├── assets └── gcp │ ├── 1.png │ ├── 2.png │ ├── 3.png │ ├── 4.png │ ├── 5.png │ ├── 6.png │ ├── 7.png │ ├── 8.png │ ├── 9.png │ ├── 10.png │ ├── 11.png │ ├── 12.png │ ├── 13.png │ ├── 14.png │ ├── 15.png │ ├── 16.png │ ├── 17.png │ ├── 18.png │ ├── 19.png │ ├── 20.png │ ├── 21.png │ ├── 22.png │ ├── 23.gif │ ├── 24.png │ └── 25.png ├── docs └── assets │ └── logo.png ├── .infragenie └── infrastructure_model.png ├── .devcontainer ├── Dockerfile └── devcontainer.json ├── .vscode └── launch.json ├── network-variables.tf ├── .editorconfig ├── ubnt-vm-output.tf ├── provider-main.tf ├── provider-variables.tf ├── ubnt-versions.tf ├── ubnt-vm-variables.tf ├── network-main.tf ├── terraform.tfvars ├── LICENSE ├── network-firewall.tf ├── SUPPORT.md ├── CONTRIBUTING.md ├── startup.sh ├── docker-compose.yml ├── SECURITY.md ├── ubnt-vm-main.tf ├── CODE_OF_CONDUCT.md └── README.md /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @sudo-kraken -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: sudo-kraken 2 | buy_me_a_coffee: jharrison94 -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /assets/gcp/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm/HEAD/assets/gcp/1.png -------------------------------------------------------------------------------- /assets/gcp/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm/HEAD/assets/gcp/2.png -------------------------------------------------------------------------------- /assets/gcp/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm/HEAD/assets/gcp/3.png -------------------------------------------------------------------------------- /assets/gcp/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm/HEAD/assets/gcp/4.png -------------------------------------------------------------------------------- /assets/gcp/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm/HEAD/assets/gcp/5.png -------------------------------------------------------------------------------- /assets/gcp/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm/HEAD/assets/gcp/6.png -------------------------------------------------------------------------------- /assets/gcp/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm/HEAD/assets/gcp/7.png -------------------------------------------------------------------------------- /assets/gcp/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm/HEAD/assets/gcp/8.png -------------------------------------------------------------------------------- /assets/gcp/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm/HEAD/assets/gcp/9.png -------------------------------------------------------------------------------- /assets/gcp/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm/HEAD/assets/gcp/10.png -------------------------------------------------------------------------------- /assets/gcp/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm/HEAD/assets/gcp/11.png -------------------------------------------------------------------------------- /assets/gcp/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm/HEAD/assets/gcp/12.png -------------------------------------------------------------------------------- /assets/gcp/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm/HEAD/assets/gcp/13.png -------------------------------------------------------------------------------- /assets/gcp/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm/HEAD/assets/gcp/14.png -------------------------------------------------------------------------------- /assets/gcp/15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm/HEAD/assets/gcp/15.png -------------------------------------------------------------------------------- /assets/gcp/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm/HEAD/assets/gcp/16.png -------------------------------------------------------------------------------- /assets/gcp/17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm/HEAD/assets/gcp/17.png -------------------------------------------------------------------------------- /assets/gcp/18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm/HEAD/assets/gcp/18.png -------------------------------------------------------------------------------- /assets/gcp/19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm/HEAD/assets/gcp/19.png -------------------------------------------------------------------------------- /assets/gcp/20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm/HEAD/assets/gcp/20.png -------------------------------------------------------------------------------- /assets/gcp/21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm/HEAD/assets/gcp/21.png -------------------------------------------------------------------------------- /assets/gcp/22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm/HEAD/assets/gcp/22.png -------------------------------------------------------------------------------- /assets/gcp/23.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm/HEAD/assets/gcp/23.gif -------------------------------------------------------------------------------- /assets/gcp/24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm/HEAD/assets/gcp/24.png -------------------------------------------------------------------------------- /assets/gcp/25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm/HEAD/assets/gcp/25.png -------------------------------------------------------------------------------- /docs/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm/HEAD/docs/assets/logo.png -------------------------------------------------------------------------------- /.infragenie/infrastructure_model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm/HEAD/.infragenie/infrastructure_model.png -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/devcontainers/base:ubuntu-24.04 2 | 3 | RUN sudo apt update && sudo apt install -y \ 4 | python3-pip \ 5 | python3-venv \ 6 | curl \ 7 | git \ 8 | bash-completion \ 9 | && sudo apt clean 10 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Python Debugger: Python File", 6 | "type": "debugpy", 7 | "request": "launch", 8 | "program": "${file}" 9 | } 10 | ] 11 | } -------------------------------------------------------------------------------- /network-variables.tf: -------------------------------------------------------------------------------- 1 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 2 | ## Network - Variables ## 3 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 4 | ## Change as Required ## 5 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 6 | 7 | variable "network-subnet-cidr" { 8 | type = string 9 | description = "The CIDR for the network subnet" 10 | } 11 | -------------------------------------------------------------------------------- /.github/renovate/actions.json5: -------------------------------------------------------------------------------- 1 | { 2 | $schema: "https://docs.renovatebot.com/renovate-schema.json", 3 | 4 | extends: ["helpers:pinGitHubActionDigests"], 5 | 6 | packageRules: [ 7 | { 8 | matchManagers: ["github-actions"], 9 | minimumReleaseAge: null, 10 | pinDigests: true, 11 | automerge: true, 12 | matchUpdateTypes: ["minor", "patch"], 13 | }, 14 | ], 15 | } 16 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | end_of_line = lf 10 | indent_size = 2 11 | indent_style = space 12 | insert_final_newline = true 13 | 14 | # Python 15 | [*.py] 16 | indent_size = 4 17 | 18 | # JSON 19 | [*.json] 20 | indent_size = 2 21 | insert_final_newline = ignore 22 | 23 | # YAML 24 | [*.{yaml,yml}] 25 | indent_size = 2 26 | -------------------------------------------------------------------------------- /ubnt-vm-output.tf: -------------------------------------------------------------------------------- 1 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 2 | ## GCP Linux VM - Output ## 3 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 4 | ## Change as Required ## 5 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 6 | 7 | output "vm-name" { 8 | value = google_compute_instance.gcp-ubnt-vm.name 9 | } 10 | 11 | output "vm-external-ip" { 12 | value = google_compute_instance.gcp-ubnt-vm.network_interface.0.access_config.0.nat_ip 13 | } 14 | 15 | output "vm-internal-ip" { 16 | value = google_compute_instance.gcp-ubnt-vm.network_interface.0.network_ip 17 | } 18 | -------------------------------------------------------------------------------- /.github/renovate/devcontainers.json5: -------------------------------------------------------------------------------- 1 | { 2 | $schema: "https://docs.renovatebot.com/renovate-schema.json", 3 | customManagers: [ 4 | { 5 | description: ["Process Devcontainer features"], 6 | customType: "regex", 7 | fileMatch: ["devcontainer.json$"], 8 | matchStrings: [ 9 | 'datasource=(?\\S*)[\\s]+depName=(?\\S*)[\\s]+"\\w+":[\\s]+"(?[a-zA-Z0-9-_.]+)"', 10 | ], 11 | versioningTemplate: "regex:^v?(?\\d+)\\.(?\\d+)\\.?(?\\d+)?-?(?\\S+)?$", 12 | }, 13 | ], 14 | } 15 | -------------------------------------------------------------------------------- /provider-main.tf: -------------------------------------------------------------------------------- 1 | ###~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 2 | ## GCP Provider - Main ## 3 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 4 | ## Change as Required ## 5 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 6 | 7 | # Define Terraform provider 8 | terraform { 9 | required_version = "~> 1.0" 10 | 11 | required_providers { 12 | google = { 13 | source = "hashicorp/google" 14 | // version = "4.11.0" # pinning version 15 | } 16 | } 17 | } 18 | 19 | provider "google" { 20 | credentials = file(var.gcp_auth_file) 21 | project = var.gcp_project 22 | region = var.gcp_region 23 | zone = var.gcp_zone 24 | } 25 | -------------------------------------------------------------------------------- /.github/workflows/dependency-review.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json 3 | name: Dependency Review 4 | 5 | on: 6 | pull_request: 7 | 8 | permissions: {} 9 | 10 | concurrency: 11 | group: dependency-review-${{ github.ref }} 12 | cancel-in-progress: true 13 | 14 | jobs: 15 | dependency-review: 16 | runs-on: ubuntu-24.04 17 | permissions: 18 | contents: read 19 | steps: 20 | - name: 'Checkout Repository' 21 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 22 | 23 | - name: 'Dependency Review' 24 | uses: actions/dependency-review-action@3c4e3dcb1aa7874d2c16be7d79418e9b7efd6261 # v4.8.2 25 | -------------------------------------------------------------------------------- /provider-variables.tf: -------------------------------------------------------------------------------- 1 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 2 | ## GCP Provider - Variables ## 3 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 4 | ## Change as Required ## 5 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 6 | 7 | # GCP authentication file 8 | variable "gcp_auth_file" { 9 | type = string 10 | description = "GCP authentication file" 11 | } 12 | 13 | # define GCP project name 14 | variable "gcp_project" { 15 | type = string 16 | description = "GCP project name" 17 | } 18 | 19 | # define GCP region 20 | variable "gcp_region" { 21 | type = string 22 | description = "GCP region" 23 | } 24 | 25 | # define GCP region 26 | variable "gcp_zone" { 27 | type = string 28 | description = "GCP zone" 29 | } 30 | -------------------------------------------------------------------------------- /ubnt-versions.tf: -------------------------------------------------------------------------------- 1 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 2 | ## Ubuntu Versions ## 3 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 4 | ## Change as Required ## 5 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 6 | 7 | variable "ubnt_1804" { 8 | type = string 9 | description = "Ubuntu Minimal - 18.04 - Bionic - LTS" 10 | default = "ubuntu-os-cloud/ubuntu-minimal-1804-lts" 11 | } 12 | 13 | variable "ubnt_2004" { 14 | type = string 15 | description = "Ubuntu Minimal - 20.04 - Focal - LTS" 16 | default = "ubuntu-os-cloud/ubuntu-minimal-2004-lts" 17 | } 18 | 19 | variable "ubnt_2204" { 20 | type = string 21 | description = "Ubuntu Minimal - 22.04 - Jammy - LTS" 22 | default = "ubuntu-os-cloud/ubuntu-minimal-2204-lts" 23 | } -------------------------------------------------------------------------------- /ubnt-vm-variables.tf: -------------------------------------------------------------------------------- 1 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 2 | ## GCP Ubuntu VM - Variables ## 3 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 4 | ## Change as Required ## 5 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 6 | 7 | variable "vm_instance_type" { 8 | type = string 9 | description = "VM instance type" 10 | default = "e2-micro" 11 | } 12 | 13 | variable "vm_name" { 14 | type = string 15 | description = "VM name" 16 | } 17 | 18 | variable "privatekeypath" { 19 | type = string 20 | default = "~/.ssh/sshkey" 21 | } 22 | 23 | variable "publickeypath" { 24 | type = string 25 | default = "~/.ssh/sshkey.pub" 26 | } 27 | 28 | variable "user" { 29 | type = string 30 | } 31 | 32 | variable "email" { 33 | type = string 34 | } -------------------------------------------------------------------------------- /.github/workflows/lint-pr.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json 3 | name: Validate PR Title 4 | 5 | on: 6 | pull_request: 7 | types: 8 | - opened 9 | - edited 10 | - synchronize 11 | - reopened 12 | 13 | permissions: {} 14 | 15 | concurrency: 16 | group: validate-pr-title-${{ github.ref }} 17 | cancel-in-progress: true 18 | 19 | jobs: 20 | lint-pr: 21 | name: Validate PR title 22 | runs-on: ubuntu-24.04 23 | permissions: 24 | contents: read 25 | pull-requests: read 26 | checks: write 27 | steps: 28 | - uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6.1.1 29 | env: 30 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 31 | -------------------------------------------------------------------------------- /network-main.tf: -------------------------------------------------------------------------------- 1 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 2 | ## Network - Main ## 3 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 4 | ## Change as Required ## 5 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 6 | 7 | # Update IDENTIFIER in the name fields below with something unique to you like VM name or your initials. 8 | 9 | # Create VPC 10 | resource "google_compute_network" "vpc" { 11 | name = "IDENTIFIER-vpc" 12 | auto_create_subnetworks = "false" 13 | routing_mode = "GLOBAL" 14 | } 15 | 16 | # create public subnet 17 | resource "google_compute_subnetwork" "network_subnet" { 18 | name = "IDENTIFIER-subnet" 19 | ip_cidr_range = var.network-subnet-cidr 20 | network = google_compute_network.vpc.name 21 | region = var.gcp_region 22 | } 23 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | **Description** 7 | 8 | 9 | 10 | # Linked issue(s) 11 | 15 | Fixes #0000 | Relates #0000 16 | 17 | **Checklist** 18 | 19 | - [ ] Unit tests updated 20 | - [ ] End user documentation updated 21 | 22 | ### Community Note 23 | 24 | - Please do not leave "+1" or other comments that do not add relevant new information or questions, they generate extra noise for pull request followers and do not help prioritise the request 25 | -------------------------------------------------------------------------------- /terraform.tfvars: -------------------------------------------------------------------------------- 1 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 2 | ## Terraform - Variables ## 3 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 4 | ## Change as Required ## 5 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 6 | 7 | # Please update all the info below with your own project ID, region you want this hosted in, network CIDR and instance type. 8 | 9 | # GCP Settings 10 | gcp_project = "PROJECT-ID-HERE" 11 | gcp_region = "us-west1" 12 | gcp_zone = "us-west1-a" 13 | gcp_auth_file = "../auth/google-key.json" 14 | 15 | # GCP Netwok 16 | network-subnet-cidr = "10.0.10.0/24" 17 | 18 | # Linux VM 19 | vm_instance_type = "e2-micro" 20 | user = "middlewareinvetory_gmail_com" # this should match the username set by the OS Login 21 | email = "tf-serviceaccount@PROJECTNAME.iam.gserviceaccount.com" # this should match the service account we set earlier 22 | -------------------------------------------------------------------------------- /.github/workflows/terraform-lint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json 3 | name: Terraform Lint 4 | 5 | on: 6 | push: 7 | paths: 8 | - '**.tf' 9 | - .github/workflows/terraform-lint.yml 10 | pull_request: 11 | workflow_dispatch: 12 | 13 | permissions: {} 14 | 15 | concurrency: 16 | group: terraform-lint-${{ github.ref }} 17 | cancel-in-progress: true 18 | 19 | jobs: 20 | terraform-lint: 21 | name: Lint terraform Playbooks 22 | runs-on: ubuntu-24.04 23 | permissions: 24 | contents: read 25 | pull-requests: read 26 | steps: 27 | - name: Checkout code 28 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 29 | with: 30 | persist-credentials: false 31 | 32 | - name: Setup Terraform 33 | uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd # v3.1.2 34 | with: 35 | terraform_version: latest 36 | 37 | - name: Check Terraform formatting 38 | run: terraform fmt -recursive . 39 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "terraform-gcp-ubuntu-container-ready-e2-micro-vm", 3 | "build": { 4 | "context": "../", 5 | "dockerfile": "Dockerfile" 6 | }, 7 | "features": { 8 | "ghcr.io/audacioustux/devcontainers/taskfile:1": {}, 9 | "ghcr.io/devcontainers/features/terraform:1": { "version": "1.13.3"} 10 | }, 11 | "mounts": [ 12 | "source=/tmp,target=/tmp,type=bind,consistency=cached" 13 | ], 14 | "userEnvProbe": "loginInteractiveShell", 15 | "customizations": { 16 | "vscode": { 17 | "extensions": [ 18 | "wholroyd.jinja", 19 | "mrmlnc.vscode-json5", 20 | "coolbear.systemd-unit-file", 21 | "hashicorp.hcl", 22 | "hashicorp.terraform", 23 | "DavidAnson.vscode-markdownlint", 24 | "ms-python.python", 25 | "medo64.render-crlf", 26 | "redhat.vscode-yaml", 27 | "github.vscode-github-actions", 28 | "donjayamanne.githistory", 29 | "eamodio.gitlens", 30 | "task.vscode-task", 31 | "EditorConfig.EditorConfig" 32 | ] 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /.github/renovate/labels.json5: -------------------------------------------------------------------------------- 1 | { 2 | $schema: "https://docs.renovatebot.com/renovate-schema.json", 3 | 4 | packageRules: [ 5 | { 6 | matchManagers: ["github-actions"], 7 | addLabels: ["renovate/github_actions"], 8 | }, 9 | { 10 | matchDatasources: ["github-tags"], 11 | addLabels: ["renovate/github-tags"], 12 | }, 13 | { 14 | matchDatasources: ["github-releases"], 15 | addLabels: ["renovate/github-releases"], 16 | }, 17 | { 18 | matchDatasources: ["terraform-provider"], 19 | addLabels: ["renovate/terraform"], 20 | }, 21 | { 22 | matchManagers: ["dockerfile", "docker-compose"], 23 | addLabels: ["renovate/docker"], 24 | }, 25 | { 26 | matchUpdateTypes: ["major"], 27 | labels: ["type/major"], 28 | }, 29 | { 30 | matchUpdateTypes: ["minor"], 31 | labels: ["type/minor"], 32 | }, 33 | { 34 | matchUpdateTypes: ["patch"], 35 | labels: ["type/patch"], 36 | }, 37 | { 38 | matchUpdateTypes: ["digest"], 39 | labels: ["type/digest"], 40 | }, 41 | ], 42 | } 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 sudo-kraken 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/scorecard.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json 3 | name: Scorecard Supply-Chain Security 4 | 5 | on: 6 | schedule: 7 | - cron: '0 7 * * *' 8 | push: 9 | branches: 10 | - main 11 | 12 | permissions: {} 13 | 14 | concurrency: 15 | group: scorecard-${{ github.ref }} 16 | cancel-in-progress: true 17 | 18 | jobs: 19 | analysis: 20 | name: Scorecard analysis 21 | runs-on: ubuntu-24.04 22 | permissions: 23 | security-events: write 24 | id-token: write 25 | steps: 26 | - name: Checkout code 27 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 28 | with: 29 | persist-credentials: false 30 | 31 | - name: Run analysis 32 | uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 33 | with: 34 | results_file: results.sarif 35 | results_format: sarif 36 | publish_results: true 37 | 38 | - name: Upload to code-scanning 39 | uses: github/codeql-action/upload-sarif@1b168cd39490f61582a9beae412bb7057a6b2c4e # v4.31.8 40 | with: 41 | sarif_file: results.sarif 42 | -------------------------------------------------------------------------------- /.github/workflows/devcontainer-smoke.yml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json 2 | name: Devcontainer Smoke Test 3 | 4 | on: 5 | pull_request: 6 | push: 7 | branches: 8 | - main 9 | workflow_dispatch: 10 | 11 | concurrency: 12 | group: devcontainer-smoke-${{ github.ref }} 13 | cancel-in-progress: true 14 | 15 | jobs: 16 | smoke: 17 | name: Smoke Test Dev Container 18 | runs-on: ubuntu-24.04 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6 22 | 23 | - name: Build devcontainer 24 | uses: devcontainers/ci@8bf61b26e9c3a98f69cb6ce2f88d24ff59b785c6 # v0.3 25 | with: 26 | push: never 27 | runCmd: echo "container up" 28 | 29 | - name: Verify Terraform in devcontainer 30 | uses: devcontainers/ci@8bf61b26e9c3a98f69cb6ce2f88d24ff59b785c6 # v0.3 31 | with: 32 | push: never 33 | runCmd: | 34 | bash -lc ' 35 | set -euo pipefail 36 | 37 | echo "Terraform version" 38 | terraform version 39 | 40 | echo "OK: Terraform is working in devcontainer" 41 | ' 42 | -------------------------------------------------------------------------------- /network-firewall.tf: -------------------------------------------------------------------------------- 1 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 2 | ## Network Firewall Rules - Main ## 3 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 4 | ## Change as Required ## 5 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 6 | 7 | # Update all instances of IDENTIFIER in the name fields below with something unique to you like VM name or your initials. 8 | 9 | # Allow http 10 | resource "google_compute_firewall" "allow-http" { 11 | name = "IDENTIFIER-fw-allow-http" 12 | network = google_compute_network.vpc.name 13 | allow { 14 | protocol = "tcp" 15 | ports = ["80"] 16 | } 17 | 18 | source_ranges = ["0.0.0.0/0"] 19 | target_tags = ["http-server"] 20 | } 21 | 22 | # allow https 23 | resource "google_compute_firewall" "allow-https" { 24 | name = "IDENTIFIER-fw-allow-https" 25 | network = google_compute_network.vpc.name 26 | allow { 27 | protocol = "tcp" 28 | ports = ["443"] 29 | } 30 | 31 | source_ranges = ["0.0.0.0/0"] 32 | target_tags = ["https-server"] 33 | } 34 | 35 | # allow ssh 36 | resource "google_compute_firewall" "allow-ssh" { 37 | name = "IDENTIFIER-fw-allow-http-fw-allow-ssh" 38 | network = google_compute_network.vpc.name 39 | allow { 40 | protocol = "tcp" 41 | ports = ["22"] 42 | } 43 | 44 | source_ranges = ["0.0.0.0/0"] 45 | target_tags = ["ssh"] 46 | } 47 | -------------------------------------------------------------------------------- /SUPPORT.md: -------------------------------------------------------------------------------- 1 | # 🙋‍♂️ Support 2 | 3 | This document explains where and how to get help with most of my projects. 4 | Please ensure you read through it thoroughly. 5 | 6 | > [!NOTE] 7 | > 👉 Before participating in the community, please read our 8 | > [Code of Conduct](CODE_OF_CONDUCT.md). 9 | > By interacting with this repository, organization, or community you agree to 10 | > abide by its terms. 11 | 12 | ## ❔ Asking quality questions 13 | 14 | Help me help you! Spend time framing questions and add links and resources. 15 | Spending the extra time up front can help save everyone time in the long run. 16 | Here are some tips: 17 | 18 | * Don't fall for the [XY problem](https://mywiki.wooledge.org/XyProblem). 19 | * Search to find out if a similar question has been asked or if a similar 20 | issue/bug has been reported. 21 | * Try to define what you need help with: 22 | * Is there something in particular you want to do? 23 | * What problem are you encountering and what steps have you taken to try 24 | and fix it? 25 | * Is there a concept you don't understand? 26 | * Provide sample code, such as a a simple snippet, if 27 | possible. 28 | * Screenshots can help, but if there's important text such as code or error 29 | messages in them, please also provide those. 30 | * The more time you put into asking your question, the better I and others 31 | can help you. 32 | -------------------------------------------------------------------------------- /.github/renovate.json5: -------------------------------------------------------------------------------- 1 | { 2 | $schema: "https://docs.renovatebot.com/renovate-schema.json", 3 | description: "Automated dependency updates for terraform-gcp-ubuntu-container-ready-e2-micro-vm", 4 | extends: [ 5 | "config:recommended", 6 | "replacements:k8s-registry-move", 7 | ":automergePr", 8 | ":automergePatch", 9 | ":automergeDigest", 10 | ":disableRateLimiting", 11 | ":dependencyDashboard", 12 | ":semanticCommits", 13 | ":timezone(Europe/London)", 14 | "github>sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm//.github/renovate/actions.json5", 15 | "github>sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm//.github/renovate/devcontainers.json5", 16 | "github>sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm//.github/renovate/labels.json5", 17 | "github>sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm//.github/renovate/semanticCommits.json5", 18 | "github>sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm//.github/renovate/terraform.json5", 19 | ], 20 | dependencyDashboardTitle: "Renovate Dashboard 🤖", 21 | suppressNotifications: ["prEditedNotification", "prIgnoreNotification"], 22 | rebaseWhen: "conflicted", 23 | pruneStaleBranches: true, 24 | pruneBranchAfterAutomerge: true, 25 | prConcurrentLimit: 5, 26 | labels: ["dependencies"], 27 | schedule: ["after 9pm on sunday"], 28 | minimumReleaseAge: "7 days", 29 | } 30 | -------------------------------------------------------------------------------- /.github/renovate/terraform.json5: -------------------------------------------------------------------------------- 1 | { 2 | $schema: "https://docs.renovatebot.com/renovate-schema.json", 3 | customManagers: [ 4 | { 5 | description: ["Process Terraform/Terragrunt files"], 6 | customType: "regex", 7 | fileMatch: ["(^|/)terragrunt\\.hcl$"], 8 | matchStrings: [ 9 | '(?\\S*)_version_constraint\\s+=\\s+"(?\\S*)"', 10 | ], 11 | datasourceTemplate: "github-releases", 12 | depNameTemplate: '{{#if (containsString depName "terragrunt")}}gruntwork-io/terragrunt{{else}}hashicorp/terraform{{/if}}', 13 | }, 14 | { 15 | description: ["Process Terraform plugin"], 16 | customType: "regex", 17 | fileMatch: ["(^|/)terragrunt\\.hcl$"], 18 | matchStrings: [ 19 | 'source[\\s]+=[\\s]+"(?\\S*)"[\\s]+version[\\s]+=[\\s]+"=?(?\\S*)"', 20 | ], 21 | datasourceTemplate: "terraform-provider", 22 | }, 23 | ], 24 | packageRules: [ 25 | { 26 | description: ["Process terragrunt files"], 27 | matchPackagePatterns: ["terragrunt"], 28 | matchDatasources: ["github-releases"], 29 | versioning: "regex:^v?(?\\d+)\\.(?\\d+)\\.(?\\d+)", 30 | }, 31 | { 32 | description: ["Process terraform files"], 33 | matchPackagePatterns: ["terraform"], 34 | matchDatasources: ["github-releases"], 35 | versioning: "regex:^v?(?\\d+)\\.(?\\d+)\\.(?\\d+)", 36 | }, 37 | ], 38 | } 39 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json 3 | name: Close Stale Issues and PRs 4 | 5 | on: 6 | schedule: 7 | - cron: "0 7 * * *" 8 | 9 | permissions: {} 10 | 11 | concurrency: 12 | group: close-stale-${{ github.ref }} 13 | cancel-in-progress: true 14 | 15 | jobs: 16 | stale: 17 | name: Close stale issues and PRs 18 | runs-on: ubuntu-24.04 19 | permissions: 20 | actions: write 21 | issues: write 22 | pull-requests: write 23 | steps: 24 | - uses: actions/stale@997185467fa4f803885201cee163a9f38240193d # v10.1.1 25 | with: 26 | any-of-labels: "⌛ pending author's response" 27 | days-before-stale: 30 28 | days-before-close: 30 29 | stale-issue-label: "⏰ stale" 30 | stale-issue-message: "This issue is stale because it has been open 30 days with no activity. Please provide an update or the requested information to keep it open." 31 | close-issue-message: "This issue was closed because it has been stalled for 30 days with no activity. Feel free to reopen it once you provide the required update or information." 32 | stale-pr-label: "⏰ stale" 33 | stale-pr-message: "This PR is stale because it has been open 30 days with no activity. Please address the feedback or provide an update to keep it open." 34 | close-pr-message: "This PR was closed because it has been stalled for 30 days with no activity. You can reopen it once you address the feedback or provide the requested changes." 35 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/enhancement.yml: -------------------------------------------------------------------------------- 1 | name: ✨ Feature Request 2 | description: Suggest an idea 3 | labels: ['enhancement', 'awaiting triage'] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | Thanks for taking the time to fill out this feature request! 9 | 10 | Please note that we use GitHub issues exclusively for bug reports and feature requests. For support requests, please use our other support channels to get help. 11 | - type: textarea 12 | id: description 13 | attributes: 14 | label: Description 15 | description: Is your feature request related to a problem? If so, please provide a clear and concise description of the problem; e.g., "I'm always frustrated when [...]." 16 | validations: 17 | required: true 18 | - type: textarea 19 | id: desired-behavior 20 | attributes: 21 | label: Desired Behavior 22 | description: Provide a clear and concise description of what you want to happen. 23 | validations: 24 | required: true 25 | - type: textarea 26 | id: additional-context 27 | attributes: 28 | label: Additional Context 29 | description: Provide any additional information or screenshots that may be relevant or helpful. 30 | - type: checkboxes 31 | id: terms 32 | attributes: 33 | label: Code of Conduct 34 | description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm/blob/main/CODE_OF_CONDUCT.md) 35 | options: 36 | - label: I agree to follow this project's Code of Conduct 37 | required: true -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | **First:** if you're unsure or afraid of _anything_, ask for help! You can 4 | submit a work in progress (WIP) pull request, or file an issue with the parts 5 | you know. We'll do our best to guide you in the right direction, and let you 6 | know if there are guidelines we will need to follow. We want people to be able 7 | to participate without fear of doing the wrong thing. 8 | 9 | ## Commit message conventions 10 | 11 | We expect that all commit messages follow the 12 | [Conventional Commits](https://www.conventionalcommits.org/) specification. 13 | Please use the `feat`, `fix` or `chore` types for your commits. 14 | 15 | ### Developer Certificate of Origin 16 | 17 | In order for a code change to be accepted, you'll also have to accept the 18 | Developer Certificate of Origin (DCO). 19 | It's very lightweight, and you can find it [here](https://developercertificate.org). 20 | Accepting is accomplished by signing off on your commits, you can do this by 21 | adding a `Signed-off-by` line to your commit message, like here: 22 | 23 | ```commit 24 | feat: add support for the XXXX operation 25 | 26 | Signed-off-by: Random Developer 27 | ``` 28 | 29 | Please use your real name and a valid email address. 30 | 31 | ## Submitting changes 32 | 33 | Please create a new PR against the `main` branch which must be based on the 34 | project's [pull request template](.github/PULL_REQUEST_TEMPLATE.md). 35 | 36 | We usually squash all PRs commits on merge, and use the PR title as the commit 37 | message. Therefore, the PR title should follow the 38 | [Conventional Commits](https://www.conventionalcommits.org/) specification as well. -------------------------------------------------------------------------------- /startup.sh: -------------------------------------------------------------------------------- 1 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 2 | ## Change as Required ## 3 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 4 | 5 | # Update 6 | sudo apt update 7 | 8 | # Mount App Data 9 | fsck.ext4 -tvy /dev/sdb || mkfs.ext4 /dev/sdb 10 | mkdir -p /mnt/disks/docker 11 | mount -o defaults -t ext4 /dev/sdb /mnt/disks/docker 12 | mkdir -p /mnt/disks/docker/projects/app 13 | sudo chmod 777 /mnt/disks/docker/projects/app 14 | 15 | # Allow user account access to sudo without password for these actions - update the username to your own 16 | sudo echo "USERNAMEHERE ALL=(ALL) NOPASSWD:/bin/mkdir,/bin/mv,/bin/cat,/bin/rm,/bin/nano" >> /etc/sudoers 17 | 18 | # Install Docker 19 | sudo apt install apt-transport-https ca-certificates curl software-properties-common gnupg lsb-release -y 20 | sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg --batch --yes 21 | echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null 22 | sudo apt update -y 23 | sudo apt install docker-ce nano -y 24 | 25 | # Install Docker Compose - manually add your username to the path 26 | sudo mkdir -p /usr/local/lib/docker/cli-plugins 27 | sudo curl -L https://github.com/docker/compose/releases/download/v2.4.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/lib/docker/cli-plugins/docker-compose 28 | sudo chmod +x /usr/local/lib/docker/cli-plugins/docker-compose 29 | sudo usermod -aG sudo USERNAMEHERE 30 | sudo usermod -aG docker USERNAMEHERE 31 | sleep 30 32 | 33 | # Move compose file - again update the username here 34 | sudo mv /home/USERNAMEHERE/docker-compose.yaml /mnt/disks/docker/projects/app/docker-compose.yaml 35 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 2 | ## Change as Required ## 3 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 4 | 5 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 6 | ################################## Networks #################################### 7 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 8 | 9 | networks: 10 | proxy_net: 11 | name: proxy_net 12 | driver: bridge 13 | ipam: 14 | config: 15 | - subnet: 10.0.0.0/24 16 | 17 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 18 | ################################## Services #################################### 19 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 20 | 21 | services: 22 | 23 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 24 | ################################## Uptime Kuma #################################### 25 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 26 | 27 | uptime-kuma: 28 | container_name: uptime-kuma 29 | image: louislam/uptime-kuma:latest 30 | restart: unless-stopped 31 | volumes: 32 | - /mnt/disks/docker/uptime-kuma:/app/data 33 | networks: 34 | - proxy_net 35 | ports: 36 | - 3001:3001 37 | security_opt: 38 | - no-new-privileges:true 39 | 40 | ##~~~~~~~~~~~~~~~~~~~~## 41 | ##### Healthchecks ##### 42 | ##~~~~~~~~~~~~~~~~~~~~## 43 | 44 | healthchecks: 45 | container_name: healthchecks 46 | image: linuxserver/healthchecks:latest 47 | restart: unless-stopped 48 | environment: 49 | - TZ=Europe/London 50 | - SITE_ROOT=https://healthchecks.domainhere 51 | - SITE_NAME=Health Checks 52 | - SUPERUSER_EMAIL=adminemailhere 53 | - SUPERUSER_PASSWORD=adminpasshere 54 | - APPRISE_ENABLED=True 55 | - PING_BODY_LIMIT=100000 56 | - DEBUG=False 57 | volumes: 58 | - /mnt/disks/docker/healthchecks:/config 59 | networks: 60 | - proxy_net 61 | ports: 62 | - 8000:8000 63 | security_opt: 64 | - no-new-privileges:true 65 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting Security Issues 4 | 5 | Maintainers and community take security bugs seriously. We appreciate your efforts to responsibly disclose your findings, and will make every effort to acknowledge your contributions. 6 | 7 | To report a security issue, please use the GitHub Security Advisory ["Report a Vulnerability"](../../security/advisories/new) tab. 8 | 9 | **Please do not report security vulnerabilities through public GitHub issues, discussions, or Discord.** 10 | 11 | ## What to Include in Your Report 12 | 13 | To help us better understand and resolve the issue, please include as much of the following information as possible: 14 | 15 | - Full paths of source file(s) related to the manifestation of the issue 16 | - The location of the affected source code (tag/branch/commit or direct URL) 17 | - Any special configuration required to reproduce the issue 18 | - Step-by-step instructions to reproduce the issue 19 | - Proof-of-concept or exploit code (if possible) 20 | - Impact of the issue 21 | 22 | ## Response Timeline 23 | 24 | We will send a response indicating the next steps in handling your report. After the initial reply to your report, the security team will keep you informed of the progress towards a fix and full announcement, and may ask for additional information or guidance. 25 | 26 | ## Disclosure Policy 27 | 28 | - Security issues will be disclosed in a coordinated manner 29 | - We will credit reporters in the security advisory unless anonymity is requested 30 | - We request that you do not publicly disclose the issue until we have released a fix 31 | 32 | ## Third-Party Dependencies 33 | 34 | If you discover a security vulnerability in a third-party dependency used by Seerr, please report it directly to the maintainers of that module. You can also notify us through our security advisory process so we can: 35 | 36 | - Track the issue and monitor for updates 37 | - Apply patches or workarounds if available 38 | - Coordinate with upstream maintainers when necessary 39 | - Communicate the impact to our users 40 | 41 | We regularly monitor and update our dependencies to address known security vulnerabilities. 42 | 43 | ## Security Updates 44 | 45 | Security updates and advisories will be published on our [GitHub Security Advisories page](../../security/advisories). 46 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug.yml: -------------------------------------------------------------------------------- 1 | name: 🐛 Bug Report 2 | description: Report a problem 3 | labels: ['bug', 'awaiting triage'] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | Thanks for taking the time to fill out this bug report! 9 | 10 | Please note that we use GitHub issues exclusively for bug reports and feature requests. For support requests, please use our other support channels to get help. 11 | - type: textarea 12 | id: description 13 | attributes: 14 | label: Description 15 | description: Please provide a clear and concise description of the bug or issue. 16 | validations: 17 | required: true 18 | - type: input 19 | id: version 20 | attributes: 21 | label: Version 22 | description: What version of the project are you running? 23 | validations: 24 | required: true 25 | - type: textarea 26 | id: repro-steps 27 | attributes: 28 | label: Steps to Reproduce 29 | description: Please tell us how we can reproduce the undesired behavior. 30 | placeholder: | 31 | 1. Go to [...] 32 | 2. Click on [...] 33 | 3. Scroll down to [...] 34 | 4. See error in [...] 35 | validations: 36 | required: true 37 | - type: textarea 38 | id: screenshots 39 | attributes: 40 | label: Screenshots 41 | description: If applicable, please provide screenshots depicting the problem. 42 | - type: textarea 43 | id: logs 44 | attributes: 45 | label: Logs 46 | description: Please copy and paste any relevant log output. (This will be automatically formatted into code, so no need for backticks.) 47 | render: shell 48 | - type: dropdown 49 | id: platform 50 | attributes: 51 | label: Platform 52 | options: 53 | - desktop 54 | - smartphone 55 | - tablet 56 | validations: 57 | required: true 58 | - type: input 59 | id: device 60 | attributes: 61 | label: Device 62 | description: e.g., iPhone X, Surface Pro, Samsung Galaxy Tab 63 | validations: 64 | required: true 65 | - type: input 66 | id: os 67 | attributes: 68 | label: Operating System 69 | description: e.g., iOS 8.1, Windows 10, Android 12 70 | validations: 71 | required: true 72 | - type: input 73 | id: browser 74 | attributes: 75 | label: Browser 76 | description: e.g., Chrome, Safari, Edge, Firefox 77 | validations: 78 | required: true 79 | - type: textarea 80 | id: additional-context 81 | attributes: 82 | label: Additional Context 83 | description: Please provide any additional information that may be relevant or helpful. 84 | - type: checkboxes 85 | id: terms 86 | attributes: 87 | label: Code of Conduct 88 | description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm/blob/main/CODE_OF_CONDUCT.md) 89 | options: 90 | - label: I agree to follow the project's Code of Conduct 91 | required: true -------------------------------------------------------------------------------- /ubnt-vm-main.tf: -------------------------------------------------------------------------------- 1 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 2 | ## GCP Linux VM - Main ## 3 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 4 | ## Change as Required ## 5 | ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~## 6 | 7 | /* App Data Disk --------------------------------------------------------------------- */ 8 | resource "google_compute_disk" "app-data" { 9 | name = "app-data" 10 | type = "pd-standard" 11 | zone = "${var.gcp_zone}" 12 | size = 20 13 | labels = { 14 | vm = "gcp-cos-vm-01" 15 | managedby = "terraform" 16 | } 17 | } 18 | 19 | /* VM --------------------------------------------------------------------- */ 20 | resource "google_compute_instance" "gcp-ubnt-vm" { 21 | name = var.vm_name 22 | machine_type = var.vm_instance_type 23 | zone = var.gcp_zone 24 | can_ip_forward = "true" 25 | allow_stopping_for_update = "true" 26 | tags = ["ssh","http-server","https-server"] 27 | 28 | 29 | /* Boot Disk --------------------------------------------------------------------- */ 30 | boot_disk { 31 | initialize_params { 32 | image = var.ubnt_2204 33 | } 34 | } 35 | 36 | /* App Data Disk --------------------------------------------------------------------- */ 37 | attached_disk { 38 | source = google_compute_disk.app-data.self_link 39 | device_name = google_compute_disk.app-data.name 40 | } 41 | 42 | /* Startup Script --------------------------------------------------------------------- */ 43 | metadata = { 44 | ssh-keys = "${var.user}:${file(var.publickeypath)}" 45 | } 46 | 47 | metadata_startup_script = "${file("../startup/startup.sh")}" 48 | 49 | /* Network --------------------------------------------------------------------- */ 50 | network_interface { 51 | network = google_compute_network.vpc.name 52 | subnetwork = google_compute_subnetwork.network_subnet.name 53 | access_config { 54 | network_tier = "STANDARD" 55 | } 56 | } 57 | 58 | /* Options --------------------------------------------------------------------- */ 59 | scheduling { 60 | automatic_restart = true 61 | } 62 | 63 | lifecycle { 64 | ignore_changes = [attached_disk] 65 | } 66 | 67 | /* File Copy --------------------------------------------------------------------- */ 68 | provisioner "file" { 69 | # source file name on the local machine where you execute terraform plan and apply 70 | source = "../compose_files/docker-compose.yaml" 71 | # destination is the file location on the newly created instance 72 | destination = "/home/${var.user}/docker-compose.yaml" 73 | connection { 74 | host = google_compute_instance.gcp-ubnt-vm.network_interface.0.access_config.0.nat_ip 75 | type = "ssh" 76 | # username of the instance would vary for each account refer the OS Login in GCP documentation 77 | user = var.user 78 | timeout = "500s" 79 | private_key = file(var.privatekeypath) 80 | } 81 | # Commands to be executed as the instance gets ready. 82 | # installing nginx 83 | #inline = [ 84 | # "sudo /tmp/startupscript.sh" 85 | #] 86 | } 87 | 88 | } 89 | 90 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to make participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies within all project spaces, and it also applies when 49 | an individual is representing the project or its community in public spaces. 50 | Examples of representing a project or community include using an official 51 | project e-mail address, posting via an official social media account, or acting 52 | as an appointed representative at an online or offline event. Representation of 53 | a project may be further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at . All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | -------------------------------------------------------------------------------- /.github/cliff.toml: -------------------------------------------------------------------------------- 1 | # git-cliff ~ configuration 2 | # https://git-cliff.org/docs/configuration 3 | 4 | [changelog] 5 | header = "" 6 | body = """ 7 | {%- macro remote_url() -%} 8 | https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }} 9 | {%- endmacro -%} 10 | 11 | {%- set excluded_users = ["github-actions[bot]", "dependabot[bot]", "renovate[bot]"] -%} 12 | 13 | {% macro print_commit(commit) -%} 14 | - {% if commit.scope %}*({{ commit.scope }})* {% endif %}\ 15 | {% if commit.breaking %}[**breaking**] {% endif %}\ 16 | {{ commit.message | upper_first }} - \ 17 | ([{{ commit.id | truncate(length=7, end="") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\ 18 | {% endmacro -%} 19 | 20 | {% if version %}\ 21 | {% if previous.version %}\ 22 | ## [{{ version | trim_start_matches(pat="v") }}]({{ self::remote_url() }}/compare/{{ previous.version }}..{{ version }}) - {{ timestamp | date(format="%Y-%m-%d") }} 23 | {% else %}\ 24 | ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} 25 | {% endif %}\ 26 | {% else %}\ 27 | ## [unreleased] 28 | {% endif %}\ 29 | 30 | {%- for group, commits in commits | group_by(attribute="group") %} 31 | ### {{ group | striptags | trim | upper_first }} 32 | {%- for commit in commits | filter(attribute="scope") | sort(attribute="scope") %} 33 | {{ self::print_commit(commit=commit) }} 34 | {%- endfor %} 35 | {%- for commit in commits %} 36 | {%- if not commit.scope -%} 37 | {{ self::print_commit(commit=commit) }} 38 | {%- endif -%} 39 | {%- endfor -%} 40 | {%- endfor -%} 41 | 42 | {%- set valid_contributors = [] -%} 43 | {%- for c in github.contributors | filter(attribute="is_first_time", value=true) %} 44 | {%- if c.username and c.username not in excluded_users and c.username not in valid_contributors %} 45 | {%- set_global valid_contributors = valid_contributors | concat(with=c.username) %} 46 | {%- endif %} 47 | {%- endfor %} 48 | 49 | {%- if valid_contributors | length > 0 %} 50 | ## New Contributors ❤️ 51 | {%- for username in valid_contributors %} 52 | * @{{ username }} made their first contribution 53 | {%- endfor %} 54 | {%- endif %} 55 | """ 56 | footer = """ 57 | 58 | """ 59 | trim = true 60 | postprocessors = [] 61 | 62 | [git] 63 | conventional_commits = true 64 | filter_unconventional = true 65 | split_commits = false 66 | filter_commits = true 67 | commit_preprocessors = [ 68 | { pattern = '.*\[skip ci\].*', replace = "" }, 69 | { pattern = '.*\[ci skip\].*', replace = "" }, 70 | ] 71 | commit_parsers = [ 72 | { message = "^feat", group = "🚀 Features" }, 73 | { message = "^fix", group = "🐛 Bug Fixes" }, 74 | { message = "^doc", group = "📖 Documentation" }, 75 | { message = "^perf", group = "⚡ Performance" }, 76 | { message = "^refactor", group = "🚜 Refactor" }, 77 | { message = "^style", group = "🎨 Styling" }, 78 | { message = "^test", group = "🧪 Testing" }, 79 | { message = "^chore\\(release\\): prepare for", skip = true }, 80 | { message = "^chore\\(deps.*\\)", skip = true }, 81 | { message = "^chore\\(pr\\)", skip = true }, 82 | { message = "^chore\\(pull\\)", skip = true }, 83 | { message = "^chore\\(git-sync\\)", skip = true }, 84 | { message = "^chore|^ci", group = "⚙️ Miscellaneous Tasks" }, 85 | { body = ".*security", group = "🛡️ Security" }, 86 | { message = "^revert", group = "◀️ Revert" }, 87 | { message = '.*\[skip ci\].*', skip = true }, 88 | { message = '.*\[ci skip\].*', skip = true }, 89 | ] 90 | protect_breaking_commits = false 91 | tag_pattern = "v?[0-9]+\\.[0-9]+\\.[0-9]+.*" 92 | skip_tags = "beta|alpha|rc" 93 | topo_order = false 94 | sort_commits = "newest" 95 | -------------------------------------------------------------------------------- /.github/renovate/semanticCommits.json5: -------------------------------------------------------------------------------- 1 | { 2 | $schema: "https://docs.renovatebot.com/renovate-schema.json", 3 | packageRules: [ 4 | { 5 | matchDatasources: ["docker"], 6 | matchUpdateTypes: ["major"], 7 | commitMessagePrefix: "feat(container)!: ", 8 | commitMessageTopic: "{{depName}}", 9 | commitMessageExtra: " ( {{currentVersion}} → {{newVersion}} )", 10 | }, 11 | { 12 | matchDatasources: ["docker"], 13 | matchUpdateTypes: ["minor"], 14 | semanticCommitType: "feat", 15 | semanticCommitScope: "container", 16 | commitMessageTopic: "{{depName}}", 17 | commitMessageExtra: "( {{currentVersion}} → {{newVersion}} )", 18 | }, 19 | { 20 | matchDatasources: ["docker"], 21 | matchUpdateTypes: ["patch"], 22 | semanticCommitType: "fix", 23 | semanticCommitScope: "container", 24 | commitMessageTopic: "{{depName}}", 25 | commitMessageExtra: "( {{currentVersion}} → {{newVersion}} )", 26 | }, 27 | { 28 | matchDatasources: ["docker"], 29 | matchUpdateTypes: ["digest"], 30 | semanticCommitType: "chore", 31 | semanticCommitScope: "container", 32 | commitMessageTopic: "{{depName}}", 33 | commitMessageExtra: "( {{currentDigestShort}} → {{newDigestShort}} )", 34 | }, 35 | { 36 | matchDatasources: ["terraform-provider"], 37 | matchUpdateTypes: ["major"], 38 | commitMessagePrefix: "feat(terraform)!: ", 39 | commitMessageTopic: "{{depName}}", 40 | commitMessageExtra: "( {{currentVersion}} → {{newVersion}} )", 41 | }, 42 | { 43 | matchDatasources: ["terraform-provider"], 44 | matchUpdateTypes: ["minor"], 45 | semanticCommitType: "feat", 46 | semanticCommitScope: "terraform", 47 | commitMessageTopic: "{{depName}}", 48 | commitMessageExtra: "( {{currentVersion}} → {{newVersion}} )", 49 | }, 50 | { 51 | matchDatasources: ["terraform-provider"], 52 | matchUpdateTypes: ["patch"], 53 | semanticCommitType: "fix", 54 | semanticCommitScope: "terraform", 55 | commitMessageTopic: "{{depName}}", 56 | commitMessageExtra: "( {{currentVersion}} → {{newVersion}} )", 57 | }, 58 | { 59 | matchDatasources: ["github-releases", "github-tags"], 60 | matchUpdateTypes: ["major"], 61 | commitMessagePrefix: "feat(github-release)!: ", 62 | commitMessageTopic: "{{depName}}", 63 | commitMessageExtra: "( {{currentVersion}} → {{newVersion}} )", 64 | }, 65 | { 66 | matchDatasources: ["github-releases", "github-tags"], 67 | matchUpdateTypes: ["minor"], 68 | semanticCommitType: "feat", 69 | semanticCommitScope: "github-release", 70 | commitMessageTopic: "{{depName}}", 71 | commitMessageExtra: "( {{currentVersion}} → {{newVersion}} )", 72 | }, 73 | { 74 | matchDatasources: ["github-releases", "github-tags"], 75 | matchUpdateTypes: ["patch"], 76 | semanticCommitType: "fix", 77 | semanticCommitScope: "github-release", 78 | commitMessageTopic: "{{depName}}", 79 | commitMessageExtra: "( {{currentVersion}} → {{newVersion}} )", 80 | }, 81 | { 82 | matchManagers: ["github-actions"], 83 | matchUpdateTypes: ["major"], 84 | commitMessagePrefix: "feat(github-action)!: ", 85 | commitMessageTopic: "{{depName}}", 86 | commitMessageExtra: "( {{currentVersion}} → {{newVersion}} )", 87 | }, 88 | { 89 | matchManagers: ["github-actions"], 90 | matchUpdateTypes: ["minor"], 91 | semanticCommitType: "feat", 92 | semanticCommitScope: "github-action", 93 | commitMessageTopic: "{{depName}}", 94 | commitMessageExtra: "( {{currentVersion}} → {{newVersion}} )", 95 | }, 96 | { 97 | matchManagers: ["github-actions"], 98 | matchUpdateTypes: ["patch"], 99 | semanticCommitType: "fix", 100 | semanticCommitScope: "github-action", 101 | commitMessageTopic: "{{depName}}", 102 | commitMessageExtra: "( {{currentVersion}} → {{newVersion}} )", 103 | }, 104 | ], 105 | } 106 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | ### Terraform GCP Ubuntu e2-micro VM 5 | 6 | _Deploys an Ubuntu Minimal VM on Google Cloud’s free tier with Docker CE and Docker Compose preinstalled. Injects a sample Compose project to an attached data disk for quick app bring-up._ 7 |
8 | 9 |
10 | 11 | [![Terraform](https://img.shields.io/badge/Terraform-Required-623CE4?logo=terraform&logoColor=white&style=for-the-badge)](https://www.terraform.io/) 12 | [![Terraform Version](https://img.shields.io/badge/Terraform-1.6%2B-623CE4?logo=terraform&logoColor=white&style=for-the-badge)](https://www.terraform.io/) 13 | 14 |
15 | 16 |
17 | 18 | [![OpenSSF Scorecard](https://img.shields.io/ossf-scorecard/github.com/sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm?label=openssf%20scorecard&style=for-the-badge)](https://scorecard.dev/viewer/?uri=github.com/sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm) 19 | 20 |
21 | 22 | ## Contents 23 | 24 | - [Overview](#overview) 25 | - [Architecture at a glance](#architecture-at-a-glance) 26 | - [Features](#features) 27 | - [Prerequisites](#prerequisites) 28 | - [Quick start](#quick-start) 29 | - [Repository structure](#repository-structure) 30 | - [Google Free Tier information](#google-free-tier-information) 31 | - [Troubleshooting](#troubleshooting) 32 | - [Infrastructure model](#infrastructure-model) 33 | - [Licence](#licence) 34 | - [Security](#security) 35 | - [Contributing](#contributing) 36 | - [Support](#support) 37 | 38 | ## Overview 39 | 40 | Using the supplied Terraform configuration, this project deploys a free-tier eligible **e2-micro** VM running Ubuntu Minimal, with **Docker CE** and **Docker Compose** installed automatically. A sample Compose file is injected onto a data disk at `/mnt/disks/docker/projects/app` that runs **Uptime Kuma** and **Healthchecks** as examples. 41 | 42 | > [!NOTE] 43 | > The full, step-by-step installation guide lives in my docs site: **[sudo-kraken Docs](https://sudo-kraken.github.io/docs/gcp-free-forever/)**. The sections below summarise the essentials for quick use. 44 | 45 | ## Architecture at a glance 46 | 47 | - Terraform Google provider provisions: 48 | - **Compute Engine e2-micro** instance based on **Ubuntu Minimal** 49 | - Optional **secondary persistent disk** for container data, mounted at `/mnt/disks/docker` 50 | - **Firewall rules** for required ingress such as SSH and web ports as defined in `network-firewall.tf` 51 | - **Startup script** installs Docker CE and Docker Compose then places a sample `docker-compose.yaml` under `/mnt/disks/docker/projects/app` 52 | - **SSH key injection** from `~/.ssh/sshkey.pub` 53 | - Outputs expose VM details including external IP 54 | 55 | ## Features 56 | 57 | - Free-tier friendly deployment targeting eligible US regions 58 | - Automatic install of Docker CE and Docker Compose 59 | - Sample Compose project seeded to a mounted data disk 60 | - Separate Terraform files for provider, network, VM and variables for clarity 61 | - Opinionated defaults you can customise via `terraform.tfvars` 62 | 63 | ## Prerequisites 64 | 65 | - A Google Cloud account with Free Tier enabled 66 | - A new or existing GCP project with **Compute Engine API** enabled 67 | - A **service account** with keys and the following roles at project scope: 68 | - `roles/viewer` 69 | - `roles/storage.admin` 70 | - `roles/compute.instanceAdmin.v1` 71 | - `roles/compute.networkAdmin` 72 | - `roles/compute.securityAdmin` 73 | - SSH keypair in `~/.ssh/sshkey` and `~/.ssh/sshkey.pub` in OpenSSH format 74 | - Terraform 1.6 or newer 75 | 76 | > [!NOTE] 77 | > Google defaults VM network service tier to Premium. Switch to **Standard** to stay aligned with free-tier usage. See the screenshot below. 78 | 79 | ## Quick start 80 | 81 | Create basic folders in Cloud Shell or your workstation: 82 | 83 | ```bash 84 | cd ~ 85 | mkdir -p terraform auth compose_files startup .ssh 86 | ``` 87 | 88 | Clone and copy files: 89 | 90 | ```bash 91 | git clone https://github.com/sudo-kraken/terraform-gcp-ubuntu-container-ready-e2-micro-vm.git ~/terraform 92 | # Place your docker-compose.yaml into ~/compose_files 93 | # Place startup.sh into ~/startup 94 | ``` 95 | 96 | Create a service account and key: 97 | 98 | ```bash 99 | # Replace PROJECT-ID-HERE with your project id 100 | gcloud iam service-accounts create tf-serviceaccount \ 101 | --description="service account for terraform" \ 102 | --display-name="terraform_service_account" 103 | 104 | gcloud iam service-accounts keys create ~/auth/google-key.json \ 105 | --iam-account tf-serviceaccount@PROJECT-ID-HERE.iam.gserviceaccount.com 106 | ``` 107 | 108 | Enable required services and bind roles: 109 | 110 | ```bash 111 | gcloud services enable cloudresourcemanager.googleapis.com cloudbilling.googleapis.com iam.googleapis.com storage.googleapis.com serviceusage.googleapis.com 112 | 113 | gcloud projects add-iam-policy-binding PROJECT-ID-HERE --member serviceAccount:tf-serviceaccount@PROJECT-ID-HERE.iam.gserviceaccount.com --role roles/viewer 114 | gcloud projects add-iam-policy-binding PROJECT-ID-HERE --member serviceAccount:tf-serviceaccount@PROJECT-ID-HERE.iam.gserviceaccount.com --role roles/storage.admin 115 | gcloud projects add-iam-policy-binding PROJECT-ID-HERE --member serviceAccount:tf-serviceaccount@PROJECT-ID-HERE.iam.gserviceaccount.com --role roles/compute.instanceAdmin.v1 116 | gcloud projects add-iam-policy-binding PROJECT-ID-HERE --member serviceAccount:tf-serviceaccount@PROJECT-ID-HERE.iam.gserviceaccount.com --role roles/compute.networkAdmin 117 | gcloud projects add-iam-policy-binding PROJECT-ID-HERE --member serviceAccount:tf-serviceaccount@PROJECT-ID-HERE.iam.gserviceaccount.com --role roles/compute.securityAdmin 118 | ``` 119 | 120 | Copy the `.tf` files from this repo into your `~/terraform` folder, review and update variables to match your project and region, then run: 121 | 122 | ```bash 123 | cd ~/terraform 124 | terraform init 125 | terraform plan 126 | terraform apply 127 | ``` 128 | 129 | After apply completes, connect via the external IP using your SSH key or use the Cloud Console’s SSH. Allow a few minutes for the startup script to finish installing Docker and placing the Compose project. 130 | 131 | ## Repository structure 132 | 133 | ```text 134 | . 135 | ├─ auth/ # API user credentials 136 | ├─ compose_files/ 137 | │ └─ docker-compose.yaml # Docker Compose configuration 138 | ├─ startup/ 139 | │ └─ startup.sh # Installs dependencies and seeds files 140 | └─ terraform/ 141 | ├─ network-firewall.tf # Firewall rule definitions 142 | ├─ network-main.tf # Network definitions 143 | ├─ network-variables.tf # Network variables 144 | ├─ provider-main.tf # GCP provider setup 145 | ├─ provider-variables.tf # Provider variables 146 | ├─ terraform.tfvars # Your variable values 147 | ├─ ubnt-versions.tf # Ubuntu version data 148 | ├─ ubnt-vm-main.tf # VM resource definitions 149 | ├─ ubnt-vm-output.tf # Outputs post-provision 150 | └─ ubnt-vm-variables.tf # VM variables 151 | ``` 152 | 153 | ## Google Free Tier information 154 | 155 | Key points highlighted in bold. 156 | 157 | - **Compute Engine** 158 | - 1 non-preemptible **e2-micro VM** per month in one of: 159 | - Oregon: **us-west1** 160 | - Iowa: us-central1 161 | - South Carolina: us-east1 162 | - 30 GB-months standard persistent disk 163 | - 5 GB-month snapshot storage in: 164 | - Oregon: **us-west1** 165 | - Iowa: us-central1 166 | - South Carolina: us-east1 167 | - Taiwan: asia-east1 168 | - Belgium: europe-west1 169 | - **1 GB egress from North America to all regions** per month excluding China and Australia 170 | - **Usage is time-based for e2-micro** across supported regions 171 | - **External IP address is not charged** under the free tier 172 | - GPUs and TPUs are excluded from the free tier 173 | 174 | ### Network service tier screenshot 175 | 176 | By default Google sets the VM networking to Premium. Change it to **Standard** as shown here: 177 | 178 | ![Change network service tier to Standard](https://user-images.githubusercontent.com/53116754/171113057-e9b5409d-1719-422e-a28c-36da70bfee2d.png) 179 | 180 | ## Troubleshooting 181 | 182 | - **APIs or permissions** 183 | Errors during plan or apply often indicate a missing enabled API or insufficient IAM roles on the service account. 184 | - **Startup work still in progress** 185 | Give the VM a few minutes after first boot for Docker install and file injection. Check serial console logs if needed. 186 | - **Network service tier charges** 187 | Switch the VM’s network service tier from Premium to **Standard** to stick to free-tier limits. 188 | 189 | ## Infrastructure model 190 | 191 | ![Infrastructure model](.infragenie/infrastructure_model.png) 192 | 193 | ## Licence 194 | 195 | This project is licensed under the MIT Licence. See the [LICENCE](LICENCE) file for details. 196 | 197 | ## Security 198 | 199 | If you discover a security issue, please review and follow the guidance in [SECURITY.md](SECURITY.md), or open a private security-focused issue with minimal details and request a secure contact channel. 200 | 201 | ## Contributing 202 | 203 | Feel free to open issues or submit pull requests if you have suggestions or improvements. 204 | See [CONTRIBUTING.md](CONTRIBUTING.md) 205 | 206 | ## Support 207 | 208 | Open an [issue](/../../issues) with as much detail as possible, including your project id, region and any Terraform output or error logs that help reproduce the problem. 209 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json 3 | name: Release 4 | 5 | on: 6 | push: 7 | tags: 8 | - 'v*' 9 | 10 | permissions: 11 | contents: read 12 | 13 | concurrency: 14 | group: release-${{ github.ref }} 15 | cancel-in-progress: true 16 | 17 | jobs: 18 | changelog: 19 | name: Generate changelog 20 | runs-on: ubuntu-24.04 21 | permissions: 22 | contents: read 23 | outputs: 24 | release_body: ${{ steps.git-cliff.outputs.content }} 25 | steps: 26 | - name: Checkout 27 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 28 | with: 29 | fetch-depth: 0 30 | persist-credentials: false 31 | 32 | - name: Generate changelog 33 | id: git-cliff 34 | uses: orhun/git-cliff-action@e16f179f0be49ecdfe63753837f20b9531642772 # v4.7.0 35 | with: 36 | config: .github/cliff.toml 37 | args: -vv --current 38 | env: 39 | OUTPUT: CHANGELOG.md 40 | GITHUB_REPO: ${{ github.repository }} 41 | 42 | create-draft-release: 43 | name: Create draft release 44 | runs-on: ubuntu-24.04 45 | needs: changelog 46 | permissions: 47 | contents: write 48 | steps: 49 | - name: Checkout 50 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 51 | with: 52 | persist-credentials: false 53 | 54 | - name: Draft Release 55 | run: gh release create ${GITHUB_REF_NAME} -t "Release ${GITHUB_REF_NAME}" -n "${RELEASE_BODY}" --draft 56 | env: 57 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 58 | RELEASE_BODY: ${{ needs.changelog.outputs.release_body }} 59 | 60 | prepare-artifacts: 61 | name: Prepare release artifacts 62 | runs-on: ubuntu-24.04 63 | permissions: 64 | contents: read 65 | env: 66 | VERSION: ${{ github.ref_name }} 67 | steps: 68 | - name: Checkout 69 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 70 | with: 71 | persist-credentials: false 72 | 73 | - name: Create release archive 74 | run: | 75 | mkdir -p release 76 | 77 | # Create tar.gz with main script and essential files 78 | tar -czf release/terraform-gcp-${VERSION}.tar.gz \ 79 | *.tf \ 80 | terraform.tfvars \ 81 | startup.sh \ 82 | docker-compose.yml \ 83 | README.md \ 84 | LICENSE \ 85 | SECURITY.md \ 86 | SUPPORT.md 87 | 88 | # Create consolidated checksums.txt with sha256 lines for each tarball 89 | cd release 90 | : > checksums.txt 91 | for f in *.tar.gz; do 92 | sha256sum "$f" >> checksums.txt 93 | done 94 | 95 | - name: Upload artifacts 96 | uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 97 | with: 98 | name: release-artifacts-${{ env.VERSION }} 99 | path: release/* 100 | if-no-files-found: error 101 | retention-days: 1 102 | 103 | sign: 104 | if: startsWith(github.ref, 'refs/tags/') 105 | name: Sign artifacts and create SBOM attestation 106 | needs: prepare-artifacts 107 | runs-on: ubuntu-24.04 108 | permissions: 109 | contents: read 110 | id-token: write 111 | env: 112 | VERSION: ${{ github.ref_name }} 113 | COSIGN_YES: 'true' 114 | steps: 115 | - name: Checkout 116 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 117 | with: 118 | persist-credentials: false 119 | 120 | - name: Install Cosign 121 | uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0 122 | 123 | - name: Install Trivy 124 | uses: aquasecurity/setup-trivy@e6c2c5e321ed9123bda567646e2f96565e34abe1 # v0.2.4 125 | 126 | - name: Download artifacts 127 | uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 128 | with: 129 | name: release-artifacts-${{ env.VERSION }} 130 | path: release 131 | 132 | - name: Generate SBOM with Trivy 133 | run: | 134 | trivy fs --format cyclonedx --output terraform-gcp-${{ env.VERSION }}.sbom . 135 | 136 | - name: Sign release artifacts 137 | run: | 138 | cd release 139 | cosign sign-blob \ 140 | --bundle terraform-gcp-${VERSION}.tar.gz.bundle \ 141 | terraform-gcp-${VERSION}.tar.gz 142 | 143 | - name: Create SBOM attestation for the archive 144 | run: | 145 | # Attach the SBOM to the tarball as an attestation bundle 146 | cosign attest-blob -y \ 147 | --type cyclonedx \ 148 | --new-bundle-format \ 149 | --predicate terraform-gcp-${{ env.VERSION }}.sbom \ 150 | --bundle terraform-gcp-${{ env.VERSION }}.sbom.bundle \ 151 | release/terraform-gcp-${{ env.VERSION }}.tar.gz 152 | 153 | - name: Upload signed artifacts 154 | uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 155 | with: 156 | name: signed-artifacts-${{ env.VERSION }} 157 | path: | 158 | release/*.bundle 159 | *.sbom 160 | *.bundle 161 | if-no-files-found: error 162 | retention-days: 1 163 | 164 | verify: 165 | name: Verify signatures and attestation 166 | needs: [prepare-artifacts, sign] 167 | runs-on: ubuntu-24.04 168 | permissions: 169 | contents: read 170 | env: 171 | VERSION: ${{ github.ref_name }} 172 | steps: 173 | - name: Install Cosign 174 | uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0 175 | 176 | - name: Download release artifacts 177 | uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 178 | with: 179 | name: release-artifacts-${{ env.VERSION }} 180 | path: release 181 | 182 | - name: Download signed artifacts 183 | uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 184 | with: 185 | name: signed-artifacts-${{ env.VERSION }} 186 | path: signed 187 | 188 | - name: Verify signatures 189 | run: | 190 | cosign verify-blob \ 191 | --bundle signed/release/terraform-gcp-${VERSION}.tar.gz.bundle \ 192 | --certificate-identity "https://github.com/${{ github.workflow_ref }}" \ 193 | --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \ 194 | release/terraform-gcp-${VERSION}.tar.gz 195 | 196 | - name: Verify SBOM attestation 197 | run: | 198 | cosign verify-blob-attestation \ 199 | --type cyclonedx \ 200 | --new-bundle-format \ 201 | --bundle signed/terraform-gcp-${VERSION}.sbom.bundle \ 202 | --certificate-identity "https://github.com/${{ github.workflow_ref }}" \ 203 | --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \ 204 | release/terraform-gcp-${VERSION}.tar.gz 205 | 206 | - name: Verify checksums 207 | run: | 208 | cd release 209 | sha256sum -c checksums.txt 210 | 211 | publish-release: 212 | name: Publish release 213 | needs: [create-draft-release, verify] 214 | runs-on: ubuntu-24.04 215 | permissions: 216 | contents: write 217 | env: 218 | VERSION: ${{ github.ref_name }} 219 | steps: 220 | - name: Download release artifacts 221 | uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 222 | with: 223 | name: release-artifacts-${{ env.VERSION }} 224 | path: release 225 | 226 | - name: Download signed artifacts 227 | uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 228 | with: 229 | name: signed-artifacts-${{ env.VERSION }} 230 | path: signed 231 | 232 | - name: Upload artifacts to release 233 | run: | 234 | gh release upload "${{ env.VERSION }}" release/* --repo "${{ github.repository }}" 235 | gh release upload "${{ env.VERSION }}" signed/*.sbom signed/*.bundle --repo "${{ github.repository }}" 236 | env: 237 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 238 | 239 | - name: Publish release 240 | run: | 241 | gh release edit "${{ env.VERSION }}" --draft=false --repo "${{ github.repository }}" 242 | env: 243 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 244 | 245 | discord: 246 | name: Send Discord Notification 247 | needs: publish-release 248 | if: always() 249 | runs-on: ubuntu-24.04 250 | steps: 251 | - name: Determine status 252 | id: status 253 | run: | 254 | case "${{ needs.publish-release.result }}" in 255 | success) echo "status=Success" >> $GITHUB_OUTPUT; echo "colour=3066993" >> $GITHUB_OUTPUT ;; 256 | failure) echo "status=Failure" >> $GITHUB_OUTPUT; echo "colour=15158332" >> $GITHUB_OUTPUT ;; 257 | cancelled) echo "status=Cancelled" >> $GITHUB_OUTPUT; echo "colour=10181046" >> $GITHUB_OUTPUT ;; 258 | *) echo "status=Skipped" >> $GITHUB_OUTPUT; echo "colour=9807270" >> $GITHUB_OUTPUT ;; 259 | esac 260 | 261 | - name: Send notification 262 | run: | 263 | WEBHOOK="${{ secrets.DISCORD_WEBHOOK }}" 264 | 265 | PAYLOAD=$(cat <