Switch to terraform
This commit is contained in:
281
ansible/netbird/setup-users.yml
Normal file
281
ansible/netbird/setup-users.yml
Normal file
@@ -0,0 +1,281 @@
|
||||
---
|
||||
# =============================================================================
|
||||
# NetBird v1.6 - User Provisioning
|
||||
# =============================================================================
|
||||
# Creates users with embedded IdP and stores generated passwords.
|
||||
# Requires: service user PAT in vault.yml (see setup-bootstrap.yml)
|
||||
#
|
||||
# Run:
|
||||
# ansible-playbook -i inventory.yml setup-users.yml --ask-vault-pass
|
||||
#
|
||||
# Optional variables:
|
||||
# -e "dry_run=true" Preview changes without creating users
|
||||
# =============================================================================
|
||||
|
||||
- name: Provision NetBird Users
|
||||
hosts: netbird_servers
|
||||
become: false
|
||||
gather_facts: true
|
||||
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"
|
||||
dry_run: false
|
||||
|
||||
pre_tasks:
|
||||
# =========================================================================
|
||||
# Validate Prerequisites
|
||||
# =========================================================================
|
||||
- name: Validate service PAT is provided
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- vault_netbird_service_pat is defined
|
||||
- vault_netbird_service_pat | length > 0
|
||||
fail_msg: |
|
||||
Service PAT not configured!
|
||||
Run setup-bootstrap.yml first, then add PAT to vault.yml
|
||||
|
||||
- name: Verify API connectivity with PAT
|
||||
ansible.builtin.uri:
|
||||
url: "{{ netbird_api_url }}/users"
|
||||
method: GET
|
||||
headers:
|
||||
Authorization: "Token {{ vault_netbird_service_pat }}"
|
||||
Accept: "application/json"
|
||||
validate_certs: false
|
||||
status_code: [200]
|
||||
register: api_check
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Display connection status
|
||||
ansible.builtin.debug:
|
||||
msg: "API connection successful. Found {{ api_check.json | length }} existing users."
|
||||
|
||||
tasks:
|
||||
# =========================================================================
|
||||
# Fetch Existing State
|
||||
# =========================================================================
|
||||
- name: Get existing users
|
||||
ansible.builtin.uri:
|
||||
url: "{{ netbird_api_url }}/users"
|
||||
method: GET
|
||||
headers:
|
||||
Authorization: "Token {{ vault_netbird_service_pat }}"
|
||||
Accept: "application/json"
|
||||
validate_certs: false
|
||||
status_code: [200]
|
||||
register: existing_users_response
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Extract existing user emails
|
||||
ansible.builtin.set_fact:
|
||||
existing_user_emails: "{{ existing_users_response.json | map(attribute='email') | list }}"
|
||||
|
||||
- name: Get existing groups
|
||||
ansible.builtin.uri:
|
||||
url: "{{ netbird_api_url }}/groups"
|
||||
method: GET
|
||||
headers:
|
||||
Authorization: "Token {{ vault_netbird_service_pat }}"
|
||||
Accept: "application/json"
|
||||
validate_certs: false
|
||||
status_code: [200]
|
||||
register: existing_groups_response
|
||||
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: "{{ existing_groups_response.json }}"
|
||||
|
||||
# =========================================================================
|
||||
# Resolve Auto-Groups for Users
|
||||
# =========================================================================
|
||||
- name: Resolve auto-groups for users
|
||||
ansible.builtin.set_fact:
|
||||
resolved_users: "{{ resolved_users | default([]) + [user_with_groups] }}"
|
||||
vars:
|
||||
battalion_group: >-
|
||||
{%- if item.battalion is defined and item.battalion -%}
|
||||
{%- if item.type | default('pilot') == 'pilot' -%}
|
||||
{{ item.battalion }}-pilots
|
||||
{%- else -%}
|
||||
{{ item.battalion }}-ground-stations
|
||||
{%- endif -%}
|
||||
{%- endif -%}
|
||||
final_auto_groups: >-
|
||||
{{ item.auto_groups | default([]) + ([battalion_group | trim] if battalion_group | trim else []) }}
|
||||
resolved_group_ids: >-
|
||||
{{ final_auto_groups | map('extract', group_id_map) | select('defined') | list }}
|
||||
user_with_groups:
|
||||
email: "{{ item.email }}"
|
||||
name: "{{ item.name }}"
|
||||
role: "{{ item.role | default('user') }}"
|
||||
auto_groups: "{{ resolved_group_ids }}"
|
||||
auto_group_names: "{{ final_auto_groups }}"
|
||||
battalion: "{{ item.battalion | default(none) }}"
|
||||
skip: "{{ item.email in existing_user_emails }}"
|
||||
loop: "{{ netbird_users | default([]) }}"
|
||||
|
||||
# =========================================================================
|
||||
# Display Plan
|
||||
# =========================================================================
|
||||
- name: Count users to process
|
||||
ansible.builtin.set_fact:
|
||||
users_to_create: "{{ resolved_users | default([]) | rejectattr('skip') | list }}"
|
||||
users_to_skip: "{{ resolved_users | default([]) | selectattr('skip') | list }}"
|
||||
|
||||
- name: Display provisioning plan
|
||||
ansible.builtin.debug:
|
||||
msg: |
|
||||
============================================
|
||||
User Provisioning Plan
|
||||
============================================
|
||||
Mode: {{ 'DRY RUN' if dry_run else 'EXECUTE' }}
|
||||
|
||||
Users to CREATE ({{ users_to_create | length }}):
|
||||
{% for user in users_to_create %}
|
||||
- {{ user.email }}
|
||||
Name: {{ user.name }}
|
||||
Role: {{ user.role }}
|
||||
Groups: {{ user.auto_group_names | join(', ') or 'None' }}
|
||||
{% endfor %}
|
||||
{% if users_to_create | length == 0 %}
|
||||
(none)
|
||||
{% endif %}
|
||||
|
||||
Users to SKIP - already exist ({{ users_to_skip | length }}):
|
||||
{% for user in users_to_skip %}
|
||||
- {{ user.email }}
|
||||
{% endfor %}
|
||||
{% if users_to_skip | length == 0 %}
|
||||
(none)
|
||||
{% endif %}
|
||||
============================================
|
||||
|
||||
- name: End play in dry run mode
|
||||
ansible.builtin.meta: end_play
|
||||
when: dry_run | bool
|
||||
|
||||
- name: End play if no users to create
|
||||
ansible.builtin.meta: end_play
|
||||
when: users_to_create | length == 0
|
||||
|
||||
# =========================================================================
|
||||
# Create Users
|
||||
# =========================================================================
|
||||
- name: Create credentials directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ playbook_dir }}/files/credentials"
|
||||
state: directory
|
||||
mode: "0700"
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Create new users
|
||||
ansible.builtin.uri:
|
||||
url: "{{ netbird_api_url }}/users"
|
||||
method: POST
|
||||
headers:
|
||||
Authorization: "Token {{ vault_netbird_service_pat }}"
|
||||
Content-Type: "application/json"
|
||||
Accept: "application/json"
|
||||
body_format: json
|
||||
body:
|
||||
email: "{{ item.email }}"
|
||||
name: "{{ item.name }}"
|
||||
role: "{{ item.role }}"
|
||||
auto_groups: "{{ item.auto_groups }}"
|
||||
is_service_user: false
|
||||
validate_certs: false
|
||||
status_code: [200, 201]
|
||||
loop: "{{ users_to_create }}"
|
||||
register: created_users
|
||||
delegate_to: localhost
|
||||
|
||||
# =========================================================================
|
||||
# Store Credentials
|
||||
# =========================================================================
|
||||
- name: Build credentials list
|
||||
ansible.builtin.set_fact:
|
||||
user_credentials: "{{ user_credentials | default([]) + [credential] }}"
|
||||
vars:
|
||||
matching_user: "{{ resolved_users | selectattr('email', 'equalto', item.json.email) | first }}"
|
||||
credential:
|
||||
email: "{{ item.json.email }}"
|
||||
name: "{{ item.json.name }}"
|
||||
password: "{{ item.json.password | default('N/A') }}"
|
||||
user_id: "{{ item.json.id }}"
|
||||
role: "{{ item.json.role }}"
|
||||
created_at: "{{ ansible_date_time.iso8601 }}"
|
||||
groups: "{{ matching_user.auto_group_names | default([]) }}"
|
||||
loop: "{{ created_users.results }}"
|
||||
when: item.json is defined
|
||||
|
||||
- name: Save credentials to file
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
---
|
||||
# =============================================================================
|
||||
# NetBird User Credentials
|
||||
# =============================================================================
|
||||
# Generated: {{ ansible_date_time.iso8601 }}
|
||||
# Instance: {{ netbird_domain }}
|
||||
#
|
||||
# WARNING: Store securely! Passwords cannot be retrieved again.
|
||||
# =============================================================================
|
||||
|
||||
users:
|
||||
{% for user in user_credentials %}
|
||||
- email: "{{ user.email }}"
|
||||
name: "{{ user.name }}"
|
||||
password: "{{ user.password }}"
|
||||
user_id: "{{ user.user_id }}"
|
||||
role: "{{ user.role }}"
|
||||
groups:
|
||||
{% for group in user.groups %}
|
||||
- "{{ group }}"
|
||||
{% endfor %}
|
||||
{% if user.groups | length == 0 %}
|
||||
[]
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
dest: "{{ playbook_dir }}/files/credentials/users-{{ ansible_date_time.date }}.yml"
|
||||
mode: "0600"
|
||||
delegate_to: localhost
|
||||
when:
|
||||
- user_credentials is defined
|
||||
- user_credentials | length > 0
|
||||
|
||||
# =========================================================================
|
||||
# Display Summary
|
||||
# =========================================================================
|
||||
- name: Display provisioning summary
|
||||
ansible.builtin.debug:
|
||||
msg: |
|
||||
============================================
|
||||
User Provisioning Complete!
|
||||
============================================
|
||||
|
||||
Created Users ({{ user_credentials | default([]) | length }}):
|
||||
{% for user in user_credentials | default([]) %}
|
||||
{{ user.email }}
|
||||
Password: {{ user.password }}
|
||||
Role: {{ user.role }}
|
||||
Groups: {{ user.groups | join(', ') or 'None' }}
|
||||
{% endfor %}
|
||||
|
||||
Credentials saved to:
|
||||
{{ playbook_dir }}/files/credentials/users-{{ ansible_date_time.date }}.yml
|
||||
|
||||
IMPORTANT:
|
||||
1. Share passwords securely with users
|
||||
2. Encrypt or delete credentials file after distribution:
|
||||
ansible-vault encrypt files/credentials/users-{{ ansible_date_time.date }}.yml
|
||||
3. Users should change passwords on first login
|
||||
|
||||
Login URL: https://{{ netbird_api_host }}
|
||||
============================================
|
||||
when: user_credentials is defined
|
||||
Reference in New Issue
Block a user