testing setting up a site end-2-end

This commit is contained in:
Daniel Tsvetkov 2020-06-21 17:45:33 +02:00
parent 03c2addf8a
commit ed841fd033
8 changed files with 128 additions and 59 deletions

2
.gitignore vendored
View File

@ -5,4 +5,4 @@ data/db.sqlite
__pycache__ __pycache__
oshipka.egg-info oshipka.egg-info
provision/tmp provision/tmp
secrets.py provision/auto_dns/sensitive.py

View File

@ -64,13 +64,9 @@ init() {
} }
install_cert() { install_cert() {
#[ ! -f /tmp/certbot-auto ] && wget -O /tmp/certbot-auto https://dl.eff.org/certbot-auto
#chmod +x /tmp/certbot-auto
#certbot=/tmp/certbot-auto
shift
PROJECT_DOMAIN=$1 PROJECT_DOMAIN=$1
sudo apt install certbot sudo apt install certbot
certbot certonly --authenticator standalone --installer nginx --pre-hook "service nginx stop" --post-hook "service nginx start" --redirect --agree-tos --no-eff-email --email danieltcv@gmail.com -d ${PROJECT_DOMAIN} --no-bootstrap sudo certbot certonly --dry-run --authenticator standalone --installer nginx --pre-hook "service nginx stop" --post-hook "service nginx start" --redirect --agree-tos --no-eff-email --email danieltcv@gmail.com -d ${PROJECT_DOMAIN} --no-bootstrap
} }
bootstrap() { bootstrap() {
@ -123,11 +119,12 @@ run_in_prod() {
} }
prod_install() { prod_install() {
set -e
shift shift
source venv/bin/activate source venv/bin/activate
PROJECT_NAME=$(basename `pwd`) PROJECT_NAME=$(basename `pwd`)
echo "1/4 Generating service and config files..." echo "1/6 Generating service and config files..."
"${OSHIPKA_PATH}/venv/bin/python" "${OSHIPKA_PATH}/provision/prod_mgmt.py" python "${OSHIPKA_PATH}/provision/prod_mgmt.py"
if [ -f "/etc/systemd/system/${PROJECT_NAME}.service" ]; then if [ -f "/etc/systemd/system/${PROJECT_NAME}.service" ]; then
echo "Service gunicorn for ${PROJECT_NAME} service exists." echo "Service gunicorn for ${PROJECT_NAME} service exists."
systemctl status ${PROJECT_NAME} systemctl status ${PROJECT_NAME}
@ -138,7 +135,7 @@ prod_install() {
sudo systemctl start "${PROJECT_NAME}" sudo systemctl start "${PROJECT_NAME}"
fi fi
echo "2/5 Installing '$PROJECT_NAME' worker service" echo "2/6 Installing '$PROJECT_NAME' worker service"
if [ -f "/etc/systemd/system/${PROJECT_NAME}_worker.service" ]; then if [ -f "/etc/systemd/system/${PROJECT_NAME}_worker.service" ]; then
echo "Service worker for ${PROJECT_NAME} service exists." echo "Service worker for ${PROJECT_NAME} service exists."
systemctl status "${PROJECT_NAME}_worker" systemctl status "${PROJECT_NAME}_worker"
@ -148,17 +145,38 @@ prod_install() {
sudo systemctl start "${PROJECT_NAME}_worker" sudo systemctl start "${PROJECT_NAME}_worker"
fi fi
# TODO: Update DNS
NGINX_CONFIG_FILE=$(basename `find $OSHIPKA_PATH/provision/tmp -name *.conf`) NGINX_CONFIG_FILE=$(basename `find $OSHIPKA_PATH/provision/tmp -name *.conf`)
DOMAIN=$(basename -s .conf $NGINX_CONFIG_FILE) DOMAIN=$(basename -s .conf $NGINX_CONFIG_FILE)
echo "3/5 Installing '$DOMAIN' domain..." echo "3/6 Installing '$DOMAIN' domain..."
"${OSHIPKA_PATH}/venv/bin/python" "${OSHIPKA_PATH}/audo_dns/set_domain.py" "$DOMAIN" python "${OSHIPKA_PATH}/provision/auto_dns/set_domain_ipv4.py" "$DOMAIN"
# TODO: Create certificate sudo apt install nginx
echo "4/5 Installing '$PROJECT_NAME' certificate..." sudo systemctl start nginx
echo "Enabling firewall rule for 192.168.1.1 -> 80/tcp..."
sudo ufw allow proto tcp from 192.168.1.1 to any port 80
echo "4/6 Installing '$PROJECT_NAME' insecure nginx config..."
if [ -f "/etc/nginx/sites-available/${DOMAIN}_insecure.conf" ]; then
echo "Insecure Nginx config for ${PROJECT_NAME} available."
if [ -f "/etc/nginx/sites-enabled/${DOMAIN}_insecure.conf" ]; then
echo "Nginx config for ${PROJECT_NAME} enabled."
else
echo "Nginx config for ${PROJECT_NAME} NOT enabled."
fi
else
echo "Installing insecure nginx config for ${PROJECT_NAME} -> enabling + available."
sudo cp "${OSHIPKA_PATH}/provision/tmp/${DOMAIN}_insecure.conf" /etc/nginx/sites-available/
sudo ln -s "/etc/nginx/sites-available/${DOMAIN}_insecure.conf" "/etc/nginx/sites-enabled/${DOMAIN}_insecure.conf"
sudo systemctl reload nginx
fi
echo "5/6 Installing '$PROJECT_NAME' certificate..."
install_cert $DOMAIN install_cert $DOMAIN
echo "5/5 Installing '$PROJECT_NAME' nginx config..." echo "6/6 Installing '$PROJECT_NAME' secure nginx config..."
echo "Enabling firewall rule for 192.168.1.1 -> 443/tcp..."
sudo ufw allow proto tcp from 192.168.1.1 to any port 443
echo "Removing '$PROJECT_NAME' insecure nginx config..."
sudo rm "/etc/nginx/sites-available/${DOMAIN}_insecure.conf" "/etc/nginx/sites-enabled/${DOMAIN}_insecure.conf"
if [ -f "/etc/nginx/sites-available/${NGINX_CONFIG_FILE}" ]; then if [ -f "/etc/nginx/sites-available/${NGINX_CONFIG_FILE}" ]; then
echo "Nginx config for ${PROJECT_NAME} available." echo "Nginx config for ${PROJECT_NAME} available."
if [ -f "/etc/nginx/sites-enabled/${NGINX_CONFIG_FILE}" ]; then if [ -f "/etc/nginx/sites-enabled/${NGINX_CONFIG_FILE}" ]; then
@ -168,8 +186,9 @@ prod_install() {
fi fi
else else
echo "Installing nginx config for ${PROJECT_NAME} -> enabling + available." echo "Installing nginx config for ${PROJECT_NAME} -> enabling + available."
sudo cp "${OSHIPKA_PATH}/provision/tmp/${NGINX_CONFIG_FILE}" /etc/nginx/sites-enabled/ sudo cp "${OSHIPKA_PATH}/provision/tmp/${NGINX_CONFIG_FILE}" /etc/nginx/sites-available/
sudo ln -s "/etc/nginx/sites-available/${NGINX_CONFIG_FILE}" "/etc/nginx/sites-enabled/${NGINX_CONFIG_FILE}" sudo ln -s "/etc/nginx/sites-available/${NGINX_CONFIG_FILE}" "/etc/nginx/sites-enabled/${NGINX_CONFIG_FILE}"
sudo systemctl reload nginx
fi fi
} }
@ -256,7 +275,7 @@ command_main() {
;; ;;
prod_install) prod_install "$@" prod_install) prod_install "$@"
;; ;;
cert) install_cert "$@" cert) shift && install_cert "$@"
;; ;;
*) >&2 echo -e "${HELP}" *) >&2 echo -e "${HELP}"
return 1 return 1

View File

@ -11,10 +11,12 @@ from lexicon.client import Client
from lexicon.config import ConfigResolver from lexicon.config import ConfigResolver
from oshipka.util.process import process_exp_backoff from oshipka.util.process import process_exp_backoff
from secrets import HOVER_USERNAME, HOVER_PASSWORD from sensitive import CLOUDFLARE_USERNAME, CLOUDFLARE_AUTH_KEY
SLEEP_SECONDS = 60 * 30 # 30 min SLEEP_SECONDS = 60 * 30 # 30 min
DEFAULT_TTL = 5 * 60
ipv4_sites = [ ipv4_sites = [
"http://www.icanhazip.com", "http://www.icanhazip.com",
"http://ipecho.net/plain", "http://ipecho.net/plain",
@ -24,19 +26,13 @@ ipv4_sites = [
] ]
ipv6_sites = [ ipv6_sites = [
"http://bot.whatismyipaddress.com",
"https://diagnostic.opendns.com/myip", "https://diagnostic.opendns.com/myip",
"https://ifconfig.co/ip", "https://ifconfig.co/ip",
] ]
dns_to_check = []
with open('dns_addresses.csv') as csvf:
csvreader = csv.reader(csvf)
for row in csvreader:
dns_to_check.append(row)
ip_checkers = ipv4_sites + ipv6_sites ip_checkers = ipv4_sites + ipv6_sites
dns_to_check = []
results = [] results = []
real = defaultdict(dict) real = defaultdict(dict)
@ -87,34 +83,35 @@ def check_dns():
t.start() t.start()
def get_hover_results(domain, ipv): def get_resolver_results(domain, ipv):
dns_config = ConfigResolver() dns_config = ConfigResolver()
dns_config.with_dict({ dns_config.with_dict({
'provider_name': 'hover', 'provider_name': 'cloudflare',
'action': 'list', 'action': 'list',
'type': ipv, 'type': ipv,
'domain': domain, 'domain': domain,
'hover': { 'cloudflare': {
'auth_username': HOVER_USERNAME, 'auth_username': CLOUDFLARE_USERNAME,
'auth_password': HOVER_PASSWORD, 'auth_token': CLOUDFLARE_AUTH_KEY,
} }
}) })
client = Client(dns_config) client = Client(dns_config)
return client.execute() return client.execute()
def set_hover_results(domain, ipv, new): def set_resolver_results(domain, ipv, new):
dns_config = ConfigResolver() dns_config = ConfigResolver()
dns_config.with_dict({ dns_config.with_dict({
'provider_name': 'hover', 'provider_name': 'cloudflare',
'action': 'update', 'action': 'create',
'type': ipv, 'type': ipv,
'domain': domain, 'domain': domain,
'name': domain, 'name': domain,
'content': new, 'content': new,
'hover': { 'ttl': DEFAULT_TTL,
'auth_username': HOVER_USERNAME, 'cloudflare': {
'auth_password': HOVER_PASSWORD, 'auth_username': CLOUDFLARE_USERNAME,
'auth_token': CLOUDFLARE_AUTH_KEY,
} }
}) })
client = Client(dns_config) client = Client(dns_config)
@ -122,7 +119,7 @@ def set_hover_results(domain, ipv, new):
def get_dns(domain, ipv): def get_dns(domain, ipv):
results = process_exp_backoff(get_hover_results, func_args=[domain, ipv]) results = process_exp_backoff(get_resolver_results, func_args=[domain, ipv])
res = [x.get('content') for x in results if x.get('name') == domain] res = [x.get('content') for x in results if x.get('name') == domain]
if len(res) == 1: if len(res) == 1:
print("Real {}: {}".format(ipv, res[0])) print("Real {}: {}".format(ipv, res[0]))
@ -130,7 +127,7 @@ def get_dns(domain, ipv):
def set_dns(domain, ipv, new): def set_dns(domain, ipv, new):
return process_exp_backoff(set_hover_results, func_args=[domain, ipv, new]) return process_exp_backoff(set_resolver_results, func_args=[domain, ipv, new])
def get_uniq(_list): def get_uniq(_list):
@ -139,6 +136,10 @@ def get_uniq(_list):
def main(): def main():
with open('dns_addresses.csv') as csvf:
csvreader = csv.reader(csvf)
for row in csvreader:
dns_to_check.append(row)
check_dns() check_dns()
check_observed() check_observed()
for t in tso: for t in tso:

View File

@ -1,6 +0,0 @@
import sys
if __name__ == "__main__":
domain = sys.argv[1]

View File

@ -0,0 +1,40 @@
import random
import sys
from time import sleep
import requests
from oshipka.util.os import run_os_cmd
from oshipka.util.process import process_exp_backoff
from provision.auto_dns.check import ipv4_sites, set_resolver_results, DEFAULT_TTL
def verify_dns_domain(domain, ipv4):
ip_on_dns = run_os_cmd("dig +short {}".format(domain))
if not ip_on_dns:
raise Exception("Record for {} doesn't exist".format(domain))
ip_on_dns = ip_on_dns.strip()
assert ip_on_dns == ipv4
def set_domain_ipv4(domain):
url = random.choice(ipv4_sites)
resp = requests.get(url)
ipv4 = resp.text.strip()
print('Got IP: {}'.format(ipv4))
try:
verify_dns_domain(domain, ipv4)
print("DNS already set up for {}".format(domain))
except Exception:
process_exp_backoff(set_resolver_results, func_args=[domain, 'A', ipv4])
print("Sleeping 5 sec...")
sleep(5)
print("Checking that {} is set".format(domain))
process_exp_backoff(verify_dns_domain, func_args=[domain, ipv4], max_attempts=0, max_sleep_time=DEFAULT_TTL)
if __name__ == "__main__":
domain = sys.argv[1]
if not domain:
print('domain is required first argument')
set_domain_ipv4(domain)

View File

@ -7,6 +7,7 @@ from provision.util import find_port, find_private_ipv4
USER = "pi2" USER = "pi2"
PARENT_DOMAIN = "pi2.dev" PARENT_DOMAIN = "pi2.dev"
MAX_UPLOAD_SIZE = "10m"
oshipka_path = os.environ.get('OSHIPKA_PATH') oshipka_path = os.environ.get('OSHIPKA_PATH')
@ -33,23 +34,22 @@ def prod_install():
project_name=project_name, project_name=project_name,
project_domain=project_domain, project_domain=project_domain,
upstream_ip=upstream_ip, upstream_ip=upstream_ip,
max_upload_size=MAX_UPLOAD_SIZE,
port=port, port=port,
) )
service_tmpl = env.get_template('gunicorn.service') tmpl_fname = [
service_txt = service_tmpl.render(ctx) ('gunicorn.service', "{}.service".format(project_name)),
with open(os.path.join(TMP_PATH, "{}.service".format(project_name)), 'w') as f: ('worker.service', "{}_worker.service".format(project_name)),
f.write(service_txt) ('nginx_insecure.conf', "{}_insecure.conf".format(project_domain)),
('nginx.conf', "{}.conf".format(project_domain)),
]
worker_service_tmpl = env.get_template('worker.service') for tmpl, fname in tmpl_fname:
worker_service_txt = worker_service_tmpl.render(ctx) actual_tmpl = env.get_template(tmpl)
with open(os.path.join(TMP_PATH, "{}_worker.service".format(project_name)), 'w') as f: rendered_tmpl = actual_tmpl.render(ctx)
f.write(worker_service_txt) with open(os.path.join(TMP_PATH, fname), 'w') as f:
f.write(rendered_tmpl)
nginx_tmpl = env.get_template('nginx.conf')
nginx_txt = nginx_tmpl.render(ctx)
with open(os.path.join(TMP_PATH, "{}.conf".format(project_domain)), 'w') as f:
f.write(nginx_txt)
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -16,7 +16,7 @@ server {
server_tokens off; server_tokens off;
charset utf-8; charset utf-8;
client_max_body_size {{ project_domain }}; client_max_body_size {{ max_upload_size }};
# certs sent to the client in SERVER HELLO are concatenated in ssl_certificate # certs sent to the client in SERVER HELLO are concatenated in ssl_certificate
ssl_certificate /etc/letsencrypt/live/{{ project_domain }}/fullchain.pem; ssl_certificate /etc/letsencrypt/live/{{ project_domain }}/fullchain.pem;

View File

@ -0,0 +1,15 @@
server {
listen 80;
listen [::]:80;
server_name {{ project_domain }};
location / {
proxy_pass http://{{ upstream_ip }}:{{ port }};
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}