├── .github ├── CODEOWNERS ├── renovate.json └── workflows │ ├── code-review.yml │ └── terraform.yml ├── ansible ├── group_vars │ └── server │ │ └── .gitkeep └── playbooks │ ├── common │ ├── roles.yml │ ├── run.sh │ ├── playbook.yml │ ├── os-updates.yml │ └── vscode-server.yml │ ├── for-devops │ ├── roles.yml │ ├── run.sh │ └── playbook.yml │ ├── cloudflare │ ├── run.sh │ └── playbook.yml │ └── oci-data-volume.yml ├── terraform ├── templates │ ├── ansible_hosts.tftpl │ ├── cloudinit.tftpl │ └── ansible_vars.tftpl ├── providers.tf ├── outputs.tf ├── cloudinit.tf ├── backups.tf ├── main.tf ├── versions.tf ├── instance_volume.tf ├── firewall.tf ├── network.tf ├── keypair.tf ├── instance.tf ├── cloudflare.tf ├── install.tf ├── variables.tf ├── .terraform.lock.hcl ├── USAGE.md └── README.md ├── .terraform-docs.yml ├── docs ├── icons │ ├── terraform.svg │ ├── cloudflare.svg │ ├── vscode.svg │ ├── docker.svg │ └── helm.svg └── diagram.d2 ├── .gitignore ├── .tflint.hcl ├── .pre-commit-config.yaml ├── .releaserc ├── README.md ├── CHANGELOG.md └── LICENSE /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | @timoa 2 | -------------------------------------------------------------------------------- /ansible/group_vars/server/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ansible/playbooks/common/roles.yml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ansible/playbooks/for-devops/roles.yml: -------------------------------------------------------------------------------- 1 | # Docker 2 | - name: geerlingguy.docker 3 | -------------------------------------------------------------------------------- /ansible/playbooks/cloudflare/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BASEDIR=$(dirname $0) 4 | 5 | # Install Cloudflare Agent & configure Cloudflare Access Tunnel 6 | ansible-playbook -i $BASEDIR/../../hosts.yml $BASEDIR/playbook.yml 7 | -------------------------------------------------------------------------------- /terraform/templates/ansible_hosts.tftpl: -------------------------------------------------------------------------------- 1 | --- 2 | server: 3 | hosts: 4 | ${hostname}: 5 | ansible_host: ${public_ip} 6 | vars: 7 | ansible_user: ${user} 8 | ansible_ssh_private_key_file: ${private_key} 9 | -------------------------------------------------------------------------------- /terraform/providers.tf: -------------------------------------------------------------------------------- 1 | provider "oci" { 2 | tenancy_ocid = var.tenancy_ocid 3 | user_ocid = var.user_ocid 4 | fingerprint = var.fingerprint 5 | private_key = var.private_key 6 | region = var.region 7 | } 8 | 9 | provider "cloudflare" {} 10 | -------------------------------------------------------------------------------- /ansible/playbooks/for-devops/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BASEDIR=$(dirname $0) 4 | 5 | # Install the Ansible roles 6 | ansible-galaxy install -r $BASEDIR/roles.yml 7 | 8 | # Run the playbook 9 | ansible-playbook -i $BASEDIR/../../hosts.yml $BASEDIR/playbook.yml 10 | -------------------------------------------------------------------------------- /terraform/templates/cloudinit.tftpl: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | # timezone: set the timezone 4 | timezone: UTC 5 | 6 | final_message: "System boot (via cloud-init) is COMPLETE, after $UPTIME seconds. Finished at $TIMESTAMP" 7 | 8 | output: 9 | all: '| tee -a /var/log/cloud-init-output.log' 10 | -------------------------------------------------------------------------------- /terraform/outputs.tf: -------------------------------------------------------------------------------- 1 | # Instance Private IP 2 | output "instance_private_ip" { 3 | description = "VS Code Server Instance Private IP" 4 | value = oci_core_instance.instance.private_ip 5 | } 6 | 7 | # Instance Public IP 8 | output "instance_public_ip" { 9 | description = "VS Code Server Instance Public IP" 10 | value = oci_core_instance.instance.public_ip 11 | } 12 | -------------------------------------------------------------------------------- /.terraform-docs.yml: -------------------------------------------------------------------------------- 1 | formatter: markdown table 2 | 3 | sections: 4 | hide: 5 | - providers 6 | 7 | output: 8 | file: "USAGE.md" 9 | mode: inject 10 | 11 | sort: 12 | enabled: false 13 | 14 | settings: 15 | anchor: true 16 | color: true 17 | default: true 18 | description: true 19 | escape: true 20 | indent: 2 21 | required: true 22 | sensitive: true 23 | type: true 24 | -------------------------------------------------------------------------------- /ansible/playbooks/common/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BASEDIR=$(dirname $0) 4 | 5 | # Install the Ansible roles 6 | # ansible-galaxy install -r $BASEDIR/roles.yml 7 | 8 | # Install updates 9 | ansible-playbook -i $BASEDIR/../../hosts.yml $BASEDIR/os-updates.yml 10 | 11 | # Install VS Code Server 12 | ansible-playbook -i $BASEDIR/../../hosts.yml $BASEDIR/vscode-server.yml 13 | 14 | # Install the other required packages 15 | ansible-playbook -i $BASEDIR/../../hosts.yml $BASEDIR/playbook.yml 16 | -------------------------------------------------------------------------------- /docs/icons/terraform.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /terraform/cloudinit.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | cloudinit = templatefile("${path.root}/templates/cloudinit.tftpl", { 3 | user = var.instance_os_user 4 | vscode_version = var.vscode_version 5 | }) 6 | } 7 | 8 | # Generate the Cloud Init config file 9 | data "cloudinit_config" "cloudinit" { 10 | 11 | # Configure the instance + install VSCode Server 12 | part { 13 | filename = "init.cfg" 14 | content_type = "text/cloud-config" 15 | content = local.cloudinit 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ansible/playbooks/common/playbook.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This playbook install the common packages 3 | - hosts: server 4 | become: true 5 | gather_facts: false 6 | 7 | tasks: 8 | - name: Install common packages (unzip, pip, openjdk) 9 | apt: 10 | pkg: 11 | - unzip 12 | - python3-pip 13 | - openjdk-16-jdk 14 | - openjdk-16-jre-headless 15 | 16 | - name: Install Ansible & pre-commit 17 | pip: 18 | name: 19 | - ansible 20 | - pre-commit 21 | -------------------------------------------------------------------------------- /terraform/backups.tf: -------------------------------------------------------------------------------- 1 | # Predefined Volume Backup Policy 2 | data "oci_core_volume_backup_policies" "predefined_volume_backup_policies" { 3 | filter { 4 | name = "display_name" 5 | 6 | values = [ 7 | "silver", 8 | ] 9 | } 10 | } 11 | 12 | # Backup policy 13 | resource "oci_core_volume_backup_policy_assignment" "policy" { 14 | asset_id = oci_core_instance.instance.boot_volume_id 15 | policy_id = data.oci_core_volume_backup_policies.predefined_volume_backup_policies.volume_backup_policies[0].id 16 | } 17 | -------------------------------------------------------------------------------- /terraform/main.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | common_labels = merge(var.labels, { 3 | # Only lowercase keys allowed 4 | "project" = var.namespace 5 | "environment" = var.stage 6 | }) 7 | availability_domains = data.oci_identity_availability_domains.ads.availability_domains[*].name 8 | availability_domain = reverse(local.availability_domains)[0] # Use last AD to try to avoid the "Out of Host capacity" on free tier 9 | } 10 | 11 | # Identity Availability Domains 12 | data "oci_identity_availability_domains" "ads" { 13 | compartment_id = var.compartment_ocid 14 | } 15 | -------------------------------------------------------------------------------- /docs/icons/cloudflare.svg: -------------------------------------------------------------------------------- 1 | 2 | 8 | -------------------------------------------------------------------------------- /terraform/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.0" 3 | 4 | required_providers { 5 | oci = { 6 | source = "oracle/oci" 7 | version = "4.123.0" 8 | } 9 | cloudflare = { 10 | source = "cloudflare/cloudflare" 11 | version = "3.35.0" 12 | } 13 | cloudinit = { 14 | source = "hashicorp/cloudinit" 15 | version = "2.3.5" 16 | } 17 | null = { 18 | source = "hashicorp/null" 19 | version = "3.2.3" 20 | } 21 | local = { 22 | source = "hashicorp/local" 23 | version = "2.5.2" 24 | } 25 | tls = { 26 | source = "hashicorp/tls" 27 | version = "4.0.6" 28 | } 29 | random = { 30 | source = "hashicorp/random" 31 | version = "3.5.1" 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /ansible/playbooks/common/os-updates.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This playbook install the common packages 3 | - hosts: server 4 | become: true 5 | 6 | tasks: 7 | - name: Update apt-get repo and cache 8 | apt: update_cache=yes force_apt_get=yes cache_valid_time=3600 9 | 10 | - name: Upgrade all apt packages 11 | apt: upgrade=dist force_apt_get=yes 12 | 13 | - name: Check if a reboot is needed (Ubuntu) 14 | register: reboot_required_file 15 | stat: path=/var/run/reboot-required get_md5=no 16 | 17 | - name: Reboot if needed (Ubuntu) 18 | reboot: 19 | msg: "Reboot initiated by Ansible due to kernel updates" 20 | connect_timeout: 5 21 | reboot_timeout: 300 22 | pre_reboot_delay: 0 23 | post_reboot_delay: 30 24 | test_command: uptime 25 | when: reboot_required_file.stat.exists 26 | -------------------------------------------------------------------------------- /terraform/templates/ansible_vars.tftpl: -------------------------------------------------------------------------------- 1 | --- 2 | # Global variables 3 | user: ${user} 4 | 5 | # Block Volume /data variables 6 | volume_iqn: ${volume_iqn} 7 | volume_ipv4: ${volume_ipv4} 8 | volume_port: ${volume_port} 9 | volume_chap_username: ${volume_chap_username} 10 | volume_chap_password: ${volume_chap_password} 11 | volume_device_name: ${volume_device_name} 12 | 13 | # VS Code Server 14 | vscode_version: ${vscode_version} 15 | 16 | # Cloudflare 17 | cf_account_id: ${cf_account_id} 18 | cf_tunnel_id: ${cf_tunnel_id} 19 | cf_tunnel_name: ${cf_tunnel_name} 20 | cf_tunnel_secret: ${cf_tunnel_secret} 21 | cf_zone: ${cf_zone} 22 | 23 | # For DevOps 24 | terraform_version: ${terraform_version} 25 | tfdocs_version: ${tfdocs_version} 26 | tfsec_version: ${tfsec_version} 27 | tflint_version: ${tflint_version} 28 | packer_version: ${packer_version} 29 | helm_version: ${helm_version} 30 | kubectl_version: ${kubectl_version} 31 | -------------------------------------------------------------------------------- /docs/icons/vscode.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "github>renovatebot/.github" 5 | ], 6 | "platform": "github", 7 | "platformAutomerge": true, 8 | "branchPrefix": "fix/deps/", 9 | "addLabels": [ 10 | "dependencies", 11 | "security" 12 | ], 13 | "assignees": [ 14 | "timoa" 15 | ], 16 | "packageRules": [ 17 | { 18 | "description": "Automerge renovate minor and patch updates", 19 | "matchPackageNames": [ 20 | "renovate/renovate" 21 | ], 22 | "matchUpdateTypes": [ 23 | "minor", 24 | "patch" 25 | ], 26 | "automerge": true, 27 | "branchTopic": "{{{depNameSanitized}}}-{{{currentValue}}}" 28 | }, 29 | { 30 | "description": "Allow updates after 7 days (exclude renovate)", 31 | "excludePackageNames": [ 32 | "renovate/renovate" 33 | ], 34 | "separateMinorPatch": true, 35 | "minimumReleaseAge": "7 days" 36 | } 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Local .terraform directories 2 | **/**/.terraform/* 3 | 4 | # .tfstate files 5 | **/*.tfstate 6 | **/*.tfstate.* 7 | 8 | # Crash log files 9 | **/crash.log 10 | 11 | # Ignore any .tfvars files that are generated automatically for each Terraform run. Most 12 | # .tfvars files are managed as part of configuration and so should be included in 13 | # version control. 14 | # 15 | # example.tfvars 16 | 17 | # Ignore override files as they are usually used to override resources locally and so 18 | # are not checked in 19 | **/override.tf 20 | **/override.tf.json 21 | **/*_override.tf 22 | **/*_override.tf.json 23 | 24 | # Include override files you do wish to add to version control using negated pattern 25 | # 26 | # !example_override.tf 27 | 28 | # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan 29 | # example: *tfplan* 30 | 31 | # Key Pair files 32 | **/keypairs/**/* 33 | 34 | # Ansible 35 | ansible/hosts.yml 36 | ansible/roles/**/* 37 | ansible/group_vars/**/*.yml 38 | ansible/host_vars/**/*.yml 39 | -------------------------------------------------------------------------------- /.tflint.hcl: -------------------------------------------------------------------------------- 1 | config { 2 | module = true 3 | force = true 4 | disabled_by_default = false 5 | } 6 | 7 | rule "terraform_deprecated_interpolation" { 8 | enabled = true 9 | } 10 | 11 | rule "terraform_deprecated_index" { 12 | enabled = true 13 | } 14 | 15 | rule "terraform_unused_declarations" { 16 | enabled = true 17 | } 18 | 19 | rule "terraform_comment_syntax" { 20 | enabled = true 21 | } 22 | 23 | rule "terraform_documented_outputs" { 24 | enabled = true 25 | } 26 | 27 | rule "terraform_documented_variables" { 28 | enabled = true 29 | } 30 | 31 | rule "terraform_typed_variables" { 32 | enabled = true 33 | } 34 | 35 | rule "terraform_naming_convention" { 36 | enabled = true 37 | } 38 | 39 | rule "terraform_required_version" { 40 | enabled = true 41 | } 42 | 43 | rule "terraform_required_providers" { 44 | enabled = true 45 | } 46 | 47 | rule "terraform_unused_required_providers" { 48 | enabled = true 49 | } 50 | 51 | rule "terraform_standard_module_structure" { 52 | enabled = true 53 | } 54 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | # 3 | - repo: https://github.com/pre-commit/pre-commit-hooks 4 | rev: v4.1.0 5 | hooks: 6 | - id: check-yaml ### Control YAML format 7 | - id: end-of-file-fixer ### Fix end of file with one line 8 | - id: trailing-whitespace ### Remove end of line spaces 9 | - id: check-added-large-files ### Check files size to add only 500ko max 10 | - id: check-merge-conflict ### Check if there is already merge conflict(s) 11 | - id: detect-private-key ### Detect private keys 12 | 13 | # Terraform 14 | - repo: https://github.com/antonbabenko/pre-commit-terraform 15 | rev: v1.62.3 16 | hooks: 17 | - id: terraform_docs ### Inserts Terraform documentation into README.md 18 | - id: terraform_fmt ### Format the Terraform files 19 | - id: terraform_validate ### Validate the Terraform project / module 20 | - id: terraform_tflint ### Lint the Terraform files following HashiCorp recommandations 21 | 22 | # Checkov 23 | - repo: https://github.com/bridgecrewio/checkov.git 24 | rev: '2.2.281' 25 | hooks: 26 | - id: checkov ### Check misconfiguration and security issues 27 | args: [--skip-path, .github] 28 | 29 | # Conventional Commit 30 | - repo: https://github.com/compilerla/conventional-pre-commit 31 | rev: v1.2.0 32 | hooks: 33 | - id: conventional-pre-commit ### Check if the commit message is compliant with the conventional commit style 34 | stages: [commit-msg] 35 | -------------------------------------------------------------------------------- /terraform/instance_volume.tf: -------------------------------------------------------------------------------- 1 | # Create the Block Volume 2 | resource "oci_core_volume" "volume" { 3 | 4 | #checkov:skip=CKV_OCI_2: The 'backup_policy_id' field has been deprecated. 5 | 6 | # Global 7 | compartment_id = var.compartment_ocid 8 | availability_domain = local.availability_domain 9 | display_name = local.block_volume_name 10 | 11 | # Volume 12 | size_in_gbs = var.block_volume_size 13 | 14 | # Encryption 15 | #checkov:skip=CKV_OCI_3: Volume Encryption with KMS will come in the next release 16 | # is_pv_encryption_in_transit_enabled = true 17 | 18 | # Labels 19 | freeform_tags = local.common_labels 20 | 21 | lifecycle { 22 | prevent_destroy = true # Avoid to destroy the volume by mistake 23 | } 24 | } 25 | 26 | # Volume attachment 27 | resource "oci_core_volume_attachment" "volume_attachment" { 28 | 29 | # Global 30 | attachment_type = "iscsi" 31 | instance_id = oci_core_instance.instance.id 32 | volume_id = oci_core_volume.volume.id 33 | device = var.block_volume_device_name 34 | 35 | # Security 36 | use_chap = true 37 | } 38 | 39 | # Mount the volume on /data if the volume has been un-attached 40 | resource "null_resource" "mount_data_volume" { 41 | depends_on = [ 42 | oci_core_instance.instance, 43 | oci_core_volume_attachment.volume_attachment, 44 | ] 45 | 46 | triggers = { 47 | volume_attachment_id = oci_core_volume_attachment.volume_attachment.id # Trigger on volume attachment changes 48 | } 49 | 50 | provisioner "local-exec" { 51 | command = "ansible-playbook -i ${path.root}/../ansible/hosts.yml ${path.root}/../ansible/playbooks/oci-data-volume.yml" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /.releaserc: -------------------------------------------------------------------------------- 1 | { 2 | "repositoryUrl": "https://github.com/timoa/terraform-oci-vscode-server.git", 3 | "branches": [ 4 | "main" 5 | ], 6 | "tagFormat": "v${version}", 7 | "plugins": [ 8 | [ 9 | "@semantic-release/commit-analyzer", 10 | { 11 | "preset": "angular", 12 | "releaseRules": [ 13 | { 14 | "type": "docs", 15 | "release": "patch" 16 | }, 17 | { 18 | "type": "refactor", 19 | "release": "patch" 20 | }, 21 | { 22 | "type": "test", 23 | "release": "patch" 24 | }, 25 | { 26 | "type": "style", 27 | "release": "patch" 28 | } 29 | ], 30 | "parserOpts": { 31 | "noteKeywords": [ 32 | "BREAKING CHANGE", 33 | "BREAKING CHANGES", 34 | "BREAKING" 35 | ] 36 | } 37 | } 38 | ], 39 | [ 40 | "@semantic-release/release-notes-generator", 41 | { 42 | "preset": "angular", 43 | "parserOpts": { 44 | "noteKeywords": [ 45 | "BREAKING CHANGE", 46 | "BREAKING CHANGES", 47 | "BREAKING" 48 | ] 49 | } 50 | } 51 | ], 52 | [ 53 | "@semantic-release/changelog", 54 | { 55 | "changelogFile": "CHANGELOG.md" 56 | } 57 | ], 58 | [ 59 | "@semantic-release/git", 60 | { 61 | "assets": [ 62 | "CHANGELOG.md", 63 | "README.md" 64 | ] 65 | } 66 | ], 67 | [ 68 | "@semantic-release/github", { 69 | "assignees": "timoa" 70 | } 71 | ] 72 | ] 73 | } 74 | -------------------------------------------------------------------------------- /docs/diagram.d2: -------------------------------------------------------------------------------- 1 | # D2 Settings 2 | direction: right 3 | 4 | # Title 5 | title: VSCode Server hosted on OCI with Zero Trust Network (CloudFlare Access) { 6 | near: top-center 7 | shape: text 8 | style: { 9 | font-size: 29 10 | bold: true 11 | underline: true 12 | } 13 | } 14 | 15 | # OCI Infrastructure 16 | VCN: { 17 | Subnet: { 18 | Instance: { 19 | Root Volume: { 20 | VSCode Server { 21 | shape: image 22 | icon: ./icons/vscode.svg 23 | } 24 | cloudflared: { 25 | shape: image 26 | icon: ./icons/cloudflare.svg 27 | } 28 | VSCode Server <-> cloudflared 29 | } 30 | } 31 | Persistent Volume: { 32 | label: Persistent Volume (/data) 33 | Tools: { 34 | docker: { 35 | shape: image 36 | icon: ./icons/docker.svg 37 | width: 50 38 | height: 50 39 | } 40 | terraform: { 41 | shape: image 42 | icon: ./icons/terraform.svg 43 | width: 50 44 | height: 50 45 | } 46 | } 47 | Config: { 48 | shape: page 49 | } 50 | } 51 | Instance -> Persistent Volume 52 | } 53 | Internet Gateway <-> _.VCN.Subnet.Instance.Root Volume.cloudflared: Tunnel 54 | } 55 | 56 | # CloudFlare Infrastructure 57 | CloudFlare Access: { 58 | shape: image 59 | icon: ./icons/cloudflare.svg 60 | _.VCN.Internet Gateway <-> _.CloudFlare Access 61 | } 62 | 63 | # User 64 | User: { 65 | shape: person 66 | } 67 | Browser: { 68 | shape: page 69 | _.User -> _.Browser 70 | } 71 | CloudFlare WARP: { 72 | label: CloudFlare WARP (client) 73 | shape: image 74 | icon: ./icons/cloudflare.svg 75 | _.Browser -> _.CloudFlare WARP -> _.CloudFlare Access 76 | } 77 | -------------------------------------------------------------------------------- /ansible/playbooks/common/vscode-server.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This playbook mount the OCI Block Volume to /data 3 | - hosts: server 4 | become: true 5 | gather_facts: false 6 | 7 | tasks: 8 | - name: Download VS Code Server 9 | get_url: 10 | url: "https://github.com/coder/code-server/releases/download/v{{vscode_version}}/code-server_{{vscode_version}}_arm64.deb" 11 | dest: "/tmp/code-server_{{vscode_version}}_arm64.deb" 12 | 13 | - name: Install VS Code Server 14 | apt: 15 | deb: "/tmp/code-server_{{vscode_version}}_arm64.deb" 16 | 17 | - name: Enable the VSCode Server service 18 | ansible.builtin.systemd: 19 | name: "code-server@{{user}}" 20 | state: started 21 | enabled: yes 22 | masked: no 23 | 24 | - name: Create the VS Code Server folder on /data 25 | file: 26 | path: "/data/code-server" 27 | state: directory 28 | mode: 0755 29 | group: "{{user}}" 30 | owner: "{{user}}" 31 | 32 | - name: Create the projects folder on /data 33 | file: 34 | path: "/data/projects" 35 | state: directory 36 | mode: 0755 37 | group: "{{user}}" 38 | owner: "{{user}}" 39 | 40 | - name: Deactivate the VSCode authentification (protected by SSH connection or Cloudflare Zero Trust) 41 | ansible.builtin.replace: 42 | path: "/home/{{user}}/.config/code-server/config.yaml" 43 | regexp: '(\s+)password(\s+.*)?$' 44 | replace: '\1none\2' 45 | 46 | - name: Update the VS Code Server user data path to /data/code-server 47 | ansible.builtin.lineinfile: 48 | path: "/home/{{user}}/.config/code-server/config.yaml" 49 | line: "user-data-dir: /data/code-server" 50 | regexp: "^user-data-dir: /data/code-server" 51 | state: present 52 | 53 | - name: Restart the VSCode Server service 54 | ansible.builtin.systemd: 55 | name: "code-server@{{user}}" 56 | state: restarted 57 | daemon_reload: yes 58 | -------------------------------------------------------------------------------- /terraform/firewall.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | security_list_ssh = "${var.namespace}-seclist-ssh-${var.stage}" 3 | security_list_vscode = "${var.namespace}-seclist-vscode-${var.stage}" 4 | } 5 | 6 | # Security List | SSH 7 | resource "oci_core_security_list" "security_list_ssh" { 8 | 9 | # Global 10 | compartment_id = var.compartment_ocid 11 | vcn_id = oci_core_vcn.vcn.id 12 | display_name = local.security_list_ssh 13 | 14 | # Ingress 15 | dynamic "ingress_security_rules" { 16 | for_each = var.allowed_ingress_ssh 17 | 18 | content { 19 | description = "Allow traffic only from the SSH allowed IPs" 20 | source = ingress_security_rules.value 21 | protocol = "6" # TCP 22 | 23 | tcp_options { 24 | min = 22 # SSH 25 | max = 22 # SSH 26 | } 27 | } 28 | } 29 | 30 | # Egress 31 | dynamic "egress_security_rules" { 32 | for_each = var.allowed_egress_ssh 33 | 34 | content { 35 | description = "Allow all outbound traffic from the SSH allowed IPs" 36 | destination = egress_security_rules.value 37 | protocol = "all" 38 | } 39 | } 40 | } 41 | 42 | # Security List | VSCode 43 | resource "oci_core_security_list" "security_list_vscode" { 44 | 45 | # Global 46 | compartment_id = var.compartment_ocid 47 | vcn_id = oci_core_vcn.vcn.id 48 | display_name = local.security_list_vscode 49 | 50 | # Ingress 51 | dynamic "ingress_security_rules" { 52 | for_each = var.allowed_ingress_vscode 53 | 54 | content { 55 | description = "Allow traffic only from the VSCode allowed IPs" 56 | source = ingress_security_rules.value 57 | protocol = "6" # TCP 58 | 59 | tcp_options { 60 | min = 443 # HTTPS 61 | max = 443 # HTTPS 62 | } 63 | } 64 | } 65 | 66 | # Egress 67 | dynamic "egress_security_rules" { 68 | for_each = var.allowed_egress_vscode 69 | 70 | content { 71 | description = "Allow all outbound traffic from the VSCode allowed IPs" 72 | destination = egress_security_rules.value 73 | protocol = "all" 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /terraform/network.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | vcn_name = "${var.namespace}-vcn-${var.stage}" 3 | dns_name = var.namespace 4 | igw_name = "${var.namespace}-igw-${var.stage}" 5 | default_rt_name = "${var.namespace}-default-rt-${var.stage}" 6 | subnet_name = "${var.namespace}-subnet-${var.stage}" 7 | } 8 | 9 | # Virtual Cloud Network 10 | resource "oci_core_vcn" "vcn" { 11 | 12 | # Global 13 | compartment_id = var.compartment_ocid 14 | 15 | # VCN 16 | display_name = local.vcn_name 17 | dns_label = local.dns_name 18 | cidr_block = "10.1.0.0/16" 19 | 20 | # Labels 21 | freeform_tags = local.common_labels 22 | } 23 | 24 | # Internet Gateway 25 | resource "oci_core_internet_gateway" "igw" { 26 | 27 | # Global 28 | compartment_id = var.compartment_ocid 29 | vcn_id = oci_core_vcn.vcn.id 30 | 31 | # Internet Gateway 32 | display_name = local.igw_name 33 | 34 | # Labels 35 | freeform_tags = local.common_labels 36 | } 37 | 38 | # Default Route Table 39 | resource "oci_core_default_route_table" "default_rt" { 40 | 41 | # Route Table 42 | manage_default_resource_id = oci_core_vcn.vcn.default_route_table_id 43 | display_name = local.default_rt_name 44 | 45 | # Route Rules 46 | route_rules { 47 | destination = "0.0.0.0/0" 48 | destination_type = "CIDR_BLOCK" 49 | network_entity_id = oci_core_internet_gateway.igw.id 50 | } 51 | 52 | # Labels 53 | freeform_tags = local.common_labels 54 | } 55 | 56 | # Subnet 57 | resource "oci_core_subnet" "subnet" { 58 | 59 | # Global 60 | compartment_id = var.compartment_ocid 61 | vcn_id = oci_core_vcn.vcn.id 62 | 63 | # Subnet 64 | display_name = local.subnet_name 65 | dns_label = local.dns_name 66 | availability_domain = local.availability_domain 67 | cidr_block = "10.1.20.0/24" 68 | route_table_id = oci_core_vcn.vcn.default_route_table_id 69 | dhcp_options_id = oci_core_vcn.vcn.default_dhcp_options_id 70 | 71 | # Security 72 | security_list_ids = [ 73 | oci_core_security_list.security_list_ssh.id, 74 | oci_core_security_list.security_list_vscode.id, 75 | ] 76 | 77 | # Labels 78 | freeform_tags = local.common_labels 79 | } 80 | -------------------------------------------------------------------------------- /terraform/keypair.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | key_name = var.keypair_name != null ? var.keypair_name : "${var.namespace}-keypair-${var.stage}" 3 | 4 | public_key_filename = format( 5 | "%s%s", 6 | local.key_name, 7 | var.keypair_public_key_extension 8 | ) 9 | 10 | public_key_path = format( 11 | "%s/%s", 12 | var.keypair_public_key_path, 13 | local.public_key_filename 14 | ) 15 | 16 | private_key_filename = format( 17 | "%s%s", 18 | local.key_name, 19 | var.keypair_private_key_extension 20 | ) 21 | 22 | private_key_path = format( 23 | "%s/%s", 24 | var.keypair_public_key_path, 25 | local.private_key_filename 26 | ) 27 | } 28 | 29 | # Generate the key pair 30 | resource "tls_private_key" "default" { 31 | count = var.keypair_public_key != null ? 0 : 1 32 | algorithm = var.keypair_key_algorithm 33 | } 34 | 35 | resource "local_file" "public_key_openssh" { 36 | count = var.keypair_public_key != null ? 0 : 1 37 | depends_on = [tls_private_key.default] 38 | content = tls_private_key.default[0].public_key_openssh 39 | filename = local.public_key_path 40 | } 41 | 42 | resource "local_file" "private_key_pem" { 43 | count = var.keypair_public_key != null ? 0 : 1 44 | depends_on = [tls_private_key.default] 45 | content = tls_private_key.default[0].private_key_pem 46 | filename = local.private_key_path 47 | } 48 | 49 | # Change permission to the Public Key 50 | resource "null_resource" "public_key_chmod" { 51 | count = var.keypair_public_key != null && var.keypair_chmod_command_public != "" ? 0 : 1 52 | depends_on = [local_file.public_key_openssh] 53 | 54 | triggers = { 55 | local_file_public_key_openssh = "local_file.public_key_openssh" 56 | } 57 | 58 | provisioner "local-exec" { 59 | command = format(var.keypair_chmod_command_public, local.public_key_path) 60 | } 61 | } 62 | 63 | # Change permission to the Private Key 64 | resource "null_resource" "private_key_chmod" { 65 | count = var.keypair_private_key != null && var.keypair_chmod_command_private != "" ? 1 : 0 66 | depends_on = [local_file.private_key_pem] 67 | 68 | triggers = { 69 | local_file_private_key_pem = "local_file.private_key_pem" 70 | } 71 | 72 | provisioner "local-exec" { 73 | command = format(var.keypair_chmod_command_private, local.private_key_path) 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /ansible/playbooks/for-devops/playbook.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This playbook install the common packages 3 | - hosts: server 4 | become: true 5 | 6 | roles: 7 | - role: geerlingguy.docker_arm 8 | 9 | tasks: 10 | - name: Install Checkov 11 | pip: 12 | name: 13 | - checkov 14 | 15 | - name: Download & Install Terraform {{terraform_version}} 16 | ansible.builtin.unarchive: 17 | src: "https://releases.hashicorp.com/terraform/{{terraform_version}}/terraform_{{terraform_version}}_linux_arm64.zip" 18 | dest: /usr/local/bin 19 | mode: a+x 20 | remote_src: yes 21 | 22 | - name: Download & Install Terraform Docs {{tfdocs_version}} 23 | ansible.builtin.unarchive: 24 | src: "https://github.com/terraform-docs/terraform-docs/releases/download/v{{tfdocs_version}}/terraform-docs-v{{tfdocs_version}}-linux-arm64.tar.gz" 25 | dest: /usr/local/bin 26 | mode: a+x 27 | remote_src: yes 28 | 29 | - name: Download & Install TFSec {{tfsec_version}} 30 | ansible.builtin.unarchive: 31 | src: "https://github.com/aquasecurity/tfsec/releases/download/v{{tfsec_version}}/tfsec_{{tfsec_version}}_linux_arm64.tar.gz" 32 | dest: /usr/local/bin 33 | mode: a+x 34 | remote_src: yes 35 | 36 | - name: Download & Install TFLint {{tflint_version}} 37 | ansible.builtin.unarchive: 38 | src: "https://github.com/terraform-linters/tflint/releases/download/v{{tflint_version}}/tflint_linux_arm64.zip" 39 | dest: /usr/local/bin 40 | mode: a+x 41 | remote_src: yes 42 | 43 | - name: Download & Install Packer {{packer_version}} 44 | ansible.builtin.unarchive: 45 | src: "https://releases.hashicorp.com/packer/{{packer_version}}/packer_{{packer_version}}_linux_arm64.zip" 46 | dest: /usr/local/bin 47 | mode: a+x 48 | remote_src: yes 49 | 50 | - name: Download & Install Helm {{helm_version}} 51 | ansible.builtin.unarchive: 52 | src: "https://get.helm.sh/helm-v{{helm_version}}-linux-arm64.tar.gz" 53 | dest: /usr/local/bin 54 | mode: a+x 55 | remote_src: yes 56 | 57 | - name: Download & Install Kubectl {{kubectl_version}} 58 | get_url: 59 | url: "https://storage.googleapis.com/kubernetes-release/release/v{{kubectl_version}}/bin/linux/arm64/kubectl" 60 | dest: /usr/local/bin 61 | mode: a+x 62 | -------------------------------------------------------------------------------- /ansible/playbooks/oci-data-volume.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This playbook mount the OCI Block Volume to /data 3 | - hosts: server 4 | become: true 5 | gather_facts: false 6 | 7 | tasks: 8 | - name: Create /data folder 9 | file: 10 | path: /data 11 | state: directory 12 | mode: 0755 13 | group: "{{user}}" 14 | owner: "{{user}}" 15 | 16 | - name: Create OCI iSCSI Node 17 | shell: "iscsiadm -m node -o new -T {{volume_iqn}} -p {{volume_ipv4}}:{{volume_port}}" 18 | 19 | - name: Start OCI iSCSI Node at boot 20 | shell: "iscsiadm -m node -o update -T {{volume_iqn}} -n node.startup -v automatic" 21 | 22 | - name: Set the auth for the OCI iSCSI Node 23 | shell: "iscsiadm -m node -T {{volume_iqn}} -p {{volume_ipv4}}:{{volume_port}} -o update -n node.session.auth.authmethod -v CHAP" 24 | 25 | - name: Set the username for the OCI iSCSI Node 26 | shell: "iscsiadm -m node -T {{volume_iqn}} -p {{volume_ipv4}}:{{volume_port}} -o update -n node.session.auth.username -v {{volume_chap_username}}" 27 | 28 | - name: Set the password for the OCI iSCSI Node 29 | shell: "iscsiadm -m node -T {{volume_iqn}} -p {{volume_ipv4}}:{{volume_port}} -o update -n node.session.auth.password -v {{volume_chap_password}}" 30 | 31 | - name: Check if there is already an iSCSI session already exists 32 | shell: "iscsiadm -m session" 33 | register: iscsi_session_exists 34 | ignore_errors: true 35 | 36 | - name: Attach the OCI iSCSI Node to the instance 37 | shell: "iscsiadm -m node -T {{volume_iqn}} -p {{volume_ipv4}}:{{volume_port}} -l" 38 | when: "iscsi_session_exists.stderr is search('iscsiadm: No active sessions.')" 39 | 40 | - name: Check if the volume is formated. if not it will be formated with ext4 41 | community.general.filesystem: 42 | fstype: ext4 43 | state: present 44 | dev: "{{volume_device_name}}" 45 | 46 | - name: Add the label "instance-data" 47 | shell: "e2label $(readlink -f {{volume_device_name}}) instance-data" 48 | 49 | - name: Remove previous ref. of the /data volume if exists on /etc/fstab 50 | shell: "sed -i -e '/^[\\/][^ \t]*[ \t]*\\/data[ \t]/d' /etc/fstab" 51 | 52 | - name: Add the entry to /etc/fstab 53 | shell: "grep -q ^LABEL=instance-data /etc/fstab || echo 'LABEL=instance-data /data ext4 defaults 0 0' | tee -a /etc/fstab >/dev/null" 54 | 55 | - name: Mount the volume on /data 56 | command: mount -a 57 | args: 58 | warn: no 59 | -------------------------------------------------------------------------------- /terraform/instance.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | instance_name = "${var.namespace}-instance-${var.stage}" 3 | instance_vnic_name = "${var.namespace}-vnic-${var.stage}" 4 | block_volume_name = "${var.namespace}-volume-${var.stage}" 5 | instance_image_filter = ["^${replace(var.instance_os, " ", "-")}-${var.instance_os_version}-aarch64-([\\.0-9-]+)$"] 6 | } 7 | 8 | # Images 9 | data "oci_core_images" "ubuntu_20_04_aarch64" { 10 | 11 | # Global 12 | compartment_id = var.compartment_ocid 13 | 14 | # Image 15 | operating_system = var.instance_os 16 | operating_system_version = var.instance_os_version 17 | filter { 18 | name = "display_name" 19 | values = local.instance_image_filter 20 | regex = true 21 | } 22 | } 23 | 24 | # Instance 25 | resource "oci_core_instance" "instance" { 26 | 27 | # Global 28 | compartment_id = var.compartment_ocid 29 | availability_domain = local.availability_domain 30 | display_name = local.instance_name 31 | 32 | # Instance 33 | shape = var.instance_shape 34 | shape_config { 35 | ocpus = var.instance_ocpus 36 | memory_in_gbs = var.instance_shape_config_memory_in_gbs 37 | } 38 | 39 | # Network 40 | create_vnic_details { 41 | subnet_id = oci_core_subnet.subnet.id 42 | display_name = local.instance_vnic_name 43 | assign_public_ip = true 44 | assign_private_dns_record = true 45 | hostname_label = local.instance_name 46 | } 47 | 48 | # Image 49 | source_details { 50 | source_type = "image" 51 | source_id = data.oci_core_images.ubuntu_20_04_aarch64.images[0].id 52 | boot_volume_size_in_gbs = 50 53 | } 54 | 55 | # Launch Options 56 | launch_options { 57 | #checkov:skip=CKV_OCI_4: Can't apply encryption in transit on preemptible instances 58 | # is_pv_encryption_in_transit_enabled = true 59 | network_type = "PARAVIRTUALIZED" 60 | } 61 | 62 | # Instance Options 63 | instance_options { 64 | are_legacy_imds_endpoints_disabled = true 65 | } 66 | 67 | metadata = { 68 | ssh_authorized_keys = tls_private_key.default[0].public_key_openssh 69 | user_data = data.cloudinit_config.cloudinit.rendered 70 | } 71 | 72 | preemptible_instance_config { 73 | preemption_action { 74 | type = "TERMINATE" 75 | preserve_boot_volume = false 76 | } 77 | } 78 | 79 | timeouts { 80 | create = "60m" 81 | } 82 | 83 | # Labels 84 | freeform_tags = local.common_labels 85 | } 86 | -------------------------------------------------------------------------------- /ansible/playbooks/cloudflare/playbook.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This playbook install the Cloudflare Agent (cloudflared) 3 | - hosts: server 4 | become: true 5 | 6 | tasks: 7 | - name: Download Cloudflare Agent (deb) 8 | get_url: 9 | url: "https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-arm64.deb" 10 | dest: "/tmp/cloudflared-linux-arm64.deb" 11 | 12 | - name: Install Cloudflare Agent 13 | apt: 14 | deb: "/tmp/cloudflared-linux-arm64.deb" 15 | 16 | - name: Create the Cloudflare Agent config folder 17 | ansible.builtin.file: 18 | path: "/etc/cloudflared" 19 | state: directory 20 | 21 | - name: Create the Cloudflare Agent cert file 22 | ansible.builtin.copy: 23 | dest: "/etc/cloudflared/cert.json" 24 | content: | 25 | { 26 | "AccountTag" : "{{cf_account_id}}", 27 | "TunnelID" : "{{cf_tunnel_id}}", 28 | "TunnelName" : "{{cf_tunnel_name}}", 29 | "TunnelSecret" : "{{cf_tunnel_secret}}" 30 | } 31 | 32 | - name: Create the Cloudflare Agent config file 33 | ansible.builtin.copy: 34 | dest: "/etc/cloudflared/config.yml" 35 | content: | 36 | tunnel: {{cf_tunnel_id}} 37 | credentials-file: /etc/cloudflared/cert.json 38 | logfile: /var/log/cloudflared.log 39 | loglevel: info 40 | 41 | ingress: 42 | - hostname: {{cf_zone}} 43 | service: http://localhost:8080 44 | - hostname: "*" 45 | service: hello-world 46 | 47 | - name: Increase the UDP Receive Buffer Size needed for the QUIC protocol 48 | shell: sysctl -w net.core.rmem_max=2500000 49 | 50 | - name: Check if the Cloudflare Access Tunnel service already exists 51 | stat: 52 | path: /etc/systemd/system/cloudflared.service 53 | register: cloudflared_service 54 | 55 | - name: Install the Cloudflare Access tunnel 56 | shell: "cloudflared service install" 57 | when: cloudflared_service.stat.exists == False 58 | 59 | - name: Enable the Cloudflare Agent service 60 | ansible.builtin.systemd: 61 | name: "cloudflared" 62 | state: started 63 | enabled: yes 64 | masked: no 65 | when: cloudflared_service.stat.exists == False 66 | 67 | - name: Restart the Cloudflare Agent service 68 | ansible.builtin.systemd: 69 | name: "cloudflared" 70 | state: restarted 71 | daemon_reload: yes 72 | when: cloudflared_service.stat.exists 73 | -------------------------------------------------------------------------------- /.github/workflows/code-review.yml: -------------------------------------------------------------------------------- 1 | name: Code Review 2 | 3 | on: [pull_request] 4 | 5 | jobs: 6 | 7 | # -- LINT ------------------------------------------------------------------- 8 | tflint: 9 | name: TFLint 10 | runs-on: ubuntu-latest 11 | 12 | env: 13 | TF_VAR_tenancy_ocid: ${{secrets.OCI_TENANCY_OCID}} 14 | TF_VAR_compartment_ocid: ${{secrets.OCI_COMPARTMENT_OCID}} 15 | TF_VAR_user_ocid: ${{secrets.OCI_USER_OCID}} 16 | TF_VAR_fingerprint: ${{secrets.OCI_FINGERPRINT}} 17 | TF_VAR_private_key: ${{secrets.OCI_PRIVATE_KEY}} 18 | TF_VAR_region: ${{secrets.OCI_REGION}} 19 | TF_VAR_cf_api_token: ${{secrets.CLOUDFLARE_API_TOKEN}} 20 | 21 | steps: 22 | - name: Harden GitHub Actions Runner 23 | uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e 24 | with: 25 | egress-policy: audit 26 | 27 | - name: Checkout 28 | uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 29 | 30 | - name: Setup Terraform 31 | uses: hashicorp/setup-terraform@633666f66e0061ca3b725c73b2ec20cd13a8fdd1 # v2.0.3 32 | 33 | # Run init to get module code to be able to use `--module` 34 | - name: Terraform init 35 | run: terraform init 36 | working-directory: ./terraform 37 | 38 | # Run TFLint 39 | - name: Run TFlint with reviewdog output on the PR 40 | uses: reviewdog/action-tflint@f17a66a19220804dfa5ba4912e1a9fe7c530fe0a # v1.24.0 41 | 42 | # -- SECURITY --------------------------------------------------------------- 43 | tfsec: 44 | name: TFSec 45 | runs-on: ubuntu-latest 46 | 47 | env: 48 | TF_VAR_tenancy_ocid: ${{secrets.OCI_TENANCY_OCID}} 49 | TF_VAR_compartment_ocid: ${{secrets.OCI_COMPARTMENT_OCID}} 50 | TF_VAR_user_ocid: ${{secrets.OCI_USER_OCID}} 51 | TF_VAR_fingerprint: ${{secrets.OCI_FINGERPRINT}} 52 | TF_VAR_private_key: ${{secrets.OCI_PRIVATE_KEY}} 53 | TF_VAR_region: ${{secrets.OCI_REGION}} 54 | TF_VAR_cf_account_id: ${{secrets.CLOUDFLARE_ACCOUNT_ID}} 55 | CLOUDFLARE_API_TOKEN: ${{secrets.CLOUDFLARE_API_TOKEN}} 56 | 57 | steps: 58 | - name: Harden GitHub Actions Runner 59 | uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e 60 | with: 61 | egress-policy: audit 62 | 63 | - name: Checkout 64 | uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 65 | 66 | # Run TFSec 67 | - name: Run TFsec with reviewdog output on the PR 68 | uses: reviewdog/action-tfsec@18beef5056ad7aa9336a29ff8188aae6615fc6ab # v1.28.4 69 | -------------------------------------------------------------------------------- /docs/icons/docker.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /terraform/cloudflare.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | cf_zone_id = var.cf_zero_trust_enabled ? data.cloudflare_zone.cf_zone[0].id : "" 3 | cf_cname = "${var.cf_subdomain}.${var.cf_domain}" 4 | cf_tunnel_name = "${var.namespace}-tunnel-${var.stage}" 5 | cf_argo_secret = var.cf_zero_trust_enabled ? random_id.argo_secret[0].b64_std : "" 6 | } 7 | 8 | # Get the zone ID for the given domain 9 | data "cloudflare_zone" "cf_zone" { 10 | 11 | count = var.cf_zero_trust_enabled ? 1 : 0 12 | 13 | name = var.cf_domain 14 | } 15 | 16 | ############################# 17 | # Cloudflare Access Tunnel 18 | ############################# 19 | 20 | # Create a secret for the Cloudflare Argo Tunnel 21 | resource "random_id" "argo_secret" { 22 | 23 | count = var.cf_zero_trust_enabled ? 1 : 0 24 | 25 | byte_length = 35 26 | } 27 | 28 | # Create the Cloudflare Argo Tunnel for Cloudflare Access 29 | resource "cloudflare_argo_tunnel" "cf_tunnel" { 30 | 31 | count = var.cf_zero_trust_enabled ? 1 : 0 32 | 33 | account_id = var.cf_account_id 34 | name = local.cf_tunnel_name 35 | secret = local.cf_argo_secret 36 | } 37 | 38 | # Create the Cloudfflare Argo Tunnel Route 39 | resource "cloudflare_tunnel_route" "cf_tunnel_route" { 40 | 41 | count = var.cf_zero_trust_enabled ? 1 : 0 42 | 43 | account_id = var.cf_account_id 44 | tunnel_id = cloudflare_argo_tunnel.cf_tunnel[0].id 45 | network = "${oci_core_instance.instance.private_ip}/32" 46 | comment = "Tunnel Route for VSCode Server" 47 | } 48 | 49 | # Create the Cloudflare DNS Record for the Cloudflare Argo Tunnel 50 | resource "cloudflare_record" "cf_tunnel_cname" { 51 | 52 | count = var.cf_zero_trust_enabled ? 1 : 0 53 | 54 | zone_id = local.cf_zone_id 55 | name = var.cf_subdomain 56 | value = "${cloudflare_argo_tunnel.cf_tunnel[0].id}.cfargotunnel.com" 57 | type = "CNAME" 58 | proxied = true 59 | } 60 | 61 | ############################# 62 | # Cloudflare Access App 63 | ############################# 64 | 65 | # Create the Cloudflare Access Application 66 | resource "cloudflare_access_application" "cf_application" { 67 | 68 | count = var.cf_zero_trust_enabled ? 1 : 0 69 | 70 | zone_id = local.cf_zone_id 71 | domain = local.cf_cname 72 | name = "VSCode Server" 73 | type = "self_hosted" 74 | logo_url = "https://upload.wikimedia.org/wikipedia/commons/thumb/9/9a/Visual_Studio_Code_1.35_icon.svg/1024px-Visual_Studio_Code_1.35_icon.svg.png" 75 | session_duration = "24h" 76 | } 77 | 78 | # Create the Cloudflare Access Application Allow Policy 79 | resource "cloudflare_access_policy" "cf_allow_policy" { 80 | 81 | count = var.cf_zero_trust_enabled ? 1 : 0 82 | # count = length(var.cf_allowed_users) != 0 ? 1 : 0 83 | 84 | application_id = cloudflare_access_application.cf_application[0].id 85 | zone_id = local.cf_zone_id 86 | name = "Allow Policy" 87 | precedence = "1" 88 | decision = "allow" 89 | 90 | include { 91 | email = var.cf_allowed_users 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deploy VSCode Server on OCI with Terraform 2 | 3 | [![Latest Release][release-badge]][release-url] 4 | [![Build Status][github-badge]][github-url] 5 | [![License][license-badge]][license-url] 6 | 7 | ![Diagram VSCode hosted on OCI with CloudFlare Access (zero trust)][diagram] 8 | 9 | Terraform project that deploys VSCode Server on Oracle Cloud Infrastructure using only the free tier. 10 | 11 | > WARNING: This project is currently under active development. 12 | > Please check back later. 13 | 14 | ## The challenge 15 | 16 | ### Goal 17 | 18 | Deploy a free and easy maintenable VSCode Server. 19 | 20 | ### Limitations 21 | 22 | Currently, Oracle Cloud Free tier provides great performance (4vCPU ARM based, 24GB of RAM, and 200GB of storage), but: 23 | 24 | * The instances are preemptible, which means that they can be terminated at any time 25 | * We can't create custom images (with Packer for ex.), so we have to install VSCode Server and other dependencies at boot time 26 | * Can be hard to find an OCI datacenter that still has available capacity 27 | 28 | ### Use cases 29 | 30 | * Code from any computer with your VSCode and your tools without any install 31 | * Code from your tablet or slow computer with a remote VSCode Server 32 | * Onboard a new team member without spending the first days configuring VSCode and other tools on their computer 33 | 34 | ## How to start 35 | 36 | ### Create an OCI account 37 | 38 | Signup for a free OCI account [here][oci-signup-url]. 39 | 40 | If you're new to Oracle Cloud Infrastructure, you need to the following: 41 | 42 | * **Tenant**: kind of an account, like a company or an organization 43 | * **Compartment**: it's a isolated area to deploy a project or an environment (similar a GCP project). 44 | 45 | I recommend to create a new compartment for deploying VSCode Server, that way you will be able to use share free tier resource for a different project or rebuild from scratch a new VSCode Server instead of using the default compartment. 46 | 47 | ### Configure the OCI authentication 48 | 49 | ### Deploy the VSCode Server instance 50 | 51 | ### Access to VSCode Server from your browser 52 | 53 | ### Create a Cloudflare acount (optional) 54 | 55 | Signup for a free Cloudflare account [here][cloudflare-signup-url]. 56 | 57 | ### Configure the Cloudflare Zero Trust (optional) 58 | 59 | ## TODO 60 | 61 | * [x] Create the custom VCN (VPC) 62 | * [x] Get the latest Ubuntu image automatically 63 | * [x] Create the block volume for `/data` (100GB) 64 | * [x] Attach the block volume to the instance 65 | * [x] Create the instance on free tier (4 vCPU, 24GB memory) 66 | * [x] Configure the instance and install VSCode Server with Cloud Init 67 | * [x] Create automatically the SSH key pair 68 | * [x] Mount and format the block volume on `/data` 69 | * [x] Restrict SSH and VS Code port access 70 | * [x] Configure backups of the block volume only 71 | * [x] Configure Cloudflare Access (ZeroTrust) to secure the instance access 72 | * [ ] Install dependencies/tools on the data volume to speed up the provisioning 73 | * [ ] Create dynamically an Ansible Vault to save the sensitive data used by Ansible 74 | * [ ] Encrypt the block volume with a KMS key 75 | * [ ] Write the documentation for the manual steps (Oracle Cloud Infrastructure & Cloudflare accounts, etc.) 76 | * [ ] Explain how to avoid the "Out of Host capacity" error on Oracle Cloud Infrastructure 77 | 78 | ## Known issues 79 | 80 | * [bug] Optional dependencies install are executed in parallel and can fail (dpkg lock) ([#11][i11]) 81 | * [bug] Inconsistent mounting of the /data volume ([#12][i12]) 82 | * [bug] Interactive terminal during Ansible run due to the SSH Host to allow ([#13][i13]) 83 | 84 | [github-badge]: https://github.com/timoa/terraform-oci-vscode-server/workflows/Terraform/badge.svg 85 | [github-url]: https://github.com/timoa/terraform-oci-vscode-server/actions?query=workflow%3ATerraform 86 | [release-badge]: https://img.shields.io/github/release/timoa/terraform-oci-vscode-server.svg 87 | [release-url]: https://github.com/timoa/terraform-oci-vscode-server/releases/latest 88 | [license-badge]: https://img.shields.io/github/license/timoa/terraform-oci-vscode-server.svg 89 | [license-url]: https://github.com/timoa/terraform-oci-vscode-server/blob/main/LICENSE 90 | 91 | [diagram]: /docs/diagram.svg 92 | 93 | [oci-signup-url]: https://signup.cloud.oracle.com 94 | [cloudflare-signup-url]: https://dash.cloudflare.com/sign-up 95 | 96 | [i11]: https://github.com/timoa/terraform-oci-vscode-server/issues/11 97 | [i12]: https://github.com/timoa/terraform-oci-vscode-server/issues/12 98 | [i13]: https://github.com/timoa/terraform-oci-vscode-server/issues/13 99 | -------------------------------------------------------------------------------- /terraform/install.tf: -------------------------------------------------------------------------------- 1 | ############################# 2 | # Configure Ansible 3 | ############################# 4 | 5 | # Create the Ansible inventory file (hosts) 6 | resource "local_file" "ansible_hosts" { 7 | content = templatefile("${path.root}/templates/ansible_hosts.tftpl", { 8 | public_ip = oci_core_instance.instance.public_ip 9 | hostname = local.instance_name 10 | user = var.instance_os_user 11 | private_key = replace(local.private_key_path, "./", "../terraform/") 12 | }) 13 | filename = "${path.root}/../ansible/hosts.yml" 14 | } 15 | 16 | # Create the Ansible variables file (vars.yml) 17 | resource "local_file" "ansible_variables" { 18 | content = templatefile("${path.root}/templates/ansible_vars.tftpl", { 19 | user = var.instance_os_user 20 | volume_iqn = oci_core_volume_attachment.volume_attachment.iqn 21 | volume_ipv4 = oci_core_volume_attachment.volume_attachment.ipv4 22 | volume_port = oci_core_volume_attachment.volume_attachment.port 23 | volume_chap_username = oci_core_volume_attachment.volume_attachment.chap_username 24 | volume_chap_password = oci_core_volume_attachment.volume_attachment.chap_secret 25 | volume_device_name = var.block_volume_device_name 26 | vscode_version = var.vscode_version 27 | cf_account_id = var.cf_zero_trust_enabled ? var.cf_account_id : "" 28 | cf_tunnel_id = var.cf_zero_trust_enabled ? cloudflare_argo_tunnel.cf_tunnel[0].id : "" 29 | cf_tunnel_name = var.cf_zero_trust_enabled ? local.cf_tunnel_name : "" 30 | cf_tunnel_secret = var.cf_zero_trust_enabled ? local.cf_argo_secret : "" 31 | cf_zone = var.cf_zero_trust_enabled ? local.cf_cname : "" 32 | terraform_version = var.terraform_version 33 | tfdocs_version = var.tfdocs_version 34 | tfsec_version = var.tfsec_version 35 | tflint_version = var.tflint_version 36 | packer_version = var.packer_version 37 | helm_version = var.helm_version 38 | kubectl_version = var.kubectl_version 39 | }) 40 | filename = "${path.root}/../ansible/group_vars/server/all.yml" 41 | } 42 | 43 | ############################# 44 | # Install the packages 45 | ############################# 46 | 47 | # Install Common roles 48 | resource "null_resource" "common_playbook" { 49 | depends_on = [ 50 | null_resource.mount_data_volume 51 | ] 52 | 53 | triggers = { 54 | volume_attachment_id = oci_core_volume_attachment.volume_attachment.id # Trigger on volume attachment changes 55 | playbook_id = filemd5("${path.root}/../ansible/playbooks/common/playbook.yml") # Trigger on playbook changes 56 | run_id = filemd5("${path.root}/../ansible/playbooks/common/run.sh") # Trigger on run script changes 57 | } 58 | 59 | provisioner "local-exec" { 60 | command = "bash ${path.root}/../ansible/playbooks/common/run.sh" 61 | } 62 | } 63 | 64 | # Install Cloudflare agent 65 | resource "null_resource" "cloudflare_playbook" { 66 | 67 | count = var.cf_zero_trust_enabled ? 1 : 0 68 | 69 | depends_on = [ 70 | null_resource.mount_data_volume, 71 | null_resource.common_playbook, 72 | ] 73 | 74 | triggers = { 75 | volume_attachment_id = oci_core_volume_attachment.volume_attachment.id # Trigger on volume attachment changes 76 | playbook_id = filemd5("${path.root}/../ansible/playbooks/cloudflare/playbook.yml") # Trigger on playbook changes 77 | run_id = filemd5("${path.root}/../ansible/playbooks/cloudflare/run.sh") # Trigger on run script changes 78 | } 79 | 80 | provisioner "local-exec" { 81 | command = "bash ${path.root}/../ansible/playbooks/cloudflare/run.sh" 82 | } 83 | } 84 | 85 | # Install DevOps roles (if enabled) 86 | resource "null_resource" "devops_roles" { 87 | 88 | count = var.install_devops_deps ? 1 : 0 89 | 90 | depends_on = [ 91 | null_resource.mount_data_volume, 92 | null_resource.common_playbook, 93 | ] 94 | 95 | triggers = { 96 | volume_attachment_id = oci_core_volume_attachment.volume_attachment.id # Trigger on volume attachment changes 97 | playbook_id = filemd5("${path.root}/../ansible/playbooks/for-devops/playbook.yml") # Trigger on playbook changes 98 | run_id = filemd5("${path.root}/../ansible/playbooks/for-devops/run.sh") # Trigger on run script changes 99 | } 100 | 101 | provisioner "local-exec" { 102 | command = "bash ${path.root}/../ansible/playbooks/for-devops/run.sh" 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /.github/workflows/terraform.yml: -------------------------------------------------------------------------------- 1 | name: Terraform 2 | 3 | on: [push] 4 | 5 | jobs: 6 | 7 | # -- TESTS ------------------------------------------------------------------ 8 | tests: 9 | name: Tests 10 | runs-on: ubuntu-latest 11 | 12 | env: 13 | TF_VAR_tenancy_ocid: ${{secrets.OCI_TENANCY_OCID}} 14 | TF_VAR_compartment_ocid: ${{secrets.OCI_COMPARTMENT_OCID}} 15 | TF_VAR_user_ocid: ${{secrets.OCI_USER_OCID}} 16 | TF_VAR_fingerprint: ${{secrets.OCI_FINGERPRINT}} 17 | TF_VAR_private_key: ${{secrets.OCI_PRIVATE_KEY}} 18 | TF_VAR_region: ${{secrets.OCI_REGION}} 19 | TF_VAR_cf_account_id: ${{secrets.CLOUDFLARE_ACCOUNT_ID}} 20 | CLOUDFLARE_API_TOKEN: ${{secrets.CLOUDFLARE_API_TOKEN}} 21 | steps: 22 | - name: Harden GitHub Actions Runner 23 | uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e 24 | with: 25 | egress-policy: block 26 | allowed-endpoints: > 27 | checkpoint-api.hashicorp.com:443 28 | registry.terraform.io:443 29 | github.com:443 30 | iaas.uk-london-1.oraclecloud.com:443 31 | identity.uk-london-1.oci.oraclecloud.com:443 32 | objects.githubusercontent.com:443 33 | releases.hashicorp.com:443 34 | api.cloudflare.com:443 35 | 36 | - name: Checkout 37 | uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 38 | 39 | - name: Setup Terraform 40 | uses: hashicorp/setup-terraform@633666f66e0061ca3b725c73b2ec20cd13a8fdd1 # v2.0.3 41 | 42 | - name: Terraform Format 43 | id: fmt 44 | run: terraform fmt -check 45 | working-directory: ./terraform 46 | continue-on-error: true 47 | 48 | - name: Terraform Init 49 | id: init 50 | working-directory: ./terraform 51 | run: terraform init -upgrade 52 | 53 | - name: Terraform Plan 54 | id: plan 55 | working-directory: ./terraform 56 | run: terraform plan 57 | 58 | # -- SAST SCAN -------------------------------------------------------------- 59 | code-security: 60 | name: Code Security 61 | runs-on: ubuntu-latest 62 | needs: tests 63 | # Skip any PR created by dependabot to avoid permission issues 64 | if: (github.actor != 'dependabot[bot]') 65 | 66 | steps: 67 | - name: Harden GitHub Actions Runner 68 | uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e 69 | with: 70 | egress-policy: block 71 | allowed-endpoints: > 72 | github.com:443 73 | api.github.com:443 74 | pipelines.actions.githubusercontent.com:443 75 | pypi.org:443 76 | 77 | - name: Checkout 78 | uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 79 | 80 | - name: Perform Scan 81 | uses: ShiftLeftSecurity/scan-action@master 82 | 83 | env: 84 | WORKSPACE: https://github.com/${{ github.repository }}/blob/${{ github.sha }} 85 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 86 | SCAN_ANNOTATE_PR: true 87 | 88 | - uses: actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5 # v3.2.1 89 | with: 90 | name: reports 91 | path: reports 92 | 93 | # -- DOCUMENTATION ---------------------------------------------------------- 94 | documentation: 95 | name: Documentation 96 | runs-on: ubuntu-latest 97 | needs: tests 98 | 99 | steps: 100 | - name: Harden GitHub Actions Runner 101 | uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e 102 | with: 103 | egress-policy: block 104 | allowed-endpoints: > 105 | github.com:443 106 | 107 | - name: Checkout 108 | uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 109 | with: 110 | ref: 'main' # Force checkout of main branch to avoid caching from previous jobs 111 | 112 | - name: Terraform Docs 113 | uses: terraform-docs/gh-actions@aeae0038ed47a547e0c0fca5c059d3335f48fb25 # v1.3.0 114 | with: 115 | working-dir: ./terraform 116 | output-file: USAGE.md 117 | output-method: inject 118 | git-push: "true" 119 | git-commit-message: "chore(docs): update Terraform docs" 120 | 121 | # -- RELEASE ---------------------------------------------------------------- 122 | release: 123 | name: Release 124 | runs-on: ubuntu-latest 125 | needs: 126 | - tests 127 | - code-security 128 | - documentation 129 | if: github.ref == 'refs/heads/main' 130 | 131 | steps: 132 | - name: Harden GitHub Actions Runner 133 | uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e 134 | with: 135 | egress-policy: audit 136 | 137 | - name: Checkout 138 | uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 139 | with: 140 | ref: 'main' # Force checkout of main branch to avoid caching from previous jobs 141 | persist-credentials: false 142 | 143 | - name: Semantic Release 144 | uses: cycjimmy/semantic-release-action@8e58d20d0f6c8773181f43eb74d6a05e3099571d # v3.4.2 145 | env: 146 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 147 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # [0.7.0](https://github.com/timoa/terraform-oci-vscode-server/compare/v0.6.0...v0.7.0) (2022-05-29) 2 | 3 | 4 | ### Bug Fixes 5 | 6 | * **ansible:** reboot only if there is kernel updates that really need a reboot ([d3296ac](https://github.com/timoa/terraform-oci-vscode-server/commit/d3296acb296bcec2fb16ebed0a10e459eb7920ab)) 7 | * **cicd:** add missing Cloudflare ENV vars ([1bd7090](https://github.com/timoa/terraform-oci-vscode-server/commit/1bd7090cf9528b67e266f5ba690ae718fa763285)) 8 | * **cicd:** add the CLoudflare API on the Harden runner allow list ([e6f4922](https://github.com/timoa/terraform-oci-vscode-server/commit/e6f492285780285bf90ef18d6a0b26315809a659)) 9 | * **cloudflare:** fix Ansible vars file when Cloudflare is not enabled ([6b2267b](https://github.com/timoa/terraform-oci-vscode-server/commit/6b2267b0e01ca4bf3d0148cbc8171cf6f70934d0)) 10 | * **cloudflare:** fix condition for zone data source ([a34b86c](https://github.com/timoa/terraform-oci-vscode-server/commit/a34b86cbfd451408834c1fcc3e73fa6a484b8396)) 11 | 12 | 13 | ### Features 14 | 15 | * **cloudflare:** add support to the Cloudflare provider ([f6b17f8](https://github.com/timoa/terraform-oci-vscode-server/commit/f6b17f8284ed21f46c955d85973dc97cd8c5329d)) 16 | * **cloudflare:** add the Cloudflare Account ID ([da14c31](https://github.com/timoa/terraform-oci-vscode-server/commit/da14c31d8277b12f6c4d9cdf4b76b56b8f6ebae4)) 17 | * **cloudflare:** create a dedicated Cloudflare Ansible playbook ([5eb5516](https://github.com/timoa/terraform-oci-vscode-server/commit/5eb5516dcf5d594cf1267f4884cb33aaeccb4e71)) 18 | * **cloudflare:** create the Cloudflare Access Tunnel ([367af1d](https://github.com/timoa/terraform-oci-vscode-server/commit/367af1d585f3169e153ff3693f802f69060339b3)) 19 | * **cloudflare:** create the Cloudflare Tunnel automatically and allow only list of users ([1251841](https://github.com/timoa/terraform-oci-vscode-server/commit/12518412147432bb40a1b91d0198e119895aecd2)) 20 | * **cloudflare:** get the Zone ID + create the Cloudflare Access Application ([1a0fe4b](https://github.com/timoa/terraform-oci-vscode-server/commit/1a0fe4bbced9e43d6608fbb3ae8424165bdca14f)) 21 | * **cloudflare:** install the Cloudflare agent (cloudflared) with Ansible ([716b194](https://github.com/timoa/terraform-oci-vscode-server/commit/716b194eff38c708cf128a8f192232edcd63d3b1)) 22 | * **cloudflare:** make Cloudflare Zero Trust optional ([62316ac](https://github.com/timoa/terraform-oci-vscode-server/commit/62316ac252b675cbf91bdd3381e3c6d821c84797)) 23 | * **vscode:** deactivate password since using SSH tunnel or Cloudflare Zero Trust ([c41c99e](https://github.com/timoa/terraform-oci-vscode-server/commit/c41c99e2ce0ab4b1c1357fd4086437eb62cade6d)) 24 | 25 | # [0.6.0](https://github.com/timoa/terraform-oci-vscode-server/compare/v0.5.1...v0.6.0) (2022-05-27) 26 | 27 | 28 | ### Bug Fixes 29 | 30 | * **ansible:** provides system information to the playbooks ([e1e4e0e](https://github.com/timoa/terraform-oci-vscode-server/commit/e1e4e0e9d309c5138c1353a18719c6fca384a71d)) 31 | * **ansible:** use Ansible command to check if the block volume is formated or not ([a88c58a](https://github.com/timoa/terraform-oci-vscode-server/commit/a88c58acd30304a1f18a2c5811c34f4b4384501b)) 32 | * **cloudinit:** update the path to the template + cleanup (WIP) ([a1bd7ff](https://github.com/timoa/terraform-oci-vscode-server/commit/a1bd7ffc009f15a9987d17004354280ca929291c)) 33 | * **install:** trigger te local exec scripts when the instance is replaced ([61a928b](https://github.com/timoa/terraform-oci-vscode-server/commit/61a928b05ab20003e13e60dcb1ef14f2d5c278db)) 34 | * **project:** fix previous messy commit ([1818695](https://github.com/timoa/terraform-oci-vscode-server/commit/1818695df13bb2fada564ed39f4736826960abe7)) 35 | 36 | 37 | ### Features 38 | 39 | * **ansible:** ad the playbooks for mounting the /data volume + VSCode Server install ([5119802](https://github.com/timoa/terraform-oci-vscode-server/commit/5119802dd2b165a507cd628b39416d05a3b69841)) 40 | * **ansible:** add common + devops deps (if enabled) with Ansible ([4598921](https://github.com/timoa/terraform-oci-vscode-server/commit/4598921e6e22881bb32cf0603398e0aef1124da6)) 41 | * **install:** create the Ansible hosts and vars files from the Terraform state ([bbde721](https://github.com/timoa/terraform-oci-vscode-server/commit/bbde7211d2041b6f2d8936177c344ff428f737b7)) 42 | * **install:** execute the Ansible Playbooks for mounting /data + VS Code Server install ([6dc2e69](https://github.com/timoa/terraform-oci-vscode-server/commit/6dc2e697840f2c6420784898906339b892c56fe2)) 43 | 44 | ## [0.5.1](https://github.com/timoa/terraform-oci-vscode-server/compare/v0.5.0...v0.5.1) (2022-05-21) 45 | 46 | 47 | ### Bug Fixes 48 | 49 | * **lint:** TFLint fixes ([42197fc](https://github.com/timoa/terraform-oci-vscode-server/commit/42197fcb4c522d82f9766d64b48e3b8314fac7ef)) 50 | 51 | # [0.5.0](https://github.com/timoa/terraform-oci-vscode-server/compare/v0.4.1...v0.5.0) (2022-05-19) 52 | 53 | 54 | ### Bug Fixes 55 | 56 | * **ad:** use dynamic AD attribution to avoid the "Out of Host capacity" error on the free tier ([254c3b0](https://github.com/timoa/terraform-oci-vscode-server/commit/254c3b0e6d11eb045a64018db441c140a7b0423f)) 57 | * **cloudinit:** remove the deprecated template provider ([8955dc7](https://github.com/timoa/terraform-oci-vscode-server/commit/8955dc7db4677dcbc3a3f3914210880b2133a910)) 58 | * **instance:** trigger the mount script on volume attachment changes ([55e5369](https://github.com/timoa/terraform-oci-vscode-server/commit/55e536923776e4d7d86c4f63f1b8f5a6343990d8)) 59 | * **network:** remove unused variable ([35208a4](https://github.com/timoa/terraform-oci-vscode-server/commit/35208a49aae25bf9efb127628a4fbb4ab3989dce)) 60 | 61 | 62 | ### Features 63 | 64 | * **firewall:** add a security list for SSH and VScode ([14cf9a4](https://github.com/timoa/terraform-oci-vscode-server/commit/14cf9a4aee110da4e67a83d06c85755a20c910bb)) 65 | 66 | ## [0.4.1](https://github.com/timoa/terraform-oci-vscode-server/compare/v0.4.0...v0.4.1) (2022-05-17) 67 | 68 | 69 | ### Bug Fixes 70 | 71 | * **key-pair:** add the automatic Key Pair generation ([173b469](https://github.com/timoa/terraform-oci-vscode-server/commit/173b4698f2eca04047d7df6316fb2245594f6fd2)) 72 | * **network:** fix too long DNS name (max 15 chars only) ([97a0865](https://github.com/timoa/terraform-oci-vscode-server/commit/97a08652502c191e154cc67421b5f40650ee2c00)) 73 | 74 | # [0.4.0](https://github.com/timoa/terraform-oci-vscode-server/compare/v0.3.0...v0.4.0) (2022-05-15) 75 | 76 | 77 | ### Bug Fixes 78 | 79 | * **backups:** remove deprecated command to create volume backups ([25f0c5e](https://github.com/timoa/terraform-oci-vscode-server/commit/25f0c5e62d5e36844dafb6cab65bb6cebf4527ba)) 80 | * **network:** use freefrom_tags instead of defined_tags ([379220a](https://github.com/timoa/terraform-oci-vscode-server/commit/379220ab91fd3f364b277ce5fcf570b73caca69e)) 81 | * **provider:** add missing template provider + TFLint fixes ([c1a09b3](https://github.com/timoa/terraform-oci-vscode-server/commit/c1a09b341f4072e42804a936f06cc12eca8337c2)) 82 | 83 | 84 | ### Features 85 | 86 | * **instance:** add the instance config + cloudinit (WIP) ([9496dc0](https://github.com/timoa/terraform-oci-vscode-server/commit/9496dc0dc9fd9a94afd15ef40712c846b28be06e)) 87 | 88 | # [0.3.0](https://github.com/timoa/terraform-oci-vscode-server/compare/v0.2.0...v0.3.0) (2022-05-13) 89 | 90 | 91 | ### Bug Fixes 92 | 93 | * **cicd:** add the missing compartment_ocid env var on the GitHub Secrets ([b236e08](https://github.com/timoa/terraform-oci-vscode-server/commit/b236e0817acc12cf0f8e6d78a1e9eed5b1a00718)) 94 | 95 | 96 | ### Features 97 | 98 | * **network:** add the creation of the network ([89ee50b](https://github.com/timoa/terraform-oci-vscode-server/commit/89ee50b8bb4ea06d282a54f9bcd9064826358bdf)) 99 | 100 | # [0.2.0](https://github.com/timoa/terraform-oci-vscode-server/compare/v0.1.0...v0.2.0) (2022-05-12) 101 | 102 | 103 | ### Features 104 | 105 | * **project:** add the core files for Terraform ([860d90f](https://github.com/timoa/terraform-oci-vscode-server/commit/860d90f651b9f646b30c712282d059ff959f33f3)) 106 | -------------------------------------------------------------------------------- /terraform/variables.tf: -------------------------------------------------------------------------------- 1 | ############################# 2 | # Global 3 | ############################# 4 | 5 | variable "namespace" { 6 | type = string 7 | description = "Project name that will be use to identifiy the resources" 8 | default = "vscode" 9 | } 10 | 11 | variable "stage" { 12 | type = string 13 | description = "Stage/environment name to tag and suffix the infrastructure composants" 14 | default = "dev" 15 | } 16 | 17 | ############################# 18 | # Oracle Cloud Infrastructure 19 | ############################# 20 | 21 | variable "tenancy_ocid" { 22 | type = string 23 | description = "Tenancy OCID" 24 | default = null # Set with TF_VAR_tenancy_ocid environment variable on ~/.zprofile or ~/.bash_profile 25 | } 26 | 27 | variable "compartment_ocid" { 28 | type = string 29 | description = "Compartment OCID" 30 | default = null # Set with TF_VAR_compartment_ocid environment variable on ~/.zprofile or ~/.bash_profile 31 | } 32 | 33 | variable "user_ocid" { 34 | type = string 35 | description = "User OCID" 36 | default = null # Set with TF_VAR_user_ocid environment variable on ~/.zprofile or ~/.bash_profile 37 | } 38 | 39 | variable "fingerprint" { 40 | type = string 41 | description = "Fingerprint" 42 | default = null # Set with TF_VAR_fingerprint environment variable on ~/.zprofile or ~/.bash_profile 43 | } 44 | 45 | variable "private_key" { 46 | type = string 47 | description = "Private Key content" 48 | default = null # Set with TF_VAR_private_key environment variable on ~/.zprofile or ~/.bash_profile 49 | } 50 | 51 | ############################# 52 | # Location 53 | ############################# 54 | 55 | variable "region" { 56 | type = string 57 | description = "Default Region" 58 | default = "uk-london-1" 59 | } 60 | 61 | ############################# 62 | # Cloudflare Zero Trust 63 | ############################# 64 | 65 | variable "cf_zero_trust_enabled" { 66 | type = bool 67 | description = "Use Cloudflare Zero Trust to access to the VSCode Server instance?" 68 | default = false 69 | } 70 | 71 | variable "cf_account_id" { 72 | type = string 73 | description = "Set by TF_VAR_cf_account_id environment variable on ~/.zprofile or ~/.bash_profile" 74 | default = null 75 | sensitive = true 76 | } 77 | 78 | variable "cf_domain" { 79 | type = string 80 | description = "Domain Name for Cloudflare Zero Trust" 81 | default = "example.com" 82 | } 83 | 84 | variable "cf_subdomain" { 85 | type = string 86 | description = "Subdomain Name for Cloudflare Zero Trust" 87 | default = "vscode" 88 | } 89 | 90 | variable "cf_allowed_users" { 91 | type = list(string) 92 | description = "Users (emails) allowed to access the VSCode Server application" 93 | default = [] 94 | } 95 | 96 | ############################# 97 | # Security Lists 98 | ############################# 99 | 100 | variable "allowed_ingress_ssh" { 101 | type = list(string) 102 | description = "List of IPs allowed to SSH on the instance" 103 | default = [] 104 | } 105 | 106 | variable "allowed_egress_ssh" { 107 | type = list(string) 108 | description = "List of IPs the instance is allowed to connect" 109 | default = ["0.0.0.0/0"] 110 | } 111 | 112 | variable "allowed_ingress_vscode" { 113 | type = list(string) 114 | description = "List of IPs allowed to access to VS Code Server" 115 | default = [] 116 | } 117 | 118 | variable "allowed_egress_vscode" { 119 | type = list(string) 120 | description = "List of IPs the instance is allowed to connect" 121 | default = ["0.0.0.0/0"] 122 | } 123 | 124 | ############################# 125 | # Instance 126 | ############################# 127 | 128 | variable "instance_shape" { 129 | type = string 130 | description = "Instance Shape" 131 | default = "VM.Standard.A1.Flex" 132 | } 133 | 134 | variable "instance_ocpus" { 135 | type = string 136 | description = "Number of OCPUS (CPU cores)" 137 | default = 4 138 | } 139 | 140 | variable "instance_shape_config_memory_in_gbs" { 141 | type = string 142 | description = "Memory in GBs" 143 | default = 24 144 | } 145 | 146 | variable "instance_os" { 147 | type = string 148 | description = "Instance OS" 149 | default = "Canonical Ubuntu" 150 | } 151 | 152 | variable "instance_os_version" { 153 | type = string 154 | description = "Instance OS Version" 155 | default = "20.04" 156 | } 157 | 158 | variable "instance_os_user" { 159 | type = string 160 | description = "Instance User" 161 | default = "ubuntu" # opc if Oracle Linux 162 | } 163 | 164 | ############################# 165 | # Block Volume (/data) 166 | ############################# 167 | 168 | variable "block_volume_size" { 169 | type = string 170 | description = "Block Volume size in GBs (/data)" 171 | default = 100 172 | } 173 | 174 | variable "block_volume_device_name" { 175 | type = string 176 | description = "Block Volume device name (/dev/oracleoci/oraclevdb)" 177 | default = "/dev/oracleoci/oraclevdb" 178 | } 179 | 180 | ############################# 181 | # VS Code Server 182 | ############################# 183 | 184 | variable "vscode_version" { 185 | type = string 186 | description = "VS Code Server Version" 187 | default = "4.4.0" 188 | } 189 | 190 | ############################# 191 | # VS Code Server Dependencies 192 | ############################# 193 | 194 | variable "install_devops_deps" { 195 | type = bool 196 | description = "Install DevOps tools like Docker, Helm, Terraform, Ansible, etc." 197 | default = false 198 | } 199 | 200 | ############################# 201 | # DevOps Tools 202 | ############################# 203 | 204 | variable "terraform_version" { 205 | type = string 206 | description = "Terraform Version" 207 | default = "1.2.1" 208 | } 209 | 210 | variable "tfdocs_version" { 211 | type = string 212 | description = "Terraform Docs Version" 213 | default = "0.16.0" 214 | } 215 | 216 | variable "tfsec_version" { 217 | type = string 218 | description = "TFSec Version" 219 | default = "1.21.2" 220 | } 221 | 222 | variable "tflint_version" { 223 | type = string 224 | description = "TFLint Version" 225 | default = "0.37.0" 226 | } 227 | 228 | variable "packer_version" { 229 | type = string 230 | description = "Packer Version" 231 | default = "1.8.1" 232 | } 233 | 234 | variable "helm_version" { 235 | type = string 236 | description = "Helm Version" 237 | default = "3.9.0" 238 | } 239 | 240 | variable "kubectl_version" { 241 | type = string 242 | description = "Kubectl Version" 243 | default = "1.24.0" 244 | } 245 | 246 | ############################# 247 | # Key Pairs 248 | ############################# 249 | 250 | variable "keypair_name" { 251 | type = string 252 | description = "Name of the Key Pair (instance or service for ex.)" 253 | default = null 254 | } 255 | 256 | variable "keypair_public_key" { 257 | type = string 258 | description = "A pregenerated OpenSSH-formatted public key. Changing this creates a new keypair. If a public key is not specified, then a public/private key pair will be automatically generated. If a pair is created, then destroying this resource means you will lose access to that keypair forever." 259 | default = null 260 | } 261 | 262 | variable "keypair_public_key_path" { 263 | type = string 264 | description = "Path to Public Key directory (e.g. `/keypairs`)" 265 | default = "./keypairs" 266 | } 267 | 268 | variable "keypair_key_algorithm" { 269 | type = string 270 | description = "Key Pair algorithm" 271 | default = "RSA" 272 | } 273 | 274 | variable "keypair_private_key" { 275 | type = string 276 | description = "A pregenerated OpenSSH-formatted private key. Changing this creates a new keypair. If a private key is not specified, then a public/private key pair will be automatically generated. If a pair is created, then destroying this resource means you will lose access to that keypair forever." 277 | default = null 278 | } 279 | 280 | variable "keypair_private_key_extension" { 281 | type = string 282 | description = "Private key extension" 283 | default = "" 284 | } 285 | 286 | variable "keypair_public_key_extension" { 287 | type = string 288 | description = "Public key extension" 289 | default = ".pub" 290 | } 291 | 292 | variable "keypair_chmod_command_public" { 293 | type = string 294 | description = "Template of the command executed on the public key file" 295 | default = "chmod 600 %v" 296 | } 297 | 298 | variable "keypair_chmod_command_private" { 299 | type = string 300 | description = "Template of the command executed on the private key file" 301 | default = "chmod 400 %v" 302 | } 303 | 304 | ############################# 305 | # Labels 306 | ############################# 307 | 308 | variable "labels" { 309 | type = map(string) 310 | description = "Default labels to associate to these resources" 311 | default = { 312 | # Only lowercase keys allowed 313 | businessunit = "mycompany" 314 | team = "devops" 315 | project = "VSCode Server" 316 | terraform = "true" 317 | } 318 | } 319 | -------------------------------------------------------------------------------- /terraform/.terraform.lock.hcl: -------------------------------------------------------------------------------- 1 | # This file is maintained automatically by "terraform init". 2 | # Manual edits may be lost in future updates. 3 | 4 | provider "registry.terraform.io/cloudflare/cloudflare" { 5 | version = "3.35.0" 6 | constraints = "3.35.0" 7 | hashes = [ 8 | "h1:D2PtNXMzPHM2Tqru1ydo0EboFUtJpmcO7dDXJoUwOX8=", 9 | "h1:Ijis9rBZQnJ49fMDc0DYuNObfFkBsHSc3XSJILWw+AM=", 10 | "h1:Kk3tN3imJl4Jz4s/gE1ecgEDWVgCbLO5JCHOAxDcl18=", 11 | "h1:MnFPQ4VOICJgdxz7ZDMvKBdK2dk3xuQF2PELjAEgQIg=", 12 | "h1:NrZXt8fHguPaNYdoOGqWLjXZ3R9/e03KNpZBVokbpZs=", 13 | "h1:Pz5TV7h/BXPJnNtlmUfbirFE9yXozYpXceo01tYlR0Y=", 14 | "h1:RRUt72l8TuYsqrHSKzM+rUsLXiWRU8CFwbPPX3prurQ=", 15 | "h1:RkxEqX6M/mrfLnveex+zJIajLfYBHc8vtvjaguuHm60=", 16 | "h1:SChRVWQId4/1h2ns5Pt6Z4VYCNBbz/24rVdCLy52zRs=", 17 | "h1:SFvdgX5bTGhOTMhywgjSOWlkET2el7STxdUSzxjz2pc=", 18 | "h1:Vy1p2QsavFh3l7Ppf1i5luUDS0/1KY4qRhL9wt2hzVk=", 19 | "h1:XdbQl3yvpzzDha8ide7jDHuLNkDsGPR2jpGn2IIJqfk=", 20 | "h1:o3eDmbpTavTKxP/NS4VMVsck6FjVjCYIMgVgoptA05A=", 21 | "h1:pn9uUSAuIE8XgqJuZ9fOs98bRN9qw4o0JHFgmwtbMyI=", 22 | ] 23 | } 24 | 25 | provider "registry.terraform.io/hashicorp/cloudinit" { 26 | version = "2.3.5" 27 | constraints = "2.3.5" 28 | hashes = [ 29 | "h1:C//ncldNugV8TpMQaj9ygoPXRVYOqltIxNB8LKrpzgU=", 30 | "h1:HCoabXm6NQwCivl1q24+l9VUufc2mFqNeulsQBA9iFg=", 31 | "h1:NCYXIt7zhG0pRLV9UAlBrKi4Rty/jRhRRHIZFEigUm8=", 32 | "h1:Sf1Lt21oTADbzsnlU38ylpkl8YXP0Beznjcy5F/Yx64=", 33 | "h1:TUljFfEUFn6szDfglwv150tNRUKPgqa5YiCTdF9Tc6c=", 34 | "h1:W+6XNutLOfQxlm8XWg4wKAYvyDt/eoE1roSeFkn/KA4=", 35 | "h1:cKe6NmJzRHiK0n73R5Dzkw8nK5i0nC4SedZhanMbQD0=", 36 | "h1:jPzwR4Um4NU8EE6o5AIx2SoeGZG5bW9aAeFpcbodjHQ=", 37 | "h1:sfaNIqomGVkYy6gGHbaFS2ehzh5CqoeBwR4QYae+cBY=", 38 | "h1:wbw64JlCobcQCAdlzHpxksQ1GabewTW1yxnACBVZh4A=", 39 | "h1:y0qqdBKvRt2MMcga7AVMkUb/vmJSKVBaimHaIHKLucs=", 40 | "zh:17c20574de8eb925b0091c9b6a4d859e9d6e399cd890b44cfbc028f4f312ac7a", 41 | "zh:348664d9a900f7baf7b091cf94d657e4c968b240d31d9e162086724e6afc19d5", 42 | "zh:5a876a468ffabff0299f8348e719cb704daf81a4867f8c6892f3c3c4add2c755", 43 | "zh:6ef97ee4c8c6a69a3d36746ba5c857cf4f4d78f32aa3d0e1ce68f2ece6a5dba5", 44 | "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", 45 | "zh:8283e5a785e3c518a440f6ac6e7cc4fc07fe266bf34974246f4e2ef05762feda", 46 | "zh:a44eb5077950168b571b7eb65491246c00f45409110f0f172cc3a7605f19dba9", 47 | "zh:aa0806cbff72b49c1b389c0b8e6904586e5259c08dabb7cb5040418568146530", 48 | "zh:bec4613c3beaad9a7be7ca99cdb2852073f782355b272892e6ee97a22856aec1", 49 | "zh:d7fe368577b6c8d1ae44c751ed42246754c10305c7f001cc0109833e95aa107d", 50 | "zh:df2409fc6a364b1f0a0f8a9cd8a86e61e80307996979ce3790243c4ce88f2915", 51 | "zh:ed3c263396ff1f4d29639cc43339b655235acf4d06296a7c120a80e4e0fd6409", 52 | ] 53 | } 54 | 55 | provider "registry.terraform.io/hashicorp/local" { 56 | version = "2.5.2" 57 | constraints = "2.5.2" 58 | hashes = [ 59 | "h1:4xE7lRjKhltkMpxJMTfuyBZpNuNitFoyvGlR7/ieppc=", 60 | "h1:6NIiHWMbE9bFZaUiqC+OokdWSbW7g3+yQYnO4yvgtuY=", 61 | "h1:6XyefmvbkprppmYbGmMcQW5NB4w6C363SSShzuhF4R0=", 62 | "h1:C5d0yPD8I0eR6CXUmhI4NxidWQy6YAzsLv4fJFmIvI4=", 63 | "h1:ERAqA7AfanDulZ9OgJDITGM27OnwiYjUNXezJ5zbBvQ=", 64 | "h1:IyFbOIO6mhikFNL/2h1iZJ6kyN3U00jgkpCLUCThAfE=", 65 | "h1:JlMZD6nYqJ8sSrFfEAH0Vk/SL8WLZRmFaMUF9PJK5wM=", 66 | "h1:lIO9I6n7x/aIE5NUowJ3a7ePuH3wel+OiPaOekwNkqg=", 67 | "h1:p99F1AoV9z51aJ4EdItxz/vLwWIyhx/0Iw7L7sWSH1o=", 68 | "h1:rQ7NWEsccZTK7aVbQCLl2TtY7WjrL++5jYdBCbbFdtM=", 69 | "h1:wkWAhCHU3SD6qWiDqF5q2Fd7DlU4JTYUBGlQN+zf5eI=", 70 | "zh:136299545178ce281c56f36965bf91c35407c11897f7082b3b983d86cb79b511", 71 | "zh:3b4486858aa9cb8163378722b642c57c529b6c64bfbfc9461d940a84cd66ebea", 72 | "zh:4855ee628ead847741aa4f4fc9bed50cfdbf197f2912775dd9fe7bc43fa077c0", 73 | "zh:4b8cd2583d1edcac4011caafe8afb7a95e8110a607a1d5fb87d921178074a69b", 74 | "zh:52084ddaff8c8cd3f9e7bcb7ce4dc1eab00602912c96da43c29b4762dc376038", 75 | "zh:71562d330d3f92d79b2952ffdda0dad167e952e46200c767dd30c6af8d7c0ed3", 76 | "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", 77 | "zh:805f81ade06ff68fa8b908d31892eaed5c180ae031c77ad35f82cb7a74b97cf4", 78 | "zh:8b6b3ebeaaa8e38dd04e56996abe80db9be6f4c1df75ac3cccc77642899bd464", 79 | "zh:ad07750576b99248037b897de71113cc19b1a8d0bc235eb99173cc83d0de3b1b", 80 | "zh:b9f1c3bfadb74068f5c205292badb0661e17ac05eb23bfe8bd809691e4583d0e", 81 | "zh:cc4cbcd67414fefb111c1bf7ab0bc4beb8c0b553d01719ad17de9a047adff4d1", 82 | ] 83 | } 84 | 85 | provider "registry.terraform.io/hashicorp/null" { 86 | version = "3.2.3" 87 | constraints = "3.2.3" 88 | hashes = [ 89 | "h1:+AnORRgFbRO6qqcfaQyeX80W0eX3VmjadjnUFUJTiXo=", 90 | "h1:I0Um8UkrMUb81Fxq/dxbr3HLP2cecTH2WMJiwKSrwQY=", 91 | "h1:KN+takGblkyoaNFclDjQavXC/FNz/CkF1UY0nqNCUHY=", 92 | "h1:et7UFgRi/FtALhVrItMeSWc/HPuMnnnkDw7fk18dkDQ=", 93 | "h1:i3HVDAY1s3/9EuPwV5QTBQSr/E/LOxUN3px1sUZGbkA=", 94 | "h1:lIvitiHbzf+j9amFhEXljXncNo3O/8SoVQYQ6O29CSI=", 95 | "h1:nKUqWEza6Lcv3xRlzeiRQrHtqvzX1BhIzjaOVXRYQXQ=", 96 | "h1:obXguGZUWtNAO09f1f9Cb7hsPCOGXuGdN8bn/ohKRBQ=", 97 | "h1:v4DuXoLvBGe0xRT5St53bNICRVbHRUO+m/TreMBCw/U=", 98 | "h1:xtNWHxcFgrYF1TwPSdVloQPPfzsva9lIy+D2avuvelw=", 99 | "h1:zxoDtu918XPWJ/Y6s4aFrZydn6SfqkRc5Ax1ZLnC6Ew=", 100 | "zh:22d062e5278d872fe7aed834f5577ba0a5afe34a3bdac2b81f828d8d3e6706d2", 101 | "zh:23dead00493ad863729495dc212fd6c29b8293e707b055ce5ba21ee453ce552d", 102 | "zh:28299accf21763ca1ca144d8f660688d7c2ad0b105b7202554ca60b02a3856d3", 103 | "zh:55c9e8a9ac25a7652df8c51a8a9a422bd67d784061b1de2dc9fe6c3cb4e77f2f", 104 | "zh:756586535d11698a216291c06b9ed8a5cc6a4ec43eee1ee09ecd5c6a9e297ac1", 105 | "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", 106 | "zh:9d5eea62fdb587eeb96a8c4d782459f4e6b73baeece4d04b4a40e44faaee9301", 107 | "zh:a6355f596a3fb8fc85c2fb054ab14e722991533f87f928e7169a486462c74670", 108 | "zh:b5a65a789cff4ada58a5baffc76cb9767dc26ec6b45c00d2ec8b1b027f6db4ed", 109 | "zh:db5ab669cf11d0e9f81dc380a6fdfcac437aea3d69109c7aef1a5426639d2d65", 110 | "zh:de655d251c470197bcbb5ac45d289595295acb8f829f6c781d4a75c8c8b7c7dd", 111 | "zh:f5c68199f2e6076bce92a12230434782bf768103a427e9bb9abee99b116af7b5", 112 | ] 113 | } 114 | 115 | provider "registry.terraform.io/hashicorp/random" { 116 | version = "3.6.3" 117 | hashes = [ 118 | "h1:+UItZOLue/moJfnI3tqZBQbXUYR4ZnqPYfJDJPgLZy0=", 119 | "h1:4LlZaEeRPQNeQVS/qkH33e0fw92dZV8bS855mhDZ5GU=", 120 | "h1:Fnaec9vA8sZ8BXVlN3Xn9Jz3zghSETIKg7ch8oXhxno=", 121 | "h1:In4XBRMdhY89yUoTUyar3wDF28RJlDpQzdjahp59FAk=", 122 | "h1:LFe/7Z6YZvnrBcYhSEQY50DfS3uoDKBakwdqVXcEQkc=", 123 | "h1:N2IQabOiZC5eCEGrfgVS6ChVmRDh1ENtfHgGjnV4QQQ=", 124 | "h1:aP69UhBhTPIVy1laxOTwOVRPB5Gv3WP9wKPyAnYd8DI=", 125 | "h1:f6jXn4MCv67kgcofx9D49qx1ZEBv8oyvwKDMPBr0A24=", 126 | "h1:ph2J8mV6yYVsaN6FIsxhpWv//QuloQESo4tAZU732Uk=", 127 | "h1:swbWBC5hf9ijj1BQcCpwLOI1m1tXH2KNGp8TEqnMiAY=", 128 | "h1:zG9uFP8l9u+yGZZvi5Te7PV62j50azpgwPunq2vTm1E=", 129 | "zh:04ceb65210251339f07cd4611885d242cd4d0c7306e86dda9785396807c00451", 130 | "zh:448f56199f3e99ff75d5c0afacae867ee795e4dfda6cb5f8e3b2a72ec3583dd8", 131 | "zh:4b4c11ccfba7319e901df2dac836b1ae8f12185e37249e8d870ee10bb87a13fe", 132 | "zh:4fa45c44c0de582c2edb8a2e054f55124520c16a39b2dfc0355929063b6395b1", 133 | "zh:588508280501a06259e023b0695f6a18149a3816d259655c424d068982cbdd36", 134 | "zh:737c4d99a87d2a4d1ac0a54a73d2cb62974ccb2edbd234f333abd079a32ebc9e", 135 | "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", 136 | "zh:a357ab512e5ebc6d1fda1382503109766e21bbfdfaa9ccda43d313c122069b30", 137 | "zh:c51bfb15e7d52cc1a2eaec2a903ac2aff15d162c172b1b4c17675190e8147615", 138 | "zh:e0951ee6fa9df90433728b96381fb867e3db98f66f735e0c3e24f8f16903f0ad", 139 | "zh:e3cdcb4e73740621dabd82ee6a37d6cfce7fee2a03d8074df65086760f5cf556", 140 | "zh:eff58323099f1bd9a0bec7cb04f717e7f1b2774c7d612bf7581797e1622613a0", 141 | ] 142 | } 143 | 144 | provider "registry.terraform.io/hashicorp/tls" { 145 | version = "4.0.6" 146 | constraints = "4.0.6" 147 | hashes = [ 148 | "h1:/GYlCthGsP6ooHpCFuMkjnuFoBX0xnvCNohf3suVw2A=", 149 | "h1:/sSdjHoiykrPdyBP1JE03V/KDgLXnHZhHcSOYIdDH/A=", 150 | "h1:17Y+vdYNKgphpe1/SU5PBnGuYKEJkJZ7MZCnmAwsAGQ=", 151 | "h1:3hTE3Ifpfh4ogQN60xa3Dw2Cbk2QyK8rJ5Zi2f5cYTo=", 152 | "h1:N7VxdRDiNZoRS9dnXJ+QuKWKn514ahS+U6f9K3cF44s=", 153 | "h1:QAuzEStYipyCgx5On0Rym6EiFfqXnBQOrgUjBY7MIbU=", 154 | "h1:W1r1GqxtFMYVCcqFpN7U8WGjbpvpA/YPcqjZbx5THG8=", 155 | "h1:dYSb3V94K5dDMtrBRLPzBpkMTPn+3cXZ/kIJdtFL+2M=", 156 | "h1:dr3jNQWLXzZ2IJ1XH2XIHScQd4HGKo+7ZoyoEP9hRpY=", 157 | "h1:irxVvxMIETCpSsiJKpu4A3htA0v2ohIkpPNXVt++pio=", 158 | "h1:n3M50qfWfRSpQV9Pwcvuse03pEizqrmYEryxKky4so4=", 159 | "zh:10de0d8af02f2e578101688fd334da3849f56ea91b0d9bd5b1f7a243417fdda8", 160 | "zh:37fc01f8b2bc9d5b055dc3e78bfd1beb7c42cfb776a4c81106e19c8911366297", 161 | "zh:4578ca03d1dd0b7f572d96bd03f744be24c726bfd282173d54b100fd221608bb", 162 | "zh:6c475491d1250050765a91a493ef330adc24689e8837a0f07da5a0e1269e11c1", 163 | "zh:81bde94d53cdababa5b376bbc6947668be4c45ab655de7aa2e8e4736dfd52509", 164 | "zh:abdce260840b7b050c4e401d4f75c7a199fafe58a8b213947a258f75ac18b3e8", 165 | "zh:b754cebfc5184873840f16a642a7c9ef78c34dc246a8ae29e056c79939963c7a", 166 | "zh:c928b66086078f9917aef0eec15982f2e337914c5c4dbc31dd4741403db7eb18", 167 | "zh:cded27bee5f24de6f2ee0cfd1df46a7f88e84aaffc2ecbf3ff7094160f193d50", 168 | "zh:d65eb3867e8f69aaf1b8bb53bd637c99c6b649ba3db16ded50fa9a01076d1a27", 169 | "zh:ecb0c8b528c7a619fa71852bb3fb5c151d47576c5aab2bf3af4db52588722eeb", 170 | "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", 171 | ] 172 | } 173 | 174 | provider "registry.terraform.io/oracle/oci" { 175 | version = "4.123.0" 176 | constraints = "4.123.0" 177 | hashes = [ 178 | "h1:+Rcz37RnGRoZ7ug56zfrGcCkgEJQWrGODL9oeWiB/WQ=", 179 | "h1:4WzJ565EaZyBvlHuT5+TRgXMt+vg6agZBQwFk39DMXM=", 180 | "h1:CHVUwKKu7uffvrk8bNseqzYm717lFy1/BhOOTqgABGA=", 181 | "h1:DnwLyufVfDncHewg3YrmmBYCov2xlVgodb3Kl6gSKQ0=", 182 | "h1:GARaKiLdEw3PLpap7b7wYCp9CSdD/O79xMMYFiIkJ/M=", 183 | "h1:MP8THD3bwzwZ0SXxrPH78RcoGM3gXFfveHuTBRSmBnI=", 184 | "h1:NoDrUjhZMr46Q0BD+qrnqNm2gRAj5JRamHr/zqFlxUA=", 185 | "h1:ThkIYke+eg9R+0wFvHxgRaD9IJXzP6PhZ2NNWdTH6I4=", 186 | "h1:UqTT88h500zyGZwyq8SqYj7QG3Hwa3HRXkoKgEEGzRs=", 187 | "h1:X0/CNMWoWp8GEqGPGwdzD/KKgFvPKsJFWd6maKomUfU=", 188 | "h1:ZpLynDJIaoNVQv/QCtdSlCPRELJ3oEgY1hSwGWt9b/M=", 189 | "h1:hCZUjfcebZustppy/OizBYFXzS6pWfVWIN6QZvfcJSw=", 190 | "h1:pqTbS8y0L8g7dVlMO++aAtK4EEjz8VXUKM3SuuF2R38=", 191 | "h1:yRnqni1E3bR4DYzFX/Iv2ycVO6H86vsfVO1v3F6S1yA=", 192 | ] 193 | } 194 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /terraform/USAGE.md: -------------------------------------------------------------------------------- 1 | 2 | ## Requirements 3 | 4 | | Name | Version | 5 | |------|---------| 6 | | [terraform](#requirement\_terraform) | >= 1.0 | 7 | | [cloudflare](#requirement\_cloudflare) | 3.15.0 | 8 | | [cloudinit](#requirement\_cloudinit) | 2.2.0 | 9 | | [local](#requirement\_local) | 2.2.3 | 10 | | [null](#requirement\_null) | 3.1.1 | 11 | | [oci](#requirement\_oci) | 4.76.0 | 12 | | [tls](#requirement\_tls) | 3.4.0 | 13 | 14 | ## Modules 15 | 16 | No modules. 17 | 18 | ## Resources 19 | 20 | | Name | Type | 21 | |------|------| 22 | | [cloudflare_access_application.cf_application](https://registry.terraform.io/providers/cloudflare/cloudflare/3.15.0/docs/resources/access_application) | resource | 23 | | [cloudflare_access_policy.cf_allow_policy](https://registry.terraform.io/providers/cloudflare/cloudflare/3.15.0/docs/resources/access_policy) | resource | 24 | | [cloudflare_argo_tunnel.cf_tunnel](https://registry.terraform.io/providers/cloudflare/cloudflare/3.15.0/docs/resources/argo_tunnel) | resource | 25 | | [cloudflare_record.cf_tunnel_cname](https://registry.terraform.io/providers/cloudflare/cloudflare/3.15.0/docs/resources/record) | resource | 26 | | [cloudflare_tunnel_route.cf_tunnel_route](https://registry.terraform.io/providers/cloudflare/cloudflare/3.15.0/docs/resources/tunnel_route) | resource | 27 | | [local_file.ansible_hosts](https://registry.terraform.io/providers/hashicorp/local/2.2.3/docs/resources/file) | resource | 28 | | [local_file.ansible_variables](https://registry.terraform.io/providers/hashicorp/local/2.2.3/docs/resources/file) | resource | 29 | | [local_file.private_key_pem](https://registry.terraform.io/providers/hashicorp/local/2.2.3/docs/resources/file) | resource | 30 | | [local_file.public_key_openssh](https://registry.terraform.io/providers/hashicorp/local/2.2.3/docs/resources/file) | resource | 31 | | [null_resource.cloudflare_playbook](https://registry.terraform.io/providers/hashicorp/null/3.1.1/docs/resources/resource) | resource | 32 | | [null_resource.common_playbook](https://registry.terraform.io/providers/hashicorp/null/3.1.1/docs/resources/resource) | resource | 33 | | [null_resource.devops_roles](https://registry.terraform.io/providers/hashicorp/null/3.1.1/docs/resources/resource) | resource | 34 | | [null_resource.mount_data_volume](https://registry.terraform.io/providers/hashicorp/null/3.1.1/docs/resources/resource) | resource | 35 | | [null_resource.private_key_chmod](https://registry.terraform.io/providers/hashicorp/null/3.1.1/docs/resources/resource) | resource | 36 | | [null_resource.public_key_chmod](https://registry.terraform.io/providers/hashicorp/null/3.1.1/docs/resources/resource) | resource | 37 | | [oci_core_default_route_table.default_rt](https://registry.terraform.io/providers/oracle/oci/4.76.0/docs/resources/core_default_route_table) | resource | 38 | | [oci_core_instance.instance](https://registry.terraform.io/providers/oracle/oci/4.76.0/docs/resources/core_instance) | resource | 39 | | [oci_core_internet_gateway.igw](https://registry.terraform.io/providers/oracle/oci/4.76.0/docs/resources/core_internet_gateway) | resource | 40 | | [oci_core_security_list.security_list_ssh](https://registry.terraform.io/providers/oracle/oci/4.76.0/docs/resources/core_security_list) | resource | 41 | | [oci_core_security_list.security_list_vscode](https://registry.terraform.io/providers/oracle/oci/4.76.0/docs/resources/core_security_list) | resource | 42 | | [oci_core_subnet.subnet](https://registry.terraform.io/providers/oracle/oci/4.76.0/docs/resources/core_subnet) | resource | 43 | | [oci_core_vcn.vcn](https://registry.terraform.io/providers/oracle/oci/4.76.0/docs/resources/core_vcn) | resource | 44 | | [oci_core_volume.volume](https://registry.terraform.io/providers/oracle/oci/4.76.0/docs/resources/core_volume) | resource | 45 | | [oci_core_volume_attachment.volume_attachment](https://registry.terraform.io/providers/oracle/oci/4.76.0/docs/resources/core_volume_attachment) | resource | 46 | | [oci_core_volume_backup_policy_assignment.policy](https://registry.terraform.io/providers/oracle/oci/4.76.0/docs/resources/core_volume_backup_policy_assignment) | resource | 47 | | [random_id.argo_secret](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/id) | resource | 48 | | [tls_private_key.default](https://registry.terraform.io/providers/hashicorp/tls/3.4.0/docs/resources/private_key) | resource | 49 | | [cloudflare_zone.cf_zone](https://registry.terraform.io/providers/cloudflare/cloudflare/3.15.0/docs/data-sources/zone) | data source | 50 | | [cloudinit_config.cloudinit](https://registry.terraform.io/providers/hashicorp/cloudinit/2.2.0/docs/data-sources/config) | data source | 51 | | [oci_core_images.ubuntu_20_04_aarch64](https://registry.terraform.io/providers/oracle/oci/4.76.0/docs/data-sources/core_images) | data source | 52 | | [oci_core_volume_backup_policies.predefined_volume_backup_policies](https://registry.terraform.io/providers/oracle/oci/4.76.0/docs/data-sources/core_volume_backup_policies) | data source | 53 | | [oci_identity_availability_domains.ads](https://registry.terraform.io/providers/oracle/oci/4.76.0/docs/data-sources/identity_availability_domains) | data source | 54 | 55 | ## Inputs 56 | 57 | | Name | Description | Type | Default | Required | 58 | |------|-------------|------|---------|:--------:| 59 | | [namespace](#input\_namespace) | Project name that will be use to identifiy the resources | `string` | `"vscode"` | no | 60 | | [stage](#input\_stage) | Stage/environment name to tag and suffix the infrastructure composants | `string` | `"dev"` | no | 61 | | [tenancy\_ocid](#input\_tenancy\_ocid) | Tenancy OCID | `string` | `null` | no | 62 | | [compartment\_ocid](#input\_compartment\_ocid) | Compartment OCID | `string` | `null` | no | 63 | | [user\_ocid](#input\_user\_ocid) | User OCID | `string` | `null` | no | 64 | | [fingerprint](#input\_fingerprint) | Fingerprint | `string` | `null` | no | 65 | | [private\_key](#input\_private\_key) | Private Key content | `string` | `null` | no | 66 | | [region](#input\_region) | Default Region | `string` | `"uk-london-1"` | no | 67 | | [cf\_zero\_trust\_enabled](#input\_cf\_zero\_trust\_enabled) | Register VSCode with Cloudflare Zero Trust | `bool` | `false` | no | 68 | | [cf\_account\_id](#input\_cf\_account\_id) | Set by TF\_VAR\_cf\_account\_id environment variable on ~/.zprofile or ~/.bash\_profile | `string` | `null` | no | 69 | | [cf\_domain](#input\_cf\_domain) | Domain Name for Cloudflare Zero Trust | `string` | `"example.com"` | no | 70 | | [cf\_subdomain](#input\_cf\_subdomain) | Subdomain Name for Cloudflare Zero Trust | `string` | `"vscode"` | no | 71 | | [cf\_allowed\_users](#input\_cf\_allowed\_users) | Users (emails) allowed to access the VSCode Server application | `list(string)` | `[]` | no | 72 | | [allowed\_ingress\_ssh](#input\_allowed\_ingress\_ssh) | List of IPs allowed to SSH on the instance | `list(string)` | `[]` | no | 73 | | [allowed\_egress\_ssh](#input\_allowed\_egress\_ssh) | List of IPs the instance is allowed to connect | `list(string)` |
[| no | 74 | | [allowed\_ingress\_vscode](#input\_allowed\_ingress\_vscode) | List of IPs allowed to access to VS Code Server | `list(string)` | `[]` | no | 75 | | [allowed\_egress\_vscode](#input\_allowed\_egress\_vscode) | List of IPs the instance is allowed to connect | `list(string)` |
"0.0.0.0/0"
]
[| no | 76 | | [instance\_shape](#input\_instance\_shape) | Instance Shape | `string` | `"VM.Standard.A1.Flex"` | no | 77 | | [instance\_ocpus](#input\_instance\_ocpus) | Number of OCPUS (CPU cores) | `string` | `4` | no | 78 | | [instance\_shape\_config\_memory\_in\_gbs](#input\_instance\_shape\_config\_memory\_in\_gbs) | Memory in GBs | `string` | `24` | no | 79 | | [instance\_os](#input\_instance\_os) | Instance OS | `string` | `"Canonical Ubuntu"` | no | 80 | | [instance\_os\_version](#input\_instance\_os\_version) | Instance OS Version | `string` | `"20.04"` | no | 81 | | [instance\_os\_user](#input\_instance\_os\_user) | Instance User | `string` | `"ubuntu"` | no | 82 | | [block\_volume\_size](#input\_block\_volume\_size) | Block Volume size in GBs (/data) | `string` | `100` | no | 83 | | [block\_volume\_device\_name](#input\_block\_volume\_device\_name) | Block Volume device name (/dev/oracleoci/oraclevdb) | `string` | `"/dev/oracleoci/oraclevdb"` | no | 84 | | [vscode\_version](#input\_vscode\_version) | VS Code Server Version | `string` | `"4.4.0"` | no | 85 | | [install\_devops\_deps](#input\_install\_devops\_deps) | Install DevOps tools like Docker, Helm, Terraform, Ansible, etc. | `bool` | `false` | no | 86 | | [terraform\_version](#input\_terraform\_version) | Terraform Version | `string` | `"1.2.1"` | no | 87 | | [tfdocs\_version](#input\_tfdocs\_version) | Terraform Docs Version | `string` | `"0.16.0"` | no | 88 | | [tfsec\_version](#input\_tfsec\_version) | TFSec Version | `string` | `"1.21.2"` | no | 89 | | [tflint\_version](#input\_tflint\_version) | TFLint Version | `string` | `"0.37.0"` | no | 90 | | [packer\_version](#input\_packer\_version) | Packer Version | `string` | `"1.8.1"` | no | 91 | | [helm\_version](#input\_helm\_version) | Helm Version | `string` | `"3.9.0"` | no | 92 | | [kubectl\_version](#input\_kubectl\_version) | Kubectl Version | `string` | `"1.24.0"` | no | 93 | | [keypair\_name](#input\_keypair\_name) | Name of the Key Pair (instance or service for ex.) | `string` | `null` | no | 94 | | [keypair\_public\_key](#input\_keypair\_public\_key) | A pregenerated OpenSSH-formatted public key. Changing this creates a new keypair. If a public key is not specified, then a public/private key pair will be automatically generated. If a pair is created, then destroying this resource means you will lose access to that keypair forever. | `string` | `null` | no | 95 | | [keypair\_public\_key\_path](#input\_keypair\_public\_key\_path) | Path to Public Key directory (e.g. `/keypairs`) | `string` | `"./keypairs"` | no | 96 | | [keypair\_key\_algorithm](#input\_keypair\_key\_algorithm) | Key Pair algorithm | `string` | `"RSA"` | no | 97 | | [keypair\_private\_key](#input\_keypair\_private\_key) | A pregenerated OpenSSH-formatted private key. Changing this creates a new keypair. If a private key is not specified, then a public/private key pair will be automatically generated. If a pair is created, then destroying this resource means you will lose access to that keypair forever. | `string` | `null` | no | 98 | | [keypair\_private\_key\_extension](#input\_keypair\_private\_key\_extension) | Private key extension | `string` | `""` | no | 99 | | [keypair\_public\_key\_extension](#input\_keypair\_public\_key\_extension) | Public key extension | `string` | `".pub"` | no | 100 | | [keypair\_chmod\_command\_public](#input\_keypair\_chmod\_command\_public) | Template of the command executed on the public key file | `string` | `"chmod 600 %v"` | no | 101 | | [keypair\_chmod\_command\_private](#input\_keypair\_chmod\_command\_private) | Template of the command executed on the private key file | `string` | `"chmod 400 %v"` | no | 102 | | [labels](#input\_labels) | Default labels to associate to these resources | `map(string)` |
"0.0.0.0/0"
]
{
"businessunit": "mycompany",
"project": "VSCode Server",
"team": "devops",
"terraform": "true"
} | no |
103 |
104 | ## Outputs
105 |
106 | | Name | Description |
107 | |------|-------------|
108 | | [instance\_private\_ip](#output\_instance\_private\_ip) | VS Code Server Instance Private IP |
109 | | [instance\_public\_ip](#output\_instance\_public\_ip) | VS Code Server Instance Public IP |
110 |
111 |
--------------------------------------------------------------------------------
/terraform/README.md:
--------------------------------------------------------------------------------
1 | # Terraform
2 |
3 |
4 | ## Requirements
5 |
6 | | Name | Version |
7 | |------|---------|
8 | | [terraform](#requirement\_terraform) | >= 1.0 |
9 | | [cloudflare](#requirement\_cloudflare) | 3.32.0 |
10 | | [cloudinit](#requirement\_cloudinit) | 2.2.0 |
11 | | [local](#requirement\_local) | 2.3.0 |
12 | | [null](#requirement\_null) | 3.2.1 |
13 | | [oci](#requirement\_oci) | 4.103.0 |
14 | | [random](#requirement\_random) | 3.4.3 |
15 | | [tls](#requirement\_tls) | 4.0.4 |
16 |
17 | ## Providers
18 |
19 | | Name | Version |
20 | |------|---------|
21 | | [cloudflare](#provider\_cloudflare) | 3.32.0 |
22 | | [cloudinit](#provider\_cloudinit) | 2.2.0 |
23 | | [local](#provider\_local) | 2.3.0 |
24 | | [null](#provider\_null) | 3.2.1 |
25 | | [oci](#provider\_oci) | 4.103.0 |
26 | | [random](#provider\_random) | 3.4.3 |
27 | | [tls](#provider\_tls) | 4.0.4 |
28 |
29 | ## Modules
30 |
31 | No modules.
32 |
33 | ## Resources
34 |
35 | | Name | Type |
36 | |------|------|
37 | | [cloudflare_access_application.cf_application](https://registry.terraform.io/providers/cloudflare/cloudflare/3.32.0/docs/resources/access_application) | resource |
38 | | [cloudflare_access_policy.cf_allow_policy](https://registry.terraform.io/providers/cloudflare/cloudflare/3.32.0/docs/resources/access_policy) | resource |
39 | | [cloudflare_argo_tunnel.cf_tunnel](https://registry.terraform.io/providers/cloudflare/cloudflare/3.32.0/docs/resources/argo_tunnel) | resource |
40 | | [cloudflare_record.cf_tunnel_cname](https://registry.terraform.io/providers/cloudflare/cloudflare/3.32.0/docs/resources/record) | resource |
41 | | [cloudflare_tunnel_route.cf_tunnel_route](https://registry.terraform.io/providers/cloudflare/cloudflare/3.32.0/docs/resources/tunnel_route) | resource |
42 | | [local_file.ansible_hosts](https://registry.terraform.io/providers/hashicorp/local/2.3.0/docs/resources/file) | resource |
43 | | [local_file.ansible_variables](https://registry.terraform.io/providers/hashicorp/local/2.3.0/docs/resources/file) | resource |
44 | | [local_file.private_key_pem](https://registry.terraform.io/providers/hashicorp/local/2.3.0/docs/resources/file) | resource |
45 | | [local_file.public_key_openssh](https://registry.terraform.io/providers/hashicorp/local/2.3.0/docs/resources/file) | resource |
46 | | [null_resource.cloudflare_playbook](https://registry.terraform.io/providers/hashicorp/null/3.2.1/docs/resources/resource) | resource |
47 | | [null_resource.common_playbook](https://registry.terraform.io/providers/hashicorp/null/3.2.1/docs/resources/resource) | resource |
48 | | [null_resource.devops_roles](https://registry.terraform.io/providers/hashicorp/null/3.2.1/docs/resources/resource) | resource |
49 | | [null_resource.mount_data_volume](https://registry.terraform.io/providers/hashicorp/null/3.2.1/docs/resources/resource) | resource |
50 | | [null_resource.private_key_chmod](https://registry.terraform.io/providers/hashicorp/null/3.2.1/docs/resources/resource) | resource |
51 | | [null_resource.public_key_chmod](https://registry.terraform.io/providers/hashicorp/null/3.2.1/docs/resources/resource) | resource |
52 | | [oci_core_default_route_table.default_rt](https://registry.terraform.io/providers/oracle/oci/4.103.0/docs/resources/core_default_route_table) | resource |
53 | | [oci_core_instance.instance](https://registry.terraform.io/providers/oracle/oci/4.103.0/docs/resources/core_instance) | resource |
54 | | [oci_core_internet_gateway.igw](https://registry.terraform.io/providers/oracle/oci/4.103.0/docs/resources/core_internet_gateway) | resource |
55 | | [oci_core_security_list.security_list_ssh](https://registry.terraform.io/providers/oracle/oci/4.103.0/docs/resources/core_security_list) | resource |
56 | | [oci_core_security_list.security_list_vscode](https://registry.terraform.io/providers/oracle/oci/4.103.0/docs/resources/core_security_list) | resource |
57 | | [oci_core_subnet.subnet](https://registry.terraform.io/providers/oracle/oci/4.103.0/docs/resources/core_subnet) | resource |
58 | | [oci_core_vcn.vcn](https://registry.terraform.io/providers/oracle/oci/4.103.0/docs/resources/core_vcn) | resource |
59 | | [oci_core_volume.volume](https://registry.terraform.io/providers/oracle/oci/4.103.0/docs/resources/core_volume) | resource |
60 | | [oci_core_volume_attachment.volume_attachment](https://registry.terraform.io/providers/oracle/oci/4.103.0/docs/resources/core_volume_attachment) | resource |
61 | | [oci_core_volume_backup_policy_assignment.policy](https://registry.terraform.io/providers/oracle/oci/4.103.0/docs/resources/core_volume_backup_policy_assignment) | resource |
62 | | [random_id.argo_secret](https://registry.terraform.io/providers/hashicorp/random/3.4.3/docs/resources/id) | resource |
63 | | [tls_private_key.default](https://registry.terraform.io/providers/hashicorp/tls/4.0.4/docs/resources/private_key) | resource |
64 | | [cloudflare_zone.cf_zone](https://registry.terraform.io/providers/cloudflare/cloudflare/3.32.0/docs/data-sources/zone) | data source |
65 | | [cloudinit_config.cloudinit](https://registry.terraform.io/providers/hashicorp/cloudinit/2.2.0/docs/data-sources/config) | data source |
66 | | [oci_core_images.ubuntu_20_04_aarch64](https://registry.terraform.io/providers/oracle/oci/4.103.0/docs/data-sources/core_images) | data source |
67 | | [oci_core_volume_backup_policies.predefined_volume_backup_policies](https://registry.terraform.io/providers/oracle/oci/4.103.0/docs/data-sources/core_volume_backup_policies) | data source |
68 | | [oci_identity_availability_domains.ads](https://registry.terraform.io/providers/oracle/oci/4.103.0/docs/data-sources/identity_availability_domains) | data source |
69 |
70 | ## Inputs
71 |
72 | | Name | Description | Type | Default | Required |
73 | |------|-------------|------|---------|:--------:|
74 | | [allowed\_egress\_ssh](#input\_allowed\_egress\_ssh) | List of IPs the instance is allowed to connect | `list(string)` | [| no | 75 | | [allowed\_egress\_vscode](#input\_allowed\_egress\_vscode) | List of IPs the instance is allowed to connect | `list(string)` |
"0.0.0.0/0"
]
[| no | 76 | | [allowed\_ingress\_ssh](#input\_allowed\_ingress\_ssh) | List of IPs allowed to SSH on the instance | `list(string)` |
"0.0.0.0/0"
]
[| no | 77 | | [allowed\_ingress\_vscode](#input\_allowed\_ingress\_vscode) | List of IPs allowed to access to VS Code Server | `list(string)` |
"78.249.116.152/32"
]
[| no | 78 | | [block\_volume\_device\_name](#input\_block\_volume\_device\_name) | Block Volume device name (/dev/oracleoci/oraclevdb) | `string` | `"/dev/oracleoci/oraclevdb"` | no | 79 | | [block\_volume\_size](#input\_block\_volume\_size) | Block Volume size in GBs (/data) | `string` | `100` | no | 80 | | [cf\_account\_id](#input\_cf\_account\_id) | Set by TF\_VAR\_cf\_account\_id environment variable on ~/.zprofile or ~/.bash\_profile | `string` | `null` | no | 81 | | [cf\_allowed\_users](#input\_cf\_allowed\_users) | Users (emails) allowed to access the VSCode Server application | `list(string)` |
"78.249.116.152/32"
]
[| no | 82 | | [cf\_domain](#input\_cf\_domain) | Domain Name for Cloudflare Zero Trust | `string` | `"timoa.com"` | no | 83 | | [cf\_subdomain](#input\_cf\_subdomain) | Subdomain Name for Cloudflare Zero Trust | `string` | `"vsdev"` | no | 84 | | [cf\_zero\_trust\_enabled](#input\_cf\_zero\_trust\_enabled) | Register VSCode with Cloudflare Zero Trust | `bool` | `true` | no | 85 | | [compartment\_ocid](#input\_compartment\_ocid) | Compartment OCID | `string` | `null` | no | 86 | | [fingerprint](#input\_fingerprint) | Fingerprint | `string` | `null` | no | 87 | | [helm\_version](#input\_helm\_version) | Helm Version | `string` | `"3.9.0"` | no | 88 | | [install\_devops\_deps](#input\_install\_devops\_deps) | Install DevOps tools like Docker, Helm, Terraform, Ansible, etc. | `bool` | `true` | no | 89 | | [instance\_ocpus](#input\_instance\_ocpus) | Number of OCPUS (CPU cores) | `string` | `4` | no | 90 | | [instance\_os](#input\_instance\_os) | Instance OS | `string` | `"Canonical Ubuntu"` | no | 91 | | [instance\_os\_user](#input\_instance\_os\_user) | Instance User | `string` | `"ubuntu"` | no | 92 | | [instance\_os\_version](#input\_instance\_os\_version) | Instance OS Version | `string` | `"20.04"` | no | 93 | | [instance\_shape](#input\_instance\_shape) | Instance Shape | `string` | `"VM.Standard.A1.Flex"` | no | 94 | | [instance\_shape\_config\_memory\_in\_gbs](#input\_instance\_shape\_config\_memory\_in\_gbs) | Memory in GBs | `string` | `24` | no | 95 | | [keypair\_chmod\_command\_private](#input\_keypair\_chmod\_command\_private) | Template of the command executed on the private key file | `string` | `"chmod 400 %v"` | no | 96 | | [keypair\_chmod\_command\_public](#input\_keypair\_chmod\_command\_public) | Template of the command executed on the public key file | `string` | `"chmod 600 %v"` | no | 97 | | [keypair\_key\_algorithm](#input\_keypair\_key\_algorithm) | Key Pair algorithm | `string` | `"RSA"` | no | 98 | | [keypair\_name](#input\_keypair\_name) | Name of the Key Pair (instance or service for ex.) | `string` | `null` | no | 99 | | [keypair\_private\_key](#input\_keypair\_private\_key) | A pregenerated OpenSSH-formatted private key. Changing this creates a new keypair. If a private key is not specified, then a public/private key pair will be automatically generated. If a pair is created, then destroying this resource means you will lose access to that keypair forever. | `string` | `null` | no | 100 | | [keypair\_private\_key\_extension](#input\_keypair\_private\_key\_extension) | Private key extension | `string` | `""` | no | 101 | | [keypair\_public\_key](#input\_keypair\_public\_key) | A pregenerated OpenSSH-formatted public key. Changing this creates a new keypair. If a public key is not specified, then a public/private key pair will be automatically generated. If a pair is created, then destroying this resource means you will lose access to that keypair forever. | `string` | `null` | no | 102 | | [keypair\_public\_key\_extension](#input\_keypair\_public\_key\_extension) | Public key extension | `string` | `".pub"` | no | 103 | | [keypair\_public\_key\_path](#input\_keypair\_public\_key\_path) | Path to Public Key directory (e.g. `/keypairs`) | `string` | `"./keypairs"` | no | 104 | | [kubectl\_version](#input\_kubectl\_version) | Kubectl Version | `string` | `"1.24.0"` | no | 105 | | [labels](#input\_labels) | Default labels to associate to these resources | `map(string)` |
"d.laureaux@timoa.com"
]
{
"businessunit": "timoa",
"project": "VSCode Server",
"team": "devops",
"terraform": "true"
} | no |
106 | | [namespace](#input\_namespace) | Project name that will be use to identifiy the resources | `string` | `"vscode"` | no |
107 | | [packer\_version](#input\_packer\_version) | Packer Version | `string` | `"1.8.1"` | no |
108 | | [private\_key](#input\_private\_key) | Private Key content | `string` | `null` | no |
109 | | [region](#input\_region) | Default Region | `string` | `"uk-london-1"` | no |
110 | | [stage](#input\_stage) | Stage/environment name to tag and suffix the infrastructure composants | `string` | `"dev"` | no |
111 | | [tenancy\_ocid](#input\_tenancy\_ocid) | Tenancy OCID | `string` | `null` | no |
112 | | [terraform\_version](#input\_terraform\_version) | Terraform Version | `string` | `"1.2.1"` | no |
113 | | [tfdocs\_version](#input\_tfdocs\_version) | Terraform Docs Version | `string` | `"0.16.0"` | no |
114 | | [tflint\_version](#input\_tflint\_version) | TFLint Version | `string` | `"0.37.0"` | no |
115 | | [tfsec\_version](#input\_tfsec\_version) | TFSec Version | `string` | `"1.21.2"` | no |
116 | | [user\_ocid](#input\_user\_ocid) | User OCID | `string` | `null` | no |
117 | | [vscode\_version](#input\_vscode\_version) | VS Code Server Version | `string` | `"4.4.0"` | no |
118 |
119 | ## Outputs
120 |
121 | | Name | Description |
122 | |------|-------------|
123 | | [instance\_private\_ip](#output\_instance\_private\_ip) | VS Code Server Instance Private IP |
124 | | [instance\_public\_ip](#output\_instance\_public\_ip) | VS Code Server Instance Public IP |
125 |
126 |
--------------------------------------------------------------------------------
/docs/icons/helm.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------