diff --git a/README.md b/README.md index ca91e52..1c9e883 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,9 @@ prerequisites: * Create a DigitalOcean API token, and pass it to the inventory generator by setting the `DO_API_TOKEN` environment variable. +* If you are creating a new droplet, and want to configure DNS as well, then + create a CloudFlare API token, and pass it to the Ansible playbook by setting + the `CLOUDFLARE_TOKEN` environment variable. * Set the vault decryption password of the Ansible vaulted file with our secrets. This may be done by setting the `ANSIBLE_VAULT_PASSWORD_FILE` environment variable to point to a file containing the password. @@ -99,9 +102,11 @@ Naming We follow a simplified version of the naming scheme on [this blog post](https://mnx.io/blog/a-proper-server-naming-scheme/): -* Servers are named `.matplotlib.org` in A records. -* Servers get a functional CNAME alias (e.g., `web01.matplotlib.org`). -* matplotlib.org is a CNAME to the functional CNAME of a server. +* Servers are named `.matplotlib.org` in A records, pointing to the + IPv4 address of the droplet. +* Servers get a functional CNAME alias (e.g., `web01.matplotlib.org`) pointing + to the hostname `.matplotlib.org`. +* matplotlib.org is a CNAME alias of the functional CNAME of a server. We use [planets in our Solar System](https://namingschemes.com/Solar_System) for the name prefix. When creating a new server, pick the next one in the list. @@ -113,51 +118,34 @@ The summary of the initial setup is: 1. Create the droplet with monitoring and relevant SSH keys. 2. Assign new droplet to the matplotlib.org project and the Web firewall. -3. Grab the SSH host fingerprints. -4. Reboot. +3. Add DNS entries pointing to the server on CloudFlare. +4. Grab the SSH host fingerprints. +5. Reboot. -We currently use a simple $10 droplet from DigitalOcean. You can create one -from the control panel, or using the `doctl` utility. Be sure to enable -monitoring, and add the `website` tag and relevant SSH keys to the droplet. An -example of using `doctl` is the following: +We currently use a simple $12 droplet from DigitalOcean. You can create one +from the control panel, or using the `create.yml` Ansible playbook: ``` -doctl compute droplet create \ - --image fedora-35-x64 \ - --region tor1 \ - --size s-1vcpu-2gb \ - --ssh-keys , \ - --tag-name website \ - --enable-monitoring \ - venus.matplotlib.org +ansible-playbook create.yml ``` -Note, you will have to use `doctl compute ssh-key list` to get the IDs of the -relevant SSH keys saved on DigitalOcean, and substitute them above. Save the ID -of the new droplet from the output, e.g., in: +This playbook will prompt you for 3 settings: -``` -ID Name Public IPv4 Private IPv4 Public IPv6 Memory VCPUs Disk Region Image VPC UUID Status Tags Features Volumes -294098687 mpl.org 2048 1 50 tor1 Fedora 35 x64 new website monitoring,droplet_agent -``` - -the droplet ID is 294098687. +1. The host name of the droplet, which should follow the naming convention + above. +2. The functional CNAME alias of the droplet. +3. The names of SSH keys to add to the droplet. - -You should also assign the new droplet to the `matplotlib.org` project and the -`Web` firewall: +You may also pass these directly to Ansible as: ``` -doctl projects list -# Get ID of the matplotlib.org project from the output. -doctl projects resources assign --resource=do:droplet: - - -doctl compute firewall list -# Get ID of the Web firewall from the output. -doctl compute firewall add-droplets --droplet-ids +ansible-playbook create.yml --extra-vars "host=pluto functional=web99 ssh_keys='a b c'" ``` +The playbook will create the server, as well as add DNS records on CloudFlare. +Note, you must set `DO_API_TOKEN` and `CLOUDFLARE_TOKEN` in the environment to +access these services. + Then, to ensure you are connecting to the expected server, you should grab the SSH host keys via the DigitalOcean Droplet Console: @@ -181,14 +169,6 @@ Finally, you should reboot the droplet. This is due to a bug in cloud-init on DigitalOcean, which generates a new machine ID after startup, causing system logs to be seem invisible. -DNS setup ---------- - -1. Add an A record for `.matplotlib.org` to the IPv4 address of the new - droplet. -2. Add a CNAME record for `webNN.matplotlib.org` pointing to the given - ``. - Running Ansible --------------- diff --git a/collections/requirements.yml b/collections/requirements.yml index cb8953c..4a795f3 100644 --- a/collections/requirements.yml +++ b/collections/requirements.yml @@ -2,4 +2,5 @@ collections: - name: ansible.posix - name: community.general + version: ">=2.0.0" - name: community.digitalocean diff --git a/create.yml b/create.yml new file mode 100644 index 0000000..f23dbdd --- /dev/null +++ b/create.yml @@ -0,0 +1,142 @@ +--- +- hosts: localhost + tasks: + - name: Gather information about DigitalOcean droplets + community.digitalocean.digital_ocean_droplet_info: + register: do_droplets + - name: Gather information about DigitalOcean SSH keys + community.digitalocean.digital_ocean_sshkey_info: + register: do_ssh_keys + + - name: Print info on existing droplets + ansible.builtin.debug: + msg: >- + {{ item.name }}: + {{ item.networks.v4 | map(attribute='ip_address') | join(',') }} + loop: "{{ do_droplets.data }}" + loop_control: + label: "{{ item.id }}" + + - name: "Enter name for new droplet (subdomain only)" + ansible.builtin.pause: + register: input_name + when: host is not defined + + - name: "Enter functional name for new droplet (webNN)" + ansible.builtin.pause: + register: input_functional + when: functional is not defined + + - name: Print available SSH public keys + ansible.builtin.debug: + msg: "{{ item.name}} {{ item.fingerprint }}" + loop: "{{ do_ssh_keys.data }}" + loop_control: + label: "{{ item.id }}" + + - name: "Enter SSH key names for new droplet (space separated)" + ansible.builtin.pause: + register: input_ssh_keys + when: ssh_keys is not defined + + - name: Set droplet facts + ansible.builtin.set_fact: + host: >- + {{ + (host if host is defined else input_name.user_input) | + trim + }} + functional: >- + {{ + (functional if functional is defined else input_functional.user_input) | + trim + }} + ssh_fingerprints: >- + {{ + do_ssh_keys.data | + selectattr( + 'name', + 'in', + (ssh_keys if ssh_keys is defined + else input_ssh_keys.user_input) | split) | + map(attribute='fingerprint') + }} + + - name: Verify droplet configuration + ansible.builtin.assert: + that: + - host in valid_planets + # Must not be an existing name. + - >- + do_droplets.data | + selectattr('name', 'equalto', '{{ host }}.matplotlib.org') | + count == 0 + # TODO: Also check that functional name doesn't already exist. + - functional is regex('^web[0-9][0-9]$') + # At least 1 key, and same number as requested. + - ssh_fingerprints | length >= 1 + - >- + ssh_fingerprints | length == ( + ssh_keys if ssh_keys is defined + else input_ssh_keys.user_input) | split | length + + - name: Print configuration + ansible.builtin.debug: + msg: "Creating droplet '{{ host }}' with SSH keys {{ ssh_fingerprints }}" + + - name: Please verify the above configuration + ansible.builtin.pause: + + - name: Create droplet on DigitalOcean + community.digitalocean.digital_ocean_droplet: + state: present + name: "{{ host }}.matplotlib.org" + firewall: + - Web + image: fedora-39-x64 + monitoring: true + project: matplotlib.org + region: tor1 + size: s-1vcpu-2gb + ssh_keys: "{{ ssh_fingerprints }}" + tags: + - website + unique_name: true + register: new_droplet + + - name: Setup DNS for droplet on CloudFlare + community.general.cloudflare_dns: + state: present + proxied: true + record: "{{ host }}" + type: A + value: >- + {{ + new_droplet.data.droplet.networks.v4 | + selectattr('type', 'equalto', 'public') | + map(attribute='ip_address') | + first + }} + zone: matplotlib.org + + - name: Setup functional DNS for droplet on CloudFlare + community.general.cloudflare_dns: + state: present + proxied: true + record: "{{ functional }}" + type: CNAME + value: "{{ host }}.matplotlib.org" + zone: matplotlib.org + + vars: + # We currently name servers based on planets in the Solar System. + valid_planets: + - mercury + - venus + - earth + - mars + - jupiter + - saturn + - uranus + - neptune + - pluto pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy