368 lines
13 KiB
YAML
368 lines
13 KiB
YAML
---
|
|
# =============================================================================
|
|
# NetBird v1.6 - Battalion Group & Access Control Setup
|
|
# =============================================================================
|
|
# Creates:
|
|
# - Groups for each battalion (pilots + ground stations)
|
|
# - Dev team group with full access
|
|
# - Setup keys with auto-group assignment
|
|
# - Access control policies (battalion isolation + dev access)
|
|
#
|
|
# Prerequisites:
|
|
# 1. NetBird deployed and running (playbook-ssl.yml or playbook-no-ssl.yml)
|
|
# 2. Admin user created via dashboard
|
|
# 3. PAT (Personal Access Token) generated from dashboard
|
|
#
|
|
# Run:
|
|
# ansible-playbook -i inventory.yml setup-groups.yml --ask-vault-pass
|
|
# =============================================================================
|
|
|
|
- name: Configure NetBird Battalion Access Control
|
|
hosts: netbird_servers
|
|
become: false
|
|
gather_facts: false
|
|
vars_files:
|
|
- group_vars/netbird_servers.yml
|
|
- group_vars/vault.yml
|
|
vars:
|
|
# For SSL-IP mode, use server IP; for domain mode, use netbird_domain
|
|
netbird_api_host: "{{ hostvars[inventory_hostname].ansible_host | default(netbird_domain) }}"
|
|
netbird_api_url: "https://{{ netbird_api_host }}/api"
|
|
# Use PAT from vault, or allow override via command line
|
|
netbird_pat: "{{ vault_netbird_service_pat }}"
|
|
|
|
pre_tasks:
|
|
- name: Validate PAT is provided
|
|
ansible.builtin.assert:
|
|
that:
|
|
- netbird_pat is defined
|
|
- netbird_pat | length > 0
|
|
fail_msg: |
|
|
Service PAT not configured in vault.yml!
|
|
1. Create service user + PAT in dashboard
|
|
2. Store in vault: ansible-vault edit group_vars/vault.yml
|
|
Set: vault_netbird_service_pat: "<your-token>"
|
|
|
|
tasks:
|
|
# =========================================================================
|
|
# Get Existing Groups (to avoid duplicates)
|
|
# =========================================================================
|
|
- name: Get existing groups
|
|
ansible.builtin.uri:
|
|
url: "{{ netbird_api_url }}/groups"
|
|
method: GET
|
|
headers:
|
|
Authorization: "Token {{ netbird_pat }}"
|
|
Accept: "application/json"
|
|
validate_certs: false
|
|
status_code: [200]
|
|
register: existing_groups
|
|
delegate_to: localhost
|
|
|
|
- name: Extract existing group names
|
|
ansible.builtin.set_fact:
|
|
existing_group_names: "{{ existing_groups.json | map(attribute='name') | list }}"
|
|
|
|
# =========================================================================
|
|
# Create Battalion Groups
|
|
# =========================================================================
|
|
- name: Create battalion pilot groups
|
|
ansible.builtin.uri:
|
|
url: "{{ netbird_api_url }}/groups"
|
|
method: POST
|
|
headers:
|
|
Authorization: "Token {{ netbird_pat }}"
|
|
Content-Type: "application/json"
|
|
body_format: json
|
|
body:
|
|
name: "{{ item.name }}-pilots"
|
|
validate_certs: false
|
|
status_code: [200, 201]
|
|
loop: "{{ battalions }}"
|
|
when: "item.name + '-pilots' not in existing_group_names"
|
|
register: pilot_groups_created
|
|
delegate_to: localhost
|
|
|
|
- name: Create battalion ground station groups
|
|
ansible.builtin.uri:
|
|
url: "{{ netbird_api_url }}/groups"
|
|
method: POST
|
|
headers:
|
|
Authorization: "Token {{ netbird_pat }}"
|
|
Content-Type: "application/json"
|
|
body_format: json
|
|
body:
|
|
name: "{{ item.name }}-ground-stations"
|
|
validate_certs: false
|
|
status_code: [200, 201]
|
|
loop: "{{ battalions }}"
|
|
when: "item.name + '-ground-stations' not in existing_group_names"
|
|
register: gs_groups_created
|
|
delegate_to: localhost
|
|
|
|
- name: Create dev team group
|
|
ansible.builtin.uri:
|
|
url: "{{ netbird_api_url }}/groups"
|
|
method: POST
|
|
headers:
|
|
Authorization: "Token {{ netbird_pat }}"
|
|
Content-Type: "application/json"
|
|
body_format: json
|
|
body:
|
|
name: "{{ dev_team_group }}"
|
|
validate_certs: false
|
|
status_code: [200, 201]
|
|
when: "dev_team_group not in existing_group_names"
|
|
delegate_to: localhost
|
|
|
|
# =========================================================================
|
|
# Re-fetch Groups to Get IDs
|
|
# =========================================================================
|
|
- name: Get all groups with IDs
|
|
ansible.builtin.uri:
|
|
url: "{{ netbird_api_url }}/groups"
|
|
method: GET
|
|
headers:
|
|
Authorization: "Token {{ netbird_pat }}"
|
|
Accept: "application/json"
|
|
validate_certs: false
|
|
status_code: [200]
|
|
register: all_groups
|
|
delegate_to: localhost
|
|
|
|
- name: Build group ID mapping
|
|
ansible.builtin.set_fact:
|
|
group_id_map: "{{ group_id_map | default({}) | combine({item.name: item.id}) }}"
|
|
loop: "{{ all_groups.json }}"
|
|
|
|
- name: Get All group ID
|
|
ansible.builtin.set_fact:
|
|
all_group_id: "{{ (all_groups.json | selectattr('name', 'equalto', 'All') | first).id }}"
|
|
|
|
# =========================================================================
|
|
# Create Setup Keys
|
|
# =========================================================================
|
|
- name: Get existing setup keys
|
|
ansible.builtin.uri:
|
|
url: "{{ netbird_api_url }}/setup-keys"
|
|
method: GET
|
|
headers:
|
|
Authorization: "Token {{ netbird_pat }}"
|
|
Accept: "application/json"
|
|
validate_certs: false
|
|
status_code: [200]
|
|
register: existing_keys
|
|
delegate_to: localhost
|
|
|
|
- name: Extract existing setup key names
|
|
ansible.builtin.set_fact:
|
|
existing_key_names: "{{ existing_keys.json | map(attribute='name') | list }}"
|
|
|
|
- name: Create setup keys for battalion pilots
|
|
ansible.builtin.uri:
|
|
url: "{{ netbird_api_url }}/setup-keys"
|
|
method: POST
|
|
headers:
|
|
Authorization: "Token {{ netbird_pat }}"
|
|
Content-Type: "application/json"
|
|
body_format: json
|
|
body:
|
|
name: "{{ item.name }}-pilot-key"
|
|
type: "reusable"
|
|
expires_in: 31536000 # 1 year in seconds
|
|
revoked: false
|
|
auto_groups:
|
|
- "{{ group_id_map[item.name + '-pilots'] }}"
|
|
usage_limit: 0 # unlimited
|
|
validate_certs: false
|
|
status_code: [200, 201]
|
|
loop: "{{ battalions }}"
|
|
when: "item.name + '-pilot-key' not in existing_key_names"
|
|
register: pilot_keys
|
|
delegate_to: localhost
|
|
|
|
- name: Create setup keys for battalion ground stations
|
|
ansible.builtin.uri:
|
|
url: "{{ netbird_api_url }}/setup-keys"
|
|
method: POST
|
|
headers:
|
|
Authorization: "Token {{ netbird_pat }}"
|
|
Content-Type: "application/json"
|
|
body_format: json
|
|
body:
|
|
name: "{{ item.name }}-gs-key"
|
|
type: "reusable"
|
|
expires_in: 31536000
|
|
revoked: false
|
|
auto_groups:
|
|
- "{{ group_id_map[item.name + '-ground-stations'] }}"
|
|
usage_limit: 0
|
|
validate_certs: false
|
|
status_code: [200, 201]
|
|
loop: "{{ battalions }}"
|
|
when: "item.name + '-gs-key' not in existing_key_names"
|
|
register: gs_keys
|
|
delegate_to: localhost
|
|
|
|
- name: Create setup key for dev team
|
|
ansible.builtin.uri:
|
|
url: "{{ netbird_api_url }}/setup-keys"
|
|
method: POST
|
|
headers:
|
|
Authorization: "Token {{ netbird_pat }}"
|
|
Content-Type: "application/json"
|
|
body_format: json
|
|
body:
|
|
name: "dev-team-key"
|
|
type: "reusable"
|
|
expires_in: 31536000
|
|
revoked: false
|
|
auto_groups:
|
|
- "{{ group_id_map[dev_team_group] }}"
|
|
usage_limit: 0
|
|
validate_certs: false
|
|
status_code: [200, 201]
|
|
when: "'dev-team-key' not in existing_key_names"
|
|
register: dev_key
|
|
delegate_to: localhost
|
|
|
|
# =========================================================================
|
|
# Create Access Control Policies
|
|
# =========================================================================
|
|
- name: Get existing policies
|
|
ansible.builtin.uri:
|
|
url: "{{ netbird_api_url }}/policies"
|
|
method: GET
|
|
headers:
|
|
Authorization: "Token {{ netbird_pat }}"
|
|
Accept: "application/json"
|
|
validate_certs: false
|
|
status_code: [200]
|
|
register: existing_policies
|
|
delegate_to: localhost
|
|
|
|
- name: Extract existing policy names
|
|
ansible.builtin.set_fact:
|
|
existing_policy_names: "{{ existing_policies.json | map(attribute='name') | list }}"
|
|
|
|
- name: Create battalion internal access policies
|
|
ansible.builtin.uri:
|
|
url: "{{ netbird_api_url }}/policies"
|
|
method: POST
|
|
headers:
|
|
Authorization: "Token {{ netbird_pat }}"
|
|
Content-Type: "application/json"
|
|
body_format: json
|
|
body:
|
|
name: "{{ item.display_name }} - Internal Access"
|
|
description: "Allow {{ item.display_name }} pilots to access their ground stations"
|
|
enabled: true
|
|
rules:
|
|
- name: "{{ item.name }}-pilot-to-gs"
|
|
description: "Pilots can access ground stations"
|
|
enabled: true
|
|
sources:
|
|
- "{{ group_id_map[item.name + '-pilots'] }}"
|
|
destinations:
|
|
- "{{ group_id_map[item.name + '-ground-stations'] }}"
|
|
bidirectional: true
|
|
protocol: "all"
|
|
action: "accept"
|
|
validate_certs: false
|
|
status_code: [200, 201]
|
|
loop: "{{ battalions }}"
|
|
when: "item.display_name + ' - Internal Access' not in existing_policy_names"
|
|
delegate_to: localhost
|
|
|
|
- name: Create dev team full access policy
|
|
ansible.builtin.uri:
|
|
url: "{{ netbird_api_url }}/policies"
|
|
method: POST
|
|
headers:
|
|
Authorization: "Token {{ netbird_pat }}"
|
|
Content-Type: "application/json"
|
|
body_format: json
|
|
body:
|
|
name: "Dev Team - Full Access"
|
|
description: "Dev team can access all peers for troubleshooting"
|
|
enabled: true
|
|
rules:
|
|
- name: "dev-full-access"
|
|
description: "Dev team has access to all peers"
|
|
enabled: true
|
|
sources:
|
|
- "{{ group_id_map[dev_team_group] }}"
|
|
destinations:
|
|
- "{{ all_group_id }}"
|
|
bidirectional: true
|
|
protocol: "all"
|
|
action: "accept"
|
|
validate_certs: false
|
|
status_code: [200, 201]
|
|
when: "'Dev Team - Full Access' not in existing_policy_names"
|
|
delegate_to: localhost
|
|
|
|
# =========================================================================
|
|
# Fetch and Display Setup Keys
|
|
# =========================================================================
|
|
- name: Get all setup keys
|
|
ansible.builtin.uri:
|
|
url: "{{ netbird_api_url }}/setup-keys"
|
|
method: GET
|
|
headers:
|
|
Authorization: "Token {{ netbird_pat }}"
|
|
Accept: "application/json"
|
|
validate_certs: false
|
|
status_code: [200]
|
|
register: final_keys
|
|
delegate_to: localhost
|
|
|
|
- name: Display configuration summary
|
|
ansible.builtin.debug:
|
|
msg: |
|
|
============================================
|
|
Battalion Access Control Configured!
|
|
============================================
|
|
|
|
Groups Created:
|
|
{% for bat in battalions %}
|
|
- {{ bat.name }}-pilots
|
|
- {{ bat.name }}-ground-stations
|
|
{% endfor %}
|
|
- {{ dev_team_group }}
|
|
|
|
Access Control Matrix:
|
|
{% for bat in battalions %}
|
|
[{{ bat.display_name }}]
|
|
{{ bat.name }}-pilots <--> {{ bat.name }}-ground-stations
|
|
{% endfor %}
|
|
[Dev Team]
|
|
{{ dev_team_group }} --> All (full access)
|
|
|
|
Setup Keys (use these to register peers):
|
|
{% for key in final_keys.json %}
|
|
{% if key.name.endswith('-pilot-key') or key.name.endswith('-gs-key') or key.name == 'dev-team-key' %}
|
|
{{ key.name }}: {{ key.key }}
|
|
{% endif %}
|
|
{% endfor %}
|
|
|
|
Peer Registration Commands:
|
|
{% for bat in battalions %}
|
|
# {{ bat.display_name }} Pilot:
|
|
netbird up --management-url {{ netbird_protocol }}://{{ netbird_domain }} \
|
|
--setup-key <{{ bat.name }}-pilot-key> \
|
|
--hostname pilot-{{ bat.name }}-<callsign>
|
|
|
|
# {{ bat.display_name }} Ground Station:
|
|
netbird up --management-url {{ netbird_protocol }}://{{ netbird_domain }} \
|
|
--setup-key <{{ bat.name }}-gs-key> \
|
|
--hostname gs-{{ bat.name }}-<location>
|
|
|
|
{% endfor %}
|
|
# Dev Team:
|
|
netbird up --management-url {{ netbird_protocol }}://{{ netbird_domain }} \
|
|
--setup-key <dev-team-key> \
|
|
--hostname dev-<name>
|
|
|
|
============================================
|