Skip to content

Commit 64a87b8

Browse files
committed
add api server task
1 parent e4e89d6 commit 64a87b8

4 files changed

Lines changed: 227 additions & 21 deletions

File tree

README.md

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,30 @@ It is further possible to roll out playbooks.
1414

1515
| Variable name | Type | Default | Description |
1616
| ------------------------------ | ------------ | ----------------------------------------- | -------------------------------------------------------- |
17-
| attackmate_url | url | https://github.com/ait-aecid/attackmate.git | Official attackmate repository |
18-
| attackmate_version | version-str | main | Version/Branch of the Git-Repository in attackmate_url |
19-
| attackmate_shared_dir | path | /usr/local/share | Installation path |
20-
| attackmate_dest | path | `{{ attackmate_shared_dir }}/attackmate` | Installation path of the attackmate repository |
21-
| attackmate_sliverfix | bool | True | [Install sliver-fix](https://aeciddocs.ait.ac.at/attackmate/development/installation/sliverfix.html#sliver-fix) |
22-
| attackmate_grpc_dest | path | `{{ attackmate_shared_dir }}/grpc` | Temporary install grpc to this path if sliverfix is enabled |
23-
| attackmate_bindir | path | /usr/local/bin | Installpath for the tmux-wrapper |
24-
| attackmate_tmux | bool | True | Deploy tmux-wrapper |
25-
| attackmate_tmux_session | str | attackmate | Use this existing session-name for the tmux-wrapper |
26-
| attackmate_tmux_window | str | attackmate | The name of the tmux-window for attackmate |
27-
| attackmate_config_dir | path | /etc/attackmate | Path to the config-directory |
28-
| attackmate_playbook_path | path | `{{ attackmate_config_dir }}/playbooks` | Path to the playbooks-directory |
29-
| attackmate_playbooks | list of playbook-templates(j2) | `[]` | List of playbooks to deploy |
30-
| attackmate_config_tpl | str | attackmate.yml.j2 | Name of the config-template(jinja) |
31-
| attackmate_sliver_config | path | **None** | Path to the generated sliver-config. (only needed for sliver-commands) |
32-
| attackmate_msf_server | hostname | **None** | Hostname of the Metasploit rpcd. (only needed for msf-commands) |
33-
| attackmate_msf_passwd | password | **None** | Password for the Metasploit rpcd. (only needed for msf-commands) |
34-
| attackmate_playwright | bool | True | Whether to install Playwright and its dependencies |
35-
| command_delay | float | **None** | delay in seconds before commands for the CommandConfig |
36-
| attackmate_remote_config | dict | {} | Optional map of named remote AttackMate connections. Each entry requires url, username, password, and optionally cafile. If empty, no remote_config section is written to the config file. |
17+
| attackmate_url | url | https://github.com/ait-aecid/attackmate.git | Official attackmate repository |
18+
| attackmate_version | version-str | main | Version/Branch of the Git-Repository in attackmate_url |
19+
| attackmate_shared_dir | path | /usr/local/share | Installation path |
20+
| attackmate_dest | path | `{{ attackmate_shared_dir }}/attackmate` | Installation path of the attackmate repository |
21+
| attackmate_sliverfix | bool | True | [Install sliver-fix](https://aeciddocs.ait.ac.at/attackmate/development/installation/sliverfix.html#sliver-fix) |
22+
| attackmate_grpc_dest | path | `{{ attackmate_shared_dir }}/grpc` | Temporary install grpc to this path if sliverfix is enabled |
23+
| attackmate_bindir | path | /usr/local/bin | Installpath for the tmux-wrapper |
24+
| attackmate_tmux | bool | True | Deploy tmux-wrapper |
25+
| attackmate_tmux_session | str | attackmate | Use this existing session-name for the tmux-wrapper |
26+
| attackmate_tmux_window | str | attackmate | The name of the tmux-window for attackmate |
27+
| attackmate_config_dir | path | /etc/attackmate | Path to the config-directory |
28+
| attackmate_playbook_path | path | `{{ attackmate_config_dir }}/playbooks` | Path to the playbooks-directory |
29+
| attackmate_playbooks | list of playbook-templates(j2) | `[]` | List of playbooks to deploy |
30+
| attackmate_config_tpl | str | attackmate.yml.j2 | Name of the config-template(jinja) |
31+
| attackmate_sliver_config | path | **None** | Path to the generated sliver-config. (only needed for sliver-commands) |
32+
| attackmate_msf_server | hostname | **None** | Hostname of the Metasploit rpcd. (only needed for msf-commands) |
33+
| attackmate_msf_passwd | password | **None** | Password for the Metasploit rpcd. (only needed for msf-commands) |
34+
| attackmate_playwright | bool | True | Whether to install Playwright and its dependencies |
35+
| command_delay | float | **None** | delay in seconds before commands for the CommandConfig |
36+
| attackmate_remote_config | dict | {} | Optional map of named remote AttackMate connections. Each entry requires url, username, password, and optionally cafile. If empty, no remote_config section is written to the config file.|
37+
| attackmate_api_server | bool | False | Install the attackmate-api-server |
38+
| attackmate_api_server_url | url | https://github.com/ait-testbed/attackmate-api-server.git | Repository URL for the api server |
39+
| attackmate_api_server_version | version-str | main | Version/Branch of the api server repository |
40+
| attackmate_api_server_dest | path | {{ attackmate_shared_dir }}/attackmate-api-server | Installation path of the api server |
3741

3842
## Example Playbook
3943

@@ -66,6 +70,27 @@ This role installs to executables:
6670
* **/usr/local/bin/attackm8**: a wrapper for attackmate that uses the virtual environment
6771
* **/usr/local/bin/attackmate-tmux**: a wrapper that executes attackmate in a tmux-session
6872
73+
## Installing as API Server
74+
75+
AttackMate can optionally be installed together with the [AttackMate API Server](https://github.com/ait-testbed/attackmate-api-server),
76+
which exposes AttackMate's functionality via a REST API and allows remote instances to be controlled over the network.
77+
The API server is installed into the same virtual environment as AttackMate, since it depends on it.
78+
79+
To enable the API server, set `attackmate_api_server: True` in your playbook:
80+
```yaml
81+
- name: Install attackmate with API server
82+
become: true
83+
hosts: localhost
84+
roles:
85+
- role: attackmate
86+
vars:
87+
attackmate_api_server: True
88+
```
89+
90+
installs to executables:
91+
92+
* **/usr/local/bin/attackmate-api-server**: a wrapper for attackmate that uses the virtual environment
93+
6994
## Role testing with molecule
7095

7196
### Role testing locally

defaults/main.yml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,16 @@ distribution_lower: "{{ ansible_distribution | lower }}"
5151
# username: user
5252
# password: anotherpassword
5353
# cafile: "/path/to/another_cert.pem"
54-
attackmate_remote_config: {}
54+
55+
# If no Remote AttackMate connections configured set to empty dict
56+
attackmate_remote_config: {}
57+
58+
# Installation as api server
59+
attackmate_api_server: False
60+
attackmate_api_server_url: "https://github.com/ait-testbed/attackmate-api-server.git"
61+
attackmate_api_server_version: "main"
62+
attackmate_api_server_dest: "{{ attackmate_shared_dir }}/attackmate-api-server"
63+
64+
attackmate_api_logs_to_disk: "False"
65+
attackmate_api_log_dir: "/var/log/attackmate-api"
66+

tasks/api_server.yml

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
- name: Git checkout attackmate-api-server
2+
ansible.builtin.git:
3+
repo: "{{ attackmate_api_server_url }}"
4+
dest: "{{ attackmate_api_server_dest }}"
5+
version: "{{ attackmate_api_server_version }}"
6+
tags:
7+
- molecule-idempotence-notest
8+
9+
- name: Install attackmate-api-server with uv
10+
become: true
11+
ansible.builtin.shell:
12+
chdir: "{{ attackmate_api_server_dest }}"
13+
cmd: "uv pip install --python {{ attackmate_dest }}/.venv/bin/python ."
14+
tags:
15+
- molecule-idempotence-notest
16+
17+
- name: Create dedicated API service user
18+
become: true
19+
ansible.builtin.user:
20+
name: attackmate-api
21+
system: yes
22+
shell: /usr/sbin/nologin
23+
create_home: no
24+
25+
- name: Create symlink for attackmate-api-server executable
26+
become: true
27+
ansible.builtin.file:
28+
src: "{{ attackmate_dest }}/.venv/bin/attackmate-api"
29+
dest: "/usr/local/bin/attackmate-api"
30+
state: link
31+
force: true
32+
33+
- name: Get site-packages path from the venv
34+
become: true
35+
ansible.builtin.shell:
36+
cmd: "{{ attackmate_dest }}/.venv/bin/python -c 'import site; print(site.getsitepackages()[0])'"
37+
register: venv_site_packages
38+
changed_when: false
39+
40+
- name: Set API package destination path
41+
ansible.builtin.set_fact:
42+
api_package_path: "{{ venv_site_packages.stdout }}/attackmate_api_server"
43+
44+
- name: Create API log directory
45+
become: true
46+
ansible.builtin.file:
47+
path: "{{ attackmate_api_log_dir }}"
48+
state: directory
49+
mode: '0755'
50+
51+
- name: Ensure SSL directories exist with correct permissions
52+
become: true
53+
ansible.builtin.file:
54+
path: "{{ item.path }}"
55+
state: directory
56+
owner: root
57+
group: root
58+
mode: "{{ item.mode }}"
59+
loop:
60+
- { path: '/etc/ssl/private', mode: '0711' }
61+
- { path: '/etc/ssl/certs', mode: '0755' }
62+
63+
- name: Ensure OpenSSL is installed
64+
ansible.builtin.package:
65+
name: openssl
66+
state: present
67+
68+
- name: Generate Private Key
69+
community.crypto.openssl_privatekey:
70+
path: "/etc/ssl/private/attackmate.key"
71+
type: RSA
72+
size: 4096
73+
owner: root
74+
group: attackmate-api
75+
mode: '0640'
76+
77+
- name: Generate Certificate Signing Request (CSR)
78+
community.crypto.openssl_csr:
79+
path: "/etc/ssl/private/attackmate.csr"
80+
privatekey_path: "/etc/ssl/private/attackmate.key"
81+
common_name: "{{ ansible_host }}"
82+
subject_alt_name: "IP:{{ ansible_host }},DNS:localhost"
83+
84+
- name: Generate Self-Signed Certificate
85+
community.crypto.x509_certificate:
86+
path: "/etc/ssl/certs/attackmate.pem"
87+
privatekey_path: "/etc/ssl/private/attackmate.key"
88+
csr_path: "/etc/ssl/private/attackmate.csr"
89+
provider: selfsigned
90+
91+
- name: Create .env file in project root
92+
become: true
93+
ansible.builtin.copy:
94+
dest: "{{ attackmate_api_server_dest }}/.env"
95+
content: |
96+
SSL_KEY_PATH="/etc/ssl/private/attackmate.key"
97+
SSL_CERT_PATH="/etc/ssl/certs/attackmate.pem"
98+
ATTACKMATE_CONFIG_PATH="/etc/attackmate.yml"
99+
WRITE_PLAYBOOK_LOGS_TO_DISK="{{ attackmate_api_logs_to_disk }}"
100+
LOG_DIR="{{ attackmate_api_log_dir }}"
101+
owner: attackmate-api
102+
group: attackmate-api
103+
mode: '0600' # Only the API user can read the secrets
104+
105+
106+
107+
- name: Ensure API log directory is owned by the service user
108+
become: true
109+
ansible.builtin.file:
110+
path: "{{ attackmate_api_log_dir }}"
111+
state: directory
112+
owner: attackmate-api
113+
group: attackmate-api
114+
mode: '0750'
115+
116+
- name: Fix permissions on SSL keys for the service user
117+
become: true
118+
ansible.builtin.file:
119+
path: "{{ item.path }}"
120+
owner: root
121+
group: attackmate-api # Allow the API user to read the key
122+
mode: "{{ item.mode }}"
123+
loop:
124+
- { path: '/etc/ssl/private', mode: '0710' }
125+
- { path: '/etc/ssl/private/attackmate.key', mode: '0640' }
126+
- { path: '/etc/ssl/certs/attackmate.pem', mode: '0644' }
127+
128+
- name: Install AttackMate API Systemd service
129+
become: true
130+
ansible.builtin.copy:
131+
dest: /etc/systemd/system/attackmate-api.service
132+
content: |
133+
[Unit]
134+
Description=AttackMate API Server
135+
After=network.target
136+
137+
[Service]
138+
Type=simple
139+
User=attackmate-api
140+
Group=attackmate-api
141+
# This tells Pydantic where to look for the .env file
142+
WorkingDirectory={{ attackmate_api_server_dest }}
143+
ExecStart=/usr/local/bin/attackmate-api
144+
Restart=always
145+
146+
NoNewPrivileges=yes
147+
PrivateTmp=yes
148+
ProtectSystem=full
149+
ProtectHome=yes
150+
151+
[Install]
152+
WantedBy=multi-user.target
153+
154+
- name: Start and enable AttackMate API
155+
become: true
156+
ansible.builtin.systemd:
157+
name: attackmate-api
158+
state: restarted
159+
enabled: yes
160+
daemon_reload: yes

tasks/main.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,12 @@
156156
tags:
157157
- playwright
158158
when: attackmate_playwright
159+
160+
- name: Include api_server setup
161+
ansible.builtin.include_tasks:
162+
file: "api_server.yml"
163+
apply:
164+
tags:
165+
- api_server
166+
when: attackmate_api_server
167+

0 commit comments

Comments
 (0)