From ad77d0317ae15c66772db2f6f435d534125b10d8 Mon Sep 17 00:00:00 2001 From: "Glenn Y. Rolland" Date: Thu, 26 May 2022 17:31:39 +0200 Subject: [PATCH] Add terraform files --- .gitignore | 1 + README.md | 28 ++++++++++ Vagrantfile | 52 +++++++++++++++++++ ansible/ansible.cfg | 3 ++ ansible/group_vars/all/vars.yml | 2 + ansible/inventories/terraform | 1 + ansible/inventories/vagrant | 1 + ansible/playbook.yml | 26 ++++++++++ ansible/requirements.yml | 6 +++ ansible/tasks/setup_base.yml | 20 ++++++++ ansible/tasks/setup_caddy.yml | 0 ansible/tasks/setup_docker.yml | 59 +++++++++++++++++++++ ansible/tasks/setup_mongo.yml | 0 ansible/tasks/setup_sshaccess.yml | 12 +++++ ansible/tasks/setup_sshwifty.yml | 30 +++++++++++ ansible/templates/Caddyfile.j2 | 11 ++++ ansible/templates/docker-compose.yml.j2 | 21 ++++++++ ansible/templates/sshwifty.conf.j2 | 48 +++++++++++++++++ terraform/.gitignore | 4 ++ terraform/domains.tf | 18 +++++++ terraform/instances.tf | 68 +++++++++++++++++++++++++ terraform/output.tf | 12 +++++ terraform/outputs/.empty | 0 terraform/provider.tf | 37 ++++++++++++++ terraform/provisionners.tf | 4 ++ terraform/templates/inventory.tmpl | 40 +++++++++++++++ terraform/variables.tf | 20 ++++++++ 27 files changed, 524 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 Vagrantfile create mode 100644 ansible/ansible.cfg create mode 100644 ansible/group_vars/all/vars.yml create mode 120000 ansible/inventories/terraform create mode 120000 ansible/inventories/vagrant create mode 100644 ansible/playbook.yml create mode 100644 ansible/requirements.yml create mode 100644 ansible/tasks/setup_base.yml create mode 100644 ansible/tasks/setup_caddy.yml create mode 100644 ansible/tasks/setup_docker.yml create mode 100644 ansible/tasks/setup_mongo.yml create mode 100644 ansible/tasks/setup_sshaccess.yml create mode 100644 ansible/tasks/setup_sshwifty.yml create mode 100644 ansible/templates/Caddyfile.j2 create mode 100644 ansible/templates/docker-compose.yml.j2 create mode 100644 ansible/templates/sshwifty.conf.j2 create mode 100644 terraform/.gitignore create mode 100644 terraform/domains.tf create mode 100644 terraform/instances.tf create mode 100644 terraform/output.tf create mode 100644 terraform/outputs/.empty create mode 100644 terraform/provider.tf create mode 100644 terraform/provisionners.tf create mode 100644 terraform/templates/inventory.tmpl create mode 100644 terraform/variables.tf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8000dd9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.vagrant diff --git a/README.md b/README.md new file mode 100644 index 0000000..55a5bfb --- /dev/null +++ b/README.md @@ -0,0 +1,28 @@ + + +## Web SSH terminal + +* sshwifty (go) +* webssh (python) + https://hub.docker.com/r/snsyzb/webssh +* Guacamole +* Bastillion + https://github.com/bastillion-io/Bastillion +* SSHy + https://github.com/stuicey/SSHy +* ssh-web-console + https://github.com/genshen/ssh-web-console +* webssh2 + https://github.com/billchurch/webssh2 +* webssh + https://github.com/huashengdun/webssh +* https://github.com/gravitational/teleport +* https://github.com/roke22/PHP-SSH2-Web-Client +* https://www.shellvault.io/ +* https://github.com/huashengdun/webssh +* https://github.com/xtermjs/xterm.js/ + +## Terraform + Ansible + +https://www.digitalocean.com/community/tutorials/how-to-use-ansible-with-terraform-for-configuration-management + diff --git a/Vagrantfile b/Vagrantfile new file mode 100644 index 0000000..e702821 --- /dev/null +++ b/Vagrantfile @@ -0,0 +1,52 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby sw=2 st=2 et : + +# frozen_string_literal: true + +SERVERS_COUNT=3 + +Vagrant.configure('2') do |config| + # Common settings for virtual machines + config.vm.box = 'debian/bullseye64' + config.vm.box_check_update = false + + ## + ## gateway: Guacamole proxy + entrypoint + ## + config.vm.define 'gateway' do |machine| + machine.vm.hostname = 'gateway' + machine.vm.network 'private_network', ip: '192.168.50.250' + machine.vm.network 'forwarded_port', guest: 80, host: 1080 + machine.vm.network 'forwarded_port', guest: 8080, host: 8080 + machine.vm.provider 'virtualbox' do |vb| + vb.memory = '4000' + vb.gui = false + end + end + + ## + ## serverX : host servers with mongo, etc + ## + server_ip = ->(index) { "192.168.50.#{10 + index * 10}" } + SERVERS_COUNT.times do |index| + config.vm.define "server#{index}" do |machine| + machine.vm.hostname = "server#{index}" + machine.vm.network 'private_network', ip: server_ip.call(index) + machine.vm.provider 'virtualbox' do |vb| + vb.memory = '3000' + vb.gui = false + end + end + end + + config.vm.provision 'ansible' do |ansible| + ansible.playbook = 'ansible/playbook.yml' + # ansible.verbose = true + ansible.config_file = 'ansible/ansible.cfg' + ansible.groups = { + 'app_sshwifty' => ['gateway'], + 'app_mongo' => SERVERS_COUNT.times.map { |i| "server#{i}" }, + 'all_groups:children' => ['app_mongo'] + } + end +end diff --git a/ansible/ansible.cfg b/ansible/ansible.cfg new file mode 100644 index 0000000..0436ec0 --- /dev/null +++ b/ansible/ansible.cfg @@ -0,0 +1,3 @@ +[ssh_connection] +ssh_args=-o ControlMaster=auto -o ControlPersist=7200s +pipelining=True diff --git a/ansible/group_vars/all/vars.yml b/ansible/group_vars/all/vars.yml new file mode 100644 index 0000000..4880604 --- /dev/null +++ b/ansible/group_vars/all/vars.yml @@ -0,0 +1,2 @@ +--- +sshwifty_shared_key: admin diff --git a/ansible/inventories/terraform b/ansible/inventories/terraform new file mode 120000 index 0000000..4fa6a06 --- /dev/null +++ b/ansible/inventories/terraform @@ -0,0 +1 @@ +../../terraform/outputs/inventory \ No newline at end of file diff --git a/ansible/inventories/vagrant b/ansible/inventories/vagrant new file mode 120000 index 0000000..94d6406 --- /dev/null +++ b/ansible/inventories/vagrant @@ -0,0 +1 @@ +../../.vagrant/provisioners/ansible/inventory/vagrant_ansible_inventory \ No newline at end of file diff --git a/ansible/playbook.yml b/ansible/playbook.yml new file mode 100644 index 0000000..e392d4a --- /dev/null +++ b/ansible/playbook.yml @@ -0,0 +1,26 @@ +--- +- hosts: app_sshwifty + become: true + tasks: + - include_tasks: tasks/setup_base.yml + - include_tasks: tasks/setup_docker.yml + - include_tasks: tasks/setup_sshwifty.yml + - include_tasks: tasks/setup_caddy.yml + - include_tasks: tasks/setup_sshaccess.yml + + roles: + - role: caddy_ansible.caddy_ansible + caddy_setcap: 'yes' + caddy_systemd_network_dependency: false + caddy_systemd_capabilities_enabled: true + caddy_config: "{{ lookup('template', 'templates/Caddyfile.j2') }}" + +- hosts: app_mongo + become: true + tasks: + - include_tasks: tasks/setup_base.yml + - include_tasks: tasks/setup_docker.yml + - include_tasks: tasks/setup_mongo.yml + - include_tasks: tasks/setup_sshaccess.yml + +# diff --git a/ansible/requirements.yml b/ansible/requirements.yml new file mode 100644 index 0000000..2b0bc65 --- /dev/null +++ b/ansible/requirements.yml @@ -0,0 +1,6 @@ +--- +roles: + - name: caddy_ansible.caddy_ansible + src: https://github.com/caddy-ansible/caddy-ansible + type: git + version: master diff --git a/ansible/tasks/setup_base.yml b/ansible/tasks/setup_base.yml new file mode 100644 index 0000000..d9a4d0f --- /dev/null +++ b/ansible/tasks/setup_base.yml @@ -0,0 +1,20 @@ +--- + +- name: Sync time + ansible.builtin.shell: + cmd: ntpdate 0.debian.pool.ntp.org + ignore_errors: yes + +- name: Install required system packages + ansible.builtin.apt: + name: + - vim + - ntpdate + state: latest + update_cache: true + +- name: Sync time + ansible.builtin.command: + cmd: ntpdate 0.debian.pool.ntp.org + +# diff --git a/ansible/tasks/setup_caddy.yml b/ansible/tasks/setup_caddy.yml new file mode 100644 index 0000000..e69de29 diff --git a/ansible/tasks/setup_docker.yml b/ansible/tasks/setup_docker.yml new file mode 100644 index 0000000..d78036b --- /dev/null +++ b/ansible/tasks/setup_docker.yml @@ -0,0 +1,59 @@ +--- +- name: Install required system packages + ansible.builtin.apt: + name: + - apt-transport-https + - ca-certificates + - curl + - software-properties-common + - python3-pip + - virtualenv + - python3-setuptools + state: latest + update_cache: true + +- name: Create keyring directory + ansible.builtin.file: + dest: /etc/apt/keyrings + state: directory + +- name: Add signing key + ansible.builtin.get_url: + url: "https://download.docker.com/linux/{{ ansible_distribution | lower }}/gpg" + dest: /etc/apt/keyrings/docker.gpg_armored + +- name: De-Armor Docker GPG key + shell: > + gpg --dearmor + < /etc/apt/keyrings/docker.gpg_armored + > /etc/apt/keyrings/docker.gpg + # no_log: true + args: + creates: /etc/apt/keyrings/docker.gpg + +- name: Get DEB architecture + shell: dpkg --print-architecture + register: deb_architecture + +- name: Add repository into sources list + ansible.builtin.apt_repository: + repo: "deb [arch={{ deb_architecture.stdout }} signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/{{ ansible_distribution | lower }} {{ ansible_distribution_release }} stable" + state: present + filename: docker + +- name: Install Docker + ansible.builtin.apt: + name: + - docker-ce + - docker-ce-cli + - containerd.io + - docker-compose-plugin + - docker-compose + state: latest + update_cache: true + +- name: Install Docker Module for Python + pip: + name: docker + +# diff --git a/ansible/tasks/setup_mongo.yml b/ansible/tasks/setup_mongo.yml new file mode 100644 index 0000000..e69de29 diff --git a/ansible/tasks/setup_sshaccess.yml b/ansible/tasks/setup_sshaccess.yml new file mode 100644 index 0000000..5963e3b --- /dev/null +++ b/ansible/tasks/setup_sshaccess.yml @@ -0,0 +1,12 @@ +--- +# Password needs to be encrypted. Use the following command to change password +# python3 -c 'import crypt,getpass;pw=getpass.getpass();print(crypt.crypt(pw) if (pw==getpass.getpass("Confirm: ")) else exit())' +- name: Add the user 'debian' + ansible.builtin.user: + name: debian + password: '$6$7SKND.wc64QSchcm$eGS36vIXypLHSd.PQM0gIq6ILx9QiRQxWNej3Gb32sKk2MuLrRlceXCJmidYATNZeJTbBXNf3c5qTmm7BB.EA1' + shell: /bin/bash + state: present + update_password: always + +# diff --git a/ansible/tasks/setup_sshwifty.yml b/ansible/tasks/setup_sshwifty.yml new file mode 100644 index 0000000..1a5bc2f --- /dev/null +++ b/ansible/tasks/setup_sshwifty.yml @@ -0,0 +1,30 @@ +--- +- name: Install required system packages + ansible.builtin.apt: + name: + - vim + state: latest + update_cache: true + +- name: Deploy SSHwifty configuration + template: + src: templates/sshwifty.conf.j2 + dest: /etc/sshwifty.conf + +- name: Create SSHwifty directory + file: + path: /var/lib/sshwifty + state: directory + +- name: Deploy SSHwifty configuration + template: + src: templates/docker-compose.yml.j2 + dest: /var/lib/sshwifty/docker-compose.yml + +- name: Run SSHwifty + community.docker.docker_compose: + project_src: /var/lib/sshwifty + recreate: smart + state: present + +# diff --git a/ansible/templates/Caddyfile.j2 b/ansible/templates/Caddyfile.j2 new file mode 100644 index 0000000..9b9b685 --- /dev/null +++ b/ansible/templates/Caddyfile.j2 @@ -0,0 +1,11 @@ +http://0.0.0.0:80 { + log + + reverse_proxy http://localhost:8080 { + header_up Host {http.request.host} + header_up X-Real-IP {http.request.remote.host} + header_up X-Forwarded-For {http.request.remote.host} + header_up X-Forwarded-Port {http.request.port} + header_up X-Forwarded-Proto {http.request.scheme} + } +} diff --git a/ansible/templates/docker-compose.yml.j2 b/ansible/templates/docker-compose.yml.j2 new file mode 100644 index 0000000..e0c5597 --- /dev/null +++ b/ansible/templates/docker-compose.yml.j2 @@ -0,0 +1,21 @@ +--- +# vim: set ts=2 sw=2 et ft=yaml : +version: "3.4" + +services: + sshwifty: + image: niruix/sshwifty:latest + restart: always + ports: + - 8080:8182 + environment: + SSHWIFTY_SHAREDKEY: admin + SSHWIFTY_CONFIG: /etc/sshwifty.conf + volumes: + - /etc/sshwifty.conf:/etc/sshwifty.conf + +volumes: {} + +networks: {} + +# diff --git a/ansible/templates/sshwifty.conf.j2 b/ansible/templates/sshwifty.conf.j2 new file mode 100644 index 0000000..084c4e6 --- /dev/null +++ b/ansible/templates/sshwifty.conf.j2 @@ -0,0 +1,48 @@ +{ + {# "HostName": "localhost", #} + "SharedKey": "{{ sshwifty_shared_key }}", + "DialTimeout": 10, + "Servers": [ + { + "ListenInterface": "0.0.0.0", + "ListenPort": 8182, + "InitialTimeout": 3, + "ReadTimeout": 60, + "WriteTimeout": 60, + "HeartbeatTimeout": 20, + "ReadDelay": 10, + "WriteDelay": 10 {# , #} + {# "TLSCertificateFile": "", #} + {# "TLSCertificateKeyFile": "" #} + } + ], + "Presets": [ + { + "Title": "Gateway", + "Type": "SSH", + "Host": "{{ansible_facts.all_ipv4_addresses | ansible.netcommon.ipaddr('192.168.50.0/24') | first }}:22", + "Meta": { + "User": "debian", + "Encoding": "utf-8", + "Password": "debian", + "Authentication": "Password" {# , #} + {# "Private Key": "file:///home/user/.ssh/private_key", #} + {# "Fingerprint": "SHA256:bgO...." #} + } + }, + { + "Title": "SDF.org Unix Shell", + "Type": "SSH", + "Host": "sdf.org:22", + "Meta": { + "User": "debian", + "Encoding": "utf-8", + "Password": "debian", + "Authentication": "Password" {# , #} + {# "Private Key": "file:///home/user/.ssh/private_key", #} + {# "Fingerprint": "SHA256:bgO...." #} + } + } + ], + "OnlyAllowPresetRemotes": true +} diff --git a/terraform/.gitignore b/terraform/.gitignore new file mode 100644 index 0000000..3eff84e --- /dev/null +++ b/terraform/.gitignore @@ -0,0 +1,4 @@ +.terraform +.terraform.lock.hcl +outputs/* +*.tfstate* diff --git a/terraform/domains.tf b/terraform/domains.tf new file mode 100644 index 0000000..d4a5111 --- /dev/null +++ b/terraform/domains.tf @@ -0,0 +1,18 @@ + +resource "gandi_livedns_record" "gateways_exploreko_org" { + count = var.mongo_groups_count + zone = var.domain_name + name = "gateway${count.index}.teaching" + type = "A" + ttl = 3600 + values = [openstack_compute_instance_v2.mongo_gateway[count.index].access_ip_v4] +} + +resource "gandi_livedns_record" "mongos_exploreko_org" { + count = var.mongo_replicas_count * var.mongo_groups_count + zone = var.domain_name + name = "mongo${count.index}.teaching" + type = "A" + ttl = 3600 + values = [openstack_compute_instance_v2.mongo_servers[count.index].access_ip_v4] +} diff --git a/terraform/instances.tf b/terraform/instances.tf new file mode 100644 index 0000000..a4b828a --- /dev/null +++ b/terraform/instances.tf @@ -0,0 +1,68 @@ + +# Création d'une ressource de paire de clés SSH +resource "openstack_compute_keypair_v2" "provision_keypair" { + provider = openstack.ovh + name = "provision_keypair" + public_key = file(var.ssh_public_key) +} + +resource "openstack_compute_instance_v2" "mongo_gateway" { + count = var.mongo_groups_count + name = "prod-gateway${count.index}" # Nom de l'instance + provider = openstack.ovh # Nom du fournisseur + image_name = "Debian 11" # Nom de l'image + flavor_name = "s1-2" # Nom du type d'instance + # flavor_name = "s1-8" # Nom du type d'instance + # flavor_name = "d2-8" # Nom du type d'instance + # Nom de la ressource openstack_compute_keypair_v2 nommée test_keypair + key_pair = openstack_compute_keypair_v2.provision_keypair.name + + metadata = { + ansible-group = "gateways" + mongo-group-id = count.index + } + + # Ajoute le composant réseau pour atteindre votre instance + network { + name = "Ext-Net" + } + + # provisioner "local-exec" { + # command = "ansible-playbook -i inventories/terraform --private-key ${var.ssh_private_key} -e 'pub_key=${var.ssh_public_key}' playbook.yml --limit ${self.name}" + # working_dir = "../ansible" + # environment = { + # ANSIBLE_HOST_KEY_CHECKING = "False" + # } + + # } +} + +# Création d'une instance +resource "openstack_compute_instance_v2" "mongo_servers" { + count = var.mongo_replicas_count * var.mongo_groups_count + name = "prod-server${count.index}" # Nom de l'instance + provider = openstack.ovh # Nom du fournisseur + image_name = "Debian 11" # Nom de l'image + flavor_name = "s1-2" # Nom du type d'instance + # flavor_name = "s1-8" # Nom du type d'instance + # flavor_name = "d2-8" # Nom du type d'instance + # Nom de la ressource openstack_compute_keypair_v2 nommée test_keypair + key_pair = openstack_compute_keypair_v2.provision_keypair.name + + metadata = { + ansible-group = "mongos" + mongo-group-id = floor(count.index / var.mongo_replicas_count) + mongo-group-index = count.index % var.mongo_replicas_count + } + # Ajoute le composant réseau pour atteindre votre instance + network { + name = "Ext-Net" + } + + # provisioner "local-exec" { + # command = "cd ../ansible && ansible-playbook -i inventories/terraform --private-key ${var.ssh_private_key} -e 'pub_key=${var.ssh_public_key}' playbook.yml --limit ${self.name}" + # environment = { + # ANSIBLE_HOST_KEY_CHECKING = "False" + # } + # } +} diff --git a/terraform/output.tf b/terraform/output.tf new file mode 100644 index 0000000..d5320f1 --- /dev/null +++ b/terraform/output.tf @@ -0,0 +1,12 @@ +resource "local_file" "ansible_inventory" { + content = templatefile("templates/inventory.tmpl", + { + mongo_gateways = openstack_compute_instance_v2.mongo_gateway.* + mongo_servers = openstack_compute_instance_v2.mongo_servers.* + mongo_groups_count = var.mongo_groups_count + mongo_replicas_count = var.mongo_replicas_count + } + ) + filename = "outputs/inventory" + file_permission = "0644" +} diff --git a/terraform/outputs/.empty b/terraform/outputs/.empty new file mode 100644 index 0000000..e69de29 diff --git a/terraform/provider.tf b/terraform/provider.tf new file mode 100644 index 0000000..1ccf73d --- /dev/null +++ b/terraform/provider.tf @@ -0,0 +1,37 @@ +terraform { + required_version = ">= 0.14.0" # Prend en compte les versions de terraform à partir de la 0.14.0 + required_providers { + openstack = { + source = "terraform-provider-openstack/openstack" + version = "~> 1.42.0" + } + + ovh = { + source = "ovh/ovh" + version = ">= 0.13.0" + } + + gandi = { + source = "go-gandi/gandi" + version = "~> 2.0.1" + } + } +} + +provider "gandi" { + key = "${var.gandi_key}" +} + +provider "openstack" { + auth_url = "https://auth.cloud.ovh.net/v3/" # URL d'authentification + domain_name = "default" # Toujours à "default" pour OVHcloud + alias = "ovh" # Un alias + + region = "GRA5" +} + +provider "ovh" { + endpoint = "ovh-eu" # Provider entry point + alias = "ovh" # Provider alias +} + diff --git a/terraform/provisionners.tf b/terraform/provisionners.tf new file mode 100644 index 0000000..b28dbe4 --- /dev/null +++ b/terraform/provisionners.tf @@ -0,0 +1,4 @@ + +# provisioner "local-exec" { +# command = "ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook -i outputs/inventory --private-key ${var.private_key} -e 'pub_key=${var.pub_key}' playbook.yml" +# } diff --git a/terraform/templates/inventory.tmpl b/terraform/templates/inventory.tmpl new file mode 100644 index 0000000..0989403 --- /dev/null +++ b/terraform/templates/inventory.tmpl @@ -0,0 +1,40 @@ +%{ for index, instance in mongo_gateways ~} +${ instance.name } ansible_user=debian ansible_host=${instance.network[0].fixed_ip_v4} +%{ endfor ~} +%{ for index, instance in mongo_servers ~} +${ instance.name } ansible_user=debian ansible_host=${instance.network[0].fixed_ip_v4} +%{ endfor ~} + +[stage_development] + +[stage_testing] + +[stage_production] +%{ for index, instance in mongo_gateways ~} +${ instance.name } +%{ endfor ~} +%{ for index, instance in mongo_servers ~} +${ instance.name } +%{ endfor ~} + +[role_gateway] +%{ for index, instance in mongo_gateways ~} +${ instance.name } +%{ endfor ~} + +[role_mongo] +%{ for index, instance in mongo_servers ~} +${ instance.name } +%{ endfor ~} + +[all_groups:children] +role_gateway +role_mongo +stage_development +stage_testing +stage_production + +[all:vars] +mongo_groups_count = ${ mongo_groups_count } +mongo_replicas_count = ${ mongo_replicas_count } + diff --git a/terraform/variables.tf b/terraform/variables.tf new file mode 100644 index 0000000..bc5d72a --- /dev/null +++ b/terraform/variables.tf @@ -0,0 +1,20 @@ + +variable "mongo_groups_count" { + default = "1" + description = "How many replicas per mongo" +} + +variable "mongo_replicas_count" { + default = "2" + description = "How many replicas per mongo group" +} + +variable "ssh_private_key" {} + +variable "ssh_public_key" {} + +variable "gandi_key" {} + +variable "domain_name" {} + +