Skip to content

Instantly share code, notes, and snippets.

@pythoninthegrass
Last active October 15, 2024 20:34
Show Gist options
  • Save pythoninthegrass/2f280c76d5fc9bef5621e1a222823484 to your computer and use it in GitHub Desktop.
Save pythoninthegrass/2f280c76d5fc9bef5621e1a222823484 to your computer and use it in GitHub Desktop.
Setup cockpit on multiple servers via ansible
{%- set excluded_ips = [
'^192\.168\.8\.',
'^192\.168\.25\.',
'^192\.168\.105\.'
] -%}
{
{% for host in groups['all'] %}
{%- set ip = hostvars[host]['ansible_host'] | default(host) -%}
{%- if ip is not match(excluded_ips | join('|')) and host != 'localhost' and host != 'lance@orb' %}
"{{ ip }}": {
"address": "{{ ip }}",
"user": "{{ hostvars[host]['ansible_user'] | default('<SOMEUSER>') }}",
"port": {{ hostvars[host]['ansible_port'] | default(22) }},
"visible": true,
"color": "rgb({{ range(0, 256) | random }}, {{ range(0, 256) | random }}, {{ range(0, 256) | random }})"
}{% if not loop.last %},{% endif %}
{%- endif %}
{% endfor %}
}

cockpit

Per the docs (see also here and here), Cockpit can be scaled dramatically using ansible.

Not gonna detail all the things, but essentially setting up a temporary hosts group of n servers like

# hosts

[temp]
10.13.37.100
10.13.37.101
10.13.37.102
10.13.37.103
10.13.37.104

[all:vars]
ansible_become_method=sudo
ansible_become_user=root
ansible_python_interpreter=/usr/bin/python3
ansible_async_dir=/tmp/.ansible_async

[temp:vars]
ansible_user=<sudoer>

then running

ansible-playbook -i hosts tasks/cockpit.yml -b -K --limit 'temp' -v

against a directory structure like

.
├── cockpit.yml
├── templates
│   ├── 01-machines.json.j2
│   └── cockpit.conf.j2

will dynamically generate a 01-machines.json file based on your hosts inventory while excluding IP address ranges.

It also creates the cockpit.conf with multiple hosts enabled, disabled login on the home page (no traversing connected servers), limited ssh sessions, and idle timeout set.

With a little more elbow grease, installing ssl certs would be fairly trivial as well as placing each server behind a reverse proxy.

It's also idempotent and will only update configs and restart the cockpit service when they change 🎉

[WebService]
# Origins = https://somedomain1.com https://somedomain2.com:9090
AllowMultiHost = true
LoginTo = false
MaxStartups = 10
[Session]
IdleTimeout = 30
# code: language=ansible
---
- hosts: all
become: true
gather_facts: true
any_errors_fatal: true
roles:
- role: pre-tasks
tags: pre
tasks:
- name: Get OS codename
ansible.builtin.set_fact:
codename: "{{ ansible_distribution_release }}"
when: ansible_os_family == 'Debian'
- name: Check if backports repository exists
ansible.builtin.apt_repository:
repo: "deb http://archive.ubuntu.com/ubuntu {{ codename }}-backports main restricted universe multiverse"
state: present
check_mode: true
register: backports_check
when: ansible_os_family == 'Debian'
- name: Install Cockpit from backports (Debian/Ubuntu)
ansible.builtin.apt:
name: "{{ item }}"
state: present
default_release: "{{ codename }}-backports"
update_cache: true
cache_valid_time: 3600
with_items:
- cockpit
when:
- ansible_os_family == 'Debian'
- backports_check.changed == false
- name: Install Cockpit from main repository (Debian/Ubuntu)
ansible.builtin.apt:
name: "{{ item }}"
state: present
update_cache: true
cache_valid_time: 3600
with_items:
- cockpit
when:
- ansible_os_family == 'Debian'
- backports_check.changed == true
- name: Install Red Hat cockpit packages
ansible.builtin.dnf:
name: "{{ item }}"
state: present
with_items:
- cockpit
when: ansible_os_family == 'RedHat'
- name: Install additional cockpit packages
ansible.builtin.package:
name: "{{ item }}"
state: present
with_items:
- cockpit-machines
- name: Start and enable cockpit
ansible.builtin.systemd:
name: cockpit.socket
state: started
enabled: true
- name: Gather service facts
ansible.builtin.service_facts:
- name: Check if firewalld is installed
ansible.builtin.set_fact:
firewalld_status: >-
{{
(ansible_facts.services['firewalld'].state
if 'firewalld' in ansible_facts.services else 'not_installed')
if ansible_facts.services is defined else 'not_installed'
}}
- name: Open firewall ports for Cockpit
ansible.builtin.firewalld:
service: cockpit
permanent: true
state: enabled
when: firewalld_status == 'running'
- name: Create /etc/cockpit/cockpit.conf
ansible.builtin.template:
src: "{{ playbook_dir }}/templates/cockpit.conf.j2"
dest: /etc/cockpit/cockpit.conf
mode: '0644'
notify: Restart Cockpit service
- name: Ensure Cockpit machines.d directory exists
ansible.builtin.file:
path: /etc/cockpit/machines.d
state: directory
mode: '0755'
- name: Add 01-machines.json to Cockpit configuration
ansible.builtin.template:
src: "{{ playbook_dir }}/templates/01-machines.json.j2"
dest: /etc/cockpit/machines.d/01-machines.json
mode: '0644'
handlers:
- name: Restart Cockpit service
ansible.builtin.systemd:
name: cockpit.service
state: restarted
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment