Skip to content

Commit

Permalink
Certboot changed to Lego
Browse files Browse the repository at this point in the history
  • Loading branch information
rmalenko committed Sep 3, 2023
1 parent 61d528d commit 338c941
Show file tree
Hide file tree
Showing 15 changed files with 148 additions and 62 deletions.
15 changes: 0 additions & 15 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,15 +0,0 @@
[submodule "ansible-role-nginx"]
path = ansible-role-nginx
url = https://github.com/nginxinc/ansible-role-nginx.git
[submodule "ansible/roles/ansible-role-nginx"]
path = ansible/roles/ansible-role-nginx
url = https://github.com/nginxinc/ansible-role-nginx.git
[submodule "ansible/roles/ansible-role-nginx-config"]
path = ansible/roles/ansible-role-nginx-config
url = https://github.com/nginxinc/ansible-role-nginx-config.git
[submodule "ansible/roles/ansible-role-certbot"]
path = ansible/roles/ansible-role-certbot
url = [email protected]:geerlingguy/ansible-role-certbot.git
[submodule "ansible/roles/postgresql"]
path = ansible/roles/postgresql
url = [email protected]:ANXS/postgresql.git
4 changes: 2 additions & 2 deletions 01-main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module "vultr" {
instance_tags = ["go", "app"]
ssh_key_name = ["rostyslav"]
plan = var.plan_5_usd_vc2-1c-1gb
os_id = var.os_id_ubuntu_20_04_lts
os_id = var.os_id_ubuntu_22_04_lts
enable_ipv6 = true
backups = "enabled"
backups_schedule = "monthly"
Expand All @@ -27,7 +27,7 @@ module "vultr" {
# instance_tags = ["go", "db"]
# ssh_key_name = ["rostyslav"]
# plan = var.plan_5_usd_vc2-1c-1gb
# os_id = var.os_id_ubuntu_20_04_lts
# os_id = var.os_id_ubuntu_22_04_lts
# enable_ipv6 = false
# backups = "enabled"
# backups_schedule = "monthly"
Expand Down
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,25 @@ If you have already done that, you may skip these steps
## Variables
It the file `01-main.tf` add or, change the number of servers you need, or remove one server. Look for `# Instanse`.

### Domain and DNS
### Domain and SSL certificates
These keys are used for server and host names and Ansible playbook names.

*For example:*
- `app-server` + `var.domain` = `app-server.jazzfest.link`

In this case, `app-server` is the first key `[0]`, and the public IP of this instance will be used as the primary server in this infrastructure. This server could be a load balancer or just for all wanted applications.

Important:

- IP of the first server used for `@` and `www` DNS records.
- SSL certificate (Letsencrypt) will be generated for domains: `jazzfest.link`, `www.jazzfest.link`, `app-server.jazzfest.link`.
- SSL certificate (Letsencrypt) will be issued for wildcard domains: `jazzfest.link`, `*.jazzfest.link` using [Lego](https://github.com/go-acme/lego) - Let's Encrypt client and ACME library. Follow the link for more information. We assume we use Vultr DNS. And our NS servers were appropriately configured.

### Ansible configuration
- app-servr = app-server.yaml ansible playbooks name. So, each server uses its playbook, which allows for preparing specific configurations for each server. It means you must create a playbook named as `${each.key}.yaml` in the folder `./ansible`


`sleep 180` in `06-templates.tf` may not be enough to get a letsencrypt certificate because DNS isn't propagated yet.

![Vultr](./docs/servers_key.png)

All variables in file `variables.tf`. I hope they are described itself.
Expand Down
53 changes: 36 additions & 17 deletions ansible/app-server.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
- role: systemd_journald
- role: systemd_timesyncd
- role: node_exporter
- role: geerlingguy.certbot
- role: lego_encrypt_acme
- role: ansible-systemd-timers
# - role: geerlingguy.certbot

tasks:
- name: Install NGINX
Expand Down Expand Up @@ -135,6 +137,8 @@
keepalive_timeout: 75s
server_name:
- "{{ domain_name }}"
- "www.{{ domain_name }}"
- "{{ domain_name_nginx }}"
listen:
- address: 0.0.0.0
port: 80
Expand Down Expand Up @@ -172,6 +176,8 @@
keepalive_timeout: 75s
server_name:
- "{{ domain_name }}"
- "www.{{ domain_name }}"
- "{{ domain_name_nginx }}"
listen:
- address: 0.0.0.0
port: 443
Expand Down Expand Up @@ -204,9 +210,9 @@
autoindex:
enable: false
ssl:
certificate: /etc/letsencrypt/live/{{ domain_name }}/fullchain.pem
certificate_key: /etc/letsencrypt/live/{{ domain_name }}/privkey.pem
trusted_certificate: /etc/letsencrypt/live/{{ domain_name }}/cert.pem
certificate: /etc/letsencrypt/{{ domain_name }}/certificates/_.{{ domain_name }}.crt
certificate_key: /etc/letsencrypt/{{ domain_name }}/certificates/_.{{ domain_name }}.key
# trusted_certificate: /etc/letsencrypt/{{ domain_name }}/certificates/cert.pem
ciphers:
- ECDHE-ECDSA-AES128-GCM-SHA256
- ECDHE-RSA-AES128-GCM-SHA256
Expand Down Expand Up @@ -278,6 +284,19 @@
value: $remote_addr

vars:
domain_name: "{{ domain_name }}" # The primary domain name to obtain wildcard letsencrypt SSL and for paths and certificates name.
api_key: "{{ api_key }}"
email: "{{ email }}"
lego_v: "v4.14.0"

timers: # https://wiki.archlinux.org/title/systemd/Timers
renewal_letsencrypt:
timer_command: "{{ script_path }} renew && nginx -s reload"
timer_user: root
timer_OnCalendar: "*-*-* 02:37:00 EST"
# timer_persistent: true
timer_AccuracySec: 2h

docker_compose_version: "2.20.3"
systemd_journald_systemmaxuse: "2G"
node_exporter_version: 1.6.1 # https://github.com/prometheus/node_exporter/releases
Expand All @@ -289,16 +308,16 @@
ignored-mount-points: "^/(sys|proc|dev)($|/)"
ignored-fs-types: "^(sys|proc|auto)fs$"

certbot_admin_email: [email protected]
certbot_auto_renew: true
certbot_auto_renew_hour: 2
certbot_auto_renew_minute: 16
certbot_auto_renew_options: --quiet
certbot_create_if_missing: true
certbot_create_method: standalone
certbot_install_method: snap
certbot_testmode: true # Enable test mode to only run a test request without actually creating certificates.
certbot_create_standalone_stop_services:
- nginx
certbot_certs:
- domains: "{{ domain_name }}"
# certbot_admin_email: [email protected]
# certbot_auto_renew: true
# certbot_auto_renew_hour: 2
# certbot_auto_renew_minute: 16
# certbot_auto_renew_options: --quiet
# certbot_create_if_missing: true
# certbot_create_method: standalone
# certbot_install_method: snap
# certbot_testmode: true # Enable test mode to only run a test request without actually creating certificates.
# certbot_create_standalone_stop_services:
# - nginx
# certbot_certs:
# - domains: "{{ domain_name }}"
22 changes: 0 additions & 22 deletions ansible/playbook.yml

This file was deleted.

1 change: 0 additions & 1 deletion ansible/roles/anxs.postgresql
Submodule anxs.postgresql deleted from 2697f9
6 changes: 6 additions & 0 deletions ansible/roles/lego_encrypt_acme/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
domain: "{{ domain_name }}"
apikey: "{{ api_key }}"
email: "{{ email }}"
lego_v: v4.14.0
script_path: "/etc/letsencrypt/lego_ssl.sh"
55 changes: 55 additions & 0 deletions ansible/roles/lego_encrypt_acme/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
- name: Get URL of latest Lego
ansible.builtin.uri:
url: https://api.github.com/repos/go-acme/lego/releases/latest
body_format: json
return_content: true
remote_src: false
# delegate_to: localhost
register: json_response

- name: Debug json_response
debug:
msg: >-
{{
(json_response.json.assets | selectattr('browser_download_url', 'search', 'lego_' + (lego_v) + '_linux_amd64.tar.gz')
| list | first).browser_download_url
}}
- name: "Install {{ json_response.json.tag_name }}"
ansible.builtin.unarchive:
src: >-
{{
(json_response.json.assets | selectattr('browser_download_url', 'search', 'lego_' + (lego_v) + '_linux_amd64.tar.gz')
| list | first).browser_download_url
}}
dest: /usr/bin/
remote_src: true

- name: Create Letsencrypt directory
ansible.builtin.file:
path: '{{ item.src }}'
state: directory
owner: root
group: root
mode: '0755'
loop:
- { src: /etc/letsencrypt/ }

- name: Template a file to /etc/file.conf
ansible.builtin.template:
src: lego_ssl.sh.j2
dest: "{{ script_path }}"
owner: root
group: root
mode: '0700'

# - name: Issue a Letsencrypt certificate
# ansible.builtin.command: "${{ script_path }}"

- name: Issue a Letsencrypt certificate
ansible.builtin.command:
argv:
- "{{ script_path }}"
- run

17 changes: 17 additions & 0 deletions ansible/roles/lego_encrypt_acme/templates/lego_ssl.sh.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/sh

{{ ansible_managed | comment }}

export VULTR_API_KEY={{ apikey }}
export VULTR_HTTP_TIMEOUT=300
export VULTR_POLLING_INTERVAL=120
export VULTR_PROPAGATION_TIMEOUT=600
export VULTR_TTL=300
lego --dns vultr \
--domains *.{{ domain }} \
--domains {{ domain }} \
--email {{ email }} \
--path="/etc/letsencrypt/{{ domain }}" \
--http.port 81 \
--tls.port 82 \
--accept-tos {{ '${1}' }}
1 change: 0 additions & 1 deletion ansible/roles/nginxinc.nginx
Submodule nginxinc.nginx deleted from 2d0843
1 change: 0 additions & 1 deletion ansible/roles/nginxinc.nginx_config
Submodule nginxinc.nginx_config deleted from 4f5ff6
11 changes: 11 additions & 0 deletions modules/03-firewall.tf
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@ resource "vultr_firewall_rule" "httpv4" {
notes = "Allow HTTP"
}

resource "vultr_firewall_rule" "lego_httpv4" {
# count = var.firewall_name != "" ? 1 : 0
firewall_group_id = vultr_firewall_group.firewallgroups.id
protocol = "tcp"
ip_type = "v4"
subnet = "0.0.0.0"
subnet_size = 0
port = "81-82"
notes = "Allow HTTP for Lego to obtain SSL certificates from Letsencrypt"
}

# Add a firewall rule to the group allowing HTTP IPv6 access.
resource "vultr_firewall_rule" "httpv6" {
# count = var.firewall_name != "" ? 1 : 0
Expand Down
3 changes: 2 additions & 1 deletion modules/06-templates.tf
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,9 @@ resource "local_file" "ansible_inventory" {
filename = "./ansible/ansible_inventory.yaml"
depends_on = [data.vultr_instance.instance_ip]

# 180 seconds of sleep may not be enough to get a letsencrypt certificate because DNS isn't propagated yet.
provisioner "local-exec" {
command = "export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES && sleep 90 && cd ./ansible && ansible-playbook -i ./ansible_inventory.yaml ./${each.key}.yaml --limit '${each.key}.${var.domain}' --extra-vars {domain_name: [var.domain, www.${var.domain}, ${keys(var.instance)[0]}.${var.domain}]}"
command = "export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES && sleep 180 && cd ./ansible && ansible-playbook -i ./ansible_inventory.yaml ./${each.key}.yaml --limit '${each.key}.${var.domain}' --extra-vars \"{domain_name: [var.domain, www.${var.domain}, ${keys(var.instance)[0]}.${var.domain}]}\" domain_name_main=${var.domain}"
}
}

Expand Down
5 changes: 5 additions & 0 deletions modules/templates/cloud_config_app_server.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#cloud-config
"package_update": false
"package_upgrade": false
"timezone": "Europe/Kiev"

7 changes: 7 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,13 @@ variable "os_id_ubuntu_20_04_lts" {
default = "387"
}

variable "os_id_ubuntu_22_04_lts" {
description = "Ubuntu 22.04 LTS x64"
type = string
default = "1743"
}


# Plans
# curl "https://api.vultr.com/v2/plans" -X GET -H "Authorization: Bearer IO...LQ"

Expand Down

0 comments on commit 338c941

Please sign in to comment.