repositorio inicial de proxy reverso, basado en Latina.Red
es una version jibarizada, que solo incluye los roles principales: - althost que orquesta todo - proxy reverso Nginx dockerizado - certbot maneja SSL de este - dns es un servidor DNS bind9 - rap es la VPN - users gestiona usuarixs linux
This commit is contained in:
commit
8c1a6e13e4
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*.retry
|
||||
*keys.yml
|
10
abyayala.yml
Normal file
10
abyayala.yml
Normal file
@ -0,0 +1,10 @@
|
||||
althost: abyayala
|
||||
matrix:
|
||||
- service_name: chem
|
||||
roles:
|
||||
- web
|
||||
domains:
|
||||
- marmite.abyaya.la
|
||||
- wordpress.marmite.abyaya.la
|
||||
nodo: marmite.comun.abyaya.la
|
||||
ssl: yes
|
2
ansible.cfg
Normal file
2
ansible.cfg
Normal file
@ -0,0 +1,2 @@
|
||||
[defaults]
|
||||
inventory = ./hosts.production
|
5
group_vars/abyayala/vars
Normal file
5
group_vars/abyayala/vars
Normal file
@ -0,0 +1,5 @@
|
||||
primary_dns_server: abyaya.la
|
||||
host_ip: 5.161.236.18
|
||||
compose_path: /opt/{{ althost }}
|
||||
oculta: "~/.oculta"
|
||||
proxy_scale: 2
|
7
group_vars/all/main.yml
Normal file
7
group_vars/all/main.yml
Normal file
@ -0,0 +1,7 @@
|
||||
compose_path: /opt/{{ althost }}
|
||||
local_compose_path: /tmp/{{ althost }}
|
||||
admin_email: beta@numerica.cl
|
||||
keys_file: ~/keys.yml
|
||||
# docker swarm
|
||||
manager_node_ip: 5.161.236.18
|
||||
# worker_token:
|
5
group_vars/localhost/vars
Normal file
5
group_vars/localhost/vars
Normal file
@ -0,0 +1,5 @@
|
||||
primary_dns_server: abyaya.la
|
||||
host_ip: 127.0.0.1
|
||||
compose_path: /tmp/{{ althost }}
|
||||
oculta: "~/.oculta"
|
||||
proxy_scale: 1
|
8
hosts.production
Normal file
8
hosts.production
Normal file
@ -0,0 +1,8 @@
|
||||
[localhost]
|
||||
127.0.0.1
|
||||
|
||||
[abyayala]
|
||||
5.161.236.18
|
||||
|
||||
[abyayala:vars]
|
||||
ansible_ssh_user=root
|
7
roles/althost/handlers/main.yml
Normal file
7
roles/althost/handlers/main.yml
Normal file
@ -0,0 +1,7 @@
|
||||
---
|
||||
|
||||
- name: deploy docker
|
||||
command: "docker stack deploy -c {{ compose_path }}/docker-compose.yml {{ althost }}"
|
||||
|
||||
- name: deploy service update
|
||||
command: docker stack deploy -c {{ compose_path }}/docker-compose-mini.yml {{ althost }}
|
35
roles/althost/tasks/compose.yml
Normal file
35
roles/althost/tasks/compose.yml
Normal file
@ -0,0 +1,35 @@
|
||||
- set_fact:
|
||||
services_content: "{{ lookup('template', 'templates/services.yml') }}"
|
||||
volumes_content: "{{ lookup('template', 'templates/volumes.yml') }}"
|
||||
networks_content: "{{ lookup('template', 'templates/networks.yml') }}"
|
||||
|
||||
- name: define services in local composition
|
||||
local_action:
|
||||
module: blockinfile
|
||||
path: "{{ local_compose_path }}/docker-compose.yml"
|
||||
insertafter: "services:"
|
||||
marker: "# {mark} {{ service_name|upper }}"
|
||||
block: "{{ services_content }}"
|
||||
changed_when: false
|
||||
|
||||
- name: define volumes in local composition
|
||||
local_action:
|
||||
module: lineinfile
|
||||
path: "{{ local_compose_path }}/docker-compose.yml"
|
||||
insertafter: "volumes: #"
|
||||
line: "{{ volumes_content }}"
|
||||
state: present
|
||||
regexp: "{{ volumes_content }}"
|
||||
when: volumes_content is defined
|
||||
changed_when: false
|
||||
|
||||
- name: define networks in local composition
|
||||
local_action:
|
||||
module: lineinfile
|
||||
path: "{{ local_compose_path }}/docker-compose.yml"
|
||||
insertafter: "networks: #"
|
||||
line: "{{ networks_content }}"
|
||||
regexp: "{{ networks_content }}"
|
||||
state: present
|
||||
when: networks_content is defined
|
||||
changed_when: false
|
113
roles/althost/tasks/main.yml
Normal file
113
roles/althost/tasks/main.yml
Normal file
@ -0,0 +1,113 @@
|
||||
# DOCKER CE this is specific for Debian
|
||||
# https://docs.docker.com/install/linux/docker-ce/debian/
|
||||
- block:
|
||||
|
||||
- name: required packages
|
||||
apt:
|
||||
name: ['apt-transport-https', 'ca-certificates', 'curl', 'gnupg2', 'software-properties-common', 'python3-pip']
|
||||
state: present
|
||||
|
||||
- name: docker signing key
|
||||
apt_key:
|
||||
url: https://download.docker.com/linux/debian/gpg
|
||||
state: present
|
||||
|
||||
- name: docker apt repository
|
||||
apt_repository:
|
||||
repo: deb [arch=amd64] https://download.docker.com/linux/debian bullseye stable
|
||||
|
||||
- name: install docker community edition
|
||||
apt:
|
||||
name: docker-ce
|
||||
update_cache: yes
|
||||
|
||||
- name: is node already in swarm mode
|
||||
shell: docker info
|
||||
register: swarm_status
|
||||
changed_when: False
|
||||
|
||||
- name: declare this node as swarm manager
|
||||
shell: docker swarm init --advertise-addr {{ ansible_default_ipv4.address }}
|
||||
when: "worker is undefined and swarm_status.stdout.find('Swarm: active') == -1"
|
||||
|
||||
- name: join this node to the swarm manager
|
||||
shell: docker swarm join --token {{ worker_token }} {{ manager_node_ip }}:2377
|
||||
when: worker is defined
|
||||
|
||||
# TODO APPARMOR ?
|
||||
|
||||
# ANSIBLE requirements
|
||||
- name: ensure python is present
|
||||
apt: name=python3 state=present
|
||||
|
||||
- name: ensure pip is present
|
||||
apt:
|
||||
name: python3-pip
|
||||
state: present
|
||||
|
||||
# ansible-docker requirements
|
||||
- name: python package docker-py is deprecated
|
||||
pip:
|
||||
name: docker-py
|
||||
state: absent
|
||||
break_system_packages: true
|
||||
|
||||
- name: ensure python package docker is present
|
||||
pip:
|
||||
name: docker
|
||||
state: present
|
||||
break_system_packages: true
|
||||
|
||||
# https://stackoverflow.com/questions/77490435/attributeerror-cython-sources
|
||||
- name: fix python package Cython version
|
||||
pip:
|
||||
name: Cython
|
||||
state: present
|
||||
version: <3.0.0
|
||||
break_system_packages: true
|
||||
|
||||
- name: fix python package PyYAML version
|
||||
shell: pip install "pyyaml==5.4.1" --no-build-isolation --break-system-packages
|
||||
|
||||
- name: ensure python package docker-compose is present
|
||||
pip:
|
||||
name: docker-compose
|
||||
state: present
|
||||
break_system_packages: true
|
||||
|
||||
tags: installation
|
||||
|
||||
|
||||
# DOCKER COMPOSITION IN MASTER
|
||||
- block:
|
||||
- name: make sure compose path exists
|
||||
file: path={{ compose_path }} state=directory
|
||||
|
||||
- name: make sure local compose path exists
|
||||
local_action:
|
||||
module: file
|
||||
path: "{{ local_compose_path }}"
|
||||
state: directory
|
||||
|
||||
- name: clean docker-compose.yml
|
||||
local_action:
|
||||
module: template
|
||||
dest: "{{ local_compose_path }}/docker-compose.yml"
|
||||
src: roles/althost/templates/docker-compose.yml
|
||||
changed_when: false
|
||||
|
||||
- name: make base keys dictionary
|
||||
local_action:
|
||||
module: lineinfile
|
||||
path: "{{ keys_file }}"
|
||||
line: "KEYS:"
|
||||
regexp: "KEYS:"
|
||||
changed_when: false
|
||||
|
||||
- name: execute roles per domain mapping
|
||||
include_tasks: roles.yml
|
||||
with_items: "{{ matrix }}"
|
||||
|
||||
# TODO
|
||||
# service undefined: ejecuta todos los roles
|
||||
# service defined: si es master, ejecuta su rol | si es worker, tambien pero en el otro host
|
11
roles/althost/tasks/roles.yml
Normal file
11
roles/althost/tasks/roles.yml
Normal file
@ -0,0 +1,11 @@
|
||||
- set_fact:
|
||||
current_service: "{{ item }}"
|
||||
service_name: "{{ item.service_name }}"
|
||||
service_roles: "{{ item.roles }}"
|
||||
|
||||
- include_role:
|
||||
name: "{{ current_role_name }}"
|
||||
with_items: "{{ service_roles }}"
|
||||
loop_control:
|
||||
loop_var: current_role_name
|
||||
when: (service is undefined) or (service is defined and service_name == service)
|
11
roles/althost/templates/docker-compose.yml
Normal file
11
roles/althost/templates/docker-compose.yml
Normal file
@ -0,0 +1,11 @@
|
||||
version: '3.3'
|
||||
|
||||
# servicios docker
|
||||
services:
|
||||
|
||||
# volumenes compartidos
|
||||
volumes: #
|
||||
|
||||
# redes compartidas
|
||||
networks: #
|
||||
|
8
roles/althost/templates/service_placement.yml
Normal file
8
roles/althost/templates/service_placement.yml
Normal file
@ -0,0 +1,8 @@
|
||||
deploy:
|
||||
placement:
|
||||
constraints:
|
||||
{% if item.worker is defined %}
|
||||
- node.role == worker
|
||||
{% else %}
|
||||
- node.role == manager
|
||||
{% endif %}
|
0
roles/althost/vars/main.yml
Normal file
0
roles/althost/vars/main.yml
Normal file
48
roles/certbot/tasks/certbot.yml
Normal file
48
roles/certbot/tasks/certbot.yml
Normal file
@ -0,0 +1,48 @@
|
||||
- name: check if the certificate exists
|
||||
stat:
|
||||
path: "{{ certs_mountpoint }}/live/{{ loop.domains[0] }}"
|
||||
register: ssl_cert
|
||||
become: yes
|
||||
|
||||
- name: check if vhost already exists
|
||||
stat:
|
||||
path: "{{ vhosts_path }}/{{ loop.domains[0] }}.conf"
|
||||
register: vhost_stat
|
||||
|
||||
- set_fact:
|
||||
needs_cert: (loop.ssl | default(domains_default_ssl) ) or (loop.force_https | default(domains_default_force_https))
|
||||
needs_vhost: needs_cert and not vhost_stat.stat.exists
|
||||
obtain_cert: needs_cert and not ssl_cert.stat.exists
|
||||
|
||||
- name: certificate obtention
|
||||
block:
|
||||
- set_fact:
|
||||
vhost: "{{ loop }}"
|
||||
|
||||
- name: add plain vhost to proxy for certbot test
|
||||
template:
|
||||
src: vhost.conf
|
||||
dest: "{{ vhosts_path }}/{{ loop.domains[0] }}.conf"
|
||||
when: needs_vhost
|
||||
|
||||
- name: fetch certificate with certbot container
|
||||
docker_container:
|
||||
name: chencriptemos
|
||||
image: certbot/certbot
|
||||
state: started
|
||||
volumes:
|
||||
- "{{ althost }}_certs_data:/etc/letsencrypt"
|
||||
- "{{ althost }}_certs_www:{{ certs_www_path }}"
|
||||
command: "certonly --webroot --agree-tos --expand --email {{ webmaster_email }} -w {{ certs_www_path }} -d {{ loop.domains | join(' -d ') }}"
|
||||
detach: yes
|
||||
cleanup: yes
|
||||
notify:
|
||||
- reload proxy
|
||||
register: cert_result
|
||||
|
||||
when: obtain_cert
|
||||
|
||||
# RESET
|
||||
- set_fact:
|
||||
needs_vhost: no
|
||||
|
56
roles/certbot/tasks/main.yml
Normal file
56
roles/certbot/tasks/main.yml
Normal file
@ -0,0 +1,56 @@
|
||||
- name: ensure certs volume exists
|
||||
docker_volume:
|
||||
name: "{{ althost }}_certs_data"
|
||||
state: present
|
||||
register: vol_certs
|
||||
|
||||
# TODO dict vol_certs no tiene ansible_facts : The error was: 'dict object' has no attribute 'docker_volume'
|
||||
- name: get certificates mountpoint
|
||||
set_fact:
|
||||
# certs_mountpoint: "{{ vol_certs.docker_volume.Mountpoint }}"
|
||||
certs_mountpoint: "/var/lib/docker/volumes/{{ alt }}_certs_data/_data"
|
||||
|
||||
# docker_compose could use proxy.state.running if we used docker compose instead of swarm
|
||||
- name: check if proxy is running
|
||||
shell: netstat -tunl | grep ":80 " | cat
|
||||
register: http_port
|
||||
changed_when: false
|
||||
|
||||
- set_fact:
|
||||
proxy_running: "{{ http_port.stdout != \"\" }}"
|
||||
|
||||
- name: ensure docker is in crontab's PATH
|
||||
cron:
|
||||
name: PATH
|
||||
env: yes
|
||||
value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
|
||||
- name: ensure cron uses bash
|
||||
cron:
|
||||
name: SHELL
|
||||
env: yes
|
||||
value: /bin/bash
|
||||
|
||||
- name: automatic letsencrypt certs renewal
|
||||
cron:
|
||||
name: certificate renewal
|
||||
day: 4,18
|
||||
hour: 0
|
||||
minute: 0
|
||||
job: "docker run --rm -v {{ althost }}_certs_data:/etc/letsencrypt -v {{ althost }}_certs_www:/var/www/letsencrypt certbot/certbot renew >> /var/log/renewal.log 2>&1"
|
||||
|
||||
- name: proxy update, after certs renewal
|
||||
cron:
|
||||
name: proxy update
|
||||
day: 4,18
|
||||
hour: 6
|
||||
minute: 10
|
||||
job: "docker service update --force {{ althost }}_proxy"
|
||||
|
||||
- name: mail proxy update, after certs renewal
|
||||
cron:
|
||||
name: mail proxy update
|
||||
day: 4,18
|
||||
hour: 6
|
||||
minute: 20
|
||||
job: "docker service update {{ althost }}_correspondencia_front"
|
8
roles/dns/backup/back.yml
Normal file
8
roles/dns/backup/back.yml
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
- include_tasks: ../roles/backup/tasks/back/common.yml
|
||||
|
||||
- set_fact:
|
||||
db_vol: "{{ alt }}_dns_server_bind"
|
||||
|
||||
- name: backup binary files
|
||||
include_tasks: ../roles/backup/tasks/back/dbvol.yml
|
4
roles/dns/handlers/main.yml
Normal file
4
roles/dns/handlers/main.yml
Normal file
@ -0,0 +1,4 @@
|
||||
---
|
||||
|
||||
- name: reload dns
|
||||
command: "docker service update --force {{ althost }}_nombres"
|
39
roles/dns/tasks/cnames.yml
Normal file
39
roles/dns/tasks/cnames.yml
Normal file
@ -0,0 +1,39 @@
|
||||
- set_fact:
|
||||
main_domain: "{{ zone.domains[0] }}"
|
||||
|
||||
- name: generate authoritative zones
|
||||
local_action:
|
||||
module: template
|
||||
src: "soa.hosts"
|
||||
dest: "{{ local_zone_path }}/{{ main_domain }}.hosts"
|
||||
changed_when: false
|
||||
|
||||
- name: add other zone's domains as CNAME
|
||||
local_action:
|
||||
module: blockinfile
|
||||
path: "{{ local_zone_path }}/{{ main_domain }}.hosts"
|
||||
insertafter: ";{{ main_domain }}. IN HINFO comment"
|
||||
marker: "; {mark} {{ subdomain | upper }}"
|
||||
block: "{{ subdomain }}. IN CNAME {{ main_domain }}."
|
||||
when: subdomain != main_domain
|
||||
with_items: "{{ zone.domains }}"
|
||||
loop_control:
|
||||
loop_var: subdomain
|
||||
changed_when: false
|
||||
|
||||
- name: include authoritative zones in config file
|
||||
local_action:
|
||||
module: blockinfile
|
||||
path: "{{ local_conf_file }}"
|
||||
insertafter: "// {{ althost }}"
|
||||
marker: "// {mark} {{ main_domain | upper }}"
|
||||
block: "{{ lookup('template', 'zone.conf') }}"
|
||||
changed_when: false
|
||||
|
||||
# we publish here not to have to iterate authoritative domains again
|
||||
- name: publish zone file
|
||||
copy:
|
||||
src: "{{ local_zone_path }}/{{ main_domain }}.hosts"
|
||||
dest: "{{ zone_path }}/{{ main_domain }}.hosts"
|
||||
notify:
|
||||
- reload dns
|
95
roles/dns/tasks/main.yml
Normal file
95
roles/dns/tasks/main.yml
Normal file
@ -0,0 +1,95 @@
|
||||
- include_tasks: ../../althost/tasks/compose.yml
|
||||
|
||||
- name: pull BIND dns server's image
|
||||
docker_image:
|
||||
name: "{{ DNS_image }}"
|
||||
state: present
|
||||
tags: installation
|
||||
|
||||
- set_fact:
|
||||
local_zone_file: "{{ local_zone_path }}/{{ primary_dns_server }}.hosts"
|
||||
local_conf_file: "{{ local_dns_path }}/named.conf.local"
|
||||
|
||||
- local_action:
|
||||
module: file
|
||||
dest: "{{ local_zone_path }}"
|
||||
state: directory
|
||||
|
||||
- file: dest="{{ zone_path }}" state=directory
|
||||
|
||||
- name: generate main zone in local
|
||||
local_action:
|
||||
module: template
|
||||
src: "althost.hosts"
|
||||
dest: "{{ local_zone_file }}"
|
||||
changed_when: false
|
||||
|
||||
- name: generate main configuration file in local
|
||||
local_action:
|
||||
module: template
|
||||
src: named.conf.local
|
||||
dest: "{{ local_conf_file }}"
|
||||
changed_when: false
|
||||
|
||||
# a non-authoritative matrix is a libertarian one
|
||||
- name: slice matrix with those having domains defined
|
||||
set_fact:
|
||||
matrix_domains: "{{ matrix_domains | default([]) | union(neo.domains) }}"
|
||||
with_items: "{{ matrix }}"
|
||||
when: (neo.domains is defined) and not (neo.authoritative is defined and neo.authoritative)
|
||||
loop_control:
|
||||
loop_var: neo
|
||||
|
||||
# DNS server pointed to althost with an A record
|
||||
# TODO and dominio regexp.match prmary_dns_server
|
||||
# TEST point domain A record and not declare authoritative, see if these CNAMES work
|
||||
- name: for each domain add a CNAME to main zone
|
||||
local_action:
|
||||
module: blockinfile
|
||||
path: "{{ local_zone_file }}"
|
||||
insertafter: "{{ primary_dns_server }}. IN HINFO Libre Abierta"
|
||||
marker: "; {mark} {{ dominio | upper }}"
|
||||
block: "{{ dominio }}. IN CNAME {{ primary_dns_server }}."
|
||||
with_items: "{{ matrix_domains }}"
|
||||
when: dominio != primary_dns_server and dominio != "ns1.{{ primary_dns_server }}" and dominio != "{{ mail_server }}"
|
||||
loop_control:
|
||||
loop_var: dominio
|
||||
changed_when: false
|
||||
|
||||
# DNS server pointed to althost with a NS record
|
||||
- name: slice matrix with authoritative domains
|
||||
set_fact:
|
||||
authoritative_domains: "{{ authoritative_domains | default([]) | union([zona]) }}"
|
||||
with_items: "{{ matrix }}"
|
||||
when: (zona.domains is defined) and (zona.authoritative is defined and zona.authoritative)
|
||||
loop_control:
|
||||
loop_var: zona
|
||||
|
||||
# TODO primary_dns_server domain cannot be declared as authoritative, it would be a duplicate entry
|
||||
- name: handle authoritative zones
|
||||
include_tasks: cnames.yml
|
||||
with_items: "{{ authoritative_domains }}"
|
||||
when: authoritative_domains is defined
|
||||
loop_control:
|
||||
loop_var: zone
|
||||
|
||||
- name: publish DNS changes
|
||||
block:
|
||||
- name: create directories
|
||||
file:
|
||||
dest: "{{ zone_path }}"
|
||||
state: directory
|
||||
|
||||
- name: publish main zone file
|
||||
copy:
|
||||
src: "{{ local_zone_file }}"
|
||||
dest: "{{ zone_path }}/{{ primary_dns_server }}.hosts"
|
||||
notify:
|
||||
- reload dns
|
||||
|
||||
- name: publish config file
|
||||
copy:
|
||||
src: "{{ local_conf_file }}"
|
||||
dest: "{{ dns_path }}/named.conf.local"
|
||||
notify:
|
||||
- reload dns
|
13
roles/dns/templates/althost.hosts
Normal file
13
roles/dns/templates/althost.hosts
Normal file
@ -0,0 +1,13 @@
|
||||
$ttl 38400
|
||||
{{ primary_dns_server }}. IN SOA {{ primary_dns_server }}. {{ admin_email | regex_replace('@','.') }}. (
|
||||
{{ ansible_date_time.epoch }} ; serial
|
||||
43200 ; refresh
|
||||
1800 ; retry
|
||||
3600000 ; expire
|
||||
86400 ) ; ttl
|
||||
{{ primary_dns_server }}. IN NS {{ primary_dns_server }}.
|
||||
{{ primary_dns_server }}. IN A {{ host_ip }}
|
||||
ns1.{{ primary_dns_server }}. IN A {{ host_ip }}
|
||||
{{ primary_dns_server }}. IN HINFO Libre Abierta
|
||||
|
||||
{% include "files/custom_dns_records/" ~ primary_dns_server ignore missing %}
|
17
roles/dns/templates/named.conf.local
Normal file
17
roles/dns/templates/named.conf.local
Normal file
@ -0,0 +1,17 @@
|
||||
//
|
||||
// Do any local configuration here
|
||||
//
|
||||
|
||||
// Consider adding the 1918 zones here, if they are not used in your
|
||||
// organization
|
||||
//include "/etc/bind/zones.rfc1918";
|
||||
|
||||
// master server zone
|
||||
zone "{{ primary_dns_server }}" {
|
||||
type master;
|
||||
file "/var/lib/bind/{{ primary_dns_server }}.hosts";
|
||||
};
|
||||
|
||||
// {{ althost }}
|
||||
|
||||
|
1
roles/dns/templates/networks.yml
Normal file
1
roles/dns/templates/networks.yml
Normal file
@ -0,0 +1 @@
|
||||
proxy:
|
9
roles/dns/templates/proxy.conf
Normal file
9
roles/dns/templates/proxy.conf
Normal file
@ -0,0 +1,9 @@
|
||||
# BEGIN PROXY
|
||||
location / {
|
||||
proxy_pass https://{{ vhost.service_name }}:10000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
# END PROXY
|
11
roles/dns/templates/services.yml
Normal file
11
roles/dns/templates/services.yml
Normal file
@ -0,0 +1,11 @@
|
||||
{{ service_name }}:
|
||||
image: "{{ DNS_image }}"
|
||||
networks:
|
||||
- proxy
|
||||
ports:
|
||||
- "53:53/udp"
|
||||
- "53:53/tcp"
|
||||
volumes:
|
||||
- "{{ zone_path }}/:/var/lib/bind/"
|
||||
- "{{ dns_path }}/named.conf.local:/etc/bind/named.conf.local"
|
||||
{% include "service_placement.yml" %}
|
15
roles/dns/templates/soa.hosts
Normal file
15
roles/dns/templates/soa.hosts
Normal file
@ -0,0 +1,15 @@
|
||||
$ttl 38400
|
||||
{{ zone.domains[0] }}. IN SOA {{ primary_dns_server }}. {{ admin_email | regex_replace('@','.') }}. (
|
||||
{{ ansible_date_time.epoch }} ; serial
|
||||
43200 ; refresh
|
||||
1800 ; retry
|
||||
3600000 ; expire
|
||||
86400 ) ; ttl
|
||||
|
||||
{{ zone.domains[0] }}. IN NS {{ primary_dns_server }}.
|
||||
{{ zone.domains[0] }}. IN A {{ host_ip }}
|
||||
|
||||
{% include "files/custom_dns_records/" ~ zone.domains[0] ignore missing %}
|
||||
|
||||
;{{ zone.domains[0] }}. IN HINFO comment
|
||||
|
0
roles/dns/templates/volumes.yml
Normal file
0
roles/dns/templates/volumes.yml
Normal file
5
roles/dns/templates/zone.conf
Normal file
5
roles/dns/templates/zone.conf
Normal file
@ -0,0 +1,5 @@
|
||||
zone "{{ main_domain }}" {
|
||||
type master;
|
||||
file "/var/lib/bind/{{ main_domain }}.hosts";
|
||||
};
|
||||
|
5
roles/dns/vars/main.yml
Normal file
5
roles/dns/vars/main.yml
Normal file
@ -0,0 +1,5 @@
|
||||
DNS_image: numericalatina/bind9
|
||||
dns_path: "{{ compose_path }}/dns"
|
||||
zone_path: "{{ dns_path }}/zones"
|
||||
local_dns_path: "{{ local_compose_path }}/dns"
|
||||
local_zone_path: "{{ local_dns_path }}/zones"
|
8
roles/proxy/backup/back.yml
Normal file
8
roles/proxy/backup/back.yml
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
- include_tasks: ../roles/backup/tasks/back/common.yml
|
||||
|
||||
- set_fact:
|
||||
db_vol: "{{ alt }}_certs_data"
|
||||
|
||||
- name: backup cert files
|
||||
include_tasks: ../roles/backup/tasks/back/dbvol.yml
|
5
roles/proxy/handlers/main.yml
Normal file
5
roles/proxy/handlers/main.yml
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
|
||||
- name: reload proxy
|
||||
command: docker service update --force {{ althost }}_proxy
|
||||
|
14
roles/proxy/handlers/reload_proxy.yml
Normal file
14
roles/proxy/handlers/reload_proxy.yml
Normal file
@ -0,0 +1,14 @@
|
||||
---
|
||||
# TODO no sirve para 4 replicas
|
||||
#- name: get service container name
|
||||
# command: "docker ps -f name={{ althost }}_proxy --quiet"
|
||||
# register: service_container_ID_
|
||||
# changed_when: false#
|
||||
#
|
||||
#- set_fact:
|
||||
# service_container_ID: "{{ service_container_ID_.stdout }}"
|
||||
# reload_command: "bash -l -c \"nginx -s reload\""
|
||||
|
||||
#- name: reload nginx conf
|
||||
# shell: "docker exec {{ service_container_ID }} {{ reload_command }}"
|
||||
|
56
roles/proxy/tasks/main.yml
Normal file
56
roles/proxy/tasks/main.yml
Normal file
@ -0,0 +1,56 @@
|
||||
- name: certbot role
|
||||
include_role: name=certbot
|
||||
tags: certbot
|
||||
|
||||
- include_tasks: ../../althost/tasks/compose.yml
|
||||
vars: # forcing since this role is included statically
|
||||
service_name: proxy
|
||||
|
||||
- name: configuration path
|
||||
file: path={{ conf_path }} state=directory
|
||||
|
||||
# TODO leaving unused vhosts bugs proxy
|
||||
- name: clean vhosts_path
|
||||
file: path={{ vhosts_path }} state=absent
|
||||
when: clean_vhosts is defined
|
||||
|
||||
- name: virtual hosts path
|
||||
file: path={{ vhosts_path }} state=directory
|
||||
|
||||
- name: generate dhparams
|
||||
command: openssl dhparam -outform pem -out {{ conf_path }}/dhparam2048.pem 2048
|
||||
args:
|
||||
creates: "{{ conf_path }}/dhparam2048.pem"
|
||||
|
||||
- name: copy nginx common files
|
||||
template: dest={{ conf_path }}/{{ common }} src={{ common }} backup=yes
|
||||
with_items:
|
||||
- common.conf
|
||||
- common_ssl.conf
|
||||
loop_control:
|
||||
loop_var: common
|
||||
|
||||
- name: domains' stuff
|
||||
block:
|
||||
- name: slice matrix with those having domains defined
|
||||
set_fact:
|
||||
matrix_loop: "{{ matrix_loop | default([]) | union([ domino ]) }}"
|
||||
with_items: "{{ matrix }}"
|
||||
when: "{{ domino.domains is defined and domino.roles[0]!='dns' }}"
|
||||
loop_control:
|
||||
loop_var: domino
|
||||
|
||||
- name: certificates loop
|
||||
include_tasks: ../../certbot/tasks/certbot.yml
|
||||
with_items: "{{ matrix_loop | default([]) }}"
|
||||
tags: certbot
|
||||
loop_control:
|
||||
loop_var: loop
|
||||
when: (service is undefined) or (service is defined and service == loop.service_name)
|
||||
|
||||
- name: vhosts loop
|
||||
include_tasks: vhosts.yml
|
||||
with_items: "{{ matrix_loop }}"
|
||||
loop_control:
|
||||
loop_var: vhost
|
||||
when: (service is undefined) or (service is defined and service == vhost.service_name)
|
25
roles/proxy/tasks/vhosts.yml
Normal file
25
roles/proxy/tasks/vhosts.yml
Normal file
@ -0,0 +1,25 @@
|
||||
|
||||
- set_fact:
|
||||
custom_vhost: "roles/{{ vhost.roles[0] }}/templates/vhost.conf"
|
||||
vhost_dest: "{{ vhosts_path }}/{{ vhost.domains[0] }}.conf"
|
||||
proxy_conf: "roles/{{ vhost.roles[0] }}/templates/proxy.conf"
|
||||
|
||||
- set_fact:
|
||||
proxy_conf_look: "{{ lookup('template', proxy_conf) }}"
|
||||
when: proxy_conf is is_file
|
||||
|
||||
- name: generate nginx vhosts
|
||||
template:
|
||||
src: "{{ default_vhost }}"
|
||||
dest: "{{ vhost_dest }}"
|
||||
when: custom_vhost is not is_file
|
||||
notify:
|
||||
- reload proxy
|
||||
|
||||
- name: generate nginx custom vhosts
|
||||
template:
|
||||
src: "{{ custom_vhost }}"
|
||||
dest: "{{ vhost_dest }}"
|
||||
when: custom_vhost is is_file
|
||||
notify:
|
||||
- reload proxy
|
3
roles/proxy/templates/common.conf
Normal file
3
roles/proxy/templates/common.conf
Normal file
@ -0,0 +1,3 @@
|
||||
location /.well-known/acme-challenge {
|
||||
root {{ certs_www_path }};
|
||||
}
|
11
roles/proxy/templates/common_ssl.conf
Normal file
11
roles/proxy/templates/common_ssl.conf
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
# Now let's really get fancy, and pre-generate a 2048 bit random parameter
|
||||
# for DH elliptic curves. If not created and specified, default is only 1024 bits.
|
||||
#
|
||||
# Generated by OpenSSL with the following command:
|
||||
# openssl dhparam -outform pem -out dhparam2048.pem 2048
|
||||
ssl_dhparam /etc/nginx/conf/dhparam2048.pem;
|
||||
|
||||
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
|
||||
ssl_prefer_server_ciphers on;
|
||||
|
16
roles/proxy/templates/default_proxy.conf
Normal file
16
roles/proxy/templates/default_proxy.conf
Normal file
@ -0,0 +1,16 @@
|
||||
# BEGIN PROXY
|
||||
location / {
|
||||
proxy_ssl_verify off;
|
||||
proxy_ssl_name $comun;
|
||||
proxy_ssl_server_name on;
|
||||
|
||||
proxy_pass https://$comun;
|
||||
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
{% include "files/custom_proxy_includes/" ~ vhost.domains[0] ignore missing %}
|
||||
}
|
||||
# END PROXY
|
1
roles/proxy/templates/networks.yml
Normal file
1
roles/proxy/templates/networks.yml
Normal file
@ -0,0 +1 @@
|
||||
proxy:
|
19
roles/proxy/templates/services.yml
Normal file
19
roles/proxy/templates/services.yml
Normal file
@ -0,0 +1,19 @@
|
||||
proxy:
|
||||
image: nginx
|
||||
deploy:
|
||||
replicas: {{ proxy_scale }}
|
||||
placement:
|
||||
constraints:
|
||||
- node.role == manager
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
networks:
|
||||
- proxy
|
||||
volumes:
|
||||
- "{{ vhosts_path }}:/etc/nginx/conf.d/"
|
||||
- "{{ conf_path }}:/etc/nginx/conf/"
|
||||
- "certs_www:{{ certs_www_path }}"
|
||||
- "certs_data:{{ nginx_certs_path }}:ro"
|
||||
|
||||
|
52
roles/proxy/templates/vhost.conf
Normal file
52
roles/proxy/templates/vhost.conf
Normal file
@ -0,0 +1,52 @@
|
||||
map $http_host $comun {
|
||||
hostnames;
|
||||
.{{ vhost.domains[0] }} {{ vhost.nodo }};
|
||||
}
|
||||
|
||||
server {
|
||||
server_name {{ vhost.domains | join(' ') }};
|
||||
|
||||
listen 80;
|
||||
|
||||
resolver 8.8.8.8 8.8.4.4 valid=300s;
|
||||
resolver_timeout 5s;
|
||||
|
||||
{% if not needs_vhost and ((vhost.ssl | default(domains_default_ssl) ) or (vhost.force_https | default(domains_default_force_https))) %}
|
||||
listen 443 ssl;
|
||||
|
||||
# letsencrypt
|
||||
ssl_certificate {{ nginx_certs_path }}/live/{{ vhost.domains[0] }}/fullchain.pem;
|
||||
ssl_certificate_key {{ nginx_certs_path }}/live/{{ vhost.domains[0] }}/privkey.pem;
|
||||
|
||||
include conf/common_ssl.conf;
|
||||
|
||||
{% if vhost.force_https | default(domains_default_force_https) %}
|
||||
if ($scheme != 'https') {
|
||||
rewrite ^/(.*)$ https://$host/$1 redirect;
|
||||
}
|
||||
|
||||
{% else %}
|
||||
if ($scheme != 'https') {
|
||||
rewrite ^/(.*)admin/(.*)$ https://$host/$1admin/$2 redirect;
|
||||
rewrite ^/(.*)login/(.*)$ https://$host/$1login/$2 redirect;
|
||||
}
|
||||
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
include conf/common.conf;
|
||||
|
||||
{% if not needs_vhost %}
|
||||
{% if proxy_conf is is_file %}
|
||||
{{ proxy_conf_look }}
|
||||
{% else %}
|
||||
{% include "default_proxy.conf" %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% include "files/custom_server_includes/" ~ vhost.domains[0] ignore missing %}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
2
roles/proxy/templates/volumes.yml
Normal file
2
roles/proxy/templates/volumes.yml
Normal file
@ -0,0 +1,2 @@
|
||||
certs_data:
|
||||
certs_www:
|
15
roles/proxy/vars/main.yml
Normal file
15
roles/proxy/vars/main.yml
Normal file
@ -0,0 +1,15 @@
|
||||
domains_default_ssl: no
|
||||
domains_default_force_https: no
|
||||
|
||||
# nginx
|
||||
vhosts_path: "{{ compose_path }}/proxy/vhosts"
|
||||
conf_path: "{{ compose_path }}/proxy/conf"
|
||||
certs_www_path: /var/www/letsencrypt
|
||||
nginx_certs_path: /etc/nginx/certs
|
||||
|
||||
# defaults
|
||||
needs_vhost: no
|
||||
default_vhost: roles/proxy/templates/vhost.conf
|
||||
|
||||
# certbot
|
||||
webmaster_email: webmaster@numerica.cl
|
16
roles/rap/hosts/latinared
Normal file
16
roles/rap/hosts/latinared
Normal file
@ -0,0 +1,16 @@
|
||||
Address = latina.red
|
||||
Port = 65000
|
||||
|
||||
-----BEGIN RSA PUBLIC KEY-----
|
||||
MIICCgKCAgEAv0oPDlf8mbr8fbiLLfUEucm5QxFLxarqhuph/ui3PmDXoiJGQK0d
|
||||
zHl92dYDdgRMw+4b1ogThGUZ8ryAt3UtpD8B6oLCRmhGn2tjNIFQN3kUIJQ3aa+M
|
||||
5nEBf6ys0IHEieUYVHXr5lxSc09Y/wsNbtATVZ25VT0ercR0c3gbpcypu8JpTdyn
|
||||
iul43IXiO8zKjeQhn9VQAnwIMzAa+6Y5Aj4y2HtFsUqzjJYY3KZBRTTNR1277QJ8
|
||||
NDMuQT0opE79E8ipOZaOdcFRZIUOG8cBhhavozSVCzjI8A1iA8QrJpEjo/zjV+D4
|
||||
h5EQpztvvzYdlOsE/9Cclc+iAGbnxOUt6K2bopMu/TI+gNh7DoA2wgFZ7DlQhCuO
|
||||
MiYV+9dzI4gKZvAO0IxiGnmq8s2UjWRnD9zVZztU5IOE1xBo7OrmcHnnOvsMMsmx
|
||||
Bc8F8jR6u8XgfSODS22sNK62N9joC2E3Gg/ulW75IUqIlyyHumwjm0XMuIXI6qDZ
|
||||
AUv0lOnYOWATveQlgCqLO9OyJmocbejz1ZtkcLgI/EDzwDYEpaKLf+39a7eLuNRa
|
||||
sqf+BIoJkGxi6LVG8gW5YhOLaaPclmsOztiID7vPHs0jH4bY7N0JR2TI8aaIlY9O
|
||||
P6ZJArG60IPtMUvurTrSmUGdHLoSg6+PSPZLfYMXoqKatrAhdEcc9ssCAwEAAQ==
|
||||
-----END RSA PUBLIC KEY-----
|
16
roles/rap/hosts/tierra
Normal file
16
roles/rap/hosts/tierra
Normal file
@ -0,0 +1,16 @@
|
||||
Address = tierra
|
||||
Port = 65000
|
||||
|
||||
-----BEGIN RSA PUBLIC KEY-----
|
||||
MIICCgKCAgEAtr75G3mVKBr8k7Sz5LQLuOBMdN2cwIZVQt0BVPq/gWeUowDPM8he
|
||||
QcjmSDZrwRE0NUQRiB5/Gicb9UXoQaEfq7xQfgcMl4Nt9MfHbhY6sORviAyHOsjM
|
||||
xYw/vy5SfWq3O7E/sH01BEbUt5r/oVoG2dy2rDQ5xBW30zeMJisvTMH5kMwHAWIG
|
||||
kdq0xI1WgFEa8eXo004Li8QD9k064wajN3mU0rUXEY0FCl9GbjP1S6a6ge3Sz+MP
|
||||
Je5RZzbNxvtY/YVeQBzjwUDawsjTZ9Lx968U9RaO2Z7LBrltLSSVU4aw6tH78zN8
|
||||
qVZ5PR0LmUQ38FWYNGcbUtfWRQACZOYkgBKbR0UOyLIbEODMUMmqZD7yOwAWf9BI
|
||||
Tw8NemFmkCs+Jb2LrayIOYaqvV3iY01oL2NgPhjV01XLs51GnHmiWUTfsEvu1lmM
|
||||
2uJoX75AzlL8We2RgWjknux3m4ce1sVTzMM36uatoz2lLDwBw9F6RKd2h6Gwb0kI
|
||||
k5ltlnjEttyQg/X1NowQClOfaUza+75mGaj1owK1zoYWZEUk4iRwoCT0KM1jnSKz
|
||||
z4w0uDz9YHhHDEG/evD6VLgPLcXdU2a+dKMU5GLGOcElKxi0p9bfzLJ9Efb2+PEY
|
||||
IJYfFlMT3YEacWsxLFuxUGbTbVCNccCIwv6QVQ8gnio+rowr8q64wwkCAwEAAQ==
|
||||
-----END RSA PUBLIC KEY-----
|
60
roles/users/tasks/main.yml
Normal file
60
roles/users/tasks/main.yml
Normal file
@ -0,0 +1,60 @@
|
||||
- block:
|
||||
- name: ensure sudo is present
|
||||
tags: apt
|
||||
apt: name=sudo state=present
|
||||
|
||||
- name: Make sure we have a 'sudo' group
|
||||
group: name=sudo state=present
|
||||
|
||||
- name: Allow 'sudo' group to have passwordless sudo
|
||||
lineinfile:
|
||||
dest: /etc/sudoers
|
||||
state: present
|
||||
regexp: '^%sudo'
|
||||
line: '%sudo ALL=(ALL) NOPASSWD: ALL'
|
||||
|
||||
- name: Ensure user is present
|
||||
user:
|
||||
name: "{{ item.0.name }}"
|
||||
comment: "{{ item.0.comment }}"
|
||||
state: present
|
||||
shell: "{{ item.0.shell | default('/bin/bash') }}"
|
||||
with_subelements:
|
||||
- "{{ ssh_users }}"
|
||||
- servers_allow
|
||||
- skip_missing: true
|
||||
when: (item.1 == inventory_hostname or item.1 == "all") and (item.0.root is undefined)
|
||||
|
||||
- name: Ensure user is in sudo group
|
||||
user:
|
||||
name: "{{ item.0.name }}"
|
||||
state: present
|
||||
groups: sudo
|
||||
append: yes
|
||||
with_subelements:
|
||||
- "{{ ssh_users }}"
|
||||
- servers_allow
|
||||
- skip_missing: true
|
||||
when: ( item.1 == inventory_hostname or item.1 == "all" ) and (item.0.sudo is defined and item.0.sudo)
|
||||
|
||||
- name: Populate user authorized_keys
|
||||
authorized_key: user="{{ item.0.name }}"
|
||||
key="{{ lookup('file', 'ssh/'+item.0.name+'.pub') }}"
|
||||
state=present
|
||||
with_subelements:
|
||||
- "{{ ssh_users }}"
|
||||
- servers_allow
|
||||
- skip_missing: true
|
||||
when: (item.1 == inventory_hostname or item.1 == "all") and (item.0.root is undefined)
|
||||
|
||||
- name: Populate root's authorized_keys
|
||||
authorized_key: user="root"
|
||||
key="{{ lookup('file', 'ssh/'+item.0.name+'.pub') }}"
|
||||
state=present
|
||||
with_subelements:
|
||||
- "{{ ssh_users }}"
|
||||
- servers_allow
|
||||
- skip_missing: true
|
||||
when: (item.1 == inventory_hostname or item.1 == "all") and (item.0.root is defined and item.0.root)
|
||||
|
||||
tags: users
|
39
tasks/deploy.yml
Normal file
39
tasks/deploy.yml
Normal file
@ -0,0 +1,39 @@
|
||||
# ansible-playbook --vault-id @prompt deploy.yml -e "host=digitalocean alt=numerica"
|
||||
# opcional: service define despliegue de servicio especifico
|
||||
---
|
||||
- hosts: "{{ host }}"
|
||||
vars_files:
|
||||
- "{{ keys_file }}"
|
||||
tasks:
|
||||
- name: import matrix
|
||||
local_action: "include_vars dir=./ files_matching={{ alt }}.yml"
|
||||
|
||||
- include_role: name=althost
|
||||
# tags: installation
|
||||
|
||||
- include_role: name=users
|
||||
tags: users, installation
|
||||
|
||||
- include_role: name=proxy
|
||||
tags: proxy
|
||||
|
||||
- name: publish docker composition
|
||||
copy:
|
||||
src: "{{ local_compose_path }}/docker-compose.yml"
|
||||
dest: "{{ compose_path }}/docker-compose.yml"
|
||||
notify:
|
||||
- deploy docker
|
||||
when: service is undefined
|
||||
|
||||
- name: publish a mini composition for single services
|
||||
copy:
|
||||
src: "{{ local_compose_path }}/docker-compose.yml"
|
||||
dest: "{{ compose_path }}/docker-compose-mini.yml"
|
||||
notify:
|
||||
- deploy service update
|
||||
when: service is defined
|
||||
|
||||
- name: self-destruct from crontab
|
||||
cron:
|
||||
name: nightly deploy
|
||||
state: absent
|
72
tasks/rap.yml
Normal file
72
tasks/rap.yml
Normal file
@ -0,0 +1,72 @@
|
||||
# ansible-playbook rap.yml -e "host=hetzner"
|
||||
---
|
||||
- hosts: "{{ host }}"
|
||||
vars:
|
||||
rap:
|
||||
port: 65000
|
||||
rap_dir: "{{ directory | default('/root') }}"
|
||||
environment:
|
||||
PATH: "/usr/sbin:{{ ansible_env.PATH }}"
|
||||
tasks:
|
||||
|
||||
- name: install dependencies
|
||||
package:
|
||||
name: "{{ item }}"
|
||||
state: present
|
||||
loop:
|
||||
- rsync
|
||||
- git
|
||||
- tinc
|
||||
become: yes
|
||||
|
||||
- name: iptables
|
||||
iptables:
|
||||
action: append
|
||||
chain: INPUT
|
||||
table: filter
|
||||
destination_port: "{{ rap.port }}"
|
||||
protocol: "{{ item }}"
|
||||
jump: ACCEPT
|
||||
loop:
|
||||
- tcp
|
||||
- udp
|
||||
become: yes
|
||||
|
||||
- name: install rap
|
||||
git:
|
||||
repo: "https://0xacab.org/pip/rap.git"
|
||||
dest: "{{ rap_dir }}/rap"
|
||||
|
||||
- set_fact:
|
||||
hostname: "{% if '{{ host }} != localhost' %} {{ ansible_hostname }} {% else %} {{ inventory_hostname }} {% endif %}"
|
||||
# inventory_hostname=> localhost/IP | ansible_hostname=>infra
|
||||
|
||||
- name: node name
|
||||
shell: 'echo {{ hostname }} | tr -cd "[:alnum:]" | tr "[:upper:]" "[:lower:]"'
|
||||
register: node_name
|
||||
changed_when: false
|
||||
|
||||
- stat:
|
||||
path: "{{ rap_dir }}/rap/hosts/{{ node_name.stdout }}"
|
||||
register: node_exists
|
||||
|
||||
- name: init node
|
||||
when: "node_exists.stat.exists == False"
|
||||
shell: "cd {{ rap_dir }}/rap && ./rap init -f -a {{ hostname }} -p {{ rap.port }}"
|
||||
|
||||
- name: fetch hosts files
|
||||
fetch:
|
||||
flat: true
|
||||
src: "{{ rap_dir }}/rap/hosts/{{ node_name.stdout }}"
|
||||
dest: "./rap/hosts/{{ node_name.stdout }}"
|
||||
|
||||
- name: copy hosts files
|
||||
copy:
|
||||
src: "./rap/hosts/"
|
||||
dest: "{{ rap_dir }}/rap/hosts/"
|
||||
|
||||
- name: connectto
|
||||
shell: 'cd {{ rap_dir }}/rap && for host in ./hosts/*; do test "./hosts/{{ node_name.stdout }}" = "${host}" && continue ; basename "${host}" | xargs -r ./rap connectto "{{ node_name.stdout }}"; done'
|
||||
|
||||
- name: install node
|
||||
shell: "cd {{ rap_dir }}/rap && ./rap install {{ node_name.stdout }}"
|
6
tasks/users.yml
Normal file
6
tasks/users.yml
Normal file
@ -0,0 +1,6 @@
|
||||
# ansible-playbook --vault-id @prompt users.yml -e "host=hetzner"
|
||||
---
|
||||
- hosts: "{{ host }}"
|
||||
tasks:
|
||||
- include_role:
|
||||
name: users
|
Loading…
x
Reference in New Issue
Block a user