119b3e2150
Multi-provider (Linode/AWS/FlokiNET) scan orchestration: - Flatten all country CIDRs, chunk by IP count (sprint/balanced/economy presets) - Assign chunks round-robin across providers - Cost+time estimate table before deploy - Ansible provisions N nodes in parallel, runs masscan/nmap/probe per node - Results fetched back and merged into unified JSON report - Scanner IPs logged per engagement for client IR reporting - Operator IP whitelisting, enhanced OPSEC mode, YAML targets.yaml support
91 lines
2.8 KiB
YAML
91 lines
2.8 KiB
YAML
---
|
|
# Linode provision tasks for one WEBRUNNER node
|
|
# Called in a loop — loop_var: node_chunk
|
|
# Requires: linode_token, ssh_key_name, webrunner_name, deployment_id,
|
|
# linode_instance_type, linode_region, scanner_ip_log, results_dir
|
|
|
|
- name: Generate root password for {{ node_chunk.node_name }}
|
|
set_fact:
|
|
wr_root_pass: "{{ lookup('password', '/dev/null chars=ascii_letters,digits length=32') }}"
|
|
|
|
- name: Read public key
|
|
slurp:
|
|
src: "~/.ssh/{{ ssh_key_name }}.pub"
|
|
register: wr_pubkey
|
|
|
|
- name: Register SSH key in Linode ({{ node_chunk.node_name }})
|
|
uri:
|
|
url: "https://api.linode.com/v4/profile/sshkeys"
|
|
method: POST
|
|
headers:
|
|
Authorization: "Bearer {{ linode_token }}"
|
|
Content-Type: "application/json"
|
|
body_format: json
|
|
body:
|
|
label: "{{ webrunner_name }}"
|
|
ssh_key: "{{ wr_pubkey.content | b64decode | trim }}"
|
|
status_code: [200, 201]
|
|
ignore_errors: true
|
|
|
|
- name: Create Linode instance {{ node_chunk.node_name }}
|
|
uri:
|
|
url: "https://api.linode.com/v4/linode/instances"
|
|
method: POST
|
|
headers:
|
|
Authorization: "Bearer {{ linode_token }}"
|
|
Content-Type: "application/json"
|
|
body_format: json
|
|
body:
|
|
label: "{{ node_chunk.node_name }}"
|
|
type: "{{ linode_instance_type | default('g6-standard-2') }}"
|
|
region: "{{ linode_region | default('us-east') }}"
|
|
image: "linode/debian12"
|
|
root_pass: "{{ wr_root_pass }}"
|
|
authorized_keys:
|
|
- "{{ wr_pubkey.content | b64decode | trim }}"
|
|
booted: true
|
|
backups_enabled: false
|
|
private_ip: false
|
|
tags:
|
|
- "webrunner"
|
|
- "{{ webrunner_name }}"
|
|
- "{{ deployment_id }}"
|
|
status_code: [200, 201]
|
|
register: wr_linode
|
|
|
|
- name: Extract node IP
|
|
set_fact:
|
|
wr_node_ip: "{{ wr_linode.json.ipv4[0] }}"
|
|
|
|
- name: Log scanner IP
|
|
lineinfile:
|
|
path: "{{ scanner_ip_log }}"
|
|
line: "{{ node_chunk.node_name }}: {{ wr_node_ip }}"
|
|
create: true
|
|
|
|
- name: Wait for SSH on {{ node_chunk.node_name }} ({{ wr_node_ip }})
|
|
wait_for:
|
|
host: "{{ wr_node_ip }}"
|
|
port: 22
|
|
delay: 30
|
|
timeout: 300
|
|
|
|
- name: Add {{ node_chunk.node_name }} to inventory
|
|
add_host:
|
|
name: "{{ wr_node_ip }}"
|
|
groups: webrunner_nodes
|
|
ansible_host: "{{ wr_node_ip }}"
|
|
ansible_user: root
|
|
ansible_ssh_private_key_file: "~/.ssh/{{ ssh_key_name }}"
|
|
ansible_ssh_common_args: "-o StrictHostKeyChecking=no"
|
|
node_name: "{{ node_chunk.node_name }}"
|
|
node_cidrs: "{{ node_chunk.cidrs }}"
|
|
node_ip_count: "{{ node_chunk.ip_count }}"
|
|
node_idx: "{{ node_chunk.idx }}"
|
|
linode_instance_id: "{{ wr_linode.json.id }}"
|
|
provider: linode
|
|
|
|
- name: Show {{ node_chunk.node_name }} ready
|
|
debug:
|
|
msg: "Linode node ready: {{ node_chunk.node_name }} @ {{ wr_node_ip }} ({{ node_chunk.ip_count | int | string }} IPs)"
|