diff --git a/.gitignore b/.gitignore index 765d5c3..bab2a87 100644 --- a/.gitignore +++ b/.gitignore @@ -131,3 +131,46 @@ dmypy.json .idea/ .vercel + + +# Terraform +# Local .terraform directories +**/.terraform/* + +# .tfstate files +*.tfstate +*.tfstate.* + +# Crash log files +crash.log +crash.*.log + +# Exclude all .tfvars files, which are likely to contain sensitive data, such as +# password, private keys, and other secrets. These should not be part of version +# control as they are data points which are potentially sensitive and subject +# to change depending on the environment. +*.tfvars +*.tfvars.json + +# Ignore override files as they are usually used to override resources locally and so +# are not checked in +override.tf +override.tf.json +*_override.tf +*_override.tf.json + +# Include override files you do wish to add to version control using negated pattern +# !example_override.tf + +# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan +# example: *tfplan* + +# Ignore CLI configuration files +.terraformrc +terraform.rc + +.terraform.lock.hcl + + +# Ansible +*.retry \ No newline at end of file diff --git a/ansible/provision.yml b/ansible/provision.yml new file mode 100644 index 0000000..c1a3010 --- /dev/null +++ b/ansible/provision.yml @@ -0,0 +1,59 @@ +- hosts: all + become: true + + tasks: + - name: ensure repository key is installed + apt_key: + url: https://download.docker.com/linux/ubuntu/gpg + state: present + + - name: ensure docker registry is available + apt_repository: repo='deb https://download.docker.com/linux/ubuntu bionic stable' state=present + + - name: ensure docker and dependencies are installed + apt: + pkg: + - docker-ce + - docker-ce-cli + - containerd.io + - docker-buildx-plugin + - docker-compose-plugin + - python3-docker + - python3-pip + update_cache: yes + + - service: name=docker state=started + + - name: Install docker-compose python package + ansible.builtin.pip: + name: docker-compose + + - name: Log into registry + docker_login: + registry: registry.flokaiser.com + username: "{{ REGISTRY_USERNAME }}" + password: "{{ REGISTRY_PASSWORD }}" + + - name: clone repository + ansible.builtin.git: + repo: https://git.flokaiser.com/DHBW/Cloud_Computing_II.git + dest: /home/adminuser/Cloud_Computing_II + single_branch: yes + version: main + + - name: deploy docker compose stack + community.docker.docker_compose: + project_src: /home/adminuser/Cloud_Computing_II + files: + - docker-compose.yml + environment: + CERTBOT_EMAIL: "{{ CERTBOT_EMAIL }}" + DATABASE_URL: "{{ DATABASE_URL }}" + AZURE_KEY: "{{ AZURE_KEY }}" + AZURE_LOCATION: "{{ AZURE_LOCATION }}" + AZURE_ENDPOINT: "https://api.cognitive.microsofttranslator.com" + ENV: "dev" + + - name: Log out of DockerHub + docker_login: + state: absent \ No newline at end of file diff --git a/terraform/deploy.tf b/terraform/deploy.tf new file mode 100644 index 0000000..a952d24 --- /dev/null +++ b/terraform/deploy.tf @@ -0,0 +1,247 @@ +# Konfiguration einer VM in der Azure Cloud +terraform { + # Setzen der notwendigen Provider-Informationen + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "=3.46.0" + } + + cloudflare = { + source = "cloudflare/cloudflare" + version = "~> 3.0" + } + } +} + +# Variablen +variable "ssh_key" { + type = string + sensitive = true +} + +variable "azure_subscription_id" { + type = string + sensitive = true +} + +variable "azure_resource_group" { + type = string +} + +variable "azure_location" { + type = string +} + +variable "azure_location_ca" { + type = string +} + +variable "certbot_email" { + type = string + sensitive = true +} + +variable "zone_id" { + type = string + sensitive = true +} + +variable "cloudflare_token" { + type = string + sensitive = true +} + +variable "registry_username" { + type = string + sensitive = true +} + +variable "registry_password" { + type = string + sensitive = true +} + +resource "random_string" "lower" { + length = 16 + upper = false + lower = true + numeric = false + special = false +} + +# Azure Provider +provider "azurerm" { + features {} + subscription_id = var.azure_subscription_id +} + +# Cloudflare provider +provider "cloudflare" { + api_token = var.cloudflare_token +} + +# Resource Group +resource "azurerm_resource_group" "example" { + name = var.azure_resource_group + location = var.azure_location +} + +# Azure Cosmos DB +resource "azurerm_cosmosdb_account" "example" { + name = "db-${random_string.lower.result}" + location = var.azure_location + resource_group_name = var.azure_resource_group + offer_type = "Standard" + kind = "MongoDB" + + consistency_policy { + consistency_level = "BoundedStaleness" + max_interval_in_seconds = 300 + max_staleness_prefix = 100000 + } + + geo_location { + location = "westeurope" + failover_priority = 0 + } +} + +# Azure Cognitive services +resource "azurerm_cognitive_account" "example" { + name = "cognitive-account-${random_string.lower.result}" + location = var.azure_location_ca + resource_group_name = var.azure_resource_group + kind = "CognitiveServices" + sku_name = "S0" +} + +# Virtual Network +resource "azurerm_virtual_network" "example" { + name = "virtual-network-${random_string.lower.result}" + address_space = ["10.0.0.0/16"] + location = var.azure_location + resource_group_name = var.azure_resource_group +} + +# Subnet +resource "azurerm_subnet" "example" { + name = "subnet-${random_string.lower.result}" + address_prefixes = ["10.0.1.0/24"] + virtual_network_name = azurerm_virtual_network.example.name + resource_group_name = var.azure_resource_group +} + +# Network Interface +resource "azurerm_network_interface" "example" { + name = "nic-${random_string.lower.result}" + location = var.azure_location + resource_group_name = var.azure_resource_group + + ip_configuration { + name = "ip-configuration-${random_string.lower.result}" + subnet_id = azurerm_subnet.example.id + private_ip_address_allocation = "Dynamic" + public_ip_address_id = azurerm_public_ip.example.id + } +} + +# public ip address +resource "azurerm_public_ip" "example" { + name = "public-ip-${random_string.lower.result}" + location = var.azure_location + resource_group_name = var.azure_resource_group + allocation_method = "Static" +} + +# Set cloudflare dns record +resource "cloudflare_record" "example" { + zone_id = "${var.zone_id}" + name = "translator.dhbw" + value = "${azurerm_public_ip.example.ip_address}" + type = "A" + allow_overwrite = true +} + +# Network security group +resource "azurerm_network_security_group" "example" { + name = "nsg-${random_string.lower.result}" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + + security_rule { + name = "SSH" + priority = 1001 + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_range = "*" + destination_port_range = "22" + source_address_prefix = "*" + destination_address_prefix = "*" + } + + security_rule { + name = "HTTP" + priority = 1002 + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_range = "*" + destination_port_range = "80" + source_address_prefix = "*" + destination_address_prefix = "*" + } + + security_rule { + name = "HTTPS" + priority = 1003 + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_range = "*" + destination_port_range = "443" + source_address_prefix = "*" + destination_address_prefix = "*" + } +} + +# Attach network security group +resource "azurerm_network_interface_security_group_association" "example" { + network_interface_id = azurerm_network_interface.example.id + network_security_group_id = azurerm_network_security_group.example.id +} + +# Virtual maschine +resource "azurerm_linux_virtual_machine" "example" { + name = "vm-${random_string.lower.result}" + location = var.azure_location + resource_group_name = var.azure_resource_group + size = "Standard_B1s" + admin_username = "adminuser" + network_interface_ids = [ + azurerm_network_interface.example.id, + ] + + os_disk { + caching = "ReadWrite" + storage_account_type = "Standard_LRS" + } + + source_image_reference { + publisher = "Canonical" + offer = "0001-com-ubuntu-server-jammy" + sku = "22_04-lts-gen2" + version = "latest" + } + + admin_ssh_key { + username = "adminuser" + public_key = file("~/.ssh/id_rsa.pub") + } + + # Ansible + provisioner "local-exec" { + command = "ansible-playbook --ssh-common-args='-o StrictHostKeyChecking=no' --extra-vars CERTBOT_EMAIL='${var.certbot_email}' --extra-vars REGISTRY_USERNAME='${var.registry_username}' --extra-vars REGISTRY_PASSWORD='${var.registry_password}' --extra-vars AZURE_KEY='${azurerm_cognitive_account.example.primary_access_key}' --extra-vars AZURE_LOCATION='${var.azure_location_ca}' --extra-vars DATABASE_URL='${azurerm_cosmosdb_account.example.connection_strings.0}' -i adminuser@'${azurerm_public_ip.example.ip_address}', ../ansible/provision.yml" + } +} diff --git a/terraform/secrets.tfvars.example b/terraform/secrets.tfvars.example new file mode 100644 index 0000000..3e5fddf --- /dev/null +++ b/terraform/secrets.tfvars.example @@ -0,0 +1,10 @@ +ssh_key = "ssh-rsa ..." +azure_subscription_id = "" +azure_resource_group = "cloud-computing-ii-project" +azure_location_ca = "germanywestcentral" +azure_location = "westeurope" +certbot_email = "" +zone_id = "" +cloudflare_token = "" +registry_username = "" +registry_password = "" \ No newline at end of file